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/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index a3b0b45..1cdb715 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -231,6 +231,47 @@
   return false;
 }
 
+ResourceTable::CollisionResult ResourceTable::ResolveFlagCollision(FlagStatus existing,
+                                                                   FlagStatus incoming) {
+  switch (existing) {
+    case FlagStatus::NoFlag:
+      switch (incoming) {
+        case FlagStatus::NoFlag:
+          return CollisionResult::kConflict;
+        case FlagStatus::Disabled:
+          return CollisionResult::kKeepOriginal;
+        case FlagStatus::Enabled:
+          return CollisionResult::kTakeNew;
+        default:
+          return CollisionResult::kConflict;
+      }
+    case FlagStatus::Disabled:
+      switch (incoming) {
+        case FlagStatus::NoFlag:
+          return CollisionResult::kTakeNew;
+        case FlagStatus::Disabled:
+          return CollisionResult::kKeepOriginal;
+        case FlagStatus::Enabled:
+          return CollisionResult::kTakeNew;
+        default:
+          return CollisionResult::kConflict;
+      }
+    case FlagStatus::Enabled:
+      switch (incoming) {
+        case FlagStatus::NoFlag:
+          return CollisionResult::kKeepOriginal;
+        case FlagStatus::Disabled:
+          return CollisionResult::kKeepOriginal;
+        case FlagStatus::Enabled:
+          return CollisionResult::kConflict;
+        default:
+          return CollisionResult::kConflict;
+      }
+    default:
+      return CollisionResult::kConflict;
+  }
+}
+
 // The default handler for collisions.
 //
 // Typically, a weak value will be overridden by a strong value. An existing weak
@@ -564,16 +605,21 @@
     if (!config_value->value) {
       // Resource does not exist, add it now.
       config_value->value = std::move(res.value);
+      config_value->flag_status = res.flag_status;
     } else {
       // When validation is enabled, ensure that a resource cannot have multiple values defined for
-      // the same configuration.
-      auto result = validate ? ResolveValueCollision(config_value->value.get(), res.value.get())
+      // the same configuration unless protected by flags.
+      auto result = validate ? ResolveFlagCollision(config_value->flag_status, res.flag_status)
                              : CollisionResult::kKeepBoth;
+      if (result == CollisionResult::kConflict) {
+        result = ResolveValueCollision(config_value->value.get(), res.value.get());
+      }
       switch (result) {
         case CollisionResult::kKeepBoth:
           // Insert the value ignoring for duplicate configurations
           entry->values.push_back(util::make_unique<ResourceConfigValue>(res.config, res.product));
           entry->values.back()->value = std::move(res.value);
+          entry->values.back()->flag_status = res.flag_status;
           break;
 
         case CollisionResult::kTakeNew:
@@ -735,6 +781,11 @@
   return *this;
 }
 
+NewResourceBuilder& NewResourceBuilder::SetFlagStatus(FlagStatus flag_status) {
+  res_.flag_status = flag_status;
+  return *this;
+}
+
 NewResource NewResourceBuilder::Build() {
   return std::move(res_);
 }