diff options
6 files changed, 268 insertions, 3 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java index d78fa03..44814d4 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java @@ -15,6 +15,7 @@ */ package com.android.ide.eclipse.adt.internal.wizards.templates; +import static com.android.SdkConstants.ATTR_PACKAGE; import static com.android.SdkConstants.DOT_AIDL; import static com.android.SdkConstants.DOT_FTL; import static com.android.SdkConstants.DOT_JAVA; @@ -798,12 +799,28 @@ class TemplateHandler { private boolean mergeManifest(Document currentManifest, Document fragment) { // TODO change MergerLog.wrapSdkLog by a custom IMergerLog that will create // and maintain error markers. + + // Transfer package element from manifest to merged in root; required by + // manifest merger + Element fragmentRoot = fragment.getDocumentElement(); + Element manifestRoot = currentManifest.getDocumentElement(); + if (fragmentRoot == null || manifestRoot == null) { + return false; + } + String pkg = fragmentRoot.getAttribute(ATTR_PACKAGE); + if (pkg == null || pkg.isEmpty()) { + pkg = manifestRoot.getAttribute(ATTR_PACKAGE); + if (pkg != null && !pkg.isEmpty()) { + fragmentRoot.setAttribute(ATTR_PACKAGE, pkg); + } + } + ManifestMerger merger = new ManifestMerger( MergerLog.wrapSdkLog(AdtPlugin.getDefault()), - new AdtManifestMergeCallback()); + new AdtManifestMergeCallback()).setExtractPackagePrefix(true); return currentManifest != null && - fragment != null && - merger.process(currentManifest, fragment); + fragment != null && + merger.process(currentManifest, fragment); } /** diff --git a/manifmerger/src/com/android/manifmerger/ManifestMerger.java b/manifmerger/src/com/android/manifmerger/ManifestMerger.java index ded4eac..073c768 100755 --- a/manifmerger/src/com/android/manifmerger/ManifestMerger.java +++ b/manifmerger/src/com/android/manifmerger/ManifestMerger.java @@ -128,6 +128,8 @@ public class ManifestMerger { private final ICallback mCallback; private XPath mXPath; private Document mMainDoc; + /** Option to extract our package prefixes in the merged manifest */ + private boolean mExtractPackagePrefix; /** Namespace for Android attributes in an AndroidManifest.xml */ private static final String NS_URI = SdkConstants.NS_RESOURCES; @@ -172,6 +174,17 @@ public class ManifestMerger { } /** + * Sets whether the manifest merger should extract package prefixes + * + * @param extract if true, extract package prefixes + * @return this, for constructor chaining + */ + public ManifestMerger setExtractPackagePrefix(boolean extract) { + mExtractPackagePrefix = extract; + return this; + } + + /** * Performs the merge operation. * <p/> * This does NOT stop on errors, in an attempt to accumulate as much @@ -250,6 +263,11 @@ public class ManifestMerger { } cleanupToolsAttributes(mainDoc); + + if (mExtractPackagePrefix) { + extractFqcns(mainDoc); + } + mXPath = null; mMainDoc = null; return success; @@ -456,6 +474,55 @@ public class ManifestMerger { } /** + * Extracts the fully qualified class names from the manifest and uses the + * prefix notation relative to the manifest package. This basically reverses + * the effects of {@link #expandFqcns(Document)}, though of course it may + * also remove prefixes which were inlined in the original documents. + * + * @param doc the document in which to extract the FQCNs. + */ + private void extractFqcns(Document doc) { + // Find the package attribute of the manifest. + String pkg = null; + Element manifest = findFirstElement(doc, "/manifest"); + if (manifest != null) { + pkg = manifest.getAttribute("package"); + } + + if (pkg == null || pkg.length() == 0) { + return; + } + + int pkgLength = pkg.length(); + for (String elementAttr : sClassAttributes) { + String[] names = elementAttr.split("/"); + if (names.length != 2) { + continue; + } + String elemName = names[0]; + String attrName = names[1]; + NodeList elements = doc.getElementsByTagName(elemName); + for (int i = 0; i < elements.getLength(); i++) { + Node elem = elements.item(i); + if (elem instanceof Element) { + Attr attr = ((Element) elem).getAttributeNodeNS(NS_URI, attrName); + if (attr != null) { + String value = attr.getNodeValue(); + + // We know it's a shortened FQCN if it starts with a dot + // or does not contain any dot. + if (value != null && value.length() > pkgLength && + value.startsWith(pkg) && value.charAt(pkgLength) == '.') { + value = value.substring(pkgLength); + attr.setNodeValue(value); + } + } + } + } + } + } + + /** * Checks (but does not merge) the application attributes using the following rules: * <pre> * - {@code @name}: Ignore if empty. Warning if its expanded FQCN doesn't match the main doc. diff --git a/manifmerger/tests/src/com/android/manifmerger/ManifestMergerTest.java b/manifmerger/tests/src/com/android/manifmerger/ManifestMergerTest.java index 717533a..6da0bb9 100755 --- a/manifmerger/tests/src/com/android/manifmerger/ManifestMergerTest.java +++ b/manifmerger/tests/src/com/android/manifmerger/ManifestMergerTest.java @@ -177,4 +177,12 @@ public class ManifestMergerTest extends ManifestMergerTestCase { public void test69_remove_uses() throws Exception { processTestFiles(); } + + public void test70_expand_fqcns() throws Exception { + processTestFiles(); + } + + public void test71_prefixes_enable_extractprefix() throws Exception { + processTestFiles(); + } } diff --git a/manifmerger/tests/src/com/android/manifmerger/ManifestMergerTestCase.java b/manifmerger/tests/src/com/android/manifmerger/ManifestMergerTestCase.java index b044c3a..eb3a215 100755 --- a/manifmerger/tests/src/com/android/manifmerger/ManifestMergerTestCase.java +++ b/manifmerger/tests/src/com/android/manifmerger/ManifestMergerTestCase.java @@ -410,6 +410,11 @@ abstract class ManifestMergerTestCase extends TestCase { return ICallback.UNKNOWN_CODENAME; } }); + + // Test name contains "enable_extractprefix" to enable manifest extract prefix + if (getName().contains("enable_extractprefix")) { + merger.setExtractPackagePrefix(true); + } boolean processOK = merger.process(testFiles.getActualResult(), testFiles.getMain(), testFiles.getLibs(), diff --git a/manifmerger/tests/src/com/android/manifmerger/data/70_expand_fqcns.xml b/manifmerger/tests/src/com/android/manifmerger/data/70_expand_fqcns.xml new file mode 100755 index 0000000..5864345 --- /dev/null +++ b/manifmerger/tests/src/com/android/manifmerger/data/70_expand_fqcns.xml @@ -0,0 +1,84 @@ +# +# Test the option to extract prefixes +# + +@main + +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.blankactivity5" + android:versionCode="1" + android:versionName="1.0" > + + <uses-sdk + android:minSdkVersion="11" + android:targetSdkVersion="16" /> + + <application + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" + android:theme="@style/AppTheme" > + <activity + android:name=".MainActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + +</manifest> + +@lib1 + +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.blankactivity5" > + + <application> + <activity + android:name=".FooActivity" + android:label="@string/title_activity_foo" > + </activity> + </application> + +</manifest> + +@result + +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.blankactivity5" + android:versionCode="1" + android:versionName="1.0" > + + <uses-sdk + android:minSdkVersion="11" + android:targetSdkVersion="16" /> + + <application + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" + android:theme="@style/AppTheme" > + <activity + android:name="com.example.blankactivity5.MainActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <activity + android:name="com.example.blankactivity5.FooActivity" + android:label="@string/title_activity_foo" > + </activity> + </application> + +</manifest> + +@errors + + diff --git a/manifmerger/tests/src/com/android/manifmerger/data/71_prefixes_enable_extractprefix.xml b/manifmerger/tests/src/com/android/manifmerger/data/71_prefixes_enable_extractprefix.xml new file mode 100755 index 0000000..dd11dcc --- /dev/null +++ b/manifmerger/tests/src/com/android/manifmerger/data/71_prefixes_enable_extractprefix.xml @@ -0,0 +1,84 @@ +# +# Test the option to extract prefixes +# + +@main + +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.blankactivity5" + android:versionCode="1" + android:versionName="1.0" > + + <uses-sdk + android:minSdkVersion="11" + android:targetSdkVersion="16" /> + + <application + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" + android:theme="@style/AppTheme" > + <activity + android:name=".MainActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + +</manifest> + +@lib1 + +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.blankactivity5" > + + <application> + <activity + android:name=".FooActivity" + android:label="@string/title_activity_foo" > + </activity> + </application> + +</manifest> + +@result + +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.blankactivity5" + android:versionCode="1" + android:versionName="1.0" > + + <uses-sdk + android:minSdkVersion="11" + android:targetSdkVersion="16" /> + + <application + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" + android:theme="@style/AppTheme" > + <activity + android:name=".MainActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <activity + android:name=".FooActivity" + android:label="@string/title_activity_foo" > + </activity> + </application> + +</manifest> + +@errors + + |