Partially eliminate IDE model usages from ResourceVisibilityLookup
Bug: 37797956
Test: existing
Change-Id: Ib606b5dde9a8fd033215ed76c16a4a1ef1fd69f2
diff --git a/sdk-common/src/main/java/com/android/ide/common/repository/ResourceVisibilityLookup.java b/sdk-common/src/main/java/com/android/ide/common/repository/ResourceVisibilityLookup.java
index c754d84..aa9e53f 100644
--- a/sdk-common/src/main/java/com/android/ide/common/repository/ResourceVisibilityLookup.java
+++ b/sdk-common/src/main/java/com/android/ide/common/repository/ResourceVisibilityLookup.java
@@ -38,37 +38,34 @@
import java.util.Map;
/**
- * Class which provides information about whether Android resources for a given library are
- * public or private.
+ * Class which provides information about whether Android resources for a given library are public
+ * or private.
*/
public abstract class ResourceVisibilityLookup {
- /**
- * Returns true if the given resource is private.
- * Note that {@link #isPublic} is normally the opposite of {@link #isPrivate},
- * except for unknown resources - they will both return false in that case.
- *
- * @param type the type of the resource
- * @param name the resource field name of the resource (in other words, for
- * style Theme:Variant.Cls the name would be Theme_Variant_Cls
- * @return true if the given resource is private
- */
- public abstract boolean isPrivate(
- @NonNull ResourceType type,
- @NonNull String name);
/**
- * Returns true if the given resource is public.
- * Note that {@link #isPublic} is normally the opposite of {@link #isPrivate},
- * except for unknown resources - they will both return false in that case.
+ * Returns true if the given resource is private. Note that {@link #isPublic} is normally the
+ * opposite of {@link #isPrivate}, except for unknown resources - they will both return false in
+ * that case.
*
* @param type the type of the resource
- * @param name the resource field name of the resource (in other words, for
- * style Theme:Variant.Cls the name would be Theme_Variant_Cls
+ * @param name the resource field name of the resource (in other words, for style
+ * Theme:Variant.Cls the name would be Theme_Variant_Cls
+ * @return true if the given resource is private
+ */
+ public abstract boolean isPrivate(@NonNull ResourceType type, @NonNull String name);
+
+ /**
+ * Returns true if the given resource is public. Note that {@link #isPublic} is normally the
+ * opposite of {@link #isPrivate}, except for unknown resources - they will both return false in
+ * that case.
+ *
+ * @param type the type of the resource
+ * @param name the resource field name of the resource (in other words, for style
+ * Theme:Variant.Cls the name would be Theme_Variant_Cls
* @return true if the given resource is public
*/
- public abstract boolean isPublic(
- @NonNull ResourceType type,
- @NonNull String name);
+ public abstract boolean isPublic(@NonNull ResourceType type, @NonNull String name);
protected abstract boolean isKnown(
@NonNull ResourceType type,
@@ -86,8 +83,7 @@
}
/**
- * For a private resource, return the library that the resource was defined as
- * private in
+ * For a private resource, return the library that the resource was defined as private in
*
* @param type the type of the resource
* @param name the name of the resource
@@ -138,20 +134,16 @@
}
}
- /**
- * Creates a {@link ResourceVisibilityLookup} for a given library.
- *
- * <p>NOTE: The {@link Provider} class can be used to share/cache {@link
- * ResourceVisibilityLookup} instances, e.g. when you have library1 and library2 each
- * referencing libraryBase, the {@link Provider} will ensure that a the libraryBase data is
- * shared.
- *
- * @param library the library
- * @return a corresponding {@link ResourceVisibilityLookup}
- */
@NonNull
- public static ResourceVisibilityLookup create(@NonNull IdeAndroidLibrary library) {
- return new AndroidLibraryResourceVisibility(library, new SymbolProvider());
+ public static AndroidLibraryResourceVisibility create(
+ @NonNull String libraryArtifactAddress,
+ @NonNull File librarySymbolFile,
+ @NonNull File libraryPublicResources) {
+ return new AndroidLibraryResourceVisibility(
+ libraryArtifactAddress,
+ librarySymbolFile,
+ libraryPublicResources,
+ new SymbolProvider());
}
/**
@@ -174,7 +166,10 @@
ResourceVisibilityLookup v =
provider != null
? provider.get(library)
- : new AndroidLibraryResourceVisibility(library, new SymbolProvider());
+ : create(
+ library.getArtifactAddress(),
+ new File(library.getSymbolFile()),
+ new File(library.getPublicResources()));
if (!v.isEmpty()) {
list.add(v);
}
@@ -310,15 +305,15 @@
}
/**
- * Provider which keeps a set of {@link ResourceVisibilityLookup} instances around for
- * repeated queries, including from different libraries that may share dependencies
+ * Provider which keeps a set of {@link ResourceVisibilityLookup} instances around for repeated
+ * queries, including from different libraries that may share dependencies
*/
public static class Provider {
+
/**
- * We store lookup instances for multiple separate types of keys here:
- * {@link AndroidLibrary},
- * {@link com.android.builder.model.AndroidArtifact}, and
- * {@link com.android.builder.model.Variant}
+ * We store lookup instances for multiple separate types of keys here: {@link
+ * AndroidLibrary}, {@link com.android.builder.model.AndroidArtifact}, and {@link
+ * com.android.builder.model.Variant}
*/
private final Map<Object, ResourceVisibilityLookup> mInstances = Maps.newHashMap();
@@ -334,10 +329,15 @@
*/
@NonNull
public ResourceVisibilityLookup get(@NonNull IdeAndroidLibrary library) {
- String key = getMapKey(library);
+ String key = library.getArtifactAddress();
ResourceVisibilityLookup visibility = mInstances.get(key);
if (visibility == null) {
- visibility = new AndroidLibraryResourceVisibility(library, mSymbols);
+ visibility =
+ new AndroidLibraryResourceVisibility(
+ library.getArtifactAddress(),
+ new File(library.getSymbolFile()),
+ new File(library.getPublicResources()),
+ mSymbols);
if (visibility.isEmpty()) {
visibility = NONE;
}
@@ -368,7 +368,12 @@
}
}
int size = list.size();
- visibility = size == 0 ? NONE : size == 1 ? list.get(0) : new MultipleLibraryResourceVisibility(list);
+ visibility =
+ size == 0
+ ? NONE
+ : size == 1
+ ? list.get(0)
+ : new MultipleLibraryResourceVisibility(list);
mInstances.put(key, visibility);
}
return visibility;
@@ -391,17 +396,17 @@
}
return visibility;
}
-
}
/** Visibility data for a single library */
private static class LibraryResourceVisibility extends ResourceVisibilityLookup {
- private final String mMapKey;
+
+ protected final String mMapKey;
/**
- * A map from name to resource types for all resources known to this library. This
- * is used to make sure that when the {@link #isPrivate(ResourceType, String)} query method
- * is called, it can tell the difference between a resource implicitly private by not being
+ * A map from name to resource types for all resources known to this library. This is used
+ * to make sure that when the {@link #isPrivate(ResourceType, String)} query method is
+ * called, it can tell the difference between a resource implicitly private by not being
* declared as public and a resource unknown to this library (e.g. defined by a different
* library or the user's own project resources.)
*/
@@ -450,7 +455,7 @@
@Override
public String getPrivateIn(@NonNull ResourceType type, @NonNull String name) {
if (isPrivate(type, name)) {
- return getLibraryName();
+ return getLibraryName();
}
return null;
@@ -545,45 +550,58 @@
/** Visibility data for a single library */
private static class AndroidLibraryResourceVisibility extends LibraryResourceVisibility {
- @NonNull private final IdeLibrary mLibrary;
+
+ @NonNull private final String mLibraryArtifactAddress;
private AndroidLibraryResourceVisibility(
- @NonNull IdeAndroidLibrary library,
+ @NonNull String libraryArtifactAddress,
+ @NonNull File librarySymbolFile,
@Nullable Multimap<String, ResourceType> publicResources,
@NonNull SymbolProvider symbols) {
//noinspection VariableNotUsedInsideIf
- super(publicResources, publicResources != null ? symbols.getSymbols(library) : null,
- getMapKey(library));
- mLibrary = library;
+ super(
+ publicResources,
+ publicResources != null
+ ? symbols.getSymbols(librarySymbolFile, libraryArtifactAddress)
+ : null,
+ libraryArtifactAddress);
+ mLibraryArtifactAddress = libraryArtifactAddress;
}
private AndroidLibraryResourceVisibility(
- @NonNull IdeAndroidLibrary library, @NonNull SymbolProvider symbols) {
- this(library, computeVisibilityMap(new File(library.getPublicResources())), symbols);
+ @NonNull String libraryArtifactAddress,
+ @NonNull File librarySymbolFile,
+ @NonNull File libraryPublicResources,
+ @NonNull SymbolProvider symbols) {
+ this(
+ libraryArtifactAddress,
+ librarySymbolFile,
+ computeVisibilityMap(libraryPublicResources),
+ symbols);
}
@Override
public String toString() {
- return getMapKey(mLibrary);
+ return mMapKey;
}
@Nullable
@Override
protected String getLibraryName() {
- return mLibrary.getArtifactAddress();
+ return mLibraryArtifactAddress;
}
}
/**
- * Class which provides resource symbols (from R.txt) for a given library, while
- * (a) caching across multiple lookups, and (b) removing symbols from upstream
- * dependencies.
- * <p>
- * These are referred to as "symbols" to map the Gradle plugin terminology,
- * e.g. "LibraryBundle#getSymbolFile", the SymbolLoader processor, etc.
+ * Class which provides resource symbols (from R.txt) for a given library, while (a) caching
+ * across multiple lookups, and (b) removing symbols from upstream dependencies.
+ *
+ * <p>These are referred to as "symbols" to map the Gradle plugin terminology, e.g.
+ * "LibraryBundle#getSymbolFile", the SymbolLoader processor, etc.
*/
@VisibleForTesting
static class SymbolProvider {
+
/** Cache from library map keys to corresponding name-to-resource type maps */
private final Map<String, Multimap<String, ResourceType>> mCache = Maps.newHashMap();
@@ -594,14 +612,13 @@
*/
@VisibleForTesting
@NonNull
- Multimap<String, ResourceType> getSymbols(@NonNull IdeAndroidLibrary library) {
- String mapKey = getMapKey(library);
+ Multimap<String, ResourceType> getSymbols(
+ @NonNull File symbolFile, @NonNull String mapKey) {
Multimap<String, ResourceType> map = mCache.get(mapKey);
if (map != null) {
return map;
}
- File symbolFile = new File(library.getSymbolFile());
// getSymbolFile is marked @NonNull but b/157590682 shows that it can
// be null in some scenarios, possibly from loader older cached models
if (!symbolFile.exists()) {
@@ -626,7 +643,8 @@
@NonNull
private static Multimap<String, ResourceType> readSymbolFile(File symbolFile)
throws IOException {
- List<String> lines = Files.readLines(symbolFile, Charsets.UTF_8); // TODO: Switch to iterator
+ List<String> lines =
+ Files.readLines(symbolFile, Charsets.UTF_8); // TODO: Switch to iterator
Multimap<String, ResourceType> result = ArrayListMultimap.create(lines.size(), 2);
ResourceType previousType = null;
diff --git a/sdk-common/src/test/java/com/android/ide/common/repository/ResourceVisibilityLookupTest.java b/sdk-common/src/test/java/com/android/ide/common/repository/ResourceVisibilityLookupTest.java
index 8903cbf..38b6cd3 100644
--- a/sdk-common/src/test/java/com/android/ide/common/repository/ResourceVisibilityLookupTest.java
+++ b/sdk-common/src/test/java/com/android/ide/common/repository/ResourceVisibilityLookupTest.java
@@ -40,6 +40,7 @@
import junit.framework.TestCase;
public class ResourceVisibilityLookupTest extends TestCase {
+
public void test() throws IOException {
IdeAndroidLibrary library =
createMockLibrary(
@@ -59,7 +60,11 @@
+ "id action_settings\n"
+ "layout activity_main\n");
- ResourceVisibilityLookup visibility = ResourceVisibilityLookup.create(library);
+ ResourceVisibilityLookup visibility =
+ ResourceVisibilityLookup.create(
+ library.getArtifactAddress(),
+ new File(library.getSymbolFile()),
+ new File(library.getPublicResources()));
assertTrue(visibility.isPrivate(ResourceType.DIMEN, "activity_horizontal_margin"));
assertFalse(visibility.isPrivate(ResourceType.ID, "action_settings"));
assertFalse(visibility.isPrivate(ResourceType.LAYOUT, "activity_main"));
@@ -85,7 +90,11 @@
+ "int string hello_world 0x7f040002",
"");
- ResourceVisibilityLookup visibility = ResourceVisibilityLookup.create(library);
+ ResourceVisibilityLookup visibility =
+ ResourceVisibilityLookup.create(
+ library.getArtifactAddress(),
+ new File(library.getSymbolFile()),
+ new File(library.getPublicResources()));
assertTrue(visibility.isPrivate(ResourceType.DIMEN, "activity_horizontal_margin"));
assertTrue(visibility.isPrivate(ResourceType.ID, "action_settings"));
assertTrue(visibility.isPrivate(ResourceType.LAYOUT, "activity_main"));
@@ -98,7 +107,11 @@
IdeAndroidLibrary library =
createMockLibrary("com.android.tools:test-library:1.0.0", "", null);
- ResourceVisibilityLookup visibility = ResourceVisibilityLookup.create(library);
+ ResourceVisibilityLookup visibility =
+ ResourceVisibilityLookup.create(
+ library.getArtifactAddress(),
+ new File(library.getSymbolFile()),
+ new File(library.getPublicResources()));
assertFalse(visibility.isPrivate(ResourceType.DIMEN, "activity_horizontal_margin"));
assertFalse(visibility.isPrivate(ResourceType.ID, "action_settings"));
assertFalse(visibility.isPrivate(ResourceType.LAYOUT, "activity_main"));
@@ -198,13 +211,13 @@
"");
ResourceVisibilityLookup.Provider provider = new ResourceVisibilityLookup.Provider();
assertSame(provider.get(library), provider.get(library));
- assertTrue(provider.get(library).isPrivate(ResourceType.DIMEN,
- "activity_horizontal_margin"));
+ assertTrue(
+ provider.get(library).isPrivate(ResourceType.DIMEN, "activity_horizontal_margin"));
IdeAndroidArtifact artifact = createMockArtifact(Collections.singletonList(library));
assertSame(provider.get(artifact), provider.get(artifact));
- assertTrue(provider.get(artifact).isPrivate(ResourceType.DIMEN,
- "activity_horizontal_margin"));
+ assertTrue(
+ provider.get(artifact).isPrivate(ResourceType.DIMEN, "activity_horizontal_margin"));
}
public void testImportedResources() throws IOException {