AAPT2: Include package name of attributes in styleable from another package

Change-Id: I44f902e297238e7ee4ae27c02aaaf9e148652d2a
diff --git a/tools/aapt2/JavaClassGenerator.cpp b/tools/aapt2/JavaClassGenerator.cpp
index 3f92f18..2bb0e65 100644
--- a/tools/aapt2/JavaClassGenerator.cpp
+++ b/tools/aapt2/JavaClassGenerator.cpp
@@ -94,12 +94,12 @@
     std::u16string* entryName = static_cast<GenArgs&>(a).entryName;
 
     // This must be sorted by resource ID.
-    std::vector<std::pair<ResourceId, StringPiece16>> sortedAttributes;
+    std::vector<std::pair<ResourceId, ResourceNameRef>> sortedAttributes;
     sortedAttributes.reserve(styleable.entries.size());
     for (const auto& attr : styleable.entries) {
         assert(attr.id.isValid() && "no ID set for Styleable entry");
         assert(attr.name.isValid() && "no name set for Styleable entry");
-        sortedAttributes.emplace_back(attr.id, attr.name.entry);
+        sortedAttributes.emplace_back(attr.id, attr.name);
     }
     std::sort(sortedAttributes.begin(), sortedAttributes.end());
 
@@ -124,8 +124,15 @@
     for (size_t i = 0; i < attrCount; i++) {
         *out << "        "
              << "public static" << finalModifier
-             << " int " << transform(*entryName) << "_" << transform(sortedAttributes[i].second)
-             << " = " << i << ";" << std::endl;
+             << " int " << transform(*entryName);
+
+        // We may reference IDs from other packages, so prefix the entry name with
+        // the package.
+        const ResourceNameRef& itemName = sortedAttributes[i].second;
+        if (itemName.package != mTable->getPackage()) {
+            *out << "_" << transform(itemName.package);
+        }
+        *out << "_" << transform(itemName.entry) << " = " << i << ";" << std::endl;
     }
 }
 
diff --git a/tools/aapt2/JavaClassGenerator_test.cpp b/tools/aapt2/JavaClassGenerator_test.cpp
index 57b600a..d4341b6 100644
--- a/tools/aapt2/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/JavaClassGenerator_test.cpp
@@ -16,8 +16,9 @@
 
 #include "JavaClassGenerator.h"
 #include "Linker.h"
-#include "Resolver.h"
+#include "MockResolver.h"
 #include "ResourceTable.h"
+#include "ResourceTableResolver.h"
 #include "ResourceValues.h"
 #include "Util.h"
 
@@ -84,7 +85,7 @@
               output.find("public static final int hey_dude_cool_attr = 0;"));
 }
 
-/*
+
 TEST_F(JavaClassGeneratorTest, EmitPackageMangledSymbols) {
     ASSERT_TRUE(addResource(ResourceName{ {}, ResourceType::kId, u"foo" },
                             ResourceId{ 0x01, 0x02, 0x0000 }));
@@ -94,9 +95,8 @@
                                   SourceLine{ "lib.xml", 33 }, util::make_unique<Id>()));
     ASSERT_TRUE(mTable->merge(std::move(table)));
 
-    std::shared_ptr<Resolver> resolver = std::make_shared<Resolver>(mTable,
-            std::make_shared<const android::AssetManager>());
-    Linker linker(mTable, resolver);
+    Linker linker(mTable, std::make_shared<MockResolver>(mTable,
+                                                         std::map<ResourceName, ResourceId>()));
     ASSERT_TRUE(linker.linkAndValidate());
 
     JavaClassGenerator generator(mTable, {});
@@ -112,6 +112,34 @@
     output = out.str();
     EXPECT_NE(std::string::npos, output.find("int test ="));
     EXPECT_EQ(std::string::npos, output.find("int foo ="));
-}*/
+}
+
+TEST_F(JavaClassGeneratorTest, EmitOtherPackagesAttributesInStyleable) {
+    std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
+    styleable->entries.emplace_back(ResourceNameRef{ mTable->getPackage(),
+                                                     ResourceType::kAttr,
+                                                     u"bar" });
+    styleable->entries.emplace_back(ResourceNameRef{ u"com.lib", ResourceType::kAttr, u"bar" });
+    ASSERT_TRUE(mTable->addResource(ResourceName{ {}, ResourceType::kStyleable, u"Foo" }, {}, {},
+                                    std::move(styleable)));
+
+    std::shared_ptr<IResolver> resolver = std::make_shared<MockResolver>(mTable,
+            std::map<ResourceName, ResourceId>({
+                    { ResourceName{ u"android", ResourceType::kAttr, u"bar" },
+                      ResourceId{ 0x01, 0x01, 0x0000 } },
+                    { ResourceName{ u"com.lib", ResourceType::kAttr, u"bar" },
+                      ResourceId{ 0x02, 0x01, 0x0000 } }}));
+
+    Linker linker(mTable, resolver);
+    ASSERT_TRUE(linker.linkAndValidate());
+
+    JavaClassGenerator generator(mTable, {});
+
+    std::stringstream out;
+    EXPECT_TRUE(generator.generate(mTable->getPackage(), out));
+    std::string output = out.str();
+    EXPECT_NE(std::string::npos, output.find("int Foo_bar ="));
+    EXPECT_NE(std::string::npos, output.find("int Foo_com_lib_bar ="));
+}
 
 } // namespace aapt
diff --git a/tools/aapt2/MockResolver.h b/tools/aapt2/MockResolver.h
new file mode 100644
index 0000000..48ff6a6
--- /dev/null
+++ b/tools/aapt2/MockResolver.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_MOCK_RESOLVER_H
+#define AAPT_MOCK_RESOLVER_H
+
+#include "Maybe.h"
+#include "Resolver.h"
+#include "Resource.h"
+#include "ResourceTable.h"
+#include "ResourceTableResolver.h"
+#include "ResourceValues.h"
+#include "StringPiece.h"
+
+#include <map>
+#include <string>
+
+namespace aapt {
+
+struct MockResolver : public IResolver {
+    MockResolver(const std::shared_ptr<ResourceTable>& table,
+                 const std::map<ResourceName, ResourceId>& items) :
+            mResolver(std::make_shared<ResourceTableResolver>(
+                        table, std::make_shared<const android::AssetManager>())),
+            mAttr(false, android::ResTable_map::TYPE_ANY), mItems(items) {
+    }
+
+    virtual Maybe<ResourceId> findId(const ResourceName& name) override {
+        Maybe<ResourceId> result = mResolver->findId(name);
+        if (result) {
+            return result;
+        }
+
+        const auto iter = mItems.find(name);
+        if (iter != mItems.end()) {
+            return iter->second;
+        }
+        return {};
+    }
+
+    virtual Maybe<Entry> findAttribute(const ResourceName& name) override {
+        Maybe<Entry> tableResult = mResolver->findAttribute(name);
+        if (tableResult) {
+            return tableResult;
+        }
+
+        Maybe<ResourceId> result = findId(name);
+        if (result) {
+            if (name.type == ResourceType::kAttr) {
+                return Entry{ result.value(), &mAttr };
+            } else {
+                return Entry{ result.value() };
+            }
+        }
+        return {};
+    }
+
+    virtual Maybe<ResourceName> findName(ResourceId resId) override {
+        Maybe<ResourceName> result = mResolver->findName(resId);
+        if (result) {
+            return result;
+        }
+
+        for (auto& p : mItems) {
+            if (p.second == resId) {
+                return p.first;
+            }
+        }
+        return {};
+    }
+
+private:
+    std::shared_ptr<ResourceTableResolver> mResolver;
+    Attribute mAttr;
+    std::map<ResourceName, ResourceId> mItems;
+};
+
+} // namespace aapt
+
+#endif // AAPT_MOCK_RESOLVER_H
diff --git a/tools/aapt2/Resolver.h b/tools/aapt2/Resolver.h
index 2c9a8e5..cb9318e 100644
--- a/tools/aapt2/Resolver.h
+++ b/tools/aapt2/Resolver.h
@@ -52,12 +52,6 @@
     };
 
     /**
-     * Return the package to use when none is specified. This
-     * is the package name of the app being built.
-     */
-    virtual const std::u16string& getDefaultPackage() const = 0;
-
-    /**
      * Returns a ResourceID if the name is found. The ResourceID
      * may not be valid if the resource was not assigned an ID.
      */
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index 31104fbe..fa9ac07 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -96,6 +96,8 @@
     ResourceNameRef(ResourceNameRef&&) = default;
     ResourceNameRef(const ResourceName& rhs);
     ResourceNameRef(const StringPiece16& p, ResourceType t, const StringPiece16& e);
+    ResourceNameRef& operator=(const ResourceNameRef& rhs) = default;
+    ResourceNameRef& operator=(ResourceNameRef&& rhs) = default;
     ResourceNameRef& operator=(const ResourceName& rhs);
 
     ResourceName toResourceName() const;
diff --git a/tools/aapt2/ResourceTableResolver.h b/tools/aapt2/ResourceTableResolver.h
index 83818c2..c8e8ab7 100644
--- a/tools/aapt2/ResourceTableResolver.h
+++ b/tools/aapt2/ResourceTableResolver.h
@@ -45,8 +45,6 @@
 
     ResourceTableResolver(const ResourceTableResolver&) = delete; // Not copyable.
 
-    virtual const std::u16string& getDefaultPackage() const override;
-
     virtual Maybe<ResourceId> findId(const ResourceName& name) override;
 
     virtual Maybe<Entry> findAttribute(const ResourceName& name) override;
@@ -69,10 +67,6 @@
     std::unordered_set<std::u16string> mIncludedPackages;
 };
 
-inline const std::u16string& ResourceTableResolver::getDefaultPackage() const {
-    return mTable->getPackage();
-}
-
 inline const android::ResTable& ResourceTableResolver::getResTable() const {
     return mSources->getResources(false);
 }
diff --git a/tools/aapt2/XmlFlattener_test.cpp b/tools/aapt2/XmlFlattener_test.cpp
index d2139d0..b45cd9b 100644
--- a/tools/aapt2/XmlFlattener_test.cpp
+++ b/tools/aapt2/XmlFlattener_test.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "Resolver.h"
+#include "MockResolver.h"
 #include "ResourceTable.h"
 #include "ResourceValues.h"
 #include "SourceXmlPullParser.h"
@@ -33,55 +33,11 @@
 
 constexpr const char* kXmlPreamble = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
 
-struct MockResolver : public IResolver {
-    MockResolver(const StringPiece16& defaultPackage,
-                 const std::map<ResourceName, ResourceId>& items) :
-            mPackage(defaultPackage.toString()), mAttr(false, ResTable_map::TYPE_ANY),
-            mItems(items) {
-    }
-
-    virtual const std::u16string& getDefaultPackage() const override {
-        return mPackage;
-    }
-
-    virtual Maybe<ResourceId> findId(const ResourceName& name) override {
-        const auto iter = mItems.find(name);
-        if (iter != mItems.end()) {
-            return iter->second;
-        }
-        return {};
-    }
-
-    virtual Maybe<Entry> findAttribute(const ResourceName& name) override {
-        Maybe<ResourceId> result = findId(name);
-        if (result) {
-            if (name.type == ResourceType::kAttr) {
-                return Entry{ result.value(), &mAttr };
-            } else {
-                return Entry{ result.value() };
-            }
-        }
-        return {};
-    }
-
-    virtual Maybe<ResourceName> findName(ResourceId resId) override {
-        for (auto& p : mItems) {
-            if (p.second == resId) {
-                return p.first;
-            }
-        }
-        return {};
-    }
-
-    std::u16string mPackage;
-    Attribute mAttr;
-    std::map<ResourceName, ResourceId> mItems;
-};
-
 class XmlFlattenerTest : public ::testing::Test {
 public:
     virtual void SetUp() override {
-        std::shared_ptr<IResolver> resolver = std::make_shared<MockResolver>(u"android",
+        std::shared_ptr<IResolver> resolver = std::make_shared<MockResolver>(
+                std::make_shared<ResourceTable>(),
                 std::map<ResourceName, ResourceId>({
                         { ResourceName{ u"android", ResourceType::kAttr, u"attr" },
                           ResourceId{ 0x01010000u } },