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