Inline string resource values into code

This will inline resource strings that have a single value into code if the Resources:getString(int id) method is used

This is currently only inlining into code, I will follow up with inlining into xml and then implement a second round of tracing to (hopefully) eliminate the resource table entry.

Bug: b/311321134
Bug: b/287398085
Change-Id: Id5f5301a13a3d0d3a17da8a539ba0a0c7dfe9297
diff --git a/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java
index 8273c96..e0cca4f 100644
--- a/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java
+++ b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java
@@ -4,7 +4,11 @@
 
 package com.android.build.shrinker.r8integration;
 
+import com.android.aapt.Resources.ConfigValue;
+import com.android.aapt.Resources.Entry;
+import com.android.aapt.Resources.Item;
 import com.android.aapt.Resources.ResourceTable;
+import com.android.aapt.Resources.Value;
 import com.android.build.shrinker.NoDebugReporter;
 import com.android.build.shrinker.ResourceShrinkerModel;
 import com.android.build.shrinker.ResourceTableUtilKt;
@@ -16,7 +20,9 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 public class R8ResourceShrinkerState {
 
@@ -38,12 +44,17 @@
   }
 
   public static class R8ResourceShrinkerModel extends ResourceShrinkerModel {
+    private final Map<Integer, String> stringResourcesWithSingleValue = new HashMap<>();
 
     public R8ResourceShrinkerModel(
         ShrinkerDebugReporter debugReporter, boolean supportMultipackages) {
       super(debugReporter, supportMultipackages);
     }
 
+    public Map<Integer, String> getStringResourcesWithSingleValue() {
+      return stringResourcesWithSingleValue;
+    }
+
     // Similar to instantiation in ProtoResourceTableGatherer, but using an inputstream.
     void instantiateFromResourceTable(InputStream inputStream) {
       try {
@@ -60,14 +71,34 @@
           .forEachRemaining(
               entryWrapper -> {
                 ResourceType resourceType = ResourceType.fromClassName(entryWrapper.getType());
+                Entry entry = entryWrapper.getEntry();
+                int entryId = entryWrapper.getId();
+                recordSingleValueResources(resourceType, entry, entryId);
                 if (resourceType != ResourceType.STYLEABLE) {
                   this.addResource(
                       resourceType,
                       entryWrapper.getPackageName(),
-                      ResourcesUtil.resourceNameToFieldName(entryWrapper.getEntry().getName()),
-                      entryWrapper.getId());
+                      ResourcesUtil.resourceNameToFieldName(entry.getName()),
+                      entryId);
                 }
               });
     }
+
+    private void recordSingleValueResources(ResourceType resourceType, Entry entry, int entryId) {
+      if (!entry.hasOverlayableItem() && entry.getConfigValueList().size() == 1) {
+        if (resourceType == ResourceType.STRING) {
+          ConfigValue configValue = entry.getConfigValue(0);
+          if (configValue.hasValue()) {
+            Value value = configValue.getValue();
+            if (value.hasItem()) {
+              Item item = value.getItem();
+              if (item.hasStr()) {
+                stringResourcesWithSingleValue.put(entryId, item.getStr().getValue());
+              }
+            }
+          }
+        }
+      }
+    }
   }
 }