aboutsummaryrefslogtreecommitdiffstats
path: root/manifmerger
diff options
context:
space:
mode:
authorRaphael Moll <ralf@android.com>2012-09-27 16:27:14 -0700
committerRaphael Moll <ralf@android.com>2012-10-01 14:04:51 -0700
commitf3cbbdcb991676dafcf0bdf46298c689314955d7 (patch)
treeb3a9f7662317e59db3fbf53f09771aa9df13e3e4 /manifmerger
parent19206bf48631dd7997eb5a378300160df842bcf3 (diff)
downloadsdk-f3cbbdcb991676dafcf0bdf46298c689314955d7.zip
sdk-f3cbbdcb991676dafcf0bdf46298c689314955d7.tar.gz
sdk-f3cbbdcb991676dafcf0bdf46298c689314955d7.tar.bz2
Manifest Merger: override/remove attributes.
Change-Id: Ib9c08ae8eb39caa91c319534f0ab9a786d65b801
Diffstat (limited to 'manifmerger')
-rwxr-xr-xmanifmerger/src/com/android/manifmerger/ManifestMerger.java242
-rwxr-xr-xmanifmerger/src/com/android/manifmerger/MergerXmlUtils.java (renamed from manifmerger/src/com/android/manifmerger/XmlUtils.java)21
-rwxr-xr-xmanifmerger/tests/src/com/android/manifmerger/ManifestMergerTest.java20
-rwxr-xr-xmanifmerger/tests/src/com/android/manifmerger/ManifestMergerTestCase.java10
-rwxr-xr-xmanifmerger/tests/src/com/android/manifmerger/data/17_fqcn_conflict.xml4
-rwxr-xr-xmanifmerger/tests/src/com/android/manifmerger/data/21_uses_lib_errors.xml2
-rwxr-xr-xmanifmerger/tests/src/com/android/manifmerger/data/56_support_gltext_warning.xml3
-rwxr-xr-xmanifmerger/tests/src/com/android/manifmerger/data/60_merge_order.xml5
-rwxr-xr-xmanifmerger/tests/src/com/android/manifmerger/data/65_override_app.xml197
-rwxr-xr-xmanifmerger/tests/src/com/android/manifmerger/data/66_remove_app.xml53
-rwxr-xr-xmanifmerger/tests/src/com/android/manifmerger/data/67_override_activities.xml159
-rwxr-xr-xmanifmerger/tests/src/com/android/manifmerger/data/68_override_uses.xml205
-rwxr-xr-xmanifmerger/tests/src/com/android/manifmerger/data/69_remove_uses.xml177
13 files changed, 1014 insertions, 84 deletions
diff --git a/manifmerger/src/com/android/manifmerger/ManifestMerger.java b/manifmerger/src/com/android/manifmerger/ManifestMerger.java
index bbe6e25..ded4eac 100755
--- a/manifmerger/src/com/android/manifmerger/ManifestMerger.java
+++ b/manifmerger/src/com/android/manifmerger/ManifestMerger.java
@@ -21,6 +21,7 @@ import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.manifmerger.IMergerLog.FileAndLine;
import com.android.manifmerger.IMergerLog.Severity;
+import com.android.utils.XmlUtils;
import com.android.xml.AndroidXPathFactory;
import org.w3c.dom.Attr;
@@ -128,9 +129,20 @@ public class ManifestMerger {
private XPath mXPath;
private Document mMainDoc;
- private String NS_URI = SdkConstants.NS_RESOURCES;
- private String NS_PREFIX = AndroidXPathFactory.DEFAULT_NS_PREFIX;
- private int destMinSdk;
+ /** Namespace for Android attributes in an AndroidManifest.xml */
+ private static final String NS_URI = SdkConstants.NS_RESOURCES;
+ /** Prefix for the Android namespace to use in XPath expressions. */
+ private static final String NS_PREFIX = AndroidXPathFactory.DEFAULT_NS_PREFIX;
+ /** Namespace used in XML files for Android Tooling attributes */
+ private static final String TOOLS_URI = SdkConstants.TOOLS_URI;
+ /** The name of the tool:merge attribute, to either override or ignore merges. */
+ private static final String MERGE_ATTR = "merge"; //$NON-NLS-1$
+ /** tool:merge="override" means to ignore what comes from libraries and only keep the
+ * version from the main manifest. No conflict can be generated. */
+ private static final String MERGE_OVERRIDE = "override"; //$NON-NLS-1$
+ /** tool:merge="remove" means to remove a node and prevent merging -- not only is the
+ * node from the libraries not merged, but the element is removed from the main manifest. */
+ private static final String MERGE_REMOVE = "remove"; //$NON-NLS-1$
/**
* Sets of element/attribute that need to be treated as class names.
@@ -141,6 +153,7 @@ public class ManifestMerger {
"application/name",
"application/backupAgent",
"activity/name",
+ "activity-alias/name",
"receiver/name",
"service/name",
"provider/name",
@@ -183,14 +196,14 @@ public class ManifestMerger {
File mainFile,
File[] libraryFiles,
Map<String, String> injectAttributes) {
- Document mainDoc = XmlUtils.parseDocument(mainFile, mLog);
+ Document mainDoc = MergerXmlUtils.parseDocument(mainFile, mLog);
if (mainDoc == null) {
return false;
}
boolean success = process(mainDoc, libraryFiles, injectAttributes);
- if (!XmlUtils.printXmlFile(mainDoc, outputFile, mLog)) {
+ if (!MergerXmlUtils.printXmlFile(mainDoc, outputFile, mLog)) {
success = false;
}
return success;
@@ -222,20 +235,21 @@ public class ManifestMerger {
boolean success = true;
mMainDoc = mainDoc;
- XmlUtils.decorateDocument(mainDoc, IMergerLog.MAIN_MANIFEST);
- XmlUtils.injectAttributes(mainDoc, injectAttributes, mLog);
+ MergerXmlUtils.decorateDocument(mainDoc, IMergerLog.MAIN_MANIFEST);
+ MergerXmlUtils.injectAttributes(mainDoc, injectAttributes, mLog);
- String prefix = XmlUtils.lookupNsPrefix(mainDoc, SdkConstants.NS_RESOURCES);
+ String prefix = XmlUtils.lookupNamespacePrefix(mainDoc, SdkConstants.NS_RESOURCES);
mXPath = AndroidXPathFactory.newXPath(prefix);
expandFqcns(mainDoc);
for (File libFile : libraryFiles) {
- Document libDoc = XmlUtils.parseDocument(libFile, mLog);
- if (libDoc == null || !mergeLibDoc(libDoc)) {
+ Document libDoc = MergerXmlUtils.parseDocument(libFile, mLog);
+ if (libDoc == null || !mergeLibDoc(cleanupToolsAttributes(libDoc))) {
success = false;
}
}
+ cleanupToolsAttributes(mainDoc);
mXPath = null;
mMainDoc = null;
return success;
@@ -258,19 +272,20 @@ public class ManifestMerger {
boolean success = true;
mMainDoc = mainDoc;
- XmlUtils.decorateDocument(mainDoc, IMergerLog.MAIN_MANIFEST);
+ MergerXmlUtils.decorateDocument(mainDoc, IMergerLog.MAIN_MANIFEST);
- String prefix = XmlUtils.lookupNsPrefix(mainDoc, SdkConstants.NS_RESOURCES);
+ String prefix = XmlUtils.lookupNamespacePrefix(mainDoc, SdkConstants.NS_RESOURCES);
mXPath = AndroidXPathFactory.newXPath(prefix);
expandFqcns(mainDoc);
for (Document libDoc : libraryDocs) {
- XmlUtils.decorateDocument(libDoc, IMergerLog.LIBRARY);
- if (!mergeLibDoc(libDoc)) {
+ MergerXmlUtils.decorateDocument(libDoc, IMergerLog.LIBRARY);
+ if (!mergeLibDoc(cleanupToolsAttributes(libDoc))) {
success = false;
}
}
+ cleanupToolsAttributes(mainDoc);
mXPath = null;
mMainDoc = null;
return success;
@@ -300,32 +315,37 @@ public class ManifestMerger {
err |= !doNotMergeCheckEqual("/manifest/compatible-screens", libDoc); //$NON-NLS-1$
err |= !doNotMergeCheckEqual("/manifest/supports-gl-texture", libDoc); //$NON-NLS-1$
+ boolean skipApplication = hasOverrideOrRemoveTag(
+ findFirstElement(mMainDoc, "/manifest/application")); //$NON-NLS-1$
+
// Strategy C
- err |= !mergeNewOrEqual(
- "/manifest/application/activity", //$NON-NLS-1$
- "name", //$NON-NLS-1$
- libDoc,
- true);
- err |= !mergeNewOrEqual(
- "/manifest/application/activity-alias", //$NON-NLS-1$
- "name", //$NON-NLS-1$
- libDoc,
- true);
- err |= !mergeNewOrEqual(
- "/manifest/application/service", //$NON-NLS-1$
- "name", //$NON-NLS-1$
- libDoc,
- true);
- err |= !mergeNewOrEqual(
- "/manifest/application/receiver", //$NON-NLS-1$
- "name", //$NON-NLS-1$
- libDoc,
- true);
- err |= !mergeNewOrEqual(
- "/manifest/application/provider", //$NON-NLS-1$
- "name", //$NON-NLS-1$
- libDoc,
- true);
+ if (!skipApplication) {
+ err |= !mergeNewOrEqual(
+ "/manifest/application/activity", //$NON-NLS-1$
+ "name", //$NON-NLS-1$
+ libDoc,
+ true);
+ err |= !mergeNewOrEqual(
+ "/manifest/application/activity-alias", //$NON-NLS-1$
+ "name", //$NON-NLS-1$
+ libDoc,
+ true);
+ err |= !mergeNewOrEqual(
+ "/manifest/application/service", //$NON-NLS-1$
+ "name", //$NON-NLS-1$
+ libDoc,
+ true);
+ err |= !mergeNewOrEqual(
+ "/manifest/application/receiver", //$NON-NLS-1$
+ "name", //$NON-NLS-1$
+ libDoc,
+ true);
+ err |= !mergeNewOrEqual(
+ "/manifest/application/provider", //$NON-NLS-1$
+ "name", //$NON-NLS-1$
+ libDoc,
+ true);
+ }
err |= !mergeNewOrEqual(
"/manifest/permission", //$NON-NLS-1$
"name", //$NON-NLS-1$
@@ -348,12 +368,14 @@ public class ManifestMerger {
false);
// Strategy D
- err |= !mergeAdjustRequired(
- "/manifest/application/uses-library", //$NON-NLS-1$
- "name", //$NON-NLS-1$
- "required", //$NON-NLS-1$
- libDoc,
- null /*alternateKeyAttr*/);
+ if (!skipApplication) {
+ err |= !mergeAdjustRequired(
+ "/manifest/application/uses-library", //$NON-NLS-1$
+ "name", //$NON-NLS-1$
+ "required", //$NON-NLS-1$
+ libDoc,
+ null /*alternateKeyAttr*/);
+ }
err |= !mergeAdjustRequired(
"/manifest/uses-feature", //$NON-NLS-1$
"name", //$NON-NLS-1$
@@ -455,6 +477,10 @@ public class ManifestMerger {
if (libApp == null) {
return true;
}
+ if (hasOverrideOrRemoveTag(mainApp)) {
+ // Don't check the <application> element since it is tagged with override or remove.
+ return true;
+ }
for (String attrName : new String[] { "name", "backupAgent" }) {
String libValue = getAttributeValue(libApp, attrName);
@@ -506,6 +532,9 @@ public class ManifestMerger {
boolean found = false;
for (Element dest : findElements(mMainDoc, path)) {
+ if (hasOverrideOrRemoveTag(dest)) {
+ continue;
+ }
if (compareElements(dest, src, false, null /*diff*/, null /*keyAttr*/)) {
found = true;
break;
@@ -518,7 +547,7 @@ public class ManifestMerger {
xmlFileAndLine(src),
"%1$s defined in library, missing from main manifest:\n%2$s",
path,
- XmlUtils.dump(src, false /*nextSiblings*/));
+ MergerXmlUtils.dump(src, false /*nextSiblings*/));
}
}
@@ -583,7 +612,13 @@ public class ManifestMerger {
"Manifest has more than one %1$s[@%2$s=%3$s] element.",
path, keyAttr, name);
}
+ boolean doMerge = true;
for (Element dest : dests) {
+ // Don't try to merge this element since it has tools:merge=override|remove.
+ if (hasOverrideOrRemoveTag(dest)) {
+ doMerge = false;
+ continue;
+ }
// If there's already a similar node in the destination, check it's identical.
StringBuilder diff = new StringBuilder();
if (compareElements(dest, src, false, diff, keyAttr)) {
@@ -608,10 +643,12 @@ public class ManifestMerger {
}
}
- // Ready to merge element src. Select which previous siblings to merge.
- Node start = selectPreviousSiblings(src);
+ if (doMerge) {
+ // Ready to merge element src. Select which previous siblings to merge.
+ Node start = selectPreviousSiblings(src);
- insertAtEndOf(parent, start, src);
+ insertAtEndOf(parent, start, src);
+ }
}
return success;
@@ -634,7 +671,7 @@ public class ManifestMerger {
/**
* Merge elements as identified by their key name attribute.
* The element must have an option boolean "required" attribute which can be either "true" or
- * "false". Default is true if the attribute is misisng. When merging, a "false" is superseded
+ * "false". Default is true if the attribute is missisng. When merging, a "false" is superseded
* by a "true" (explicit or implicit).
* <p/>
* When merging, this does NOT merge any other attributes than {@code keyAttr} and
@@ -705,6 +742,7 @@ public class ManifestMerger {
path, keyAttr, name);
}
if (dests.size() > 0) {
+
attr = src.getAttributeNodeNS(NS_URI, requiredAttr);
String value = attr == null ? "true" : attr.getNodeValue(); //$NON-NLS-1$
if (value == null || !(value.equals("true") || value.equals("false"))) {
@@ -717,8 +755,12 @@ public class ManifestMerger {
boolean boolE = Boolean.parseBoolean(value);
for (Element dest : dests) {
- // Destination node exists. Compare the required attributes.
+ // Don't try to merge this element since it has tools:merge=override|remove.
+ if (hasOverrideOrRemoveTag(dest)) {
+ continue;
+ }
+ // Compare the required attributes.
attr = dest.getAttributeNodeNS(NS_URI, requiredAttr);
value = attr == null ? "true" : attr.getNodeValue(); //$NON-NLS-1$
if (value == null || !(value.equals("true") || value.equals("false"))) {
@@ -927,6 +969,12 @@ public class ManifestMerger {
boolean result = true;
Element destUsesSdk = findFirstElement(mMainDoc, "/manifest/uses-sdk"); //$NON-NLS-1$
+
+ if (hasOverrideOrRemoveTag(destUsesSdk)) {
+ // Don't try to check this element since it has tools:merge=override|remove.
+ return true;
+ }
+
Element srcUsesSdk = findFirstElement(libDoc, "/manifest/uses-sdk"); //$NON-NLS-1$
AtomicInteger destValue = new AtomicInteger(1);
@@ -935,7 +983,7 @@ public class ManifestMerger {
AtomicBoolean srcImplied = new AtomicBoolean(true);
// Check minSdkVersion
- destMinSdk = 1;
+ int destMinSdk = 1;
result = extractSdkVersionAttribute(
libDoc,
destUsesSdk, srcUsesSdk,
@@ -1144,8 +1192,8 @@ public class ManifestMerger {
*/
private Node insertAtEndOf(Element dest, Node start, Node end) {
// Check whether we'll need to adjust URI prefixes
- String destPrefix = XmlUtils.lookupNsPrefix(mMainDoc, NS_URI);
- String srcPrefix = XmlUtils.lookupNsPrefix(start.getOwnerDocument(), NS_URI);
+ String destPrefix = XmlUtils.lookupNamespacePrefix(mMainDoc, NS_URI);
+ String srcPrefix = XmlUtils.lookupNamespacePrefix(start.getOwnerDocument(), NS_URI);
boolean needPrefixChange = destPrefix != null && !destPrefix.equals(srcPrefix);
// First let's figure out the insertion point.
@@ -1233,13 +1281,13 @@ public class ManifestMerger {
@Nullable String keyAttr) {
Map<String, String> nsPrefixE = new HashMap<String, String>();
Map<String, String> nsPrefixA = new HashMap<String, String>();
- String sE = XmlUtils.printElement(expected, nsPrefixE, ""); //$NON-NLS-1$
- String sA = XmlUtils.printElement(actual, nsPrefixA, ""); //$NON-NLS-1$
+ String sE = MergerXmlUtils.printElement(expected, nsPrefixE, ""); //$NON-NLS-1$
+ String sA = MergerXmlUtils.printElement(actual, nsPrefixA, ""); //$NON-NLS-1$
if (sE.equals(sA)) {
return true;
} else {
if (diff != null) {
- XmlUtils.printXmlDiff(diff, sE, sA, nsPrefixE, nsPrefixA, NS_URI + ':' + keyAttr);
+ MergerXmlUtils.printXmlDiff(diff, sE, sA, nsPrefixE, nsPrefixA, NS_URI + ':' + keyAttr);
}
return false;
}
@@ -1363,8 +1411,86 @@ public class ManifestMerger {
* @return A new non-null {@link FileAndLine} combining the file name and line number.
*/
private @NonNull FileAndLine xmlFileAndLine(@NonNull Node node) {
- return XmlUtils.xmlFileAndLine(node);
+ return MergerXmlUtils.xmlFileAndLine(node);
+ }
+
+ /**
+ * Checks whether the given element has a tools:merge=override or tools:merge=remove attribute.
+ * @param node The node to check.
+ * @return True if the element has a tools:merge=override or tools:merge=remove attribute.
+ */
+ private boolean hasOverrideOrRemoveTag(@Nullable Node node) {
+ if (node == null || node.getNodeType() != Node.ELEMENT_NODE) {
+ return false;
+ }
+ NamedNodeMap attrs = node.getAttributes();
+ Node merge = attrs.getNamedItemNS(TOOLS_URI, MERGE_ATTR);
+ String value = merge == null ? null : merge.getNodeValue();
+ return MERGE_OVERRIDE.equals(value) || MERGE_REMOVE.equals(value);
}
+ /**
+ * Cleans up all tools attributes from the given node hierarchy.
+ * <p/>
+ * If an element is marked with tools:merge=override, this attribute is removed.
+ * If an element is marked with tools:merge=remove, the <em>whole</em> element is removed.
+ *
+ * @param root The root node to parse and edit, recursively.
+ */
+ private void cleanupToolsAttributes(@Nullable Node root) {
+ if (root == null) {
+ return;
+ }
+ NamedNodeMap attrs = root.getAttributes();
+ if (attrs != null) {
+ for (int i = attrs.getLength() - 1; i >= 0; i--) {
+ Node attr = attrs.item(i);
+ if (SdkConstants.XMLNS_URI.equals(attr.getNamespaceURI()) &&
+ TOOLS_URI.equals(attr.getNodeValue())) {
+ attrs.removeNamedItem(attr.getNodeName());
+ } else if (TOOLS_URI.equals(attr.getNamespaceURI()) &&
+ MERGE_ATTR.equals(attr.getLocalName())) {
+ attrs.removeNamedItem(attr.getNodeName());
+ }
+ }
+ assert attrs.getNamedItemNS(TOOLS_URI, MERGE_ATTR) == null;
+ }
+
+ for (Node child = root.getFirstChild(); child != null; ) {
+ if (child.getNodeType() != Node.ELEMENT_NODE) {
+ child = child.getNextSibling();
+ continue;
+ }
+ attrs = child.getAttributes();
+ Node merge = attrs == null ? null : attrs.getNamedItemNS(TOOLS_URI, MERGE_ATTR);
+ String value = merge == null ? null : merge.getNodeValue();
+ Node sibling = child.getNextSibling();
+ if (MERGE_REMOVE.equals(value)) {
+ // Note: save the previous sibling since removing the child will clear its siblings.
+ Node prev = child.getPreviousSibling();
+ root.removeChild(child);
+ // If there's some whitespace just before that element, clean it up too.
+ while (prev != null && prev.getNodeType() == Node.TEXT_NODE) {
+ if (prev.getNodeValue().trim().length() == 0) {
+ Node prevPrev = prev.getPreviousSibling();
+ root.removeChild(prev);
+ prev = prevPrev;
+ } else {
+ break;
+ }
+ }
+ } else {
+ cleanupToolsAttributes(child);
+ }
+ child = sibling;
+ }
+ }
+ /**
+ * @see #cleanupToolsAttributes(Node)
+ */
+ private Document cleanupToolsAttributes(@NonNull Document doc) {
+ cleanupToolsAttributes(doc.getFirstChild());
+ return doc;
+ }
}
diff --git a/manifmerger/src/com/android/manifmerger/XmlUtils.java b/manifmerger/src/com/android/manifmerger/MergerXmlUtils.java
index b17c7d4..4381479 100755
--- a/manifmerger/src/com/android/manifmerger/XmlUtils.java
+++ b/manifmerger/src/com/android/manifmerger/MergerXmlUtils.java
@@ -21,6 +21,7 @@ import com.android.annotations.Nullable;
import com.android.manifmerger.IMergerLog.FileAndLine;
import com.android.manifmerger.IMergerLog.Severity;
import com.android.utils.ILogger;
+import com.android.utils.XmlUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
@@ -57,7 +58,7 @@ import javax.xml.transform.stream.StreamResult;
/**
* A few XML handling utilities.
*/
-class XmlUtils {
+class MergerXmlUtils {
private static final String DATA_ORIGIN_FILE = "manif.merger.file"; //$NON-NLS-1$
private static final String DATA_FILE_NAME = "manif.merger.filename"; //$NON-NLS-1$
@@ -270,17 +271,6 @@ class XmlUtils {
}
/**
- * Find the prefix for the given NS_URI in the document.
- *
- * @param doc The document root.
- * @param nsUri The Namespace URI to look for.
- * @return The namespace prefix if found or null.
- */
- static String lookupNsPrefix(Document doc, String nsUri) {
- return com.android.utils.XmlUtils.lookupNamespacePrefix(doc, nsUri);
- }
-
- /**
* Outputs the given XML {@link Document} to the file {@code outFile}.
*
* TODO right now reformats the document. Needs to output as-is, respecting white-space.
@@ -617,8 +607,9 @@ class XmlUtils {
// We want to add or replace the attribute.
if (attr == null) {
attr = doc.createAttributeNS(attrNsUri, attrName);
- attr.setPrefix(
- com.android.utils.XmlUtils.lookupNamespacePrefix(element, attrNsUri));
+ if (attrNsUri != null) {
+ attr.setPrefix(XmlUtils.lookupNamespacePrefix(element, attrNsUri));
+ }
attrs.setNamedItemNS(attr);
}
attr.setNodeValue(value);
@@ -703,7 +694,7 @@ class XmlUtils {
hasText = true;
}
} else if (t == Node.ELEMENT_NODE) {
- children.add(printElement(child, nsPrefix, prefix)); //$NON-NLS-1$
+ children.add(printElement(child, nsPrefix, prefix));
if (!nextSiblings) {
break;
}
diff --git a/manifmerger/tests/src/com/android/manifmerger/ManifestMergerTest.java b/manifmerger/tests/src/com/android/manifmerger/ManifestMergerTest.java
index 63b76b8..717533a 100755
--- a/manifmerger/tests/src/com/android/manifmerger/ManifestMergerTest.java
+++ b/manifmerger/tests/src/com/android/manifmerger/ManifestMergerTest.java
@@ -157,4 +157,24 @@ public class ManifestMergerTest extends ManifestMergerTestCase {
public void test60_merge_order() throws Exception {
processTestFiles();
}
+
+ public void test65_override_app() throws Exception {
+ processTestFiles();
+ }
+
+ public void test66_remove_app() throws Exception {
+ processTestFiles();
+ }
+
+ public void test67_override_activities() throws Exception {
+ processTestFiles();
+ }
+
+ public void test68_override_uses() throws Exception {
+ processTestFiles();
+ }
+
+ public void test69_remove_uses() throws Exception {
+ processTestFiles();
+ }
}
diff --git a/manifmerger/tests/src/com/android/manifmerger/ManifestMergerTestCase.java b/manifmerger/tests/src/com/android/manifmerger/ManifestMergerTestCase.java
index b2cdfab..b044c3a 100755
--- a/manifmerger/tests/src/com/android/manifmerger/ManifestMergerTestCase.java
+++ b/manifmerger/tests/src/com/android/manifmerger/ManifestMergerTestCase.java
@@ -435,19 +435,19 @@ abstract class ManifestMergerTestCase extends TestCase {
// Test result XML. There should always be one created
// since the process action does not stop on errors.
log.clear();
- Document document = XmlUtils.parseDocument(testFiles.getActualResult(), mergerLog);
+ Document document = MergerXmlUtils.parseDocument(testFiles.getActualResult(), mergerLog);
assertNotNull(document);
assert document != null; // for Eclipse null analysis
- String actual = XmlUtils.printXmlString(document, mergerLog);
+ String actual = MergerXmlUtils.printXmlString(document, mergerLog);
assertEquals("Error parsing actual result XML", "[]", log.toString());
log.clear();
- document = XmlUtils.parseDocument(
+ document = MergerXmlUtils.parseDocument(
testFiles.getExpectedResult(),
mergerLog,
new FileAndLine("<expected-result>", 0));
- assertNotNull(document);
+ assertNotNull("Failed to parse result document: " + testFiles.getExpectedResult(),document);
assert document != null;
- String expected = XmlUtils.printXmlString(document, mergerLog);
+ String expected = MergerXmlUtils.printXmlString(document, mergerLog);
assertEquals("Error parsing expected result XML", "[]", log.toString());
assertEquals("Error comparing expected to actual result", expected, actual);
diff --git a/manifmerger/tests/src/com/android/manifmerger/data/17_fqcn_conflict.xml b/manifmerger/tests/src/com/android/manifmerger/data/17_fqcn_conflict.xml
index 7b95027..b4f5ea0 100755
--- a/manifmerger/tests/src/com/android/manifmerger/data/17_fqcn_conflict.xml
+++ b/manifmerger/tests/src/com/android/manifmerger/data/17_fqcn_conflict.xml
@@ -70,7 +70,9 @@
@lib4_not_package
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- It's an error for the manifest to lack a 'package' attribute. -->
+ <!-- It's an error for the manifest to lack a 'package' attribute.
+ We just emit a warning in this case.
+ -->
<application>
<!-- These class name can't be expanded due to the lack of 'package' attribute. -->
diff --git a/manifmerger/tests/src/com/android/manifmerger/data/21_uses_lib_errors.xml b/manifmerger/tests/src/com/android/manifmerger/data/21_uses_lib_errors.xml
index 65f0fb6..9e8f5a0 100755
--- a/manifmerger/tests/src/com/android/manifmerger/data/21_uses_lib_errors.xml
+++ b/manifmerger/tests/src/com/android/manifmerger/data/21_uses_lib_errors.xml
@@ -75,7 +75,7 @@
android:name="com.example.SomeLibrary2_RequiredTrue"
android:required="true" />
- <!-- Same as 3 from main. Warning because destination as a duplicate. -->
+ <!-- Same as 3 from main. Warning because destination has a duplicate. -->
<uses-library
android:name="com.example.SomeLibrary3_RequiredFalse"
android:required="false" />
diff --git a/manifmerger/tests/src/com/android/manifmerger/data/56_support_gltext_warning.xml b/manifmerger/tests/src/com/android/manifmerger/data/56_support_gltext_warning.xml
index 494fd2e..114e9f4 100755
--- a/manifmerger/tests/src/com/android/manifmerger/data/56_support_gltext_warning.xml
+++ b/manifmerger/tests/src/com/android/manifmerger/data/56_support_gltext_warning.xml
@@ -1,7 +1,6 @@
#
# Test supports-gl-texture:
-# - it's OK if a library defines one or multiple times an element already in the application.
-# - it's a warning if the library defines an element not in the application.
+# - it's a warning if the library defines a supports-gl-texture not in the application.
# - this does not actually merge anything. The XML is not changed at all.
#
diff --git a/manifmerger/tests/src/com/android/manifmerger/data/60_merge_order.xml b/manifmerger/tests/src/com/android/manifmerger/data/60_merge_order.xml
index e820ecb..d6767f7 100755
--- a/manifmerger/tests/src/com/android/manifmerger/data/60_merge_order.xml
+++ b/manifmerger/tests/src/com/android/manifmerger/data/60_merge_order.xml
@@ -1,8 +1,9 @@
#
-# Test:
+# Test merge order:
# - When activity / activity-alias / service / receiver / provider are merged,
# we do a comparison to check whether the elements are already present in the
-# main manifest.
+# main manifest. The order of the elements must NOT matter in the comparison,
+# nor does the whitespace between them.
# - What this checks is that the order of the elements or attributes within
# the elements should not matter.
#
diff --git a/manifmerger/tests/src/com/android/manifmerger/data/65_override_app.xml b/manifmerger/tests/src/com/android/manifmerger/data/65_override_app.xml
new file mode 100755
index 0000000..464b52f
--- /dev/null
+++ b/manifmerger/tests/src/com/android/manifmerger/data/65_override_app.xml
@@ -0,0 +1,197 @@
+#
+# Test the tools:merge="override" tag on an application.
+# It essentially ignores _any_ application tag from libraries.
+# All other non-application elements are merged as usual.
+#
+
+@main
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.example.app1"
+ android:versionCode="100"
+ android:versionName="1.0.0">
+
+ <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="11"/>
+
+ <supports-screens
+ android:largeScreens="true"
+ android:smallScreens="true"
+ android:normalScreens="true"
+ android:resizeable="true"
+ android:xlargeScreens="true"
+ />
+
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <application
+ tools:merge="override"
+ android:name="TheApp"
+ android:backupAgent=".MyBackupAgent" >
+ <activity android:name=".MainActivity" />
+ <receiver android:name="AppReceiver" />
+ <activity android:name="com.example.lib2.LibActivity" />
+ </application>
+
+</manifest>
+
+
+@lib1_widget
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.lib1">
+
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+
+ <permission
+ android:name="com.example.WhatWereYouThinking"
+ android:permissionGroup="com.example.MasterControlPermission"
+ android:protectionLevel="signatureOrSystem" />
+
+ <!-- This is overridden by main manifest and never merged, INCLUDING all activities. -->
+ <application android:name="TheApp" >
+ <activity android:name=".WidgetLibrary1" />
+ </application>
+
+</manifest>
+
+
+@lib2_widget
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.lib2">
+
+ <uses-feature
+ android:name="android.hardware.touchscreen"
+ android:required="false" />
+
+ <permission
+ android:description="Insert boring description here"
+ android:icon="@drawable/robot"
+ android:label="Danger, Will Robinson!"
+ android:name="com.example.DangerWillRobinson"
+ android:permissionGroup="com.example.MasterControlPermission"
+ android:protectionLevel="dangerous" />
+
+ <!-- This is overridden by main manifest and never merged, INCLUDING all activities. -->
+ <application
+ android:name="com.example.app1.TheApp"
+ android:backupAgent=".MyBackupAgent" >
+ <activity android:name=".WidgetLibrary2" />
+ <activity android:name=".LibActivity" />
+ </application>
+
+</manifest>
+
+
+@lib3_widget
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.lib3">
+
+ <permission-group
+ android:description="Nobody expects..."
+ android:icon="@drawable/ignored_icon"
+ android:label="the Spanish Inquisition"
+ android:name="com.example.MasterControlPermission" />
+
+ <!-- This is overridden by main manifest and never merged, INCLUDING all activities. -->
+ <application android:name="com.example.app1.TheApp">
+ <activity android:name=".WidgetLibrary3" />
+ </application>
+
+</manifest>
+
+
+@lib4_not_package
+
+<!-- It's an error for the manifest to lack a 'package' attribute.
+ We just emit a warning in this case.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <!-- Permission tree for lib4 -->
+ <permission-tree
+ android:label="This is not a label"
+ android:name="com.example.PermTree" />
+
+ <!-- This is overridden by main manifest and never merged, INCLUDING all activities. -->
+ <application>
+ <!-- These class name can't be expanded due to the lack of 'package' attribute. -->
+ <activity android:name=".LibActivity4" />
+ <service android:name=".LibService4" />
+ <receiver android:name=".LibReceiver4" />
+ <provider android:name=".LibProvider4" />
+
+ </application>
+
+</manifest>
+
+
+@result
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.app1"
+ android:versionCode="100"
+ android:versionName="1.0.0">
+
+ <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="11"/>
+
+ <supports-screens
+ android:largeScreens="true"
+ android:smallScreens="true"
+ android:normalScreens="true"
+ android:resizeable="true"
+ android:xlargeScreens="true"
+ />
+
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <application
+ android:name="com.example.app1.TheApp"
+ android:backupAgent="com.example.app1.MyBackupAgent" >
+ <activity android:name="com.example.app1.MainActivity" />
+ <receiver android:name="com.example.app1.AppReceiver" />
+ <activity android:name="com.example.lib2.LibActivity" />
+ </application>
+
+ <permission
+ android:name="com.example.WhatWereYouThinking"
+ android:permissionGroup="com.example.MasterControlPermission"
+ android:protectionLevel="signatureOrSystem" />
+
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+
+ <permission
+ android:description="Insert boring description here"
+ android:icon="@drawable/robot"
+ android:label="Danger, Will Robinson!"
+ android:name="com.example.DangerWillRobinson"
+ android:permissionGroup="com.example.MasterControlPermission"
+ android:protectionLevel="dangerous" />
+
+ <uses-feature
+ android:name="android.hardware.touchscreen"
+ android:required="false" />
+
+ <permission-group
+ android:description="Nobody expects..."
+ android:icon="@drawable/ignored_icon"
+ android:label="the Spanish Inquisition"
+ android:name="com.example.MasterControlPermission" />
+
+ <!-- Permission tree for lib4 -->
+ <permission-tree
+ android:label="This is not a label"
+ android:name="com.example.PermTree" />
+
+</manifest>
+
+@errors
+
+W [ManifestMergerTest4_lib4_not_package.xml:1] Missing 'package' attribute in manifest.
diff --git a/manifmerger/tests/src/com/android/manifmerger/data/66_remove_app.xml b/manifmerger/tests/src/com/android/manifmerger/data/66_remove_app.xml
new file mode 100755
index 0000000..a1b04b5
--- /dev/null
+++ b/manifmerger/tests/src/com/android/manifmerger/data/66_remove_app.xml
@@ -0,0 +1,53 @@
+#
+# Test how elements are removed by tools:merge="remove".
+#
+
+@main
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.example.app1"
+ android:versionCode="100"
+ android:versionName="1.0.0">
+
+ <!-- The "remove" tag will eradicate this element from the output. -->
+ <application
+ tools:merge="remove"
+ android:name="TheApp"
+ android:backupAgent=".MyBackupAgent" >
+ <activity android:name=".MainActivity" />
+ <receiver android:name="AppReceiver" />
+ <activity android:name="com.example.lib2.LibActivity" />
+ </application>
+</manifest>
+
+
+@lib1_widget
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.lib1">
+
+ <!-- This application and all its activities or content is ignored because the
+ main manifest requested to remove the application element. -->
+ <application android:name="TheApp" >
+ <activity android:name=".WidgetLibrary1" />
+ </application>
+</manifest>
+
+
+
+@result
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.app1"
+ android:versionCode="100"
+ android:versionName="1.0.0">
+
+ <!-- The "remove" tag will eradicate this element from the output. -->
+</manifest>
+
+@errors
+
diff --git a/manifmerger/tests/src/com/android/manifmerger/data/67_override_activities.xml b/manifmerger/tests/src/com/android/manifmerger/data/67_override_activities.xml
new file mode 100755
index 0000000..8bcdb63
--- /dev/null
+++ b/manifmerger/tests/src/com/android/manifmerger/data/67_override_activities.xml
@@ -0,0 +1,159 @@
+#
+# Test how elements are overriden by tools:merge="override".
+# The override only blocks elements that would be merged.
+#
+
+@main
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.example"
+ android:versionCode="100"
+ android:versionName="1.0.0">
+
+ <application
+ android:name="TheApp"
+ android:backupAgent=".MyBackupAgent" >
+ <activity android:name=".MainActivity" tools:merge="override" />
+ <receiver android:name="AppReceiver" tools:merge="override"/>
+ <activity android:name="com.example.lib2.LibActivity" />
+ <service android:name="com.example.AppService1" tools:merge="override" />
+ <provider android:name="com.example.Provider1" tools:merge="override" />
+ <activity-alias android:name="AliasActivity1" tools:merge="override" />
+
+ </application>
+</manifest>
+
+
+@lib1
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example">
+
+ <application>
+ <!-- Activity merged -->
+ <activity android:name=".WidgetLibrary1" />
+
+ <!-- Conflicting activity ignored by override -->
+ <activity
+ android:name="com.example.MainActivity"
+ android:label="@string/activity_name"
+ android:icon="@drawable/activity_icon"
+ android:theme="@style/Some.Theme">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <!-- Conflicting receiver ignored by override -->
+ <receiver
+ android:name="com.example.AppReceiver"
+ android:icon="@drawable/app_icon">
+ <intent-filter>
+ <action android:name="com.example.action.ACTION_CUSTOM" />
+ </intent-filter>
+ </receiver>
+
+ <!-- Receiver merged -->
+ <receiver android:name="LibReceiver" />
+
+ <!-- Conflicting alias activity ignored by override -->
+ <activity-alias
+ android:name="com.example.AliasActivity1"
+ android:targetActivity="com.example.MainActivity1"
+ android:label="@string/alias_name1"
+ android:icon="@drawable/alias_icon1">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity-alias>
+
+ <!-- Alias activity merged -->
+ <activity-alias
+ android:name="com.example.alias.MyActivity2"
+ android:targetActivity="com.example.MainActivity2"
+ android:label="@string/alias_name2"
+ android:icon="@drawable/alias_icon2">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity-alias>
+
+ <!-- Conflicting service ignored by override -->
+ <service
+ android:icon="@drawable/app_icon"
+ android:name="com.example.AppService1" />
+
+ <!-- Service merged -->
+ <service
+ android:icon="@drawable/app_icon"
+ android:name="com.example.AppService2" />
+
+ <!-- Conflicting provider ignored by override -->
+ <provider
+ android:name="com.example.Provider1"
+ android:authorities="com.example.android.apis.app.thingy1"
+ android:enabled="@bool/someConditionalValue" />
+
+ <!-- Provider merged -->
+ <provider
+ android:name="com.example.Provider2" />
+
+ </application>
+</manifest>
+
+
+@result
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example"
+ android:versionCode="100"
+ android:versionName="1.0.0">
+
+ <application
+ android:name="com.example.TheApp"
+ android:backupAgent="com.example.MyBackupAgent" >
+ <activity android:name="com.example.MainActivity" />
+ <receiver android:name="com.example.AppReceiver" />
+ <activity android:name="com.example.lib2.LibActivity" />
+ <service android:name="com.example.AppService1" />
+ <provider android:name="com.example.Provider1" />
+ <activity-alias android:name="com.example.AliasActivity1" />
+ <!-- Activity merged -->
+ <activity android:name="com.example.WidgetLibrary1" />
+
+ <!-- Alias activity merged -->
+ <activity-alias
+ android:name="com.example.alias.MyActivity2"
+ android:targetActivity="com.example.MainActivity2"
+ android:label="@string/alias_name2"
+ android:icon="@drawable/alias_icon2">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity-alias>
+
+ <!-- Service merged -->
+ <service
+ android:icon="@drawable/app_icon"
+ android:name="com.example.AppService2" />
+
+ <!-- Receiver merged -->
+ <receiver android:name="com.example.LibReceiver" />
+
+ <!-- Provider merged -->
+ <provider
+ android:name="com.example.Provider2" />
+
+ </application>
+</manifest>
+
+@errors
+
diff --git a/manifmerger/tests/src/com/android/manifmerger/data/68_override_uses.xml b/manifmerger/tests/src/com/android/manifmerger/data/68_override_uses.xml
new file mode 100755
index 0000000..a43d13e
--- /dev/null
+++ b/manifmerger/tests/src/com/android/manifmerger/data/68_override_uses.xml
@@ -0,0 +1,205 @@
+#
+# Test how elements are overriden by tools:merge="override".
+# The override only blocks elements that would be merged.
+# That means items which are just checked (not merged) still produce warnings.
+#
+
+@main
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.example"
+ android:versionCode="100"
+ android:versionName="1.0.0">
+
+ <!-- This is the same as writing android:minSdkVersion="1" -->
+ <uses-sdk android:targetSdkVersion="14" tools:merge="override" />
+
+ <!-- Ignore permissions elements from lib that would conflict because
+ their definition is different. -->
+ <permission
+ tools:merge="override"
+ android:name="com.example.WhatWereYouThinking"
+ android:permissionGroup="com.example.MasterControlPermission"
+ android:protectionLevel="signatureOrSystem" />
+
+ <permission-group
+ tools:merge="override"
+ android:description="Nobody expects..."
+ android:icon="@drawable/ignored_icon"
+ android:label="the Spanish Inquisition"
+ android:name="com.example.MasterControlPermission" />
+
+ <permission-tree
+ tools:merge="override"
+ android:label="This is not a label"
+ android:name="com.example.PermTree" />
+
+ <!-- uses-feature is never merged, only checked, so tools:merge=override does nothing. -->
+ <uses-feature
+ android:name="com.example.SomeFeature0"
+ android:glEsVersion="0x00020001" />
+ <!-- Ignore uses-feature from library, which would change required to
+ true if it were merged. -->
+ <uses-feature
+ tools:merge="override"
+ android:name="com.example.SomeFeature1"
+ android:required="false" />
+
+ <!-- supports-screens is never merged, only checked, so tools:merge=override does nothing. -->
+ <supports-screens
+ tools:merge="override"
+ android:smallScreens="true"
+ android:resizeable="false"
+ />
+
+ <!-- supports-gl-texture-screens-feature is never merged, only checked, so tools:merge=override does nothing. -->
+ <supports-gl-texture android:name="some.gl.texture1" tools:merge="override" />
+
+ <application android:name="com.example.TheApp" >
+ <!-- Ignore uses-library from library, which would change required to
+ true if it were merged. -->
+ <uses-library
+ android:name="com.example.SomeLibrary4_RequiredFalse"
+ android:required="false"
+ tools:merge="override" />
+
+ </application>
+
+</manifest>
+
+
+@lib1
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example">
+
+ <!-- The app can cope with API 1 but this library can only cope with API 4. -->
+ <uses-sdk android:minSdkVersion="4" />
+
+ <!-- Ignored permissions -->
+ <permission
+ android:name="com.example.WhatWereYouThinking"
+ android:permissionGroup="com.example.AnotherGroup"
+ android:protectionLevel="system" />
+
+ <permission-group
+ android:label="Nobody expects the Spanish Inquisition"
+ android:name="com.example.MasterControlPermission" />
+
+ <permission-tree
+ android:description="This is not the same label"
+ android:name="com.example.PermTree" />
+
+ <!-- GL 0.0 is a warning which is not prevented by tools:merge=override. -->
+ <uses-feature
+ android:name="com.example.SomeFeature0"
+ android:glEsVersion="0x00000000" />
+ <uses-feature
+ android:name="com.example.SomeFeature1"
+ android:required="true" />
+
+ <!-- supports-screens isn't really merged, just checked, so tools:merge=override does nothing. -->
+ <!-- this is the not same supports-screens than in the main, will till make a warning. -->
+ <supports-screens
+ android:smallScreens="false"
+ android:resizeable="false"
+ />
+
+ <!-- supports-gl-texture isn't really merged, just checked, so tools:merge=override does nothing. -->
+ <!-- this is the not same supports-gl-texture than in the main. -->
+ <supports-gl-texture android:name="some.gl.texture3" />
+
+ <application android:name="com.example.TheApp" >
+ <!-- Ignored uses-library -->
+ <uses-library
+ android:name="com.example.SomeLibrary4_RequiredFalse"
+ android:required="true" />
+
+ </application>
+
+</manifest>
+
+
+@lib2
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example">
+
+ <!-- The app targets API 14 but this library targets 42. -->
+ <uses-sdk android:targetSdkVersion="42" />
+
+</manifest>
+
+
+@result
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example"
+ android:versionCode="100"
+ android:versionName="1.0.0">
+
+ <!-- This is the same as writing android:minSdkVersion="1" -->
+ <uses-sdk android:targetSdkVersion="14" />
+
+ <!-- Ignore permissions elements from lib that would conflict because
+ their definition is different. -->
+ <permission
+ android:name="com.example.WhatWereYouThinking"
+ android:permissionGroup="com.example.MasterControlPermission"
+ android:protectionLevel="signatureOrSystem" />
+
+ <permission-group
+ android:description="Nobody expects..."
+ android:icon="@drawable/ignored_icon"
+ android:label="the Spanish Inquisition"
+ android:name="com.example.MasterControlPermission" />
+
+ <permission-tree
+ android:label="This is not a label"
+ android:name="com.example.PermTree" />
+
+ <!-- uses-feature is never merged, only checked, so tools:merge=override does nothing. -->
+ <uses-feature
+ android:name="com.example.SomeFeature0"
+ android:glEsVersion="0x00020001" />
+ <!-- Ignore uses-feature from library, which would change required to
+ true if it were merged. -->
+ <uses-feature
+ android:name="com.example.SomeFeature1"
+ android:required="false" />
+
+ <!-- supports-screens is never merged, only checked, so tools:merge=override does nothing. -->
+ <supports-screens
+ android:smallScreens="true"
+ android:resizeable="false"
+ />
+
+ <!-- supports-gl-texture-screens-feature is never merged, only checked, so tools:merge=override does nothing. -->
+ <supports-gl-texture android:name="some.gl.texture1" />
+
+ <application android:name="com.example.TheApp" >
+ <!-- Ignore uses-library from library, which would change required to
+ true if it were merged. -->
+ <uses-library
+ android:name="com.example.SomeLibrary4_RequiredFalse"
+ android:required="false" />
+
+ </application>
+
+</manifest>
+
+@errors
+
+W [ManifestMergerTest0_main.xml:1, ManifestMergerTest1_lib1.xml:19] /manifest/supports-screens defined in library, missing from main manifest:
+<supports-screens>
+ @android:resizeable = false
+ @android:smallScreens = false
+W [ManifestMergerTest0_main.xml:1, ManifestMergerTest1_lib1.xml:23] /manifest/supports-gl-texture defined in library, missing from main manifest:
+<supports-gl-texture>
+ @android:name = some.gl.texture3
+W [ManifestMergerTest1_lib1.xml:14] Ignoring <uses-feature android:glEsVersion='0x00000000'> because it's smaller than 1.0.
diff --git a/manifmerger/tests/src/com/android/manifmerger/data/69_remove_uses.xml b/manifmerger/tests/src/com/android/manifmerger/data/69_remove_uses.xml
new file mode 100755
index 0000000..c3e46c9
--- /dev/null
+++ b/manifmerger/tests/src/com/android/manifmerger/data/69_remove_uses.xml
@@ -0,0 +1,177 @@
+#
+# Test how elements are removed by tools:merge="remove".
+# The removal happens is done at the end and block merges.
+# That means items which are just checked (not merged) still produce warnings.
+#
+
+@main
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.example"
+ android:versionCode="100"
+ android:versionName="1.0.0">
+
+ <!-- This is the same as writing android:minSdkVersion="1" -->
+ <uses-sdk android:targetSdkVersion="14" tools:merge="remove" />
+
+ <!-- Ignore permissions elements from lib that would conflict because
+ their definition is different. -->
+ <permission
+ tools:merge="remove"
+ android:name="com.example.WhatWereYouThinking"
+ android:permissionGroup="com.example.MasterControlPermission"
+ android:protectionLevel="signatureOrSystem" />
+
+ <permission-group
+ tools:merge="remove"
+ android:description="Nobody expects..."
+ android:icon="@drawable/ignored_icon"
+ android:label="the Spanish Inquisition"
+ android:name="com.example.MasterControlPermission" />
+
+ <permission-tree
+ tools:merge="remove"
+ android:label="This is not a label"
+ android:name="com.example.PermTree" />
+
+ <!-- uses-feature is never merged, only checked, so tools:merge=remove does nothing. -->
+ <uses-feature
+ tools:merge="remove"
+ android:name="com.example.SomeFeature0"
+ android:glEsVersion="0x00020001" />
+ <!-- Ignore uses-feature from library, which would change required to
+ true if it were merged. -->
+ <uses-feature
+ tools:merge="remove"
+ android:name="com.example.SomeFeature1"
+ android:required="false" />
+
+ <!-- supports-screens is never merged, only checked, so tools:merge=remove does nothing. -->
+ <supports-screens
+ tools:merge="remove"
+ android:smallScreens="true"
+ android:resizeable="false"
+ />
+
+ <!-- supports-gl-texture-screens-feature is never merged, only checked, so tools:merge=remove does nothing. -->
+ <supports-gl-texture android:name="some.gl.texture1" tools:merge="remove" />
+
+ <application android:name="com.example.TheApp" >
+ <!-- Ignore uses-library from library, which would change required to
+ true if it were merged. -->
+ <uses-library
+ tools:merge="remove"
+ android:name="com.example.SomeLibrary4_RequiredFalse"
+ android:required="false" />
+
+ </application>
+
+</manifest>
+
+
+@lib1
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example">
+
+ <!-- The app can cope with API 1 but this library can only cope with API 4. -->
+ <uses-sdk android:minSdkVersion="4" />
+
+ <!-- Ignored permissions -->
+ <permission
+ android:name="com.example.WhatWereYouThinking"
+ android:permissionGroup="com.example.AnotherGroup"
+ android:protectionLevel="system" />
+
+ <permission-group
+ android:label="Nobody expects the Spanish Inquisition"
+ android:name="com.example.MasterControlPermission" />
+
+ <permission-tree
+ android:description="This is not the same label"
+ android:name="com.example.PermTree" />
+
+ <!-- GL 0.0 is a warning which is not prevented by tools:merge=remove. -->
+ <uses-feature
+ android:name="com.example.SomeFeature0"
+ android:glEsVersion="0x00000000" />
+ <uses-feature
+ android:name="com.example.SomeFeature1"
+ android:required="true" />
+
+ <!-- supports-screens isn't really merged, just checked, so tools:merge=remove does nothing. -->
+ <!-- this is the not same supports-screens than in the main, will till make a warning. -->
+ <supports-screens
+ android:smallScreens="false"
+ android:resizeable="false"
+ />
+
+ <!-- supports-gl-texture isn't really merged, just checked, so tools:merge=remove does nothing. -->
+ <!-- this is the not same supports-gl-texture than in the main. -->
+ <supports-gl-texture android:name="some.gl.texture3" />
+
+ <application android:name="com.example.TheApp" >
+ <!-- Ignored uses-library -->
+ <uses-library
+ android:name="com.example.SomeLibrary4_RequiredFalse"
+ android:required="true" />
+
+ </application>
+
+</manifest>
+
+
+@lib2
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example">
+
+ <!-- The app targets API 14 but this library targets 42. -->
+ <uses-sdk android:targetSdkVersion="42" />
+
+</manifest>
+
+
+@result
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example"
+ android:versionCode="100"
+ android:versionName="1.0.0">
+
+ <!-- This is the same as writing android:minSdkVersion="1" -->
+
+ <!-- Ignore permissions elements from lib that would conflict because
+ their definition is different. -->
+
+ <!-- uses-feature is never merged, only checked, so tools:merge=remove does nothing. -->
+ <!-- Ignore uses-feature from library, which would change required to
+ true if it were merged. -->
+
+ <!-- supports-screens is never merged, only checked, so tools:merge=remove does nothing. -->
+
+ <!-- supports-gl-texture-screens-feature is never merged, only checked, so tools:merge=remove does nothing. -->
+
+ <application android:name="com.example.TheApp" >
+ <!-- Ignore uses-library from library, which would change required to
+ true if it were merged. -->
+
+ </application>
+
+</manifest>
+
+@errors
+
+W [ManifestMergerTest0_main.xml:1, ManifestMergerTest1_lib1.xml:19] /manifest/supports-screens defined in library, missing from main manifest:
+<supports-screens>
+ @android:resizeable = false
+ @android:smallScreens = false
+W [ManifestMergerTest0_main.xml:1, ManifestMergerTest1_lib1.xml:23] /manifest/supports-gl-texture defined in library, missing from main manifest:
+<supports-gl-texture>
+ @android:name = some.gl.texture3
+W [ManifestMergerTest1_lib1.xml:14] Ignoring <uses-feature android:glEsVersion='0x00000000'> because it's smaller than 1.0.