First pass at flagged resources

This gets the main parts of resource flagging in place and the basic use
case of flagging with an xml attribute working.

Test: Automated
Bug: 329436914
Flag: EXEMPT Aconfig not supported on host tools
Change-Id: Id2b5ba450d05da00a922e98ca204b6e5aa6c6c24
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 6af39b7..2df9418 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 #include "ResourceParser.h"
 
 #include <functional>
@@ -108,6 +107,7 @@
   Visibility::Level visibility_level = Visibility::Level::kUndefined;
   bool staged_api = false;
   bool allow_new = false;
+  FlagStatus flag_status;
   std::optional<OverlayableItem> overlayable_item;
   std::optional<StagedId> staged_alias;
 
@@ -161,6 +161,8 @@
     res_builder.SetStagedId(res->staged_alias.value());
   }
 
+  res_builder.SetFlagStatus(res->flag_status);
+
   bool error = false;
   if (!res->name.entry.empty()) {
     if (!table->AddResource(res_builder.Build(), diag)) {
@@ -544,6 +546,30 @@
   });
 
   std::string resource_type = parser->element_name();
+  std::optional<StringPiece> flag =
+      xml::FindAttribute(parser, "http://schemas.android.com/apk/res/android", "featureFlag");
+  out_resource->flag_status = FlagStatus::NoFlag;
+  if (flag) {
+    auto flag_it = options_.feature_flag_values.find(flag.value());
+    if (flag_it == options_.feature_flag_values.end()) {
+      diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
+                   << "Resource flag value undefined");
+      return false;
+    }
+    const auto& flag_properties = flag_it->second;
+    if (!flag_properties.read_only) {
+      diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
+                   << "Only read only flags may be used with resources");
+      return false;
+    }
+    if (!flag_properties.enabled.has_value()) {
+      diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
+                   << "Only flags with a value may be used with resources");
+      return false;
+    }
+    out_resource->flag_status =
+        flag_properties.enabled.value() ? FlagStatus::Enabled : FlagStatus::Disabled;
+  }
 
   // The value format accepted for this resource.
   uint32_t resource_format = 0u;