AAPT2: Fixup namespace implementation

A few pieces were missing in the namespace mangling implementation.
Namespace aware libraries now work, along with R class generation.

Bug: 64706588
Test: make AaptTestNamespace_App
Change-Id: I12f78d6aa909e782c0faf7ceaa36058f2e6c864a
diff --git a/tools/aapt2/NameMangler.h b/tools/aapt2/NameMangler.h
index 1305a4c..f1aad29 100644
--- a/tools/aapt2/NameMangler.h
+++ b/tools/aapt2/NameMangler.h
@@ -69,8 +69,7 @@
    * The mangled name should contain symbols that are illegal to define in XML,
    * so that there will never be name mangling collisions.
    */
-  static std::string MangleEntry(const std::string& package,
-                                 const std::string& name) {
+  static std::string MangleEntry(const std::string& package, const std::string& name) {
     return package + "$" + name;
   }
 
@@ -86,8 +85,8 @@
     }
 
     out_package->assign(out_name->data(), pivot);
-    out_name->assign(out_name->data() + pivot + 1,
-                     out_name->size() - (pivot + 1));
+    std::string new_name = out_name->substr(pivot + 1);
+    *out_name = std::move(new_name);
     return true;
   }
 
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index a5783a5..8f85d4f 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -605,7 +605,7 @@
   if (processed_item) {
     // Fix up the reference.
     if (Reference* ref = ValueCast<Reference>(processed_item.get())) {
-      TransformReferenceFromNamespace(parser, "", ref);
+      ResolvePackage(parser, ref);
     }
     return processed_item;
   }
@@ -1074,15 +1074,13 @@
     return false;
   }
 
-  Maybe<Reference> maybe_key =
-      ResourceUtils::ParseXmlAttributeName(maybe_name.value());
+  Maybe<Reference> maybe_key = ResourceUtils::ParseXmlAttributeName(maybe_name.value());
   if (!maybe_key) {
-    diag_->Error(DiagMessage(source) << "invalid attribute name '"
-                                     << maybe_name.value() << "'");
+    diag_->Error(DiagMessage(source) << "invalid attribute name '" << maybe_name.value() << "'");
     return false;
   }
 
-  TransformReferenceFromNamespace(parser, "", &maybe_key.value());
+  ResolvePackage(parser, &maybe_key.value());
   maybe_key.value().SetSource(source);
 
   std::unique_ptr<Item> value = ParseXml(parser, 0, kAllowRawString);
@@ -1091,8 +1089,7 @@
     return false;
   }
 
-  style->entries.push_back(
-      Style::Entry{std::move(maybe_key.value()), std::move(value)});
+  style->entries.push_back(Style::Entry{std::move(maybe_key.value()), std::move(value)});
   return true;
 }
 
@@ -1104,21 +1101,18 @@
 
   Maybe<StringPiece> maybe_parent = xml::FindAttribute(parser, "parent");
   if (maybe_parent) {
-    // If the parent is empty, we don't have a parent, but we also don't infer
-    // either.
+    // If the parent is empty, we don't have a parent, but we also don't infer either.
     if (!maybe_parent.value().empty()) {
       std::string err_str;
-      style->parent = ResourceUtils::ParseStyleParentReference(
-          maybe_parent.value(), &err_str);
+      style->parent = ResourceUtils::ParseStyleParentReference(maybe_parent.value(), &err_str);
       if (!style->parent) {
         diag_->Error(DiagMessage(out_resource->source) << err_str);
         return false;
       }
 
-      // Transform the namespace prefix to the actual package name, and mark the
-      // reference as
+      // Transform the namespace prefix to the actual package name, and mark the reference as
       // private if appropriate.
-      TransformReferenceFromNamespace(parser, "", &style->parent.value());
+      ResolvePackage(parser, &style->parent.value());
     }
 
   } else {
@@ -1127,8 +1121,7 @@
     size_t pos = style_name.find_last_of(u'.');
     if (pos != std::string::npos) {
       style->parent_inferred = true;
-      style->parent = Reference(
-          ResourceName({}, ResourceType::kStyle, style_name.substr(0, pos)));
+      style->parent = Reference(ResourceName({}, ResourceType::kStyle, style_name.substr(0, pos)));
     }
   }
 
@@ -1373,7 +1366,7 @@
       }
 
       Reference& child_ref = maybe_ref.value();
-      xml::TransformReferenceFromNamespace(parser, "", &child_ref);
+      xml::ResolvePackage(parser, &child_ref);
 
       // Create the ParsedResource that will add the attribute to the table.
       ParsedResource child_resource;
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 35ab3c6..88e2dc2 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -457,7 +457,8 @@
   const Source& src = doc->file.source;
 
   if (context_->IsVerbose()) {
-    context_->GetDiagnostics()->Note(DiagMessage() << "linking " << src.path);
+    context_->GetDiagnostics()->Note(DiagMessage()
+                                     << "linking " << src.path << " (" << doc->file.name << ")");
   }
 
   XmlReferenceLinker xml_linker;
@@ -505,6 +506,8 @@
   std::map<std::pair<ConfigDescription, StringPiece>, FileOperation> config_sorted_files;
 
   for (auto& pkg : table->packages) {
+    CHECK(!pkg->name.empty()) << "Packages must have names when being linked";
+
     for (auto& type : pkg->types) {
       // Sort by config and name, so that we get better locality in the zip file.
       config_sorted_files.clear();
@@ -701,7 +704,7 @@
         util::make_unique<AssetManagerSymbolSource>();
     for (const std::string& path : options_.include_paths) {
       if (context_->IsVerbose()) {
-        context_->GetDiagnostics()->Note(DiagMessage(path) << "loading include path");
+        context_->GetDiagnostics()->Note(DiagMessage() << "including " << path);
       }
 
       // First try to load the file as a static lib.
@@ -819,11 +822,9 @@
     return app_info;
   }
 
-  /**
-   * Precondition: ResourceTable doesn't have any IDs assigned yet, nor is it linked.
-   * Postcondition: ResourceTable has only one package left. All others are
-   * stripped, or there is an error and false is returned.
-   */
+  // Precondition: ResourceTable doesn't have any IDs assigned yet, nor is it linked.
+  // Postcondition: ResourceTable has only one package left. All others are
+  // stripped, or there is an error and false is returned.
   bool VerifyNoExternalPackages() {
     auto is_ext_package_func = [&](const std::unique_ptr<ResourceTablePackage>& pkg) -> bool {
       return context_->GetCompilationPackage() != pkg->name || !pkg->id ||
@@ -965,10 +966,94 @@
       context_->GetDiagnostics()->Error(DiagMessage()
                                         << "failed writing to '" << out_path
                                         << "': " << android::base::SystemErrorCodeToString(errno));
+      return false;
     }
     return true;
   }
 
+  bool GenerateJavaClasses() {
+    // The set of packages whose R class to call in the main classes onResourcesLoaded callback.
+    std::vector<std::string> packages_to_callback;
+
+    JavaClassGeneratorOptions template_options;
+    template_options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
+    template_options.javadoc_annotations = options_.javadoc_annotations;
+
+    if (context_->GetPackageType() == PackageType::kStaticLib || options_.generate_non_final_ids) {
+      template_options.use_final = false;
+    }
+
+    if (context_->GetPackageType() == PackageType::kSharedLib) {
+      template_options.use_final = false;
+      template_options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{};
+    }
+
+    const StringPiece actual_package = context_->GetCompilationPackage();
+    StringPiece output_package = context_->GetCompilationPackage();
+    if (options_.custom_java_package) {
+      // Override the output java package to the custom one.
+      output_package = options_.custom_java_package.value();
+    }
+
+    // Generate the private symbols if required.
+    if (options_.private_symbols) {
+      packages_to_callback.push_back(options_.private_symbols.value());
+
+      // If we defined a private symbols package, we only emit Public symbols
+      // to the original package, and private and public symbols to the private package.
+      JavaClassGeneratorOptions options = template_options;
+      options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
+      if (!WriteJavaFile(&final_table_, actual_package, options_.private_symbols.value(),
+                         options)) {
+        return false;
+      }
+    }
+
+    // Generate copies of the original package R class but with different package names.
+    // This is to support non-namespaced builds.
+    for (const std::string& extra_package : options_.extra_java_packages) {
+      packages_to_callback.push_back(extra_package);
+
+      JavaClassGeneratorOptions options = template_options;
+      options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
+      if (!WriteJavaFile(&final_table_, actual_package, extra_package, options)) {
+        return false;
+      }
+    }
+
+    // Generate R classes for each package that was merged (static library).
+    // Use the actual package's resources only.
+    for (const std::string& package : table_merger_->merged_packages()) {
+      packages_to_callback.push_back(package);
+
+      JavaClassGeneratorOptions options = template_options;
+      options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
+      if (!WriteJavaFile(&final_table_, package, package, options)) {
+        return false;
+      }
+    }
+
+    // Generate the main public R class.
+    JavaClassGeneratorOptions options = template_options;
+
+    // Only generate public symbols if we have a private package.
+    if (options_.private_symbols) {
+      options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
+    }
+
+    if (options.rewrite_callback_options) {
+      options.rewrite_callback_options.value().packages_to_callback =
+          std::move(packages_to_callback);
+    }
+
+    if (!WriteJavaFile(&final_table_, actual_package, output_package, options,
+                       options_.generate_text_symbols_path)) {
+      return false;
+    }
+
+    return true;
+  }
+
   bool WriteManifestJavaFile(xml::XmlResource* manifest_xml) {
     if (!options_.generate_java_class_path) {
       return true;
@@ -1097,15 +1182,17 @@
 
     bool result;
     if (options_.no_static_lib_packages) {
-      // Merge all resources as if they were in the compilation package. This is
-      // the old behavior of aapt.
+      // Merge all resources as if they were in the compilation package. This is the old behavior
+      // of aapt.
 
-      // Add the package to the set of --extra-packages so we emit an R.java for
-      // each library package.
+      // Add the package to the set of --extra-packages so we emit an R.java for each library
+      // package.
       if (!pkg->name.empty()) {
         options_.extra_java_packages.insert(pkg->name);
       }
 
+      // Clear the package name, so as to make the resources look like they are coming from the
+      // local package.
       pkg->name = "";
       if (override) {
         result = table_merger_->MergeOverlay(Source(input), table.get(), collection.get());
@@ -1673,8 +1760,7 @@
 
     bool error = false;
     {
-      // AndroidManifest.xml has no resource name, but the CallSite is built
-      // from the name
+      // AndroidManifest.xml has no resource name, but the CallSite is built from the name
       // (aka, which package the AndroidManifest.xml is coming from).
       // So we give it a package name so it can see local resources.
       manifest_xml->file.name.package = context_->GetCompilationPackage();
@@ -1727,72 +1813,7 @@
     }
 
     if (options_.generate_java_class_path) {
-      // The set of packages whose R class to call in the main classes
-      // onResourcesLoaded callback.
-      std::vector<std::string> packages_to_callback;
-
-      JavaClassGeneratorOptions template_options;
-      template_options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
-      template_options.javadoc_annotations = options_.javadoc_annotations;
-
-      if (context_->GetPackageType() == PackageType::kStaticLib ||
-          options_.generate_non_final_ids) {
-        template_options.use_final = false;
-      }
-
-      if (context_->GetPackageType() == PackageType::kSharedLib) {
-        template_options.use_final = false;
-        template_options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{};
-      }
-
-      const StringPiece actual_package = context_->GetCompilationPackage();
-      StringPiece output_package = context_->GetCompilationPackage();
-      if (options_.custom_java_package) {
-        // Override the output java package to the custom one.
-        output_package = options_.custom_java_package.value();
-      }
-
-      // Generate the private symbols if required.
-      if (options_.private_symbols) {
-        packages_to_callback.push_back(options_.private_symbols.value());
-
-        // If we defined a private symbols package, we only emit Public symbols
-        // to the original package, and private and public symbols to the
-        // private package.
-        JavaClassGeneratorOptions options = template_options;
-        options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
-        if (!WriteJavaFile(&final_table_, actual_package, options_.private_symbols.value(),
-                           options)) {
-          return 1;
-        }
-      }
-
-      // Generate all the symbols for all extra packages.
-      for (const std::string& extra_package : options_.extra_java_packages) {
-        packages_to_callback.push_back(extra_package);
-
-        JavaClassGeneratorOptions options = template_options;
-        options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
-        if (!WriteJavaFile(&final_table_, actual_package, extra_package, options)) {
-          return 1;
-        }
-      }
-
-      // Generate the main public R class.
-      JavaClassGeneratorOptions options = template_options;
-
-      // Only generate public symbols if we have a private package.
-      if (options_.private_symbols) {
-        options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
-      }
-
-      if (options.rewrite_callback_options) {
-        options.rewrite_callback_options.value().packages_to_callback =
-            std::move(packages_to_callback);
-      }
-
-      if (!WriteJavaFile(&final_table_, actual_package, output_package, options,
-                         options_.generate_text_symbols_path)) {
+      if (!GenerateJavaClasses()) {
         return 1;
       }
     }
diff --git a/tools/aapt2/compile/InlineXmlFormatParser.cpp b/tools/aapt2/compile/InlineXmlFormatParser.cpp
index 857cdd5..a179260 100644
--- a/tools/aapt2/compile/InlineXmlFormatParser.cpp
+++ b/tools/aapt2/compile/InlineXmlFormatParser.cpp
@@ -69,10 +69,10 @@
     // Use an empty string for the compilation package because we don't want to default to
     // the local package if the user specified name="style" or something. This should just
     // be the default namespace.
-    Maybe<xml::ExtractedPackage> maybe_pkg = TransformPackageAlias(name.package, {});
+    Maybe<xml::ExtractedPackage> maybe_pkg = TransformPackageAlias(name.package);
     if (!maybe_pkg) {
-      context_->GetDiagnostics()->Error(DiagMessage(src) << "invalid namespace prefix '"
-                                                         << name.package << "'");
+      context_->GetDiagnostics()->Error(DiagMessage(src)
+                                        << "invalid namespace prefix '" << name.package << "'");
       error_ = true;
       return;
     }
diff --git a/tools/aapt2/integration-tests/NamespaceTest/Android.mk b/tools/aapt2/integration-tests/NamespaceTest/Android.mk
new file mode 100644
index 0000000..6361f9b
--- /dev/null
+++ b/tools/aapt2/integration-tests/NamespaceTest/Android.mk
@@ -0,0 +1,2 @@
+LOCAL_PATH := $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/aapt2/integration-tests/AppOne/Android.mk b/tools/aapt2/integration-tests/NamespaceTest/App/Android.mk
similarity index 73%
copy from tools/aapt2/integration-tests/AppOne/Android.mk
copy to tools/aapt2/integration-tests/NamespaceTest/App/Android.mk
index 38bd5b5..6ed07b0 100644
--- a/tools/aapt2/integration-tests/AppOne/Android.mk
+++ b/tools/aapt2/integration-tests/NamespaceTest/App/Android.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2016 The Android Open Source Project
+# Copyright (C) 2017 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.
@@ -18,12 +18,12 @@
 
 include $(CLEAR_VARS)
 LOCAL_USE_AAPT2 := true
-LOCAL_PACKAGE_NAME := AaptTestAppOne
+LOCAL_AAPT_NAMESPACES := true
+LOCAL_PACKAGE_NAME := AaptTestNamespace_App
 LOCAL_MODULE_TAGS := tests
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
-LOCAL_ASSET_DIR := $(LOCAL_PATH)/assets $(LOCAL_PATH)/assets2
 LOCAL_STATIC_ANDROID_LIBRARIES := \
-    AaptTestStaticLibOne \
-    AaptTestStaticLibTwo
-LOCAL_AAPT_FLAGS := --no-version-vectors --no-version-transitions
+    AaptTestNamespace_LibOne \
+    AaptTestNamespace_LibTwo
+LOCAL_AAPT_FLAGS := -v
 include $(BUILD_PACKAGE)
diff --git a/tools/aapt2/integration-tests/NamespaceTest/App/AndroidManifest.xml b/tools/aapt2/integration-tests/NamespaceTest/App/AndroidManifest.xml
new file mode 100644
index 0000000..6398a83
--- /dev/null
+++ b/tools/aapt2/integration-tests/NamespaceTest/App/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.aapt.namespace.app">
+
+    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="26"/>
+
+    <application android:theme="@style/AppTheme" android:label="@string/app_name">
+        <activity android:name=".MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tools/aapt2/integration-tests/NamespaceTest/App/res/layout/activity_main.xml b/tools/aapt2/integration-tests/NamespaceTest/App/res/layout/activity_main.xml
new file mode 100644
index 0000000..19bfd94
--- /dev/null
+++ b/tools/aapt2/integration-tests/NamespaceTest/App/res/layout/activity_main.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                xmlns:libone="http://schemas.android.com/apk/res/com.android.aapt.namespace.libone"
+                xmlns:libtwo="http://schemas.android.com/apk/res/com.android.aapt.namespace.libtwo"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+  <com.android.aapt.namespace.libtwo.TextView
+      android:id="@+id/textview"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:layout_centerInParent="@bool/always_true"
+      android:text="@libone:string/textview_text"
+      libtwo:textview_attr="?libone:theme_attr" />
+</RelativeLayout>
\ No newline at end of file
diff --git a/tools/aapt2/integration-tests/NamespaceTest/App/res/values/values.xml b/tools/aapt2/integration-tests/NamespaceTest/App/res/values/values.xml
new file mode 100644
index 0000000..1b80d95
--- /dev/null
+++ b/tools/aapt2/integration-tests/NamespaceTest/App/res/values/values.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<resources>
+    <string name="app_name">Namespace App</string>
+    <bool name="always_true">true</bool>
+
+    <style name="AppTheme" parent="com.android.aapt.namespace.libone:style/Theme">
+        <item name="android:colorPrimary">#3F51B5</item>
+        <item name="android:colorPrimaryDark">#303F9F</item>
+        <item name="android:colorAccent">#FF4081</item>
+        <item name="com.android.aapt.namespace.libone:theme_attr">
+            @com.android.aapt.namespace.libtwo:string/public_string
+        </item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/tools/aapt2/integration-tests/NamespaceTest/App/src/com/android/aapt/namespace/app/MainActivity.java b/tools/aapt2/integration-tests/NamespaceTest/App/src/com/android/aapt/namespace/app/MainActivity.java
new file mode 100644
index 0000000..fcb4c3c
--- /dev/null
+++ b/tools/aapt2/integration-tests/NamespaceTest/App/src/com/android/aapt/namespace/app/MainActivity.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.android.aapt.namespace.app;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.Toast;
+
+public class MainActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        com.android.aapt.namespace.libtwo.TextView tv = findViewById(R.id.textview);
+
+
+
+        Toast.makeText(this, tv.getTextViewAttr(), Toast.LENGTH_LONG).show();
+    }
+}
diff --git a/tools/aapt2/integration-tests/StaticLibOne/Android.mk b/tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk
similarity index 77%
copy from tools/aapt2/integration-tests/StaticLibOne/Android.mk
copy to tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk
index 0b7129a..b1cac68 100644
--- a/tools/aapt2/integration-tests/StaticLibOne/Android.mk
+++ b/tools/aapt2/integration-tests/NamespaceTest/LibOne/Android.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2016 The Android Open Source Project
+# Copyright (C) 2017 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.
@@ -18,11 +18,11 @@
 
 include $(CLEAR_VARS)
 LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := AaptTestStaticLibOne
+LOCAL_AAPT_NAMESPACES := true
+LOCAL_MODULE := AaptTestNamespace_LibOne
 LOCAL_MODULE_TAGS := tests
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 
-# We need this to compile the Java sources of AaptTestStaticLibTwo using javac.
+# We need this to retain the R.java generated for this library.
 LOCAL_JAR_EXCLUDE_FILES := none
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml b/tools/aapt2/integration-tests/NamespaceTest/LibOne/AndroidManifest.xml
similarity index 64%
copy from tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml
copy to tools/aapt2/integration-tests/NamespaceTest/LibOne/AndroidManifest.xml
index 9f5a4a8..70b4b22 100644
--- a/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml
+++ b/tools/aapt2/integration-tests/NamespaceTest/LibOne/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- Copyright (C) 2017 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.
@@ -14,9 +14,8 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              xmlns:support="http://schemas.android.com/apk/res/android.appcompat"
-    android:id="@+id/view"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content">
-</LinearLayout>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.aapt.namespace.libone">
+
+    <uses-sdk android:minSdkVersion="21" />
+</manifest>
diff --git a/tools/aapt2/integration-tests/NamespaceTest/LibOne/res/values/values.xml b/tools/aapt2/integration-tests/NamespaceTest/LibOne/res/values/values.xml
new file mode 100644
index 0000000..d2dcea0
--- /dev/null
+++ b/tools/aapt2/integration-tests/NamespaceTest/LibOne/res/values/values.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<resources>
+    <public type="string" name="textview_text" />
+    <string name="textview_text">LibOne\'s textview_text string!</string>
+
+    <public type="attr" name="theme_attr" />
+    <attr name="theme_attr" format="string" />
+
+    <public type="style" name="Theme" />
+    <style name="Theme" parent="android:Theme.Material.Light.DarkActionBar">
+        <item name="theme_attr">[Please override with your own value]</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/tools/aapt2/integration-tests/StaticLibOne/Android.mk b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk
similarity index 81%
copy from tools/aapt2/integration-tests/StaticLibOne/Android.mk
copy to tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk
index 0b7129a..dc16d1b 100644
--- a/tools/aapt2/integration-tests/StaticLibOne/Android.mk
+++ b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/Android.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2016 The Android Open Source Project
+# Copyright (C) 2017 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.
@@ -18,11 +18,12 @@
 
 include $(CLEAR_VARS)
 LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := AaptTestStaticLibOne
+LOCAL_AAPT_NAMESPACES := true
+LOCAL_MODULE := AaptTestNamespace_LibTwo
 LOCAL_MODULE_TAGS := tests
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 
-# We need this to compile the Java sources of AaptTestStaticLibTwo using javac.
+# We need this to retain the R.java generated for this library.
 LOCAL_JAR_EXCLUDE_FILES := none
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/AndroidManifest.xml
similarity index 64%
copy from tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml
copy to tools/aapt2/integration-tests/NamespaceTest/LibTwo/AndroidManifest.xml
index 9f5a4a8..32944a9 100644
--- a/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml
+++ b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- Copyright (C) 2017 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.
@@ -14,9 +14,8 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              xmlns:support="http://schemas.android.com/apk/res/android.appcompat"
-    android:id="@+id/view"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content">
-</LinearLayout>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.aapt.namespace.libtwo">
+
+    <uses-sdk android:minSdkVersion="21" />
+</manifest>
diff --git a/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/res/values/values.xml
similarity index 60%
copy from tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml
copy to tools/aapt2/integration-tests/NamespaceTest/LibTwo/res/values/values.xml
index 9f5a4a8..0c5f5d8 100644
--- a/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml
+++ b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/res/values/values.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- Copyright (C) 2017 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.
@@ -14,9 +14,14 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              xmlns:support="http://schemas.android.com/apk/res/android.appcompat"
-    android:id="@+id/view"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content">
-</LinearLayout>
+<resources>
+    <public type="string" name="public_string" />
+    <string name="public_string">LibTwo\'s public string!</string>
+
+    <public type="attr" name="textview_attr" />
+    <attr name="textview_attr" format="string" />
+
+    <declare-styleable name="TextView">
+        <attr name="textview_attr" />
+    </declare-styleable>
+</resources>
\ No newline at end of file
diff --git a/tools/aapt2/integration-tests/NamespaceTest/LibTwo/src/com/android/aapt/namespace/libtwo/TextView.java b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/src/com/android/aapt/namespace/libtwo/TextView.java
new file mode 100644
index 0000000..0f8024e
--- /dev/null
+++ b/tools/aapt2/integration-tests/NamespaceTest/LibTwo/src/com/android/aapt/namespace/libtwo/TextView.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+package com.android.aapt.namespace.libtwo;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+
+public class TextView extends android.widget.TextView {
+
+    private String mTextViewAttr;
+
+    public TextView(Context context) {
+        this(context, null);
+    }
+
+    public TextView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public TextView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public TextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+
+        final TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.TextView,
+                0, 0);
+        try {
+            mTextViewAttr = ta.getString(R.styleable.TextView_textview_attr);
+        } finally {
+            ta.recycle();
+        }
+    }
+
+    public String getTextViewAttr() {
+        return mTextViewAttr;
+    }
+}
diff --git a/tools/aapt2/integration-tests/StaticLibTest/Android.mk b/tools/aapt2/integration-tests/StaticLibTest/Android.mk
new file mode 100644
index 0000000..6361f9b
--- /dev/null
+++ b/tools/aapt2/integration-tests/StaticLibTest/Android.mk
@@ -0,0 +1,2 @@
+LOCAL_PATH := $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/aapt2/integration-tests/AppOne/Android.mk b/tools/aapt2/integration-tests/StaticLibTest/App/Android.mk
similarity index 89%
rename from tools/aapt2/integration-tests/AppOne/Android.mk
rename to tools/aapt2/integration-tests/StaticLibTest/App/Android.mk
index 38bd5b5..4d0c01d 100644
--- a/tools/aapt2/integration-tests/AppOne/Android.mk
+++ b/tools/aapt2/integration-tests/StaticLibTest/App/Android.mk
@@ -18,12 +18,12 @@
 
 include $(CLEAR_VARS)
 LOCAL_USE_AAPT2 := true
-LOCAL_PACKAGE_NAME := AaptTestAppOne
+LOCAL_PACKAGE_NAME := AaptTestStaticLib_App
 LOCAL_MODULE_TAGS := tests
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_ASSET_DIR := $(LOCAL_PATH)/assets $(LOCAL_PATH)/assets2
 LOCAL_STATIC_ANDROID_LIBRARIES := \
-    AaptTestStaticLibOne \
-    AaptTestStaticLibTwo
+    AaptTestStaticLib_LibOne \
+    AaptTestStaticLib_LibTwo
 LOCAL_AAPT_FLAGS := --no-version-vectors --no-version-transitions
 include $(BUILD_PACKAGE)
diff --git a/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml b/tools/aapt2/integration-tests/StaticLibTest/App/AndroidManifest.xml
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
rename to tools/aapt2/integration-tests/StaticLibTest/App/AndroidManifest.xml
diff --git a/tools/aapt2/integration-tests/AppOne/assets/subdir/subsubdir/test.txt b/tools/aapt2/integration-tests/StaticLibTest/App/assets/subdir/subsubdir/test.txt
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/assets/subdir/subsubdir/test.txt
rename to tools/aapt2/integration-tests/StaticLibTest/App/assets/subdir/subsubdir/test.txt
diff --git a/tools/aapt2/integration-tests/AppOne/assets/test.txt b/tools/aapt2/integration-tests/StaticLibTest/App/assets/test.txt
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/assets/test.txt
rename to tools/aapt2/integration-tests/StaticLibTest/App/assets/test.txt
diff --git a/tools/aapt2/integration-tests/AppOne/assets2/new.txt b/tools/aapt2/integration-tests/StaticLibTest/App/assets2/new.txt
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/assets2/new.txt
rename to tools/aapt2/integration-tests/StaticLibTest/App/assets2/new.txt
diff --git a/tools/aapt2/integration-tests/AppOne/assets2/test.txt b/tools/aapt2/integration-tests/StaticLibTest/App/assets2/test.txt
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/assets2/test.txt
rename to tools/aapt2/integration-tests/StaticLibTest/App/assets2/test.txt
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/cheap_transparency.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/cheap_transparency.png
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/drawable/cheap_transparency.png
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/cheap_transparency.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/complex.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/complex.9.png
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/drawable/complex.9.png
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/complex.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/icon.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/icon.png
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/drawable/icon.png
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/icon.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/image.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/image.xml
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/drawable/image.xml
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/image.xml
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/outline_8x8.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/outline_8x8.9.png
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/drawable/outline_8x8.9.png
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/outline_8x8.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_off_center_outline_32x16.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/round_rect_off_center_outline_32x16.9.png
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_off_center_outline_32x16.9.png
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/round_rect_off_center_outline_32x16.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_outline_32x16.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/round_rect_outline_32x16.9.png
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_outline_32x16.9.png
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/round_rect_outline_32x16.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/test.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/test.9.png
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/drawable/test.9.png
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/test.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_3x3.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/transparent_3x3.9.png
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/drawable/transparent_3x3.9.png
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/transparent_3x3.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_optical_bounds_3x3.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/transparent_optical_bounds_3x3.9.png
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/drawable/transparent_optical_bounds_3x3.9.png
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/transparent_optical_bounds_3x3.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/white_3x3.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/white_3x3.9.png
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/drawable/white_3x3.9.png
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/white_3x3.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/white_optical_bounds_3x3.9.png b/tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/white_optical_bounds_3x3.9.png
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/drawable/white_optical_bounds_3x3.9.png
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/drawable/white_optical_bounds_3x3.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/font/myfont-italic.ttf b/tools/aapt2/integration-tests/StaticLibTest/App/res/font/myfont-italic.ttf
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/font/myfont-italic.ttf
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/font/myfont-italic.ttf
diff --git a/tools/aapt2/integration-tests/AppOne/res/font/myfont-normal.ttf b/tools/aapt2/integration-tests/StaticLibTest/App/res/font/myfont-normal.ttf
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/font/myfont-normal.ttf
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/font/myfont-normal.ttf
diff --git a/tools/aapt2/integration-tests/AppOne/res/font/myfont.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/font/myfont.xml
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/font/myfont.xml
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/font/myfont.xml
diff --git a/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/layout-v21/main.xml
similarity index 91%
rename from tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/layout-v21/main.xml
index 9f5a4a8..724bfe4 100644
--- a/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml
+++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/layout-v21/main.xml
@@ -15,7 +15,6 @@
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              xmlns:support="http://schemas.android.com/apk/res/android.appcompat"
     android:id="@+id/view"
     android:layout_width="match_parent"
     android:layout_height="wrap_content">
diff --git a/tools/aapt2/integration-tests/AppOne/res/layout/main.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/layout/main.xml
similarity index 93%
rename from tools/aapt2/integration-tests/AppOne/res/layout/main.xml
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/layout/main.xml
index ab1a251..aaa884b 100644
--- a/tools/aapt2/integration-tests/AppOne/res/layout/main.xml
+++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/layout/main.xml
@@ -15,7 +15,6 @@
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              xmlns:support="http://schemas.android.com/apk/res/android.appcompat"
     android:id="@+id/view"
     android:layout_width="match_parent"
     android:layout_height="wrap_content">
diff --git a/tools/aapt2/integration-tests/AppOne/res/layout/special.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/layout/special.xml
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/layout/special.xml
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/layout/special.xml
diff --git a/tools/aapt2/integration-tests/AppOne/res/navigation/home.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/navigation/home.xml
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/navigation/home.xml
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/navigation/home.xml
diff --git a/tools/aapt2/integration-tests/AppOne/res/raw/test.txt b/tools/aapt2/integration-tests/StaticLibTest/App/res/raw/test.txt
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/raw/test.txt
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/raw/test.txt
diff --git a/tools/aapt2/integration-tests/AppOne/res/transition/transition_set.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/transition/transition_set.xml
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/transition/transition_set.xml
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/transition/transition_set.xml
diff --git a/tools/aapt2/integration-tests/AppOne/res/values-v4/styles.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/values-v4/styles.xml
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/values-v4/styles.xml
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/values-v4/styles.xml
diff --git a/tools/aapt2/integration-tests/AppOne/res/values/colors.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/values/colors.xml
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/values/colors.xml
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/values/colors.xml
diff --git a/tools/aapt2/integration-tests/AppOne/res/values/styles.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/values/styles.xml
similarity index 94%
rename from tools/aapt2/integration-tests/AppOne/res/values/styles.xml
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/values/styles.xml
index 19d96c0..a088e5d 100644
--- a/tools/aapt2/integration-tests/AppOne/res/values/styles.xml
+++ b/tools/aapt2/integration-tests/StaticLibTest/App/res/values/styles.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<resources xmlns:lib="http://schemas.android.com/apk/res/android.appcompat">
+<resources>
     <style name="App">
         <item name="android:background">@color/primary</item>
         <item name="android:colorPrimary">@color/primary</item>
diff --git a/tools/aapt2/integration-tests/AppOne/res/values/test.xml b/tools/aapt2/integration-tests/StaticLibTest/App/res/values/test.xml
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/res/values/test.xml
rename to tools/aapt2/integration-tests/StaticLibTest/App/res/values/test.xml
diff --git a/tools/aapt2/integration-tests/AppOne/src/com/android/aapt/app/one/AppOne.java b/tools/aapt2/integration-tests/StaticLibTest/App/src/com/android/aapt/app/one/AppOne.java
similarity index 100%
rename from tools/aapt2/integration-tests/AppOne/src/com/android/aapt/app/one/AppOne.java
rename to tools/aapt2/integration-tests/StaticLibTest/App/src/com/android/aapt/app/one/AppOne.java
diff --git a/tools/aapt2/integration-tests/StaticLibOne/Android.mk b/tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.mk
similarity index 87%
rename from tools/aapt2/integration-tests/StaticLibOne/Android.mk
rename to tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.mk
index 0b7129a..0c828b8 100644
--- a/tools/aapt2/integration-tests/StaticLibOne/Android.mk
+++ b/tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.mk
@@ -18,11 +18,11 @@
 
 include $(CLEAR_VARS)
 LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := AaptTestStaticLibOne
+LOCAL_MODULE := AaptTestStaticLib_LibOne
 LOCAL_MODULE_TAGS := tests
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 
-# We need this to compile the Java sources of AaptTestStaticLibTwo using javac.
+# We need this to compile the Java sources of AaptTestStaticLib_LibTwo using javac.
 LOCAL_JAR_EXCLUDE_FILES := none
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tools/aapt2/integration-tests/StaticLibOne/AndroidManifest.xml b/tools/aapt2/integration-tests/StaticLibTest/LibOne/AndroidManifest.xml
similarity index 100%
rename from tools/aapt2/integration-tests/StaticLibOne/AndroidManifest.xml
rename to tools/aapt2/integration-tests/StaticLibTest/LibOne/AndroidManifest.xml
diff --git a/tools/aapt2/integration-tests/StaticLibOne/res/layout/layout.xml b/tools/aapt2/integration-tests/StaticLibTest/LibOne/res/layout/layout.xml
similarity index 100%
rename from tools/aapt2/integration-tests/StaticLibOne/res/layout/layout.xml
rename to tools/aapt2/integration-tests/StaticLibTest/LibOne/res/layout/layout.xml
diff --git a/tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml b/tools/aapt2/integration-tests/StaticLibTest/LibOne/res/values/values.xml
similarity index 100%
rename from tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml
rename to tools/aapt2/integration-tests/StaticLibTest/LibOne/res/values/values.xml
diff --git a/tools/aapt2/integration-tests/StaticLibOne/src/com/android/aapt/staticlib/one/StaticLibOne.java b/tools/aapt2/integration-tests/StaticLibTest/LibOne/src/com/android/aapt/staticlib/one/StaticLibOne.java
similarity index 100%
rename from tools/aapt2/integration-tests/StaticLibOne/src/com/android/aapt/staticlib/one/StaticLibOne.java
rename to tools/aapt2/integration-tests/StaticLibTest/LibOne/src/com/android/aapt/staticlib/one/StaticLibOne.java
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/Android.mk b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.mk
similarity index 89%
rename from tools/aapt2/integration-tests/StaticLibTwo/Android.mk
rename to tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.mk
index 8b6eb41..538d525 100644
--- a/tools/aapt2/integration-tests/StaticLibTwo/Android.mk
+++ b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.mk
@@ -18,10 +18,10 @@
 
 include $(CLEAR_VARS)
 LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := AaptTestStaticLibTwo
+LOCAL_MODULE := AaptTestStaticLib_LibTwo
 LOCAL_MODULE_TAGS := tests
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_SHARED_ANDROID_LIBRARIES := AaptTestStaticLibOne
+LOCAL_SHARED_ANDROID_LIBRARIES := AaptTestStaticLib_LibOne
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/AndroidManifest.xml b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/AndroidManifest.xml
similarity index 100%
rename from tools/aapt2/integration-tests/StaticLibTwo/AndroidManifest.xml
rename to tools/aapt2/integration-tests/StaticLibTest/LibTwo/AndroidManifest.xml
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/res/drawable/vector.xml b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/res/drawable/vector.xml
similarity index 100%
rename from tools/aapt2/integration-tests/StaticLibTwo/res/drawable/vector.xml
rename to tools/aapt2/integration-tests/StaticLibTest/LibTwo/res/drawable/vector.xml
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/res/layout/layout_two.xml b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/res/layout/layout_two.xml
similarity index 100%
rename from tools/aapt2/integration-tests/StaticLibTwo/res/layout/layout_two.xml
rename to tools/aapt2/integration-tests/StaticLibTest/LibTwo/res/layout/layout_two.xml
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/res/values/values.xml b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/res/values/values.xml
similarity index 100%
rename from tools/aapt2/integration-tests/StaticLibTwo/res/values/values.xml
rename to tools/aapt2/integration-tests/StaticLibTest/LibTwo/res/values/values.xml
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/src/com/android/aapt/staticlib/two/StaticLibTwo.java b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/src/com/android/aapt/staticlib/two/StaticLibTwo.java
similarity index 100%
rename from tools/aapt2/integration-tests/StaticLibTwo/src/com/android/aapt/staticlib/two/StaticLibTwo.java
rename to tools/aapt2/integration-tests/StaticLibTest/LibTwo/src/com/android/aapt/staticlib/two/StaticLibTwo.java
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 44fa0f1..8da9106 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -480,7 +480,7 @@
   if (NameMangler::Unmangle(&unmangled_name, &unmangled_package)) {
     // The entry name was mangled, and we successfully unmangled it.
     // Check that we want to emit this symbol.
-    if (package_name != unmangled_package) {
+    if (package_name_to_generate != unmangled_package) {
       // Skip the entry if it doesn't belong to the package we're writing.
       return {};
     }
@@ -579,8 +579,7 @@
         continue;
       }
 
-      // Stay consistent with AAPT and generate an empty type class if the R class
-      // is public.
+      // Stay consistent with AAPT and generate an empty type class if the R class is public.
       const bool force_creation_if_empty =
           (options_.types == JavaClassGeneratorOptions::SymbolTypes::kPublic);
 
diff --git a/tools/aapt2/link/Linkers.h b/tools/aapt2/link/Linkers.h
index 5527f90..3c9c476 100644
--- a/tools/aapt2/link/Linkers.h
+++ b/tools/aapt2/link/Linkers.h
@@ -21,6 +21,7 @@
 #include <unordered_set>
 
 #include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
 
 #include "Resource.h"
 #include "SdkConstants.h"
@@ -33,18 +34,15 @@
 class ResourceEntry;
 struct ConfigDescription;
 
-/**
- * Defines the location in which a value exists. This determines visibility of
- * other package's private symbols.
- */
+// Defines the context in which a resource value is defined. Most resources are defined with the
+// implicit package name of their compilation context. Understanding the package name of a resource
+// allows to determine visibility of other symbols which may or may not have their packages defined.
 struct CallSite {
-  ResourceNameRef resource;
+  std::string package;
 };
 
-/**
- * Determines whether a versioned resource should be created. If a versioned
- * resource already exists, it takes precedence.
- */
+// Determines whether a versioned resource should be created. If a versioned resource already
+// exists, it takes precedence.
 bool ShouldGenerateVersionedResource(const ResourceEntry* entry, const ConfigDescription& config,
                                      const ApiVersion sdk_version_to_generate);
 
@@ -62,39 +60,26 @@
   DISALLOW_COPY_AND_ASSIGN(AutoVersioner);
 };
 
-/**
- * If any attribute resource values are defined as public, this consumer will
- * move all private
- * attribute resource values to a private ^private-attr type, avoiding backwards
- * compatibility
- * issues with new apps running on old platforms.
- *
- * The Android platform ignores resource attributes it doesn't recognize, so an
- * app developer can
- * use new attributes in their layout XML files without worrying about
- * versioning. This assumption
- * actually breaks on older platforms. OEMs may add private attributes that are
- * used internally.
- * AAPT originally assigned all private attributes IDs immediately proceeding
- * the public attributes'
- * IDs.
- *
- * This means that on a newer Android platform, an ID previously assigned to a
- * private attribute
- * may end up assigned to a public attribute.
- *
- * App developers assume using the newer attribute is safe on older platforms
- * because it will
- * be ignored. Instead, the platform thinks the new attribute is an older,
- * private attribute and
- * will interpret it as such. This leads to unintended styling and exceptions
- * thrown due to
- * unexpected types.
- *
- * By moving the private attributes to a completely different type, this ID
- * conflict will never
- * occur.
- */
+// If any attribute resource values are defined as public, this consumer will move all private
+// attribute resource values to a private ^private-attr type, avoiding backwards compatibility
+// issues with new apps running on old platforms.
+//
+// The Android platform ignores resource attributes it doesn't recognize, so an app developer can
+// use new attributes in their layout XML files without worrying about versioning. This assumption
+// actually breaks on older platforms. OEMs may add private attributes that are used internally.
+// AAPT originally assigned all private attributes IDs immediately proceeding the public attributes'
+// IDs.
+//
+// This means that on a newer Android platform, an ID previously assigned to a private attribute
+// may end up assigned to a public attribute.
+//
+// App developers assume using the newer attribute is safe on older platforms because it will
+// be ignored. Instead, the platform thinks the new attribute is an older, private attribute and
+// will interpret it as such. This leads to unintended styling and exceptions thrown due to
+// unexpected types.
+//
+// By moving the private attributes to a completely different type, this ID conflict will never
+// occur.
 class PrivateAttributeMover : public IResourceTableConsumer {
  public:
   PrivateAttributeMover() = default;
@@ -126,14 +111,10 @@
   std::unordered_set<std::string> products_;
 };
 
-/**
- * Removes namespace nodes and URI information from the XmlResource.
- *
- * Once an XmlResource is processed by this consumer, it is no longer able to
- * have its attributes
- * parsed. As such, this XmlResource must have already been processed by
- * XmlReferenceLinker.
- */
+// Removes namespace nodes and URI information from the XmlResource.
+//
+// Once an XmlResource is processed by this consumer, it is no longer able to have its attributes
+// parsed. As such, this XmlResource must have already been processed by XmlReferenceLinker.
 class XmlNamespaceRemover : public IXmlResourceConsumer {
  public:
   explicit XmlNamespaceRemover(bool keep_uris = false) : keep_uris_(keep_uris){};
@@ -146,11 +127,8 @@
   bool keep_uris_;
 };
 
-/**
- * Resolves attributes in the XmlResource and compiles string values to resource
- * values.
- * Once an XmlResource is processed by this linker, it is ready to be flattened.
- */
+// Resolves attributes in the XmlResource and compiles string values to resource values.
+// Once an XmlResource is processed by this linker, it is ready to be flattened.
 class XmlReferenceLinker : public IXmlResourceConsumer {
  public:
   XmlReferenceLinker() = default;
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index 414e56e..71e828b 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -30,23 +30,18 @@
 #include "util/Util.h"
 #include "xml/XmlUtil.h"
 
-using android::StringPiece;
+using ::android::StringPiece;
 
 namespace aapt {
 
 namespace {
 
-/**
- * The ReferenceLinkerVisitor will follow all references and make sure they
- * point
- * to resources that actually exist, either in the local resource table, or as
- * external
- * symbols. Once the target resource has been found, the ID of the resource will
- * be assigned
- * to the reference object.
- *
- * NOTE: All of the entries in the ResourceTable must be assigned IDs.
- */
+// The ReferenceLinkerVisitor will follow all references and make sure they point
+// to resources that actually exist, either in the local resource table, or as external
+// symbols. Once the target resource has been found, the ID of the resource will be assigned
+// to the reference object.
+//
+// NOTE: All of the entries in the ResourceTable must be assigned IDs.
 class ReferenceLinkerVisitor : public ValueVisitor {
  public:
   using ValueVisitor::Visit;
@@ -65,14 +60,9 @@
     }
   }
 
-  /**
-   * We visit the Style specially because during this phase, values of
-   * attributes are
-   * all RawString values. Now that we are expected to resolve all symbols, we
-   * can
-   * lookup the attributes to find out which types are allowed for the
-   * attributes' values.
-   */
+  // We visit the Style specially because during this phase, values of attributes are
+  // all RawString values. Now that we are expected to resolve all symbols, we can
+  // lookup the attributes to find out which types are allowed for the attributes' values.
   void Visit(Style* style) override {
     if (style->parent) {
       Visit(&style->parent.value());
@@ -81,28 +71,21 @@
     for (Style::Entry& entry : style->entries) {
       std::string err_str;
 
-      // Transform the attribute reference so that it is using the fully
-      // qualified package
-      // name. This will also mark the reference as being able to see private
-      // resources if
-      // there was a '*' in the reference or if the package came from the
-      // private namespace.
+      // Transform the attribute reference so that it is using the fully qualified package
+      // name. This will also mark the reference as being able to see private resources if
+      // there was a '*' in the reference or if the package came from the private namespace.
       Reference transformed_reference = entry.key;
-      TransformReferenceFromNamespace(package_decls_,
-                                      context_->GetCompilationPackage(),
-                                      &transformed_reference);
+      ResolvePackage(package_decls_, &transformed_reference);
 
-      // Find the attribute in the symbol table and check if it is visible from
-      // this callsite.
+      // Find the attribute in the symbol table and check if it is visible from this callsite.
       const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveAttributeCheckVisibility(
           transformed_reference, callsite_, symbols_, &err_str);
       if (symbol) {
-        // Assign our style key the correct ID.
-        // The ID may not exist.
+        // Assign our style key the correct ID. The ID may not exist.
         entry.key.id = symbol->id;
 
-        // Try to convert the value to a more specific, typed value based on the
-        // attribute it is set to.
+        // Try to convert the value to a more specific, typed value based on the attribute it is
+        // set to.
         entry.value = ParseValueWithAttribute(std::move(entry.value), symbol->attribute.get());
 
         // Link/resolve the final value (mostly if it's a reference).
@@ -115,8 +98,8 @@
           // The actual type of this item is incompatible with the attribute.
           DiagMessage msg(entry.key.GetSource());
 
-          // Call the matches method again, this time with a DiagMessage so we
-          // fill in the actual error message.
+          // Call the matches method again, this time with a DiagMessage so we fill in the actual
+          // error message.
           symbol->attribute->Matches(*entry.value, &msg);
           context_->GetDiagnostics()->Error(msg);
           error_ = true;
@@ -125,7 +108,7 @@
       } else {
         DiagMessage msg(entry.key.GetSource());
         msg << "style attribute '";
-        ReferenceLinker::WriteResourceName(&msg, entry.key, transformed_reference);
+        ReferenceLinker::WriteResourceName(entry.key, callsite_, package_decls_, &msg);
         msg << "' " << err_str;
         context_->GetDiagnostics()->Error(msg);
         error_ = true;
@@ -133,17 +116,15 @@
     }
   }
 
-  bool HasError() { return error_; }
+  bool HasError() {
+    return error_;
+  }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ReferenceLinkerVisitor);
 
-  /**
-   * Transform a RawString value into a more specific, appropriate value, based
-   * on the
-   * Attribute. If a non RawString value is passed in, this is an identity
-   * transform.
-   */
+  // Transform a RawString value into a more specific, appropriate value, based on the
+  // Attribute. If a non RawString value is passed in, this is an identity transform.
   std::unique_ptr<Item> ParseValueWithAttribute(std::unique_ptr<Item> value,
                                                 const Attribute* attr) {
     if (RawString* raw_string = ValueCast<RawString>(value.get())) {
@@ -178,11 +159,9 @@
  public:
   EmptyDeclStack() = default;
 
-  Maybe<xml::ExtractedPackage> TransformPackageAlias(
-      const StringPiece& alias,
-      const StringPiece& local_package) const override {
+  Maybe<xml::ExtractedPackage> TransformPackageAlias(const StringPiece& alias) const override {
     if (alias.empty()) {
-      return xml::ExtractedPackage{local_package.to_string(), true /* private */};
+      return xml::ExtractedPackage{{}, true /*private*/};
     }
     return {};
   }
@@ -191,32 +170,44 @@
   DISALLOW_COPY_AND_ASSIGN(EmptyDeclStack);
 };
 
-}  // namespace
-
-/**
- * The symbol is visible if it is public, or if the reference to it is
- * requesting private access
- * or if the callsite comes from the same package.
- */
-bool ReferenceLinker::IsSymbolVisible(const SymbolTable::Symbol& symbol,
-                                      const Reference& ref,
-                                      const CallSite& callsite) {
-  if (!symbol.is_public && !ref.private_reference) {
-    if (ref.name) {
-      return callsite.resource.package == ref.name.value().package;
-    } else if (ref.id && symbol.id) {
-      return ref.id.value().package_id() == symbol.id.value().package_id();
-    } else {
-      return false;
-    }
+// The symbol is visible if it is public, or if the reference to it is requesting private access
+// or if the callsite comes from the same package.
+bool IsSymbolVisible(const SymbolTable::Symbol& symbol, const Reference& ref,
+                     const CallSite& callsite) {
+  if (symbol.is_public || ref.private_reference) {
+    return true;
   }
-  return true;
+
+  if (ref.name) {
+    const ResourceName& name = ref.name.value();
+    if (name.package.empty()) {
+      // If the symbol was found, and the package is empty, that means it was found in the local
+      // scope, which is always visible (private local).
+      return true;
+    }
+
+    // The symbol is visible if the reference is local to the same package it is defined in.
+    return callsite.package == name.package;
+  }
+
+  if (ref.id && symbol.id) {
+    return ref.id.value().package_id() == symbol.id.value().package_id();
+  }
+  return false;
 }
 
+}  // namespace
+
 const SymbolTable::Symbol* ReferenceLinker::ResolveSymbol(const Reference& reference,
+                                                          const CallSite& callsite,
                                                           SymbolTable* symbols) {
   if (reference.name) {
-    return symbols->FindByName(reference.name.value());
+    const ResourceName& name = reference.name.value();
+    if (name.package.empty()) {
+      // Use the callsite's package name if no package name was defined.
+      return symbols->FindByName(ResourceName(callsite.package, name.type, name.entry));
+    }
+    return symbols->FindByName(name);
   } else if (reference.id) {
     return symbols->FindById(reference.id.value());
   } else {
@@ -228,7 +219,7 @@
                                                                          const CallSite& callsite,
                                                                          SymbolTable* symbols,
                                                                          std::string* out_error) {
-  const SymbolTable::Symbol* symbol = ResolveSymbol(reference, symbols);
+  const SymbolTable::Symbol* symbol = ResolveSymbol(reference, callsite, symbols);
   if (!symbol) {
     if (out_error) *out_error = "not found";
     return nullptr;
@@ -274,24 +265,62 @@
   return xml::AaptAttribute(*symbol->attribute, symbol->id);
 }
 
-void ReferenceLinker::WriteResourceName(DiagMessage* out_msg,
-                                        const Reference& orig,
-                                        const Reference& transformed) {
+void ReferenceLinker::WriteResourceName(const Reference& ref, const CallSite& callsite,
+                                        const xml::IPackageDeclStack* decls, DiagMessage* out_msg) {
   CHECK(out_msg != nullptr);
+  if (!ref.name) {
+    *out_msg << ref.id.value();
+    return;
+  }
 
-  if (orig.name) {
-    *out_msg << orig.name.value();
-    if (transformed.name.value() != orig.name.value()) {
-      *out_msg << " (aka " << transformed.name.value() << ")";
-    }
-  } else {
-    *out_msg << orig.id.value();
+  *out_msg << ref.name.value();
+
+  Reference fully_qualified = ref;
+  xml::ResolvePackage(decls, &fully_qualified);
+
+  ResourceName& full_name = fully_qualified.name.value();
+  if (full_name.package.empty()) {
+    full_name.package = callsite.package;
+  }
+
+  if (full_name != ref.name.value()) {
+    *out_msg << " (aka " << full_name << ")";
+  }
+}
+
+void ReferenceLinker::WriteAttributeName(const Reference& ref, const CallSite& callsite,
+                                         const xml::IPackageDeclStack* decls,
+                                         DiagMessage* out_msg) {
+  CHECK(out_msg != nullptr);
+  if (!ref.name) {
+    *out_msg << ref.id.value();
+    return;
+  }
+
+  const ResourceName& ref_name = ref.name.value();
+  CHECK_EQ(ref_name.type, ResourceType::kAttr);
+
+  if (!ref_name.package.empty()) {
+    *out_msg << ref_name.package << ":";
+  }
+  *out_msg << ref_name.entry;
+
+  Reference fully_qualified = ref;
+  xml::ResolvePackage(decls, &fully_qualified);
+
+  ResourceName& full_name = fully_qualified.name.value();
+  if (full_name.package.empty()) {
+    full_name.package = callsite.package;
+  }
+
+  if (full_name != ref.name.value()) {
+    *out_msg << " (aka " << full_name.package << ":" << full_name.entry << ")";
   }
 }
 
 bool ReferenceLinker::LinkReference(const CallSite& callsite, Reference* reference,
                                     IAaptContext* context, SymbolTable* symbols,
-                                    xml::IPackageDeclStack* decls) {
+                                    const xml::IPackageDeclStack* decls) {
   CHECK(reference != nullptr);
   if (!reference->name && !reference->id) {
     // This is @null.
@@ -299,7 +328,7 @@
   }
 
   Reference transformed_reference = *reference;
-  TransformReferenceFromNamespace(decls, context->GetCompilationPackage(), &transformed_reference);
+  xml::ResolvePackage(decls, &transformed_reference);
 
   std::string err_str;
   const SymbolTable::Symbol* s =
@@ -314,7 +343,7 @@
 
   DiagMessage error_msg(reference->GetSource());
   error_msg << "resource ";
-  WriteResourceName(&error_msg, *reference, transformed_reference);
+  WriteResourceName(*reference, callsite, decls, &error_msg);
   error_msg << " " << err_str;
   context->GetDiagnostics()->Error(error_msg);
   return false;
@@ -324,21 +353,24 @@
   EmptyDeclStack decl_stack;
   bool error = false;
   for (auto& package : table->packages) {
+    // Since we're linking, each package must have a name.
+    CHECK(!package->name.empty()) << "all packages being linked must have a name";
+
     for (auto& type : package->types) {
       for (auto& entry : type->entries) {
-        // Symbol state information may be lost if there is no value for the
-        // resource.
-        if (entry->symbol_status.state != SymbolState::kUndefined &&
-            entry->values.empty()) {
-          context->GetDiagnostics()->Error(
-              DiagMessage(entry->symbol_status.source)
-              << "no definition for declared symbol '"
-              << ResourceNameRef(package->name, type->type, entry->name)
-              << "'");
+        // First, unmangle the name if necessary.
+        ResourceName name(package->name, type->type, entry->name);
+        NameMangler::Unmangle(&name.entry, &name.package);
+
+        // Symbol state information may be lost if there is no value for the resource.
+        if (entry->symbol_status.state != SymbolState::kUndefined && entry->values.empty()) {
+          context->GetDiagnostics()->Error(DiagMessage(entry->symbol_status.source)
+                                           << "no definition for declared symbol '" << name << "'");
           error = true;
         }
 
-        CallSite callsite = {ResourceNameRef(package->name, type->type, entry->name)};
+        // The context of this resource is the package in which it is defined.
+        const CallSite callsite{name.package};
         ReferenceLinkerVisitor visitor(callsite, context, context->GetExternalSymbols(),
                                        &table->string_pool, &decl_stack);
 
diff --git a/tools/aapt2/link/ReferenceLinker.h b/tools/aapt2/link/ReferenceLinker.h
index b3d0196..3b11bee 100644
--- a/tools/aapt2/link/ReferenceLinker.h
+++ b/tools/aapt2/link/ReferenceLinker.h
@@ -29,83 +29,58 @@
 
 namespace aapt {
 
-/**
- * Resolves all references to resources in the ResourceTable and assigns them
- * IDs.
- * The ResourceTable must already have IDs assigned to each resource.
- * Once the ResourceTable is processed by this linker, it is ready to be
- * flattened.
- */
+// Resolves all references to resources in the ResourceTable and assigns them IDs.
+// The ResourceTable must already have IDs assigned to each resource.
+// Once the ResourceTable is processed by this linker, it is ready to be flattened.
 class ReferenceLinker : public IResourceTableConsumer {
  public:
   ReferenceLinker() = default;
 
-  /**
-   * Returns true if the symbol is visible by the reference and from the
-   * callsite.
-   */
-  static bool IsSymbolVisible(const SymbolTable::Symbol& symbol,
-                              const Reference& ref, const CallSite& callsite);
+  // Performs name mangling and looks up the resource in the symbol table. Uses the callsite's
+  // package if the reference has no package name defined (implicit).
+  // Returns nullptr if the symbol was not found.
+  static const SymbolTable::Symbol* ResolveSymbol(const Reference& reference,
+                                                  const CallSite& callsite, SymbolTable* symbols);
 
-  /**
-   * Performs name mangling and looks up the resource in the symbol table.
-   * Returns nullptr if the symbol was not found.
-   */
-  static const SymbolTable::Symbol* ResolveSymbol(const Reference& reference, SymbolTable* symbols);
-
-  /**
-   * Performs name mangling and looks up the resource in the symbol table. If
-   * the symbol is not visible by the reference at the callsite, nullptr is
-   * returned. out_error holds the error message.
-   */
+  // Performs name mangling and looks up the resource in the symbol table. If the symbol is not
+  // visible by the reference at the callsite, nullptr is returned.
+  // `out_error` holds the error message.
   static const SymbolTable::Symbol* ResolveSymbolCheckVisibility(const Reference& reference,
                                                                  const CallSite& callsite,
                                                                  SymbolTable* symbols,
                                                                  std::string* out_error);
 
-  /**
-   * Same as resolveSymbolCheckVisibility(), but also makes sure the symbol is
-   * an attribute.
-   * That is, the return value will have a non-null value for
-   * ISymbolTable::Symbol::attribute.
-   */
+  // Same as ResolveSymbolCheckVisibility(), but also makes sure the symbol is an attribute.
+  // That is, the return value will have a non-null value for ISymbolTable::Symbol::attribute.
   static const SymbolTable::Symbol* ResolveAttributeCheckVisibility(const Reference& reference,
                                                                     const CallSite& callsite,
                                                                     SymbolTable* symbols,
                                                                     std::string* out_error);
 
-  /**
-   * Resolves the attribute reference and returns an xml::AaptAttribute if
-   * successful.
-   * If resolution fails, outError holds the error message.
-   */
+  // Resolves the attribute reference and returns an xml::AaptAttribute if successful.
+  // If resolution fails, outError holds the error message.
   static Maybe<xml::AaptAttribute> CompileXmlAttribute(const Reference& reference,
                                                        const CallSite& callsite,
                                                        SymbolTable* symbols,
                                                        std::string* out_error);
 
-  /**
-   * Writes the resource name to the DiagMessage, using the
-   * "orig_name (aka <transformed_name>)" syntax.
-   */
-  static void WriteResourceName(DiagMessage* out_msg, const Reference& orig,
-                                const Reference& transformed);
+  // Writes the resource name to the DiagMessage, using the
+  // "orig_name (aka <transformed_name>)" syntax.
+  static void WriteResourceName(const Reference& orig, const CallSite& callsite,
+                                const xml::IPackageDeclStack* decls, DiagMessage* out_msg);
 
-  /**
-   * Transforms the package name of the reference to the fully qualified package
-   * name using
-   * the xml::IPackageDeclStack, then mangles and looks up the symbol. If the
-   * symbol is visible
-   * to the reference at the callsite, the reference is updated with an ID.
-   * Returns false on failure, and an error message is logged to the
-   * IDiagnostics in the context.
-   */
+  // Same as WriteResourceName but omits the 'attr' part.
+  static void WriteAttributeName(const Reference& ref, const CallSite& callsite,
+                                 const xml::IPackageDeclStack* decls, DiagMessage* out_msg);
+
+  // Transforms the package name of the reference to the fully qualified package name using
+  // the xml::IPackageDeclStack, then mangles and looks up the symbol. If the symbol is visible
+  // to the reference at the callsite, the reference is updated with an ID.
+  // Returns false on failure, and an error message is logged to the IDiagnostics in the context.
   static bool LinkReference(const CallSite& callsite, Reference* reference, IAaptContext* context,
-                            SymbolTable* symbols, xml::IPackageDeclStack* decls);
+                            SymbolTable* symbols, const xml::IPackageDeclStack* decls);
 
-  /**
-   * Links all references in the ResourceTable.
-   */
+  // Links all references in the ResourceTable.
   bool Consume(IAaptContext* context, ResourceTable* table) override;
 
  private:
diff --git a/tools/aapt2/link/ReferenceLinker_test.cpp b/tools/aapt2/link/ReferenceLinker_test.cpp
index 72a9168..be38b96 100644
--- a/tools/aapt2/link/ReferenceLinker_test.cpp
+++ b/tools/aapt2/link/ReferenceLinker_test.cpp
@@ -18,7 +18,9 @@
 
 #include "test/Test.h"
 
-using android::ResTable_map;
+using ::android::ResTable_map;
+using ::testing::Eq;
+using ::testing::IsNull;
 using ::testing::NotNull;
 
 namespace aapt {
@@ -263,7 +265,7 @@
                          .Build());
 
   std::string error;
-  const CallSite call_site{ResourceNameRef("com.app.test", ResourceType::kString, "foo")};
+  const CallSite call_site{"com.app.test"};
   const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveSymbolCheckVisibility(
       *test::BuildReference("com.app.test:string/foo"), call_site, &table, &error);
   ASSERT_THAT(symbol, NotNull());
@@ -281,7 +283,7 @@
                          .Build());
 
   std::string error;
-  const CallSite call_site{ResourceNameRef("com.app.ext", ResourceType::kLayout, "foo")};
+  const CallSite call_site{"com.app.ext"};
 
   EXPECT_FALSE(ReferenceLinker::CompileXmlAttribute(
       *test::BuildReference("com.app.test:attr/foo"), call_site, &table, &error));
@@ -293,4 +295,27 @@
   EXPECT_TRUE(error.empty());
 }
 
+TEST(ReferenceLinkerTest, ReferenceWithNoPackageUsesCallSitePackage) {
+  NameMangler mangler(NameManglerPolicy{"com.app.test"});
+  SymbolTable table(&mangler);
+  table.AppendSource(test::StaticSymbolSourceBuilder()
+                         .AddSymbol("com.app.test:string/foo", ResourceId(0x7f010000))
+                         .AddSymbol("com.app.lib:string/foo", ResourceId(0x7f010001))
+                         .Build());
+
+  const SymbolTable::Symbol* s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"),
+                                                                CallSite{"com.app.test"}, &table);
+  ASSERT_THAT(s, NotNull());
+  EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010000)));
+
+  s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"), CallSite{"com.app.lib"},
+                                     &table);
+  ASSERT_THAT(s, NotNull());
+  EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010001)));
+
+  EXPECT_THAT(ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"),
+                                             CallSite{"com.app.bad"}, &table),
+              IsNull());
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index 10e837c..93c904f 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -24,7 +24,7 @@
 #include "ValueVisitor.h"
 #include "util/Util.h"
 
-using android::StringPiece;
+using ::android::StringPiece;
 
 namespace aapt {
 
@@ -32,27 +32,23 @@
                          const TableMergerOptions& options)
     : context_(context), master_table_(out_table), options_(options) {
   // Create the desired package that all tables will be merged into.
-  master_package_ = master_table_->CreatePackage(
-      context_->GetCompilationPackage(), context_->GetPackageId());
+  master_package_ =
+      master_table_->CreatePackage(context_->GetCompilationPackage(), context_->GetPackageId());
   CHECK(master_package_ != nullptr) << "package name or ID already taken";
 }
 
-bool TableMerger::Merge(const Source& src, ResourceTable* table,
-                        io::IFileCollection* collection) {
-  return MergeImpl(src, table, collection, false /* overlay */, true /* allow new */);
+bool TableMerger::Merge(const Source& src, ResourceTable* table, io::IFileCollection* collection) {
+  return MergeImpl(src, table, collection, false /*overlay*/, true /*allow_new*/);
 }
 
 bool TableMerger::MergeOverlay(const Source& src, ResourceTable* table,
                                io::IFileCollection* collection) {
-  return MergeImpl(src, table, collection, true /* overlay */, options_.auto_add_overlay);
+  return MergeImpl(src, table, collection, true /*overlay*/, options_.auto_add_overlay);
 }
 
-/**
- * This will merge packages with the same package name (or no package name).
- */
+// This will merge packages with the same package name (or no package name).
 bool TableMerger::MergeImpl(const Source& src, ResourceTable* table,
-                            io::IFileCollection* collection, bool overlay,
-                            bool allow_new) {
+                            io::IFileCollection* collection, bool overlay, bool allow_new) {
   bool error = false;
   for (auto& package : table->packages) {
     // Only merge an empty package or the package we're building.
@@ -62,9 +58,8 @@
     if (package->name.empty() || context_->GetCompilationPackage() == package->name) {
       FileMergeCallback callback;
       if (collection) {
-        callback = [&](const ResourceNameRef& name,
-                       const ConfigDescription& config, FileReference* new_file,
-                       FileReference* old_file) -> bool {
+        callback = [&](const ResourceNameRef& name, const ConfigDescription& config,
+                       FileReference* new_file, FileReference* old_file) -> bool {
           // The old file's path points inside the APK, so we can use it as is.
           io::IFile* f = collection->FindFile(*old_file->path);
           if (!f) {
@@ -78,45 +73,38 @@
         };
       }
 
-      // Merge here. Once the entries are merged and mangled, any references to
-      // them are still valid. This is because un-mangled references are
-      // mangled, then looked up at resolution time.
-      // Also, when linking, we convert references with no package name to use
-      // the compilation package name.
-      error |= !DoMerge(src, table, package.get(), false /* mangle */, overlay,
-                        allow_new, callback);
+      // Merge here. Once the entries are merged and mangled, any references to them are still
+      // valid. This is because un-mangled references are mangled, then looked up at resolution
+      // time. Also, when linking, we convert references with no package name to use the compilation
+      // package name.
+      error |=
+          !DoMerge(src, table, package.get(), false /* mangle */, overlay, allow_new, callback);
     }
   }
   return !error;
 }
 
-/**
- * This will merge and mangle resources from a static library.
- */
-bool TableMerger::MergeAndMangle(const Source& src,
-                                 const StringPiece& package_name,
-                                 ResourceTable* table,
-                                 io::IFileCollection* collection) {
+// This will merge and mangle resources from a static library.
+bool TableMerger::MergeAndMangle(const Source& src, const StringPiece& package_name,
+                                 ResourceTable* table, io::IFileCollection* collection) {
   bool error = false;
   for (auto& package : table->packages) {
     // Warn of packages with an unrelated ID.
     if (package_name != package->name) {
-      context_->GetDiagnostics()->Warn(DiagMessage(src) << "ignoring package "
-                                                        << package->name);
+      context_->GetDiagnostics()->Warn(DiagMessage(src) << "ignoring package " << package->name);
       continue;
     }
 
     bool mangle = package_name != context_->GetCompilationPackage();
     merged_packages_.insert(package->name);
 
-    auto callback = [&](
-        const ResourceNameRef& name, const ConfigDescription& config,
-        FileReference* new_file, FileReference* old_file) -> bool {
+    auto callback = [&](const ResourceNameRef& name, const ConfigDescription& config,
+                        FileReference* new_file, FileReference* old_file) -> bool {
       // The old file's path points inside the APK, so we can use it as is.
       io::IFile* f = collection->FindFile(*old_file->path);
       if (!f) {
-        context_->GetDiagnostics()->Error(
-            DiagMessage(src) << "file '" << *old_file->path << "' not found");
+        context_->GetDiagnostics()->Error(DiagMessage(src)
+                                          << "file '" << *old_file->path << "' not found");
         return false;
       }
 
@@ -124,21 +112,18 @@
       return true;
     };
 
-    error |= !DoMerge(src, table, package.get(), mangle, false /* overlay */,
-                      true /* allow new */, callback);
+    error |= !DoMerge(src, table, package.get(), mangle, false /*overlay*/, true /*allow_new*/,
+                      callback);
   }
   return !error;
 }
 
-static bool MergeType(IAaptContext* context, const Source& src,
-                      ResourceTableType* dst_type,
+static bool MergeType(IAaptContext* context, const Source& src, ResourceTableType* dst_type,
                       ResourceTableType* src_type) {
   if (dst_type->symbol_status.state < src_type->symbol_status.state) {
-    // The incoming type's visibility is stronger, so we should override
-    // the visibility.
+    // The incoming type's visibility is stronger, so we should override the visibility.
     if (src_type->symbol_status.state == SymbolState::kPublic) {
-      // Only copy the ID if the source is public, or else the ID is
-      // meaningless.
+      // Only copy the ID if the source is public, or else the ID is meaningless.
       dst_type->id = src_type->id;
     }
     dst_type->symbol_status = std::move(src_type->symbol_status);
@@ -155,14 +140,12 @@
   return true;
 }
 
-static bool MergeEntry(IAaptContext* context, const Source& src,
-                       ResourceEntry* dst_entry, ResourceEntry* src_entry) {
+static bool MergeEntry(IAaptContext* context, const Source& src, ResourceEntry* dst_entry,
+                       ResourceEntry* src_entry) {
   if (dst_entry->symbol_status.state < src_entry->symbol_status.state) {
-    // The incoming type's visibility is stronger, so we should override
-    // the visibility.
+    // The incoming type's visibility is stronger, so we should override the visibility.
     if (src_entry->symbol_status.state == SymbolState::kPublic) {
-      // Only copy the ID if the source is public, or else the ID is
-      // meaningless.
+      // Only copy the ID if the source is public, or else the ID is meaningless.
       dst_entry->id = src_entry->id;
     }
     dst_entry->symbol_status = std::move(src_entry->symbol_status);
@@ -171,9 +154,8 @@
              dst_entry->id && src_entry->id &&
              dst_entry->id.value() != src_entry->id.value()) {
     // Both entries are public and have different IDs.
-    context->GetDiagnostics()->Error(
-        DiagMessage(src) << "cannot merge entry '" << src_entry->name
-                         << "': conflicting public IDs");
+    context->GetDiagnostics()->Error(DiagMessage(src) << "cannot merge entry '" << src_entry->name
+                                                      << "': conflicting public IDs");
     return false;
   }
   return true;
@@ -181,12 +163,10 @@
 
 // Modified CollisionResolver which will merge Styleables and Styles. Used with overlays.
 //
-// Styleables are not actual resources, but they are treated as such during the
-// compilation phase.
+// Styleables are not actual resources, but they are treated as such during the compilation phase.
 //
-// Styleables and Styles don't simply overlay each other, their definitions merge
-// and accumulate. If both values are Styleables/Styles, we just merge them into the
-// existing value.
+// Styleables and Styles don't simply overlay each other, their definitions merge and accumulate.
+// If both values are Styleables/Styles, we just merge them into the existing value.
 static ResourceTable::CollisionResult ResolveMergeCollision(Value* existing, Value* incoming,
                                                             StringPool* pool) {
   if (Styleable* existing_styleable = ValueCast<Styleable>(existing)) {
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index c96b1b0..81518ff 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -33,81 +33,49 @@
 namespace aapt {
 
 struct TableMergerOptions {
-  /**
-   * If true, resources in overlays can be added without previously having
-   * existed.
-   */
+  // If true, resources in overlays can be added without previously having existed.
   bool auto_add_overlay = false;
 };
 
-/**
- * TableMerger takes resource tables and merges all packages within the tables
- * that have the same
- * package ID.
- *
- * If a package has a different name, all the entries in that table have their
- * names mangled
- * to include the package name. This way there are no collisions. In order to do
- * this correctly,
- * the TableMerger needs to also mangle any FileReference paths. Once these are
- * mangled,
- * the original source path of the file, along with the new destination path is
- * recorded in the
- * queue returned from getFileMergeQueue().
- *
- * Once the merging is complete, a separate process can go collect the files
- * from the various
- * source APKs and either copy or process their XML and put them in the correct
- * location in
- * the final APK.
- */
+// TableMerger takes resource tables and merges all packages within the tables that have the same
+// package ID.
+//
+// If a package has a different name, all the entries in that table have their names mangled
+// to include the package name. This way there are no collisions. In order to do this correctly,
+// the TableMerger needs to also mangle any FileReference paths. Once these are mangled, the
+// `IFile` pointer in `FileReference` will point to the original file.
+//
+// Once the merging is complete, a separate phase can go collect the files from the various
+// source APKs and either copy or process their XML and put them in the correct location in the
+// final APK.
 class TableMerger {
  public:
-  /**
-   * Note: The out_table ResourceTable must live longer than this TableMerger.
-   * References are made to this ResourceTable for efficiency reasons.
-   */
-  TableMerger(IAaptContext* context, ResourceTable* out_table,
-              const TableMergerOptions& options);
+  // Note: The out_table ResourceTable must live longer than this TableMerger.
+  // References are made to this ResourceTable for efficiency reasons.
+  TableMerger(IAaptContext* context, ResourceTable* out_table, const TableMergerOptions& options);
 
-  const std::set<std::string>& merged_packages() const {
+  inline const std::set<std::string>& merged_packages() const {
     return merged_packages_;
   }
 
-  /**
-   * Merges resources from the same or empty package. This is for local sources.
-   * An io::IFileCollection is optional and used to find the referenced Files
-   * and process them.
-   */
-  bool Merge(const Source& src, ResourceTable* table,
-             io::IFileCollection* collection = nullptr);
+  // Merges resources from the same or empty package. This is for local sources.
+  // An io::IFileCollection is optional and used to find the referenced Files and process them.
+  bool Merge(const Source& src, ResourceTable* table, io::IFileCollection* collection = nullptr);
 
-  /**
-   * Merges resources from an overlay ResourceTable.
-   * An io::IFileCollection is optional and used to find the referenced Files
-   * and process them.
-   */
+  // Merges resources from an overlay ResourceTable.
+  // An io::IFileCollection is optional and used to find the referenced Files and process them.
   bool MergeOverlay(const Source& src, ResourceTable* table,
                     io::IFileCollection* collection = nullptr);
 
-  /**
-   * Merges resources from the given package, mangling the name. This is for
-   * static libraries.
-   * An io::IFileCollection is needed in order to find the referenced Files and
-   * process them.
-   */
+  // Merges resources from the given package, mangling the name. This is for static libraries.
+  // An io::IFileCollection is needed in order to find the referenced Files and process them.
   bool MergeAndMangle(const Source& src, const android::StringPiece& package, ResourceTable* table,
                       io::IFileCollection* collection);
 
-  /**
-   * Merges a compiled file that belongs to this same or empty package. This is
-   * for local sources.
-   */
+  // Merges a compiled file that belongs to this same or empty package. This is for local sources.
   bool MergeFile(const ResourceFile& fileDesc, io::IFile* file);
 
-  /**
-   * Merges a compiled file from an overlay, overriding an existing definition.
-   */
+  // Merges a compiled file from an overlay, overriding an existing definition.
   bool MergeFileOverlay(const ResourceFile& fileDesc, io::IFile* file);
 
  private:
diff --git a/tools/aapt2/link/XmlReferenceLinker.cpp b/tools/aapt2/link/XmlReferenceLinker.cpp
index bcecd20..6ebb80f 100644
--- a/tools/aapt2/link/XmlReferenceLinker.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker.cpp
@@ -31,13 +31,9 @@
 
 namespace {
 
-/**
- * Visits all references (including parents of styles, references in styles,
- * arrays, etc) and
- * links their symbolic name to their Resource ID, performing mangling and
- * package aliasing
- * as needed.
- */
+// Visits all references (including parents of styles, references in styles, arrays, etc) and
+// links their symbolic name to their Resource ID, performing mangling and package aliasing
+// as needed.
 class ReferenceVisitor : public ValueVisitor {
  public:
   using ValueVisitor::Visit;
@@ -52,7 +48,9 @@
     }
   }
 
-  bool HasError() const { return error_; }
+  bool HasError() const {
+    return error_;
+  }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ReferenceVisitor);
@@ -64,9 +62,7 @@
   bool error_;
 };
 
-/**
- * Visits each xml Element and compiles the attributes within.
- */
+// Visits each xml Element and compiles the attributes within.
 class XmlVisitor : public xml::PackageAwareVisitor {
  public:
   using xml::PackageAwareVisitor::Visit;
@@ -92,18 +88,12 @@
       // they were assigned to the default Attribute.
 
       const Attribute* attribute = &kDefaultAttribute;
-      std::string attribute_package;
 
       if (Maybe<xml::ExtractedPackage> maybe_package =
               xml::ExtractPackageFromNamespace(attr.namespace_uri)) {
         // There is a valid package name for this attribute. We will look this up.
-        attribute_package = maybe_package.value().package;
-        if (attribute_package.empty()) {
-          // Empty package means the 'current' or 'local' package.
-          attribute_package = context_->GetCompilationPackage();
-        }
-
-        Reference attr_ref(ResourceNameRef(attribute_package, ResourceType::kAttr, attr.name));
+        Reference attr_ref(
+            ResourceNameRef(maybe_package.value().package, ResourceType::kAttr, attr.name));
         attr_ref.private_reference = maybe_package.value().private_namespace;
 
         std::string err_str;
@@ -111,9 +101,11 @@
             ReferenceLinker::CompileXmlAttribute(attr_ref, callsite_, symbols_, &err_str);
 
         if (!attr.compiled_attribute) {
-          context_->GetDiagnostics()->Error(DiagMessage(source) << "attribute '"
-                                                                << attribute_package << ":"
-                                                                << attr.name << "' " << err_str);
+          DiagMessage error_msg(source);
+          error_msg << "attribute ";
+          ReferenceLinker::WriteAttributeName(attr_ref, callsite_, this, &error_msg);
+          error_msg << " " << err_str;
+          context_->GetDiagnostics()->Error(error_msg);
           error_ = true;
           continue;
         }
@@ -129,12 +121,8 @@
       } else if ((attribute->type_mask & android::ResTable_map::TYPE_STRING) == 0) {
         // We won't be able to encode this as a string.
         DiagMessage msg(source);
-        msg << "'" << attr.value << "' "
-            << "is incompatible with attribute ";
-        if (!attribute_package.empty()) {
-          msg << attribute_package << ":";
-        }
-        msg << attr.name << " " << *attribute;
+        msg << "'" << attr.value << "' is incompatible with attribute " << attr.name << " "
+            << *attribute;
         context_->GetDiagnostics()->Error(msg);
         error_ = true;
       }
@@ -163,7 +151,17 @@
 }  // namespace
 
 bool XmlReferenceLinker::Consume(IAaptContext* context, xml::XmlResource* resource) {
-  const CallSite callsite = {resource->file.name};
+  CallSite callsite{resource->file.name.package};
+
+  std::string out_name = resource->file.name.entry;
+  NameMangler::Unmangle(&out_name, &callsite.package);
+
+  if (callsite.package.empty()) {
+    // Assume an empty package means that the XML file is local. This is true of AndroidManifest.xml
+    // for example.
+    callsite.package = context->GetCompilationPackage();
+  }
+
   XmlVisitor visitor(resource->file.source, callsite, context, context->GetExternalSymbols());
   if (resource->root) {
     resource->root->Accept(&visitor);
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index cbb652e..19de3af 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -274,6 +274,8 @@
     switch (code) {
       case ResXMLParser::START_NAMESPACE: {
         NamespaceDecl decl;
+        decl.line_number = tree.getLineNumber();
+
         size_t len;
         const char16_t* str16 = tree.getNamespacePrefix(&len);
         if (str16) {
@@ -288,6 +290,7 @@
         if (pending_element == nullptr) {
           pending_element = util::make_unique<Element>();
         }
+        pending_element->namespace_decls.push_back(std::move(decl));
         break;
       }
 
@@ -297,8 +300,8 @@
           el = std::move(pending_element);
         } else {
           el = util::make_unique<Element>();
-          ;
         }
+        el->line_number = tree.getLineNumber();
 
         size_t len;
         const char16_t* str16 = tree.getElementNamespace(&len);
@@ -479,10 +482,9 @@
   package_decls_.pop_back();
 }
 
-Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(
-    const StringPiece& alias, const StringPiece& local_package) const {
+Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(const StringPiece& alias) const {
   if (alias.empty()) {
-    return ExtractedPackage{local_package.to_string(), false /* private */};
+    return ExtractedPackage{{}, false /*private*/};
   }
 
   const auto rend = package_decls_.rend();
@@ -493,7 +495,7 @@
       const PackageDecl& decl = *iter2;
       if (alias == decl.prefix) {
         if (decl.package.package.empty()) {
-          return ExtractedPackage{local_package.to_string(), decl.package.private_namespace};
+          return ExtractedPackage{{}, decl.package.private_namespace};
         }
         return decl.package;
       }
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index 1542243..9a9151d 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -185,8 +185,7 @@
  public:
   using Visitor::Visit;
 
-  Maybe<ExtractedPackage> TransformPackageAlias(
-      const android::StringPiece& alias, const android::StringPiece& local_package) const override;
+  Maybe<ExtractedPackage> TransformPackageAlias(const android::StringPiece& alias) const override;
 
  protected:
   PackageAwareVisitor() = default;
diff --git a/tools/aapt2/xml/XmlDom_test.cpp b/tools/aapt2/xml/XmlDom_test.cpp
index 6ed2d61..10a4587 100644
--- a/tools/aapt2/xml/XmlDom_test.cpp
+++ b/tools/aapt2/xml/XmlDom_test.cpp
@@ -86,19 +86,14 @@
 
   void Visit(Element* el) override {
     if (el->name == "View1") {
-      EXPECT_THAT(TransformPackageAlias("one", "local"),
-                  Eq(make_value(ExtractedPackage{"com.one", false})));
+      EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false})));
     } else if (el->name == "View2") {
-      EXPECT_THAT(TransformPackageAlias("one", "local"),
-                  Eq(make_value(ExtractedPackage{"com.one", false})));
-      EXPECT_THAT(TransformPackageAlias("two", "local"),
-                  Eq(make_value(ExtractedPackage{"com.two", false})));
+      EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false})));
+      EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false})));
     } else if (el->name == "View3") {
-      EXPECT_THAT(TransformPackageAlias("one", "local"),
-                  Eq(make_value(ExtractedPackage{"com.one", false})));
-      EXPECT_THAT(TransformPackageAlias("two", "local"),
-                  Eq(make_value(ExtractedPackage{"com.two", false})));
-      EXPECT_THAT(TransformPackageAlias("three", "local"),
+      EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false})));
+      EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false})));
+      EXPECT_THAT(TransformPackageAlias("three"),
                   Eq(make_value(ExtractedPackage{"com.three", false})));
     }
   }
@@ -112,7 +107,6 @@
         </View2>
       </View1>)");
 
-  Debug::DumpXml(doc.get());
   TestVisitor visitor;
   doc->root->Accept(&visitor);
 }
diff --git a/tools/aapt2/xml/XmlPullParser.cpp b/tools/aapt2/xml/XmlPullParser.cpp
index 30bdc50..402e5a4 100644
--- a/tools/aapt2/xml/XmlPullParser.cpp
+++ b/tools/aapt2/xml/XmlPullParser.cpp
@@ -141,17 +141,16 @@
   return event_queue_.front().data2;
 }
 
-Maybe<ExtractedPackage> XmlPullParser::TransformPackageAlias(
-    const StringPiece& alias, const StringPiece& local_package) const {
+Maybe<ExtractedPackage> XmlPullParser::TransformPackageAlias(const StringPiece& alias) const {
   if (alias.empty()) {
-    return ExtractedPackage{local_package.to_string(), false /* private */};
+    return ExtractedPackage{{}, false /*private*/};
   }
 
   const auto end_iter = package_aliases_.rend();
   for (auto iter = package_aliases_.rbegin(); iter != end_iter; ++iter) {
     if (alias == iter->prefix) {
       if (iter->package.package.empty()) {
-        return ExtractedPackage{local_package.to_string(), iter->package.private_namespace};
+        return ExtractedPackage{{}, iter->package.private_namespace};
       }
       return iter->package;
     }
diff --git a/tools/aapt2/xml/XmlPullParser.h b/tools/aapt2/xml/XmlPullParser.h
index a00caa1..63db66f 100644
--- a/tools/aapt2/xml/XmlPullParser.h
+++ b/tools/aapt2/xml/XmlPullParser.h
@@ -119,8 +119,7 @@
    * If xmlns:app="http://schemas.android.com/apk/res-auto", then
    * 'package' will be set to 'defaultPackage'.
    */
-  Maybe<ExtractedPackage> TransformPackageAlias(
-      const android::StringPiece& alias, const android::StringPiece& local_package) const override;
+  Maybe<ExtractedPackage> TransformPackageAlias(const android::StringPiece& alias) const override;
 
   //
   // Remaining methods are for retrieving information about attributes
diff --git a/tools/aapt2/xml/XmlUtil.cpp b/tools/aapt2/xml/XmlUtil.cpp
index fb8cee8..c1186e8 100644
--- a/tools/aapt2/xml/XmlUtil.cpp
+++ b/tools/aapt2/xml/XmlUtil.cpp
@@ -62,19 +62,15 @@
   return {};
 }
 
-void TransformReferenceFromNamespace(IPackageDeclStack* decl_stack,
-                                     const StringPiece& local_package,
-                                     Reference* in_ref) {
+void ResolvePackage(const IPackageDeclStack* decl_stack, Reference* in_ref) {
   if (in_ref->name) {
     if (Maybe<ExtractedPackage> transformed_package =
-            decl_stack->TransformPackageAlias(in_ref->name.value().package,
-                                              local_package)) {
+            decl_stack->TransformPackageAlias(in_ref->name.value().package)) {
       ExtractedPackage& extracted_package = transformed_package.value();
       in_ref->name.value().package = std::move(extracted_package.package);
 
       // If the reference was already private (with a * prefix) and the
-      // namespace is public,
-      // we keep the reference private.
+      // namespace is public, we keep the reference private.
       in_ref->private_reference |= extracted_package.private_namespace;
     }
   }
diff --git a/tools/aapt2/xml/XmlUtil.h b/tools/aapt2/xml/XmlUtil.h
index 866b6dc..4eb359a 100644
--- a/tools/aapt2/xml/XmlUtil.h
+++ b/tools/aapt2/xml/XmlUtil.h
@@ -35,7 +35,7 @@
 // Result of extracting a package name from a namespace URI declaration.
 struct ExtractedPackage {
   // The name of the package. This can be the empty string, which means that the package
-  // should be assumed to be the package being compiled.
+  // should be assumed to be the same as the CallSite it was defined in.
   std::string package;
 
   // True if the package's private namespace was declared. This means that private resources
@@ -51,8 +51,8 @@
 //   http://schemas.android.com/apk/res/<package> or
 //   http://schemas.android.com/apk/prv/res/<package>
 //
-// Special case: if namespaceUri is http://schemas.android.com/apk/res-auto,
-// returns an empty package name.
+// Special case: if namespaceUri is http://schemas.android.com/apk/res-auto, returns an empty
+// package name.
 Maybe<ExtractedPackage> ExtractPackageFromNamespace(const std::string& namespace_uri);
 
 // Returns an XML Android namespace for the given package of the form:
@@ -63,21 +63,20 @@
 std::string BuildPackageNamespace(const android::StringPiece& package,
                                   bool private_reference = false);
 
-// Interface representing a stack of XML namespace declarations. When looking up the package
-// for a namespace prefix, the stack is checked from top to bottom.
+// Interface representing a stack of XML namespace declarations. When looking up the package for a
+// namespace prefix, the stack is checked from top to bottom.
 struct IPackageDeclStack {
   virtual ~IPackageDeclStack() = default;
 
   // Returns an ExtractedPackage struct if the alias given corresponds with a package declaration.
   virtual Maybe<ExtractedPackage> TransformPackageAlias(
-      const android::StringPiece& alias, const android::StringPiece& local_package) const = 0;
+      const android::StringPiece& alias) const = 0;
 };
 
 // Helper function for transforming the original Reference inRef to a fully qualified reference
 // via the IPackageDeclStack. This will also mark the Reference as private if the namespace of the
 // package declaration was private.
-void TransformReferenceFromNamespace(IPackageDeclStack* decl_stack,
-                                     const android::StringPiece& local_package, Reference* in_ref);
+void ResolvePackage(const IPackageDeclStack* decl_stack, Reference* in_ref);
 
 }  // namespace xml
 }  // namespace aapt