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