aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiego Perez <diegoperez@google.com>2017-05-18 13:22:25 +0100
committerDiego Perez <diegoperez@google.com>2017-05-18 13:22:25 +0100
commit03faa7e778e24fbc3de3ec1212e265c2d04a8f47 (patch)
tree812bce387d3c64da714f866d7a0f7ebbdd38d6de
parent3a58b000fdabfd111e001c340c8a7ba8392b5c88 (diff)
downloadlayoutlib-03faa7e778e24fbc3de3ec1212e265c2d04a8f47.tar.gz
Remove field injection
Refactoring Resources to remove the field injection. This is needed to be able to move the existing code to ResourcesImpl. In the process, add relevant Nullable annotations and checks. Test: Existing tests pass Change-Id: Ibd3fe021ee0f7c9de01a79240581a410dfff681a
-rw-r--r--bridge/src/android/content/res/Resources_Delegate.java95
-rw-r--r--bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java10
-rw-r--r--bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java48
-rw-r--r--create/src/com/android/tools/layoutlib/create/AsmGenerator.java4
-rw-r--r--create/src/com/android/tools/layoutlib/create/FieldInjectorAdapter.java40
5 files changed, 91 insertions, 106 deletions
diff --git a/bridge/src/android/content/res/Resources_Delegate.java b/bridge/src/android/content/res/Resources_Delegate.java
index c20ee12ee3..ff8530561a 100644
--- a/bridge/src/android/content/res/Resources_Delegate.java
+++ b/bridge/src/android/content/res/Resources_Delegate.java
@@ -34,6 +34,7 @@ import com.android.layoutlib.bridge.util.NinePatchInputStream;
import com.android.ninepatch.NinePatch;
import com.android.resources.ResourceType;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+import com.android.tools.layoutlib.annotations.VisibleForTesting;
import com.android.util.Pair;
import org.xmlpull.v1.XmlPullParser;
@@ -58,41 +59,67 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Iterator;
+import java.util.Objects;
+import java.util.WeakHashMap;
@SuppressWarnings("deprecation")
public class Resources_Delegate {
+ private static WeakHashMap<Resources, LayoutlibCallback> sLayoutlibCallbacks = new
+ WeakHashMap<>();
+ private static WeakHashMap<Resources, BridgeContext> sContexts = new
+ WeakHashMap<>();
private static boolean[] mPlatformResourceFlag = new boolean[1];
// TODO: This cache is cleared every time a render session is disposed. Look into making this
// more long lived.
private static LruCache<String, Drawable.ConstantState> sDrawableCache = new LruCache<>(50);
- public static Resources initSystem(BridgeContext context,
- AssetManager assets,
- DisplayMetrics metrics,
- Configuration config,
- LayoutlibCallback layoutlibCallback) {
+ public static Resources initSystem(@NonNull BridgeContext context,
+ @NonNull AssetManager assets,
+ @NonNull DisplayMetrics metrics,
+ @NonNull Configuration config,
+ @NonNull LayoutlibCallback layoutlibCallback) {
+ assert Resources.mSystem == null :
+ "Resources_Delegate.initSystem called twice before disposeSystem was called";
Resources resources = new Resources(Resources_Delegate.class.getClassLoader());
resources.setImpl(new ResourcesImpl(assets, metrics, config, new DisplayAdjustments()));
- resources.mContext = context;
- resources.mLayoutlibCallback = layoutlibCallback;
+ sContexts.put(resources, Objects.requireNonNull(context));
+ sLayoutlibCallbacks.put(resources, Objects.requireNonNull(layoutlibCallback));
return Resources.mSystem = resources;
}
+ /** Returns the {@link BridgeContext} associated to the given {@link Resources} */
+ @VisibleForTesting
+ @NonNull
+ public static BridgeContext getContext(@NonNull Resources resources) {
+ assert sContexts.containsKey(resources) :
+ "Resources_Delegate.getContext called before initSystem";
+ return sContexts.get(resources);
+ }
+
+ /** Returns the {@link LayoutlibCallback} associated to the given {@link Resources} */
+ @VisibleForTesting
+ @NonNull
+ public static LayoutlibCallback getLayoutlibCallback(@NonNull Resources resources) {
+ assert sLayoutlibCallbacks.containsKey(resources) :
+ "Resources_Delegate.getLayoutlibCallback called before initSystem";
+ return sLayoutlibCallbacks.get(resources);
+ }
+
/**
* Disposes the static {@link Resources#mSystem} to make sure we don't leave objects around that
* would prevent us from unloading the library.
*/
public static void disposeSystem() {
sDrawableCache.evictAll();
- Resources.mSystem.mContext = null;
- Resources.mSystem.mLayoutlibCallback = null;
+ sContexts.clear();
+ sLayoutlibCallbacks.clear();
Resources.mSystem = null;
}
public static BridgeTypedArray newTypeArray(Resources resources, int numEntries,
boolean platformFile) {
- return new BridgeTypedArray(resources, resources.mContext, numEntries, platformFile);
+ return new BridgeTypedArray(resources, getContext(resources), numEntries, platformFile);
}
private static Pair<ResourceType, String> getResourceInfo(Resources resources, int id,
@@ -100,10 +127,12 @@ public class Resources_Delegate {
// first get the String related to this id in the framework
Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
+ assert Resources.mSystem != null : "Resources_Delegate.initSystem wasn't called";
// Set the layoutlib callback and context for resources
- if (resources != Resources.mSystem && resources.mLayoutlibCallback == null) {
- resources.mLayoutlibCallback = Resources.mSystem.mLayoutlibCallback;
- resources.mContext = Resources.mSystem.mContext;
+ if (resources != Resources.mSystem &&
+ (!sContexts.containsKey(resources) || !sLayoutlibCallbacks.containsKey(resources))) {
+ sLayoutlibCallbacks.put(resources, getLayoutlibCallback(Resources.mSystem));
+ sContexts.put(resources, getContext(Resources.mSystem));
}
if (resourceInfo != null) {
@@ -112,13 +141,11 @@ public class Resources_Delegate {
}
// didn't find a match in the framework? look in the project.
- if (resources.mLayoutlibCallback != null) {
- resourceInfo = resources.mLayoutlibCallback.resolveResourceId(id);
+ resourceInfo = getLayoutlibCallback(resources).resolveResourceId(id);
- if (resourceInfo != null) {
- platformResFlag_out[0] = false;
- return resourceInfo;
- }
+ if (resourceInfo != null) {
+ platformResFlag_out[0] = false;
+ return resourceInfo;
}
return null;
}
@@ -130,7 +157,7 @@ public class Resources_Delegate {
if (resourceInfo != null) {
String attributeName = resourceInfo.getSecond();
- RenderResources renderResources = resources.mContext.getRenderResources();
+ RenderResources renderResources = getContext(resources).getRenderResources();
ResourceValue value = platformResFlag_out[0] ?
renderResources.getFrameworkResource(resourceInfo.getFirst(), attributeName) :
renderResources.getProjectResource(resourceInfo.getFirst(), attributeName);
@@ -163,7 +190,7 @@ public class Resources_Delegate {
drawable = constantState.newDrawable(resources, theme);
} else {
drawable =
- ResourceHelper.getDrawable(value.getSecond(), resources.mContext, theme);
+ ResourceHelper.getDrawable(value.getSecond(), getContext(resources), theme);
if (key != null) {
sDrawableCache.put(key, drawable.getConstantState());
@@ -228,7 +255,7 @@ public class Resources_Delegate {
if (resValue != null) {
ColorStateList stateList = ResourceHelper.getColorStateList(resValue.getSecond(),
- resources.mContext);
+ getContext(resources));
if (stateList != null) {
return stateList.obtainForTheme(theme);
}
@@ -413,8 +440,8 @@ public class Resources_Delegate {
if (ref.startsWith(SdkConstants.PREFIX_RESOURCE_REF) || ref.startsWith
(SdkConstants.PREFIX_THEME_REF)) {
ResourceValue rv =
- resources.mContext.getRenderResources().findResValue(ref, forceFrameworkOnly);
- rv = resources.mContext.getRenderResources().resolveResValue(rv);
+ getContext(resources).getRenderResources().findResValue(ref, forceFrameworkOnly);
+ rv = getContext(resources).getRenderResources().resolveResValue(rv);
if (rv != null) {
return rv.getValue();
}
@@ -434,7 +461,7 @@ public class Resources_Delegate {
try {
// check if the current parser can provide us with a custom parser.
if (!mPlatformResourceFlag[0]) {
- parser = resources.mLayoutlibCallback.getParser(value);
+ parser = getLayoutlibCallback(resources).getParser(value);
}
// create a new one manually if needed.
@@ -448,7 +475,7 @@ public class Resources_Delegate {
}
if (parser != null) {
- return new BridgeXmlBlockParser(parser, resources.mContext,
+ return new BridgeXmlBlockParser(parser, getContext(resources),
mPlatformResourceFlag[0]);
}
} catch (XmlPullParserException e) {
@@ -483,7 +510,7 @@ public class Resources_Delegate {
// give that to our XmlBlockParser
parser = ParserFactory.create(xml);
- return new BridgeXmlBlockParser(parser, resources.mContext,
+ return new BridgeXmlBlockParser(parser, getContext(resources),
mPlatformResourceFlag[0]);
}
} catch (XmlPullParserException e) {
@@ -505,7 +532,7 @@ public class Resources_Delegate {
@LayoutlibDelegate
static TypedArray obtainAttributes(Resources resources, AttributeSet set, int[] attrs) {
- return resources.mContext.obtainStyledAttributes(set, attrs);
+ return getContext(resources).obtainStyledAttributes(set, attrs);
}
@LayoutlibDelegate
@@ -680,7 +707,7 @@ public class Resources_Delegate {
if (platformOut[0]) {
packageName = SdkConstants.ANDROID_NS_NAME;
} else {
- packageName = resources.mContext.getPackageName();
+ packageName = getContext(resources).getPackageName();
packageName = packageName == null ? SdkConstants.APP_PREFIX : packageName;
}
return packageName + ':' + resourceInfo.getFirst().getName() + '/' +
@@ -698,7 +725,7 @@ public class Resources_Delegate {
if (platformOut[0]) {
return SdkConstants.ANDROID_NS_NAME;
}
- String packageName = resources.mContext.getPackageName();
+ String packageName = getContext(resources).getPackageName();
return packageName == null ? SdkConstants.APP_PREFIX : packageName;
}
throwException(resid, null);
@@ -793,7 +820,7 @@ public class Resources_Delegate {
NotFoundException {
Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
if (value != null) {
- return ResourceHelper.getFont(value.getSecond(), resources.mContext, null);
+ return ResourceHelper.getFont(value.getSecond(), getContext(resources), null);
}
throwException(resources, id);
@@ -807,7 +834,7 @@ public class Resources_Delegate {
NotFoundException {
Resources_Delegate.getValue(resources, id, outValue, true);
if (outValue.string != null) {
- return ResourceHelper.getFont(outValue.string.toString(), resources.mContext, null,
+ return ResourceHelper.getFont(outValue.string.toString(), getContext(resources), null,
mPlatformResourceFlag[0]);
}
@@ -867,7 +894,7 @@ public class Resources_Delegate {
try {
XmlPullParser parser = ParserFactory.create(f);
- return new BridgeXmlBlockParser(parser, resources.mContext,
+ return new BridgeXmlBlockParser(parser, getContext(resources),
mPlatformResourceFlag[0]);
} catch (XmlPullParserException e) {
NotFoundException newE = new NotFoundException();
@@ -907,7 +934,7 @@ public class Resources_Delegate {
try {
XmlPullParser parser = ParserFactory.create(f);
- return new BridgeXmlBlockParser(parser, resources.mContext, mPlatformResourceFlag[0]);
+ return new BridgeXmlBlockParser(parser, getContext(resources), mPlatformResourceFlag[0]);
} catch (XmlPullParserException e) {
NotFoundException newE = new NotFoundException();
newE.initCause(e);
diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 8bd924ea9c..821a0e3d99 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -212,11 +212,11 @@ public class BridgeContext extends Context {
* @param config the Configuration object for this render.
* @param targetSdkVersion the targetSdkVersion of the application.
*/
- public BridgeContext(Object projectKey, DisplayMetrics metrics,
- RenderResources renderResources,
- AssetRepository assets,
- LayoutlibCallback layoutlibCallback,
- Configuration config,
+ public BridgeContext(Object projectKey, @NonNull DisplayMetrics metrics,
+ @NonNull RenderResources renderResources,
+ @NonNull AssetRepository assets,
+ @NonNull LayoutlibCallback layoutlibCallback,
+ @NonNull Configuration config,
int targetSdkVersion,
boolean hasRtlSupport) {
mProjectKey = projectKey;
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
index 833652a3a6..b0f39083bb 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
@@ -35,6 +35,7 @@ import org.junit.Test;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.Resources_Delegate;
import android.util.DisplayMetrics;
import android.util.TypedValue;
@@ -412,26 +413,28 @@ public class RenderTests extends RenderTestBase {
AssetManager assetManager = AssetManager.getSystem();
DisplayMetrics metrics = new DisplayMetrics();
Configuration configuration = RenderAction.getConfiguration(params);
- //noinspection deprecation
- Resources resources = new Resources(assetManager, metrics, configuration);
- resources.mLayoutlibCallback = params.getLayoutlibCallback();
- resources.mContext =
- new BridgeContext(params.getProjectKey(), metrics, params.getResources(),
- params.getAssets(), params.getLayoutlibCallback(), configuration,
- params.getTargetSdkVersion(), params.isRtlSupported());
+ BridgeContext context = new BridgeContext(params.getProjectKey(), metrics, params.getResources(),
+ params.getAssets(), params.getLayoutlibCallback(), configuration,
+ params.getTargetSdkVersion(), params.isRtlSupported());
+ Resources resources = Resources_Delegate.initSystem(context, assetManager, metrics,
+ configuration, params.getLayoutlibCallback());
// Test
assertEquals("android:style/ButtonBar",
resources.getResourceName(android.R.style.ButtonBar));
assertEquals("android", resources.getResourcePackageName(android.R.style.ButtonBar));
assertEquals("ButtonBar", resources.getResourceEntryName(android.R.style.ButtonBar));
assertEquals("style", resources.getResourceTypeName(android.R.style.ButtonBar));
- int id = resources.mLayoutlibCallback.getResourceId(ResourceType.STRING, "app_name");
+ int id = Resources_Delegate.getLayoutlibCallback(resources).getResourceId(
+ ResourceType.STRING,
+ "app_name");
assertEquals("com.android.layoutlib.test.myapplication:string/app_name",
resources.getResourceName(id));
assertEquals("com.android.layoutlib.test.myapplication",
resources.getResourcePackageName(id));
assertEquals("string", resources.getResourceTypeName(id));
assertEquals("app_name", resources.getResourceEntryName(id));
+
+ context.disposeResources();
}
@Test
@@ -449,20 +452,22 @@ public class RenderTests extends RenderTestBase {
AssetManager assetManager = AssetManager.getSystem();
DisplayMetrics metrics = new DisplayMetrics();
Configuration configuration = RenderAction.getConfiguration(params);
- //noinspection deprecation
- Resources resources = new Resources(assetManager, metrics, configuration);
- resources.mLayoutlibCallback = params.getLayoutlibCallback();
- resources.mContext =
- new BridgeContext(params.getProjectKey(), metrics, params.getResources(),
- params.getAssets(), params.getLayoutlibCallback(), configuration,
- params.getTargetSdkVersion(), params.isRtlSupported());
-
- int id = resources.mLayoutlibCallback.getResourceId(ResourceType.ARRAY, "string_array");
+ BridgeContext context = new BridgeContext(params.getProjectKey(), metrics, params.getResources(),
+ params.getAssets(), params.getLayoutlibCallback(), configuration,
+ params.getTargetSdkVersion(), params.isRtlSupported());
+ Resources resources = Resources_Delegate.initSystem(context, assetManager, metrics,
+ configuration, params.getLayoutlibCallback());
+
+ int id = Resources_Delegate.getLayoutlibCallback(resources).getResourceId(
+ ResourceType.ARRAY,
+ "string_array");
String[] strings = resources.getStringArray(id);
assertArrayEquals(
new String[]{"mystring", "Hello world!", "candidates", "Unknown", "?EC"},
strings);
assertTrue(sRenderMessages.isEmpty());
+
+ context.disposeResources();
}
@Test
@@ -509,19 +514,16 @@ public class RenderTests extends RenderTestBase {
layoutLibCallback.initResources();
SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_4,
layoutLibCallback, "AppTheme", true, RenderingMode.NORMAL, 22);
- AssetManager assetManager = AssetManager.getSystem();
DisplayMetrics metrics = new DisplayMetrics();
Configuration configuration = RenderAction.getConfiguration(params);
- //noinspection deprecation
- Resources resources = new Resources(assetManager, metrics, configuration);
- resources.mLayoutlibCallback = params.getLayoutlibCallback();
- resources.mContext =
+
+ BridgeContext mContext =
new BridgeContext(params.getProjectKey(), metrics, params.getResources(),
params.getAssets(), params.getLayoutlibCallback(), configuration,
params.getTargetSdkVersion(), params.isRtlSupported());
TypedValue outValue = new TypedValue();
- resources.mContext.resolveThemeAttribute(android.R.attr.colorPrimary, outValue, true);
+ mContext.resolveThemeAttribute(android.R.attr.colorPrimary, outValue, true);
assertEquals(TypedValue.TYPE_INT_COLOR_ARGB8, outValue.type);
assertNotEquals(0, outValue.data);
assertTrue(sRenderMessages.isEmpty());
diff --git a/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index d59b419801..395bfb8fa4 100644
--- a/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -378,10 +378,6 @@ public class AsmGenerator {
ClassVisitor cv = cw;
- // FIXME Generify
- if ("android/content/res/Resources".equals(className)) {
- cv = new FieldInjectorAdapter(cv);
- }
if (mReplaceMethodCallsClasses.contains(className)) {
cv = new ReplaceMethodCallsAdapter(cv, className);
}
diff --git a/create/src/com/android/tools/layoutlib/create/FieldInjectorAdapter.java b/create/src/com/android/tools/layoutlib/create/FieldInjectorAdapter.java
deleted file mode 100644
index 4608a84af3..0000000000
--- a/create/src/com/android/tools/layoutlib/create/FieldInjectorAdapter.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tools.layoutlib.create;
-
-import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.Opcodes;
-
-/**
- * Injects fields in a class.
- * <p>
- * TODO: Generify
- */
-public class FieldInjectorAdapter extends ClassVisitor {
- public FieldInjectorAdapter(ClassVisitor cv) {
- super(Opcodes.ASM4, cv);
- }
-
- @Override
- public void visitEnd() {
- super.visitField(Opcodes.ACC_PUBLIC, "mLayoutlibCallback",
- "Lcom/android/ide/common/rendering/api/LayoutlibCallback;", null, null);
- super.visitField(Opcodes.ACC_PUBLIC, "mContext",
- "Lcom/android/layoutlib/bridge/android/BridgeContext;", null, null);
- super.visitEnd();
- }
-}