Fix bug where merge conflicts for resources defined in XML with equal values were being falsely logged during build as warnings

RELNOTES: none
PiperOrigin-RevId: 161723206
diff --git a/src/test/java/com/google/devtools/build/android/AndroidDataMergerTest.java b/src/test/java/com/google/devtools/build/android/AndroidDataMergerTest.java
index 95d6eb8..1444b83 100644
--- a/src/test/java/com/google/devtools/build/android/AndroidDataMergerTest.java
+++ b/src/test/java/com/google/devtools/build/android/AndroidDataMergerTest.java
@@ -340,6 +340,39 @@
   }
 
   @Test
+  public void mergeDirectConflictDuplicatedWithDifferentSources() throws Exception {
+    Path primaryRoot = fileSystem.getPath("primary");
+    Path directRoot = fileSystem.getPath("direct");
+
+    ParsedAndroidData transitiveDependency = ParsedAndroidDataBuilder.empty();
+
+    ParsedAndroidData directDependency =
+        ParsedAndroidDataBuilder.buildOn(directRoot, fqnFactory)
+            // Two string/exit will create conflict.
+            .overwritable(
+                xml("string/exit")
+                    .source("values/strings.xml")
+                    .value(SimpleXmlResourceValue.createWithValue(Type.STRING, "way out")),
+                xml("string/exit")
+                    .source("values/more_strings.xml")
+                    .value(SimpleXmlResourceValue.createWithValue(Type.STRING, "way out")),
+                xml("string/another_key")
+                    .source("values/more_strings.xml")
+                    .value(SimpleXmlResourceValue.createWithValue(Type.STRING, "another way out")))
+            .build();
+
+    UnvalidatedAndroidData primary =
+        AndroidDataBuilder.of(primaryRoot)
+            .createManifest("AndroidManifest.xml", "com.google.mergetest")
+            .buildUnvalidated();
+
+    AndroidDataMerger merger = AndroidDataMerger.createWithDefaults();
+    merger.merge(transitiveDependency, directDependency, primary, false);
+
+    assertThat(loggingHandler.warnings).isEmpty();
+  }
+
+  @Test
   public void mergeDirectConflictWithPrimaryOverride() throws Exception {
     Path primaryRoot = fileSystem.getPath("primary");
     Path directRoot = fileSystem.getPath("direct");
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 0dcc77e..74c0bcb 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
@@ -369,4 +369,13 @@
   public String asConflictString() {
     return source.asConflictString();
   }
+
+  @Override
+  public boolean valueEquals(DataValue value) {
+    if (!(value instanceof DataResourceXml)) {
+      return false;
+    }
+    DataResourceXml other = (DataResourceXml) value;
+    return Objects.equals(xml, other.xml);
+  }
 }
diff --git a/src/tools/android/java/com/google/devtools/build/android/DataValue.java b/src/tools/android/java/com/google/devtools/build/android/DataValue.java
index b1d24f3..b399b10 100644
--- a/src/tools/android/java/com/google/devtools/build/android/DataValue.java
+++ b/src/tools/android/java/com/google/devtools/build/android/DataValue.java
@@ -38,4 +38,10 @@
 
   /** Provides a representation of the value suitable for a conflict message. */
   String asConflictString();
+
+  /**
+   * Ignores metadata in the DataValue object and returns true if the value properties are
+   * equivalent to another given DataValue object
+   */
+  boolean valueEquals(DataValue value);
 }
diff --git a/src/tools/android/java/com/google/devtools/build/android/DataValueFile.java b/src/tools/android/java/com/google/devtools/build/android/DataValueFile.java
index 7740e97..61c569c 100644
--- a/src/tools/android/java/com/google/devtools/build/android/DataValueFile.java
+++ b/src/tools/android/java/com/google/devtools/build/android/DataValueFile.java
@@ -129,4 +129,9 @@
   public String asConflictString() {
     return source.asConflictString();
   }
+
+  @Override
+  public boolean valueEquals(DataValue value) {
+    return equals(value);
+  }
 }
diff --git a/src/tools/android/java/com/google/devtools/build/android/MergeConflict.java b/src/tools/android/java/com/google/devtools/build/android/MergeConflict.java
index 2e1fcbe..958c1e8 100644
--- a/src/tools/android/java/com/google/devtools/build/android/MergeConflict.java
+++ b/src/tools/android/java/com/google/devtools/build/android/MergeConflict.java
@@ -86,7 +86,7 @@
   }
 
   boolean isValidWith(SourceChecker checker) throws IOException {
-    return !primary.equals(overwritten)
+    return !primary.valueEquals(overwritten)
         && !checker.checkEquality(primary.source(), overwritten.source());
   }