AAPT2: Strip dedicated tools namespace from XML

Android has a dedicated XML namespace dedicated for tools that should not be
included in the final APK. AAPT strips this out, but the feature was missing
from AAPT2. See: http://tools.android.com/tech-docs/tools-attributes

Bug: 29115919
Change-Id: I8f4fc79e6c8592a313a691134e44d16fd91f36ed
diff --git a/tools/aapt2/flatten/XmlFlattener.cpp b/tools/aapt2/flatten/XmlFlattener.cpp
index 3c1750c..ed5b60f 100644
--- a/tools/aapt2/flatten/XmlFlattener.cpp
+++ b/tools/aapt2/flatten/XmlFlattener.cpp
@@ -88,9 +88,14 @@
     }
 
     void visit(xml::Namespace* node) override {
-        writeNamespace(node, android::RES_XML_START_NAMESPACE_TYPE);
-        xml::Visitor::visit(node);
-        writeNamespace(node, android::RES_XML_END_NAMESPACE_TYPE);
+        if (node->namespaceUri == xml::kSchemaTools) {
+            // Skip dedicated tools namespace.
+            xml::Visitor::visit(node);
+        } else {
+            writeNamespace(node, android::RES_XML_START_NAMESPACE_TYPE);
+            xml::Visitor::visit(node);
+            writeNamespace(node, android::RES_XML_END_NAMESPACE_TYPE);
+        }
     }
 
     void visit(xml::Text* node) override {
@@ -183,6 +188,9 @@
                     continue;
                 }
             }
+            if (attr.namespaceUri == xml::kSchemaTools) {
+                continue;
+            }
             mFilteredAttrs.push_back(&attr);
         }
 
diff --git a/tools/aapt2/flatten/XmlFlattener_test.cpp b/tools/aapt2/flatten/XmlFlattener_test.cpp
index 8b3378f..d26f2e4 100644
--- a/tools/aapt2/flatten/XmlFlattener_test.cpp
+++ b/tools/aapt2/flatten/XmlFlattener_test.cpp
@@ -167,6 +167,33 @@
     EXPECT_EQ(uint32_t(0x010103b3), tree.getAttributeNameResID(0));
 }
 
+TEST_F(XmlFlattenerTest, FlattenCompiledXmlAndStripOnlyTools) {
+    std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom(R"EOF(
+            <View xmlns:tools="http://schemas.android.com/tools"
+                xmlns:foo="http://schemas.android.com/foo"
+                foo:bar="Foo"
+                tools:ignore="MissingTranslation"/>)EOF");
+
+    android::ResXMLTree tree;
+    ASSERT_TRUE(flatten(doc.get(), &tree));
+
+    ASSERT_EQ(tree.next(), android::ResXMLTree::START_NAMESPACE);
+
+    size_t len;
+    const char16_t* namespacePrefix = tree.getNamespacePrefix(&len);
+    EXPECT_EQ(StringPiece16(namespacePrefix, len), u"foo");
+
+    const char16_t* namespaceUri = tree.getNamespaceUri(&len);
+    ASSERT_EQ(StringPiece16(namespaceUri, len), u"http://schemas.android.com/foo");
+
+    ASSERT_EQ(tree.next(), android::ResXMLTree::START_TAG);
+
+    EXPECT_EQ(
+            tree.indexOfAttribute("http://schemas.android.com/tools", "ignore"),
+            android::NAME_NOT_FOUND);
+    EXPECT_GE(tree.indexOfAttribute("http://schemas.android.com/foo", "bar"), 0);
+}
+
 TEST_F(XmlFlattenerTest, AssignSpecialAttributeIndices) {
     std::unique_ptr<xml::XmlResource> doc = test::buildXmlDom(R"EOF(
             <View xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/tools/aapt2/xml/XmlUtil.h b/tools/aapt2/xml/XmlUtil.h
index f0d59b7..b75d8ac 100644
--- a/tools/aapt2/xml/XmlUtil.h
+++ b/tools/aapt2/xml/XmlUtil.h
@@ -29,6 +29,7 @@
 constexpr const char* kSchemaPublicPrefix = "http://schemas.android.com/apk/res/";
 constexpr const char* kSchemaPrivatePrefix = "http://schemas.android.com/apk/prv/res/";
 constexpr const char* kSchemaAndroid = "http://schemas.android.com/apk/res/android";
+constexpr const char* kSchemaTools = "http://schemas.android.com/tools";
 
 /**
  * Result of extracting a package name from a namespace URI declaration.