AAPT2: Support CtsContentTestCases build

- Add <feature-group> to ManifestFixer.
- Support <meta-data> in <instrumentation>
- Add support for <bag> and type="configVarying". Some CTS tests use this
  old notation, we need to support it (even though configVarying isn't
  anything supported by the framework convention).

Change-Id: I6946fa633ce513ea8437c1496db883cf27dcf6de
Test: make aapt2_tests
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 79379fe..1c750c6 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -338,50 +338,52 @@
   using BagParseFunc = std::function<bool(ResourceParser*, xml::XmlPullParser*,
                                           ParsedResource*)>;
 
-  static const auto elToItemMap =
-      ImmutableMap<std::string, ItemTypeFormat>::CreatePreSorted({
-          {"bool", {ResourceType::kBool, android::ResTable_map::TYPE_BOOLEAN}},
-          {"color", {ResourceType::kColor, android::ResTable_map::TYPE_COLOR}},
-          {"dimen",
-           {ResourceType::kDimen, android::ResTable_map::TYPE_FLOAT |
-                                      android::ResTable_map::TYPE_FRACTION |
-                                      android::ResTable_map::TYPE_DIMENSION}},
-          {"drawable",
-           {ResourceType::kDrawable, android::ResTable_map::TYPE_COLOR}},
-          {"fraction",
-           {ResourceType::kFraction,
-            android::ResTable_map::TYPE_FLOAT |
-                android::ResTable_map::TYPE_FRACTION |
-                android::ResTable_map::TYPE_DIMENSION}},
-          {"integer",
-           {ResourceType::kInteger, android::ResTable_map::TYPE_INTEGER}},
-          {"string",
-           {ResourceType::kString, android::ResTable_map::TYPE_STRING}},
-      });
+  static const auto elToItemMap = ImmutableMap<std::string, ItemTypeFormat>::CreatePreSorted({
+      {"bool", {ResourceType::kBool, android::ResTable_map::TYPE_BOOLEAN}},
+      {"color", {ResourceType::kColor, android::ResTable_map::TYPE_COLOR}},
+      {"configVarying", {ResourceType::kConfigVarying, android::ResTable_map::TYPE_ANY}},
+      {"dimen",
+       {ResourceType::kDimen,
+        android::ResTable_map::TYPE_FLOAT | android::ResTable_map::TYPE_FRACTION |
+            android::ResTable_map::TYPE_DIMENSION}},
+      {"drawable", {ResourceType::kDrawable, android::ResTable_map::TYPE_COLOR}},
+      {"fraction",
+       {ResourceType::kFraction,
+        android::ResTable_map::TYPE_FLOAT | android::ResTable_map::TYPE_FRACTION |
+            android::ResTable_map::TYPE_DIMENSION}},
+      {"integer", {ResourceType::kInteger, android::ResTable_map::TYPE_INTEGER}},
+      {"string", {ResourceType::kString, android::ResTable_map::TYPE_STRING}},
+  });
 
-  static const auto elToBagMap =
-      ImmutableMap<std::string, BagParseFunc>::CreatePreSorted({
-          {"add-resource", std::mem_fn(&ResourceParser::ParseAddResource)},
-          {"array", std::mem_fn(&ResourceParser::ParseArray)},
-          {"attr", std::mem_fn(&ResourceParser::ParseAttr)},
-          {"declare-styleable",
-           std::mem_fn(&ResourceParser::ParseDeclareStyleable)},
-          {"integer-array", std::mem_fn(&ResourceParser::ParseIntegerArray)},
-          {"java-symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
-          {"plurals", std::mem_fn(&ResourceParser::ParsePlural)},
-          {"public", std::mem_fn(&ResourceParser::ParsePublic)},
-          {"public-group", std::mem_fn(&ResourceParser::ParsePublicGroup)},
-          {"string-array", std::mem_fn(&ResourceParser::ParseStringArray)},
-          {"style", std::mem_fn(&ResourceParser::ParseStyle)},
-          {"symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
-      });
+  static const auto elToBagMap = ImmutableMap<std::string, BagParseFunc>::CreatePreSorted({
+      {"add-resource", std::mem_fn(&ResourceParser::ParseAddResource)},
+      {"array", std::mem_fn(&ResourceParser::ParseArray)},
+      {"attr", std::mem_fn(&ResourceParser::ParseAttr)},
+      {"configVarying",
+       std::bind(&ResourceParser::ParseStyle, std::placeholders::_1, ResourceType::kConfigVarying,
+                 std::placeholders::_2, std::placeholders::_3)},
+      {"declare-styleable", std::mem_fn(&ResourceParser::ParseDeclareStyleable)},
+      {"integer-array", std::mem_fn(&ResourceParser::ParseIntegerArray)},
+      {"java-symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
+      {"plurals", std::mem_fn(&ResourceParser::ParsePlural)},
+      {"public", std::mem_fn(&ResourceParser::ParsePublic)},
+      {"public-group", std::mem_fn(&ResourceParser::ParsePublicGroup)},
+      {"string-array", std::mem_fn(&ResourceParser::ParseStringArray)},
+      {"style", std::bind(&ResourceParser::ParseStyle, std::placeholders::_1, ResourceType::kStyle,
+                          std::placeholders::_2, std::placeholders::_3)},
+      {"symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
+  });
 
   std::string resource_type = parser->element_name();
 
   // The value format accepted for this resource.
   uint32_t resource_format = 0u;
 
+  bool can_be_item = true;
+  bool can_be_bag = true;
   if (resource_type == "item") {
+    can_be_bag = false;
+
     // Items have their type encoded in the type attribute.
     if (Maybe<StringPiece> maybe_type =
             xml::FindNonEmptyAttribute(parser, "type")) {
@@ -406,6 +408,17 @@
         return false;
       }
     }
+  } else if (resource_type == "bag") {
+    can_be_item = false;
+
+    // Bags have their type encoded in the type attribute.
+    if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
+      resource_type = maybe_type.value().to_string();
+    } else {
+      diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+                   << "<bag> must have a 'type' attribute");
+      return false;
+    }
   }
 
   // Get the name of the resource. This will be checked later, because not all
@@ -426,36 +439,61 @@
     return true;
   }
 
-  const auto item_iter = elToItemMap.find(resource_type);
-  if (item_iter != elToItemMap.end()) {
-    // This is an item, record its type and format and start parsing.
+  if (can_be_item) {
+    const auto item_iter = elToItemMap.find(resource_type);
+    if (item_iter != elToItemMap.end()) {
+      // This is an item, record its type and format and start parsing.
 
-    if (!maybe_name) {
-      diag_->Error(DiagMessage(out_resource->source)
-                   << "<" << parser->element_name()
-                   << "> missing 'name' attribute");
-      return false;
+      if (!maybe_name) {
+        diag_->Error(DiagMessage(out_resource->source)
+                     << "<" << parser->element_name() << "> missing 'name' attribute");
+        return false;
+      }
+
+      out_resource->name.type = item_iter->second.type;
+      out_resource->name.entry = maybe_name.value().to_string();
+
+      // Only use the implicit format for this type if it wasn't overridden.
+      if (!resource_format) {
+        resource_format = item_iter->second.format;
+      }
+
+      if (!ParseItem(parser, out_resource, resource_format)) {
+        return false;
+      }
+      return true;
     }
-
-    out_resource->name.type = item_iter->second.type;
-    out_resource->name.entry = maybe_name.value().to_string();
-
-    // Only use the implicit format for this type if it wasn't overridden.
-    if (!resource_format) {
-      resource_format = item_iter->second.format;
-    }
-
-    if (!ParseItem(parser, out_resource, resource_format)) {
-      return false;
-    }
-    return true;
   }
 
   // This might be a bag or something.
-  const auto bag_iter = elToBagMap.find(resource_type);
-  if (bag_iter != elToBagMap.end()) {
-    // Ensure we have a name (unless this is a <public-group>).
-    if (resource_type != "public-group") {
+  if (can_be_bag) {
+    const auto bag_iter = elToBagMap.find(resource_type);
+    if (bag_iter != elToBagMap.end()) {
+      // Ensure we have a name (unless this is a <public-group>).
+      if (resource_type != "public-group") {
+        if (!maybe_name) {
+          diag_->Error(DiagMessage(out_resource->source)
+                       << "<" << parser->element_name() << "> missing 'name' attribute");
+          return false;
+        }
+
+        out_resource->name.entry = maybe_name.value().to_string();
+      }
+
+      // Call the associated parse method. The type will be filled in by the
+      // parse func.
+      if (!bag_iter->second(this, parser, out_resource)) {
+        return false;
+      }
+      return true;
+    }
+  }
+
+  if (can_be_item) {
+    // Try parsing the elementName (or type) as a resource. These shall only be
+    // resources like 'layout' or 'xml' and they can only be references.
+    const ResourceType* parsed_type = ParseResourceType(resource_type);
+    if (parsed_type) {
       if (!maybe_name) {
         diag_->Error(DiagMessage(out_resource->source)
                      << "<" << parser->element_name()
@@ -463,39 +501,16 @@
         return false;
       }
 
+      out_resource->name.type = *parsed_type;
       out_resource->name.entry = maybe_name.value().to_string();
+      out_resource->value = ParseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString);
+      if (!out_resource->value) {
+        diag_->Error(DiagMessage(out_resource->source)
+                     << "invalid value for type '" << *parsed_type << "'. Expected a reference");
+        return false;
+      }
+      return true;
     }
-
-    // Call the associated parse method. The type will be filled in by the
-    // parse func.
-    if (!bag_iter->second(this, parser, out_resource)) {
-      return false;
-    }
-    return true;
-  }
-
-  // Try parsing the elementName (or type) as a resource. These shall only be
-  // resources like 'layout' or 'xml' and they can only be references.
-  const ResourceType* parsed_type = ParseResourceType(resource_type);
-  if (parsed_type) {
-    if (!maybe_name) {
-      diag_->Error(DiagMessage(out_resource->source)
-                   << "<" << parser->element_name()
-                   << "> missing 'name' attribute");
-      return false;
-    }
-
-    out_resource->name.type = *parsed_type;
-    out_resource->name.entry = maybe_name.value().to_string();
-    out_resource->value =
-        ParseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString);
-    if (!out_resource->value) {
-      diag_->Error(DiagMessage(out_resource->source)
-                   << "invalid value for type '" << *parsed_type
-                   << "'. Expected a reference");
-      return false;
-    }
-    return true;
   }
 
   diag_->Warn(DiagMessage(out_resource->source)
@@ -1048,9 +1063,9 @@
   return true;
 }
 
-bool ResourceParser::ParseStyle(xml::XmlPullParser* parser,
+bool ResourceParser::ParseStyle(const ResourceType type, xml::XmlPullParser* parser,
                                 ParsedResource* out_resource) {
-  out_resource->name.type = ResourceType::kStyle;
+  out_resource->name.type = type;
 
   std::unique_ptr<Style> style = util::make_unique<Style>();