Retain parsed attribute type

If the value of an attribute enum is defined as a hexadecimal integer,
flatten uses of the attribute as with the
android::Res_value::TYPE_INT_HEX type.

This change adds a "type" field to pb::Attribute::Symbol, which if left
unset, will have a default value of android::Res_value::TYPE_INT_DEC
when deserialized by aapt2.

Bug: 124474141
Test: aapt2_tests and manual compilation of files and inspection using
`aapt2 dump chunks`
Change-Id: Ibf12394284fdbe3a8047f7ecf4fe68517dfc3abb
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 859fe80..c557656 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -1387,7 +1387,7 @@
 
   return Attribute::Symbol{
       Reference(ResourceNameRef({}, ResourceType::kId, maybe_name.value())),
-      val.data};
+      val.data, val.dataType};
 }
 
 bool ResourceParser::ParseStyleItem(xml::XmlPullParser* parser, Style* style) {
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 464225f..4237469 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -401,7 +401,7 @@
   std::string input = R"(
       <attr name="foo">
         <enum name="bar" value="0"/>
-        <enum name="bat" value="1"/>
+        <enum name="bat" value="0x1"/>
         <enum name="baz" value="2"/>
       </attr>)";
   ASSERT_TRUE(TestParse(input));
@@ -414,14 +414,17 @@
   ASSERT_TRUE(enum_attr->symbols[0].symbol.name);
   EXPECT_THAT(enum_attr->symbols[0].symbol.name.value().entry, Eq("bar"));
   EXPECT_THAT(enum_attr->symbols[0].value, Eq(0u));
+  EXPECT_THAT(enum_attr->symbols[0].type, Eq(Res_value::TYPE_INT_DEC));
 
   ASSERT_TRUE(enum_attr->symbols[1].symbol.name);
   EXPECT_THAT(enum_attr->symbols[1].symbol.name.value().entry, Eq("bat"));
   EXPECT_THAT(enum_attr->symbols[1].value, Eq(1u));
+  EXPECT_THAT(enum_attr->symbols[1].type, Eq(Res_value::TYPE_INT_HEX));
 
   ASSERT_TRUE(enum_attr->symbols[2].symbol.name);
   EXPECT_THAT(enum_attr->symbols[2].symbol.name.value().entry, Eq("baz"));
   EXPECT_THAT(enum_attr->symbols[2].value, Eq(2u));
+  EXPECT_THAT(enum_attr->symbols[2].type, Eq(Res_value::TYPE_INT_DEC));
 }
 
 TEST_F(ResourceParserTest, ParseFlagAttr) {
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index e0040e4..bd2ab53 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -378,7 +378,7 @@
     const ResourceName& enum_symbol_resource_name = symbol.symbol.name.value();
     if (trimmed_str == enum_symbol_resource_name.entry) {
       android::Res_value value = {};
-      value.dataType = android::Res_value::TYPE_INT_DEC;
+      value.dataType = symbol.type;
       value.data = symbol.value;
       return util::make_unique<BinaryPrimitive>(value);
     }
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index 168ad61..fe0883b 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -292,6 +292,7 @@
   struct Symbol {
     Reference symbol;
     uint32_t value;
+    uint8_t type;
 
     friend std::ostream& operator<<(std::ostream& out, const Symbol& symbol);
   };
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index b2fc084..65f4652 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -388,6 +388,9 @@
 
     // The value of the enum/flag.
     uint32 value = 4;
+
+    // The data type of the enum/flag as defined in android::Res_value.
+    uint32 type = 5;
   }
 
   // Bitmask of formats allowed for an attribute.
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index fd8e36e..fcd6aaa 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -614,6 +614,7 @@
     if (attr->type_mask & (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) {
       Attribute::Symbol symbol;
       symbol.value = util::DeviceToHost32(map_entry.value.data);
+      symbol.type = map_entry.value.dataType;
       symbol.symbol = Reference(util::DeviceToHost32(map_entry.name.ident));
       attr->symbols.push_back(std::move(symbol));
     }
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index f2e72da..b932117 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -107,7 +107,7 @@
     }
 
     for (Attribute::Symbol& s : attr->symbols) {
-      BinaryPrimitive val(Res_value::TYPE_INT_DEC, s.value);
+      BinaryPrimitive val(s.type, s.value);
       FlattenEntry(&s.symbol, &val);
     }
   }
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index bb21c1c..efbf636 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -708,6 +708,8 @@
             return {};
           }
           symbol.value = pb_symbol.value();
+          symbol.type = pb_symbol.type() != 0U ? pb_symbol.type()
+                                               : android::Res_value::TYPE_INT_DEC;
           attr->symbols.push_back(std::move(symbol));
         }
         value = std::move(attr);
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index a54822b..aa6547e 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -552,6 +552,7 @@
       SerializeItemMetaDataToPb(symbol.symbol, pb_symbol, src_pool_);
       SerializeReferenceToPb(symbol.symbol, pb_symbol->mutable_name());
       pb_symbol->set_value(symbol.value);
+      pb_symbol->set_type(symbol.type);
     }
   }
 
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index f252f33..e7f2330 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -80,7 +80,7 @@
       test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u), context->GetDiagnostics()));
   ASSERT_TRUE(table->AddResource(
       test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), "tablet",
-      test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 321u), context->GetDiagnostics()));
+      test::BuildPrimitive(android::Res_value::TYPE_INT_HEX, 321u), context->GetDiagnostics()));
 
   // Make a reference with both resource name and resource ID.
   // The reference should point to a resource outside of this table to test that both name and id
@@ -133,11 +133,13 @@
       &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "");
   ASSERT_THAT(prim, NotNull());
   EXPECT_THAT(prim->value.data, Eq(123u));
+  EXPECT_THAT(prim->value.dataType, Eq(0x10));
 
   prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
       &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "tablet");
   ASSERT_THAT(prim, NotNull());
   EXPECT_THAT(prim->value.data, Eq(321u));
+  EXPECT_THAT(prim->value.dataType, Eq(0x11));
 
   Reference* actual_ref = test::GetValue<Reference>(&new_table, "com.app.a:layout/abc");
   ASSERT_THAT(actual_ref, NotNull());
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index 61a8fbb..bc09f19 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -313,6 +313,7 @@
       symbol.symbol.name = parsed_name.value();
       symbol.symbol.id = ResourceId(map_entry.key);
       symbol.value = map_entry.value.data;
+      symbol.type = map_entry.value.dataType;
       s->attribute->symbols.push_back(std::move(symbol));
     }
   }