Fix bug where path shortening breaks ColorStateLists

Android resource loader uses the file path to check if a resource is a
ColorStateList. Path shortening removed that part of the path and thus
broke the resource loader of APKs optimized with path shortening. This
cl skips path shortening for resources under "res/color/"

Test: make aapt2_tests
Bug: b/75965637

Change-Id: If94dfa398efd81522d4faed157afd35f6dabe856
diff --git a/tools/aapt2/optimize/ResourcePathShortener.cpp b/tools/aapt2/optimize/ResourcePathShortener.cpp
index c5df3dd..845262b 100644
--- a/tools/aapt2/optimize/ResourcePathShortener.cpp
+++ b/tools/aapt2/optimize/ResourcePathShortener.cpp
@@ -95,6 +95,10 @@
     android::StringPiece res_subdir, actual_filename, extension;
     util::ExtractResFilePathParts(*file_ref->path, &res_subdir, &actual_filename, &extension);
 
+    // Android detects ColorStateLists via pathname, skip res/color/*
+    if (res_subdir == android::StringPiece("res/color/"))
+      continue;
+
     std::string shortened_filename = ShortenFileName(*file_ref->path, num_chars);
     int collision_count = 0;
     std::string shortened_path = GetShortenedPath(shortened_filename, extension, collision_count);
diff --git a/tools/aapt2/optimize/ResourcePathShortener_test.cpp b/tools/aapt2/optimize/ResourcePathShortener_test.cpp
index 88cadc7..efbef8f 100644
--- a/tools/aapt2/optimize/ResourcePathShortener_test.cpp
+++ b/tools/aapt2/optimize/ResourcePathShortener_test.cpp
@@ -24,6 +24,11 @@
 using ::testing::NotNull;
 using ::testing::Eq;
 
+android::StringPiece GetExtension(android::StringPiece path) {
+  auto iter = std::find(path.begin(), path.end(), '.');
+  return android::StringPiece(iter, path.end() - iter);
+}
+
 namespace aapt {
 
 TEST(ResourcePathShortenerTest, FileRefPathsChangedInResourceTable) {
@@ -64,4 +69,45 @@
   EXPECT_THAT(path_map.find("res/should/still/be/the/same.png"), Eq(path_map.end()));
 }
 
+TEST(ResourcePathShortenerTest, SkipColorFileRefPaths) {
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+  std::unique_ptr<ResourceTable> table =
+      test::ResourceTableBuilder()
+          .AddFileReference("android:color/colorlist", "res/color/colorlist.xml")
+          .Build();
+
+  std::map<std::string, std::string> path_map;
+  ASSERT_TRUE(ResourcePathShortener(path_map).Consume(context.get(), table.get()));
+
+  // Expect that the path map to not contain the ColorStateList
+  ASSERT_THAT(path_map.find("res/color/colorlist.xml"), Eq(path_map.end()));
+}
+
+TEST(ResourcePathShortenerTest, KeepExtensions) {
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+  std::string original_xml_path = "res/drawable/xmlfile.xml";
+  std::string original_png_path = "res/drawable/pngfile.png";
+
+  std::unique_ptr<ResourceTable> table =
+      test::ResourceTableBuilder()
+          .AddFileReference("android:color/xmlfile", original_xml_path)
+          .AddFileReference("android:color/pngfile", original_png_path)
+          .Build();
+
+  std::map<std::string, std::string> path_map;
+  ASSERT_TRUE(ResourcePathShortener(path_map).Consume(context.get(), table.get()));
+
+  // Expect that the path map is populated
+  ASSERT_THAT(path_map.find("res/drawable/xmlfile.xml"), Not(Eq(path_map.end())));
+  ASSERT_THAT(path_map.find("res/drawable/pngfile.png"), Not(Eq(path_map.end())));
+
+  auto shortend_xml_path = path_map[original_xml_path];
+  auto shortend_png_path = path_map[original_png_path];
+
+  EXPECT_THAT(GetExtension(path_map[original_xml_path]), Eq(android::StringPiece(".xml")));
+  EXPECT_THAT(GetExtension(path_map[original_png_path]), Eq(android::StringPiece(".png")));
+}
+
 }   // namespace aapt