Private resources are now package-private in R classes.

Private resources thus have their visibility checked by the build system:
* unknown commit - private resources in deps omitted in R.*
* unknown commit - private resources in deps inaccessible from XML
* this CL - private resources in R.* inaccessible from other packages

PiperOrigin-RevId: 291051825
diff --git a/src/tools/android/java/com/google/devtools/build/android/PlaceholderIdFieldInitializerBuilder.java b/src/tools/android/java/com/google/devtools/build/android/PlaceholderIdFieldInitializerBuilder.java
index c4b60e9..36d3af2 100644
--- a/src/tools/android/java/com/google/devtools/build/android/PlaceholderIdFieldInitializerBuilder.java
+++ b/src/tools/android/java/com/google/devtools/build/android/PlaceholderIdFieldInitializerBuilder.java
@@ -14,6 +14,7 @@
 package com.google.devtools.build.android;
 
 import com.android.resources.ResourceType;
+import com.google.auto.value.AutoValue;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -139,7 +140,7 @@
 
   private final AndroidFrameworkAttrIdProvider androidIdProvider;
 
-  private final Map<ResourceType, SortedMap<String, DependencyInfo>> innerClasses =
+  private final Map<ResourceType, SortedMap<String, ResourceLinkageInfo>> innerClasses =
       new EnumMap<>(ResourceType.class);
 
   private final Map<String, Map<String, /*inlineable=*/ Boolean>> styleableAttrs =
@@ -151,10 +152,9 @@
 
   public void addSimpleResource(
       DependencyInfo dependencyInfo, Visibility visibility, ResourceType type, String name) {
-    Object unused = visibility; // TODO(b/26297204): use 'visibility'
     innerClasses
         .computeIfAbsent(type, t -> new TreeMap<>())
-        .put(normalizeName(name), dependencyInfo);
+        .put(normalizeName(name), ResourceLinkageInfo.create(dependencyInfo, visibility));
   }
 
   public void addStyleableResource(
@@ -162,7 +162,6 @@
       Visibility visibility,
       FullyQualifiedName key,
       Map<FullyQualifiedName, Boolean> attrs) {
-    Object unused = visibility; // TODO(b/26297204): use 'visibility'
     ResourceType type = ResourceType.STYLEABLE;
     // The configuration can play a role in sorting, but that isn't modeled yet.
     String normalizedStyleableName = normalizeName(key.name());
@@ -230,10 +229,10 @@
         new EnumMap<>(ResourceType.class);
     Map<ResourceType, Integer> typeIdMap = chooseTypeIds();
     Map<String, Integer> attrAssignments = assignAttrIds(typeIdMap.get(ResourceType.ATTR));
-    for (Map.Entry<ResourceType, SortedMap<String, DependencyInfo>> fieldEntries :
+    for (Map.Entry<ResourceType, SortedMap<String, ResourceLinkageInfo>> fieldEntries :
         innerClasses.entrySet()) {
       ResourceType type = fieldEntries.getKey();
-      SortedMap<String, DependencyInfo> sortedFields = fieldEntries.getValue();
+      SortedMap<String, ResourceLinkageInfo> sortedFields = fieldEntries.getValue();
       ImmutableList<FieldInitializer> fields;
       if (type == ResourceType.STYLEABLE) {
         fields = getStyleableInitializers(attrAssignments, sortedFields);
@@ -277,43 +276,48 @@
   }
 
   private static ImmutableList<FieldInitializer> getAttrInitializers(
-      Map<String, Integer> attrAssignments, SortedMap<String, DependencyInfo> sortedFields) {
+      Map<String, Integer> attrAssignments, SortedMap<String, ResourceLinkageInfo> sortedFields) {
     ImmutableList.Builder<FieldInitializer> initList = ImmutableList.builder();
-    for (Map.Entry<String, DependencyInfo> entry : sortedFields.entrySet()) {
+    for (Map.Entry<String, ResourceLinkageInfo> entry : sortedFields.entrySet()) {
       String field = entry.getKey();
-      DependencyInfo dependencyInfo = entry.getValue();
+      ResourceLinkageInfo linkageInfo = entry.getValue();
       int attrId = attrAssignments.get(field);
-      initList.add(IntFieldInitializer.of(dependencyInfo, field, attrId));
+      initList.add(
+          IntFieldInitializer.of(
+              linkageInfo.dependencyInfo(), linkageInfo.visibility(), field, attrId));
     }
     return initList.build();
   }
 
   private ImmutableList<FieldInitializer> getResourceInitializers(
-      int typeId, SortedMap<String, DependencyInfo> sortedFields) {
+      int typeId, SortedMap<String, ResourceLinkageInfo> sortedFields) {
     ImmutableList.Builder<FieldInitializer> initList = ImmutableList.builder();
     Map<String, Integer> publicNameToId = new LinkedHashMap<>();
     Set<Integer> assignedIds = ImmutableSet.of();
     int resourceIds = nextFreeId(getInitialIdForTypeId(typeId), assignedIds);
-    for (Map.Entry<String, DependencyInfo> entry : sortedFields.entrySet()) {
+    for (Map.Entry<String, ResourceLinkageInfo> entry : sortedFields.entrySet()) {
       String field = entry.getKey();
-      DependencyInfo dependencyInfo = entry.getValue();
+      ResourceLinkageInfo linkageInfo = entry.getValue();
       Integer fieldValue = publicNameToId.get(field);
       if (fieldValue == null) {
         fieldValue = resourceIds;
         resourceIds = nextFreeId(resourceIds + 1, assignedIds);
       }
-      initList.add(IntFieldInitializer.of(dependencyInfo, field, fieldValue));
+      initList.add(
+          IntFieldInitializer.of(
+              linkageInfo.dependencyInfo(), linkageInfo.visibility(), field, fieldValue));
     }
     return initList.build();
   }
 
   private ImmutableList<FieldInitializer> getStyleableInitializers(
-      Map<String, Integer> attrAssignments, SortedMap<String, DependencyInfo> sortedFields)
+      Map<String, Integer> attrAssignments, SortedMap<String, ResourceLinkageInfo> sortedFields)
       throws AttrLookupException {
     ImmutableList.Builder<FieldInitializer> initList = ImmutableList.builder();
-    for (Map.Entry<String, DependencyInfo> entry : sortedFields.entrySet()) {
+    for (Map.Entry<String, ResourceLinkageInfo> entry : sortedFields.entrySet()) {
       String field = entry.getKey();
-      DependencyInfo dependencyInfo = entry.getValue();
+      ResourceLinkageInfo linkageInfo = entry.getValue();
+      DependencyInfo dependencyInfo = linkageInfo.dependencyInfo();
       Set<String> attrs = styleableAttrs.get(field).keySet();
       ImmutableMap.Builder<String, Integer> arrayInitValues = ImmutableMap.builder();
       for (String attr : attrs) {
@@ -345,10 +349,15 @@
           arrayInitValues.orderEntriesByValue(Ordering.<Integer>natural()).build();
       initList.add(
           IntArrayFieldInitializer.of(
-              dependencyInfo, field, ImmutableList.copyOf(arrayInitMap.values())));
+              dependencyInfo,
+              linkageInfo.visibility(),
+              field,
+              ImmutableList.copyOf(arrayInitMap.values())));
       int index = 0;
       for (String attr : arrayInitMap.keySet()) {
-        initList.add(IntFieldInitializer.of(dependencyInfo, field + "_" + attr, index));
+        initList.add(
+            IntFieldInitializer.of(
+                dependencyInfo, linkageInfo.visibility(), field + "_" + attr, index));
         ++index;
       }
     }
@@ -365,4 +374,16 @@
   static String normalizeName(String resourceName) {
     return resourceName.replace('.', '_');
   }
+
+  @AutoValue
+  abstract static class ResourceLinkageInfo {
+    abstract DependencyInfo dependencyInfo();
+
+    abstract Visibility visibility();
+
+    static ResourceLinkageInfo create(DependencyInfo dependencyInfo, Visibility visibility) {
+      return new AutoValue_PlaceholderIdFieldInitializerBuilder_ResourceLinkageInfo(
+          dependencyInfo, visibility);
+    }
+  }
 }
diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializer.java b/src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializer.java
index 077223d..5dc0d86 100644
--- a/src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializer.java
+++ b/src/tools/android/java/com/google/devtools/build/android/resources/FieldInitializer.java
@@ -28,8 +28,7 @@
    *
    * @return true if the initializer is deferred to clinit code.
    */
-  boolean writeFieldDefinition(
-      ClassWriter cw, int accessLevel, boolean isFinal, boolean annotateTransitiveFields);
+  boolean writeFieldDefinition(ClassWriter cw, boolean isFinal, boolean annotateTransitiveFields);
 
   /**
    * Write the bytecode for the clinit portion of initializer.
diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/IntArrayFieldInitializer.java b/src/tools/android/java/com/google/devtools/build/android/resources/IntArrayFieldInitializer.java
index e198bce..5ef5506 100644
--- a/src/tools/android/java/com/google/devtools/build/android/resources/IntArrayFieldInitializer.java
+++ b/src/tools/android/java/com/google/devtools/build/android/resources/IntArrayFieldInitializer.java
@@ -24,6 +24,7 @@
 import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.ClassWriter;
 import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
 import org.objectweb.asm.commons.InstructionAdapter;
 
@@ -33,22 +34,28 @@
   private static final String DESC = "[I";
 
   private final DependencyInfo dependencyInfo;
+  private final Visibility visibility;
   private final String fieldName;
   private final ImmutableList<Integer> values;
 
   private IntArrayFieldInitializer(
-      DependencyInfo dependencyInfo, String fieldName, ImmutableList<Integer> values) {
+      DependencyInfo dependencyInfo,
+      Visibility visibility,
+      String fieldName,
+      ImmutableList<Integer> values) {
     this.dependencyInfo = dependencyInfo;
+    this.visibility = visibility;
     this.fieldName = fieldName;
     this.values = values;
   }
 
-  public static FieldInitializer of(DependencyInfo dependencyInfo, String fieldName, String value) {
+  public static FieldInitializer of(
+      DependencyInfo dependencyInfo, Visibility visibility, String fieldName, String value) {
     Preconditions.checkArgument(value.startsWith("{ "), "Expected list starting with { ");
     Preconditions.checkArgument(value.endsWith(" }"), "Expected list ending with } ");
     // Check for an empty list, which is "{ }".
     if (value.length() < 4) {
-      return of(dependencyInfo, fieldName, ImmutableList.of());
+      return of(dependencyInfo, visibility, fieldName, ImmutableList.of());
     }
     ImmutableList.Builder<Integer> intValues = ImmutableList.builder();
     String trimmedValue = value.substring(2, value.length() - 2);
@@ -56,17 +63,27 @@
     for (String valueString : valueStrings) {
       intValues.add(Integer.decode(valueString));
     }
-    return of(dependencyInfo, fieldName, intValues.build());
+    return of(dependencyInfo, visibility, fieldName, intValues.build());
   }
 
   public static IntArrayFieldInitializer of(
-      DependencyInfo dependencyInfo, String fieldName, ImmutableList<Integer> values) {
-    return new IntArrayFieldInitializer(dependencyInfo, fieldName, values);
+      DependencyInfo dependencyInfo,
+      Visibility visibility,
+      String fieldName,
+      ImmutableList<Integer> values) {
+    return new IntArrayFieldInitializer(dependencyInfo, visibility, fieldName, values);
   }
 
   @Override
   public boolean writeFieldDefinition(
-      ClassWriter cw, int accessLevel, boolean isFinal, boolean annotateTransitiveFields) {
+      ClassWriter cw, boolean isFinal, boolean annotateTransitiveFields) {
+    int accessLevel = Opcodes.ACC_STATIC;
+    if (visibility != Visibility.PRIVATE) {
+      accessLevel |= Opcodes.ACC_PUBLIC;
+    }
+    if (isFinal) {
+      accessLevel |= Opcodes.ACC_FINAL;
+    }
     FieldVisitor fv = cw.visitField(accessLevel, fieldName, DESC, null, null);
     if (annotateTransitiveFields
         && dependencyInfo.dependencyType() == DependencyInfo.DependencyType.TRANSITIVE) {
@@ -113,8 +130,11 @@
 
     writer.write(
         String.format(
-            "        public static %sint[] %s = { %s };\n",
-            finalFields ? "final " : "", fieldName, builder.toString()));
+            "        %s static %sint[] %s = { %s };\n",
+            visibility != Visibility.PRIVATE ? "public" : "",
+            finalFields ? "final " : "",
+            fieldName,
+            builder));
   }
 
   @Override
diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/IntFieldInitializer.java b/src/tools/android/java/com/google/devtools/build/android/resources/IntFieldInitializer.java
index 8948951..b651ca9 100644
--- a/src/tools/android/java/com/google/devtools/build/android/resources/IntFieldInitializer.java
+++ b/src/tools/android/java/com/google/devtools/build/android/resources/IntFieldInitializer.java
@@ -17,9 +17,11 @@
 import com.google.devtools.build.android.DependencyInfo;
 import java.io.IOException;
 import java.io.Writer;
+import java.util.Objects;
 import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.ClassWriter;
 import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.commons.InstructionAdapter;
 
 /** Models an int field initializer. */
@@ -28,26 +30,39 @@
   private static final String DESC = "I";
 
   private final DependencyInfo dependencyInfo;
+  private final Visibility visibility;
   private final String fieldName;
   private final int value;
 
-  private IntFieldInitializer(DependencyInfo dependencyInfo, String fieldName, int value) {
+  private IntFieldInitializer(
+      DependencyInfo dependencyInfo, Visibility visibility, String fieldName, int value) {
     this.dependencyInfo = dependencyInfo;
+    this.visibility = visibility;
     this.fieldName = fieldName;
     this.value = value;
   }
 
-  public static FieldInitializer of(DependencyInfo dependencyInfo, String fieldName, String value) {
-    return of(dependencyInfo, fieldName, Integer.decode(value));
+  public static FieldInitializer of(
+      DependencyInfo dependencyInfo, Visibility visibility, String fieldName, String value) {
+    return of(dependencyInfo, visibility, fieldName, Integer.decode(value));
   }
 
-  public static IntFieldInitializer of(DependencyInfo dependencyInfo, String fieldName, int value) {
-    return new IntFieldInitializer(dependencyInfo, fieldName, value);
+  public static IntFieldInitializer of(
+      DependencyInfo dependencyInfo, Visibility visibility, String fieldName, int value) {
+    return new IntFieldInitializer(dependencyInfo, visibility, fieldName, value);
   }
 
   @Override
   public boolean writeFieldDefinition(
-      ClassWriter cw, int accessLevel, boolean isFinal, boolean annotateTransitiveFields) {
+      ClassWriter cw, boolean isFinal, boolean annotateTransitiveFields) {
+    int accessLevel = Opcodes.ACC_STATIC;
+    if (visibility != Visibility.PRIVATE) {
+      accessLevel |= Opcodes.ACC_PUBLIC;
+    }
+    if (isFinal) {
+      accessLevel |= Opcodes.ACC_FINAL;
+    }
+
     FieldVisitor fv = cw.visitField(accessLevel, fieldName, DESC, null, isFinal ? value : null);
     if (annotateTransitiveFields
         && dependencyInfo.dependencyType() == DependencyInfo.DependencyType.TRANSITIVE) {
@@ -73,8 +88,11 @@
   public void writeInitSource(Writer writer, boolean finalFields) throws IOException {
     writer.write(
         String.format(
-            "        public static %sint %s = 0x%x;\n",
-            finalFields ? "final " : "", fieldName, value));
+            "        %s static %sint %s = 0x%x;\n",
+            visibility != Visibility.PRIVATE ? "public" : "",
+            finalFields ? "final " : "",
+            fieldName,
+            value));
   }
 
   @Override
@@ -96,7 +114,10 @@
   public boolean equals(Object obj) {
     if (obj instanceof IntFieldInitializer) {
       IntFieldInitializer other = (IntFieldInitializer) obj;
-      return value == other.value;
+      return Objects.equals(dependencyInfo, other.dependencyInfo)
+          && Objects.equals(visibility, other.visibility)
+          && Objects.equals(fieldName, other.fieldName)
+          && value == other.value;
     }
     return false;
   }
diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java b/src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java
index f1b6a4f..0ed89cd 100644
--- a/src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java
+++ b/src/tools/android/java/com/google/devtools/build/android/resources/RClassGenerator.java
@@ -177,15 +177,10 @@
         writeInnerClassHeader(fullyQualifiedOuterClass, innerClass, innerClassWriter);
 
     List<FieldInitializer> deferredInitializers = new ArrayList<>();
-    int fieldAccessLevel = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC;
-    if (finalFields) {
-      fieldAccessLevel |= Opcodes.ACC_FINAL;
-    }
     for (FieldInitializer init : initializers) {
       JavaIdentifierValidator.validate(
           init.getFieldName(), "in class:", fullyQualifiedInnerClass, "and package:", packageDir);
-      if (init.writeFieldDefinition(
-          innerClassWriter, fieldAccessLevel, finalFields, annotateTransitiveFields)) {
+      if (init.writeFieldDefinition(innerClassWriter, finalFields, annotateTransitiveFields)) {
         deferredInitializers.add(init);
       }
     }
diff --git a/src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java b/src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java
index d655df1..095a9e6 100644
--- a/src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java
+++ b/src/tools/android/java/com/google/devtools/build/android/resources/ResourceSymbols.java
@@ -77,9 +77,12 @@
 
           FieldInitializer initializer;
           if ("int".equals(type)) {
-            initializer = IntFieldInitializer.of(DependencyInfo.UNKNOWN, name, value);
+            initializer =
+                IntFieldInitializer.of(DependencyInfo.UNKNOWN, Visibility.UNKNOWN, name, value);
           } else {
-            initializer = IntArrayFieldInitializer.of(DependencyInfo.UNKNOWN, name, value);
+            initializer =
+                IntArrayFieldInitializer.of(
+                    DependencyInfo.UNKNOWN, Visibility.UNKNOWN, name, value);
           }
 
           initializers