XML deserialization for <macro>

Macro deserialization support is necessary for AarGeneratorAction to run successfully on macro resources.

PiperOrigin-RevId: 391055662
diff --git a/src/test/java/com/google/devtools/build/android/DataResourceXmlTest.java b/src/test/java/com/google/devtools/build/android/DataResourceXmlTest.java
index e44fba2..45fe210 100644
--- a/src/test/java/com/google/devtools/build/android/DataResourceXmlTest.java
+++ b/src/test/java/com/google/devtools/build/android/DataResourceXmlTest.java
@@ -15,6 +15,7 @@
 
 import static com.google.common.truth.Truth.assertAbout;
 import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assume.assumeTrue;
 
 import com.android.resources.ResourceType;
 import com.google.common.base.Function;
@@ -1033,6 +1034,19 @@
   }
 
   @Test
+  public void writeMacroXmlResource() throws Exception {
+    // TODO(b/193025750): The current version of the layoutlib prebuilt used by Bazel does not
+    // contain the macro type.
+    assumeTrue(ResourceType.getEnum("macro") != null);
+
+    String xml = "<macro name='foo'>@string/bar</macro>";
+    Path source = writeResourceXml(xml);
+    assertAbout(resourcePaths)
+        .that(parsedAndWritten(source, fqn("macro/foo")))
+        .xmlContentsIsEqualTo(resourcesXmlFrom(source, xml));
+  }
+
+  @Test
   public void serializeMultipleSimpleXmlResources() throws Exception {
     Path serialized = fs.getPath("out/out.bin");
     Path source = fs.getPath("res/values/values.xml");
diff --git a/src/tools/android/java/com/google/devtools/build/android/DataResourceXml.java b/src/tools/android/java/com/google/devtools/build/android/DataResourceXml.java
index 38c3d0ed..7d56958 100644
--- a/src/tools/android/java/com/google/devtools/build/android/DataResourceXml.java
+++ b/src/tools/android/java/com/google/devtools/build/android/DataResourceXml.java
@@ -323,6 +323,12 @@
       case XML:
         return XmlResourceValues.parseSimple(eventReader, resourceType, start, namespacesCollector);
       default:
+        // TODO(b/193025750): The current version of the layoutlib prebuilt used by Bazel does not
+        // contain the macro type. This work around allows using macro resource types internally
+        // until the layoutlib preuilt is updated or the dependency on it is removed.
+        if ("macro".equals(resourceType.getName())) {
+          return XmlResourceValues.parseMacro(eventReader, start, namespacesCollector);
+        }
         throw new XMLStreamException(
             String.format("Unhandled resourceType %s", resourceType), start.getLocation());
     }
diff --git a/src/tools/android/java/com/google/devtools/build/android/XmlResourceValues.java b/src/tools/android/java/com/google/devtools/build/android/XmlResourceValues.java
index f7b97a1..9967577 100644
--- a/src/tools/android/java/com/google/devtools/build/android/XmlResourceValues.java
+++ b/src/tools/android/java/com/google/devtools/build/android/XmlResourceValues.java
@@ -22,6 +22,7 @@
 import com.google.devtools.build.android.proto.SerializeFormat;
 import com.google.devtools.build.android.xml.AttrXmlResourceValue;
 import com.google.devtools.build.android.xml.IdXmlResourceValue;
+import com.google.devtools.build.android.xml.MacroXmlResourceValue;
 import com.google.devtools.build.android.xml.Namespaces;
 import com.google.devtools.build.android.xml.PluralXmlResourceValue;
 import com.google.devtools.build.android.xml.PublicXmlResourceValue;
@@ -279,6 +280,18 @@
     return attributeMap;
   }
 
+  static XmlResourceValue parseMacro(
+      XMLEventReader eventReader, StartElement start, Namespaces.Collector namespacesCollector)
+      throws XMLStreamException {
+    if (isEndTag(eventReader.peek(), start.getName())) {
+      throw new XMLStreamException(
+          String.format("<macro> must have contents %s", start), start.getLocation());
+    }
+
+    String contents = readContentsAsString(eventReader, start.getName(), namespacesCollector);
+    return MacroXmlResourceValue.of(contents);
+  }
+
   // TODO(corysmith): Replace this with real escaping system, preferably a performant high level xml
   // writing library. See AndroidDataWritingVisitor TODO.
   private static String escapeXmlValues(String data) {