From 9ca97747260b9906fc3a159ce3930109022cf2dd Mon Sep 17 00:00:00 2001 From: Deepanshu Gupta Date: Mon, 30 Mar 2015 14:53:38 -0700 Subject: [PATCH 1/4] Add @empty support. Bug: http://b.android.com/162428 Change-Id: Id7a981de2fce21213e12cdabcce4104f146fd4d3 --- .../android/content/res/BridgeTypedArray.java | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java index 18036927363f2..ae2c1735f2aca 100644 --- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java +++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java @@ -16,6 +16,7 @@ package android.content.res; +import com.android.annotations.Nullable; import com.android.ide.common.rendering.api.AttrResourceValue; import com.android.ide.common.rendering.api.LayoutLog; import com.android.ide.common.rendering.api.RenderResources; @@ -40,9 +41,12 @@ import android.view.LayoutInflater_Delegate; import android.view.ViewGroup.LayoutParams; import java.io.File; +import java.util.ArrayList; import java.util.Arrays; import java.util.Map; +import static com.android.ide.common.rendering.api.RenderResources.*; + /** * Custom implementation of TypedArray to handle non compiled resources. */ @@ -56,6 +60,11 @@ public final class BridgeTypedArray extends TypedArray { private final String[] mNames; private final boolean[] mIsFramework; + // Contains ids that are @empty. We still store null in mResourceData for that index, since we + // want to save on the check against empty, each time a resource value is requested. + @Nullable + private int[] mEmptyIds; + public BridgeTypedArray(BridgeResources resources, BridgeContext context, int len, boolean platformFile) { super(resources, null, null, 0); @@ -90,19 +99,32 @@ public final class BridgeTypedArray extends TypedArray { // fills TypedArray.mIndices which is used to implement getIndexCount/getIndexAt // first count the array size int count = 0; + ArrayList emptyIds = null; for (int i = 0; i < mResourceData.length; i++) { ResourceValue data = mResourceData[i]; if (data != null) { - if (RenderResources.REFERENCE_NULL.equals(data.getValue())) { - // No need to store this resource value. This saves needless checking for - // "@null" every time an attribute is requested. + String dataValue = data.getValue(); + if (REFERENCE_NULL.equals(dataValue) || REFERENCE_UNDEFINED.equals(dataValue)) { mResourceData[i] = null; + } else if (REFERENCE_EMPTY.equals(dataValue)) { + mResourceData[i] = null; + if (emptyIds == null) { + emptyIds = new ArrayList(4); + } + emptyIds.add(i); } else { count++; } } } + if (emptyIds != null) { + mEmptyIds = new int[emptyIds.size()]; + for (int i = 0; i < emptyIds.size(); i++) { + mEmptyIds[i] = emptyIds.get(i); + } + } + // allocate the table with an extra to store the size mIndices = new int[count+1]; mIndices[0] = count; @@ -748,6 +770,12 @@ public final class BridgeTypedArray extends TypedArray { return index >= 0 && index < mResourceData.length && mResourceData[index] != null; } + @Override + public boolean hasValueOrEmpty(int index) { + return hasValue(index) || index >= 0 && index < mResourceData.length && + mEmptyIds != null && Arrays.binarySearch(mEmptyIds, index) >= 0; + } + /** * Retrieve the raw TypedValue for the attribute at index * and return a temporary object holding its data. This object is only From 49ce36e1754243eedc124b4f7e68af1b458c821c Mon Sep 17 00:00:00 2001 From: Deepanshu Gupta Date: Tue, 14 Apr 2015 15:17:07 -0700 Subject: [PATCH 2/4] Remove implementation of deprecated method. BridgeResources.getDrawable(int) is not needed anymore, since the super method is deprecated and it calls the alternative getDrawable(int, Theme), which we override. Change-Id: I00c0bfaef6c4167a787bb74990b91cebb951c847 --- .../bridge/src/android/content/res/BridgeResources.java | 5 ----- .../com/android/layoutlib/bridge/impl/RenderSessionImpl.java | 5 +++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java index 96ca25059afa4..a744345fb9092 100644 --- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java +++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java @@ -153,11 +153,6 @@ public final class BridgeResources extends Resources { return null; } - @Override - public Drawable getDrawable(int id) throws NotFoundException { - return getDrawable(id, null); - } - @Override public Drawable getDrawable(int id, Theme theme) { Pair value = getResourceValue(id, mPlatformResourceFlag); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index fc4f9f15d6dce..ff67f65cc8eb6 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -1406,8 +1406,9 @@ public class RenderSessionImpl extends RenderAction { if (count == 0) { // Create a dummy child to get a single tab - TabSpec spec = tabHost.newTabSpec("tag").setIndicator("Tab Label", - tabHost.getResources().getDrawable(android.R.drawable.ic_menu_info_details)) + TabSpec spec = tabHost.newTabSpec("tag") + .setIndicator("Tab Label", tabHost.getResources() + .getDrawable(android.R.drawable.ic_menu_info_details, null)) .setContent(new TabHost.TabContentFactory() { @Override public View createTabContent(String tag) { From 37dbb8b7f3c069196040eed3a03006647db7fa5b Mon Sep 17 00:00:00 2001 From: Deepanshu Gupta Date: Tue, 14 Apr 2015 16:39:41 -0700 Subject: [PATCH 3/4] Update to using LayoutlibCallback. Change-Id: Ia89d418b0d40ca8efef8968a4a2a635616b945ac --- .../src/android/app/Fragment_Delegate.java | 22 +++--- .../android/content/res/BridgeResources.java | 24 +++---- .../android/content/res/BridgeTypedArray.java | 4 +- .../android/util/BridgeXmlPullAttributes.java | 6 +- .../src/android/view/BridgeInflater.java | 23 ++++--- .../internal/policy/PolicyManager.java | 2 +- .../bridge/android/BridgeContext.java | 38 +++++------ .../android/support/RecyclerViewUtil.java | 11 ++- .../bridge/bars/AppCompatActionBar.java | 2 +- .../bridge/bars/BridgeActionBar.java | 2 +- .../layoutlib/bridge/impl/RenderAction.java | 10 +-- .../bridge/impl/RenderSessionImpl.java | 61 ++++++++--------- .../bridge/impl/binding/AdapterHelper.java | 6 +- .../bridge/impl/binding/FakeAdapter.java | 13 ++-- .../impl/binding/FakeExpandableAdapter.java | 6 +- .../setup/LayoutLibTestCallback.java | 47 +++---------- .../intensive/setup/ModuleClassLoader.java | 67 +++++++++++++++++++ 17 files changed, 190 insertions(+), 154 deletions(-) create mode 100644 tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ModuleClassLoader.java diff --git a/tools/layoutlib/bridge/src/android/app/Fragment_Delegate.java b/tools/layoutlib/bridge/src/android/app/Fragment_Delegate.java index aabd3f1fbd4ed..f7654ce231b2a 100644 --- a/tools/layoutlib/bridge/src/android/app/Fragment_Delegate.java +++ b/tools/layoutlib/bridge/src/android/app/Fragment_Delegate.java @@ -16,7 +16,7 @@ package android.app; -import com.android.ide.common.rendering.api.IProjectCallback; +import com.android.ide.common.rendering.api.LayoutlibCallback; import com.android.tools.layoutlib.annotations.LayoutlibDelegate; import android.content.Context; @@ -30,19 +30,19 @@ import android.os.Bundle; * * The methods being re-implemented are the ones responsible for instantiating Fragment objects. * Because the classes of these objects are found in the project, these methods need access to - * {@link IProjectCallback} object. They are however static methods, so the callback is set - * before the inflation through {@link #setProjectCallback(IProjectCallback)}. + * {@link LayoutlibCallback} object. They are however static methods, so the callback is set + * before the inflation through {@link #setLayoutlibCallback(LayoutlibCallback)}. */ public class Fragment_Delegate { - private static IProjectCallback sProjectCallback; + private static LayoutlibCallback sLayoutlibCallback; /** - * Sets the current {@link IProjectCallback} to be used to instantiate classes coming + * Sets the current {@link LayoutlibCallback} to be used to instantiate classes coming * from the project being rendered. */ - public static void setProjectCallback(IProjectCallback projectCallback) { - sProjectCallback = projectCallback; + public static void setLayoutlibCallback(LayoutlibCallback layoutlibCallback) { + sLayoutlibCallback = layoutlibCallback; } /** @@ -62,17 +62,17 @@ public class Fragment_Delegate { * This is currently just used to get its ClassLoader. * @param fname The class name of the fragment to instantiate. * @param args Bundle of arguments to supply to the fragment, which it - * can retrieve with {@link #getArguments()}. May be null. + * can retrieve with {@link Fragment#getArguments()}. May be null. * @return Returns a new fragment instance. - * @throws InstantiationException If there is a failure in instantiating + * @throws Fragment.InstantiationException If there is a failure in instantiating * the given fragment class. This is a runtime exception; it is not * normally expected to happen. */ @LayoutlibDelegate /*package*/ static Fragment instantiate(Context context, String fname, Bundle args) { try { - if (sProjectCallback != null) { - Fragment f = (Fragment) sProjectCallback.loadView(fname, + if (sLayoutlibCallback != null) { + Fragment f = (Fragment) sLayoutlibCallback.loadView(fname, new Class[0], new Object[0]); if (args != null) { diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java index a744345fb9092..2c2c6723f981f 100644 --- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java +++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java @@ -16,8 +16,8 @@ package android.content.res; -import com.android.ide.common.rendering.api.IProjectCallback; import com.android.ide.common.rendering.api.LayoutLog; +import com.android.ide.common.rendering.api.LayoutlibCallback; import com.android.ide.common.rendering.api.ResourceValue; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.BridgeConstants; @@ -49,7 +49,7 @@ import java.io.InputStream; public final class BridgeResources extends Resources { private BridgeContext mContext; - private IProjectCallback mProjectCallback; + private LayoutlibCallback mLayoutlibCallback; private boolean[] mPlatformResourceFlag = new boolean[1]; private TypedValue mTmpValue = new TypedValue(); @@ -94,12 +94,12 @@ public final class BridgeResources extends Resources { AssetManager assets, DisplayMetrics metrics, Configuration config, - IProjectCallback projectCallback) { + LayoutlibCallback layoutlibCallback) { return Resources.mSystem = new BridgeResources(context, assets, metrics, config, - projectCallback); + layoutlibCallback); } /** @@ -109,16 +109,16 @@ public final class BridgeResources extends Resources { public static void disposeSystem() { if (Resources.mSystem instanceof BridgeResources) { ((BridgeResources)(Resources.mSystem)).mContext = null; - ((BridgeResources)(Resources.mSystem)).mProjectCallback = null; + ((BridgeResources)(Resources.mSystem)).mLayoutlibCallback = null; } Resources.mSystem = null; } private BridgeResources(BridgeContext context, AssetManager assets, DisplayMetrics metrics, - Configuration config, IProjectCallback projectCallback) { + Configuration config, LayoutlibCallback layoutlibCallback) { super(assets, metrics, config); mContext = context; - mProjectCallback = projectCallback; + mLayoutlibCallback = layoutlibCallback; } public BridgeTypedArray newTypeArray(int numEntries, boolean platformFile) { @@ -138,8 +138,8 @@ public final class BridgeResources extends Resources { } // didn't find a match in the framework? look in the project. - if (mProjectCallback != null) { - resourceInfo = mProjectCallback.resolveResourceId(id); + if (mLayoutlibCallback != null) { + resourceInfo = mLayoutlibCallback.resolveResourceId(id); if (resourceInfo != null) { platformResFlag_out[0] = false; @@ -252,7 +252,7 @@ public final class BridgeResources extends Resources { try { // check if the current parser can provide us with a custom parser. if (mPlatformResourceFlag[0] == false) { - parser = mProjectCallback.getParser(value); + parser = mLayoutlibCallback.getParser(value); } // create a new one manually if needed. @@ -687,8 +687,8 @@ public final class BridgeResources extends Resources { Pair resourceInfo = Bridge.resolveResourceId(id); // if the name is unknown in the framework, get it from the custom view loader. - if (resourceInfo == null && mProjectCallback != null) { - resourceInfo = mProjectCallback.resolveResourceId(id); + if (resourceInfo == null && mLayoutlibCallback != null) { + resourceInfo = mLayoutlibCallback.resolveResourceId(id); } String message = null; diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java index ae2c1735f2aca..7d4271bc7688f 100644 --- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java +++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java @@ -646,7 +646,7 @@ public final class BridgeTypedArray extends TypedArray { if (isFrameworkId) { idValue = Bridge.getResourceId(ResourceType.ID, idName); } else { - idValue = mContext.getProjectCallback().getResourceId(ResourceType.ID, idName); + idValue = mContext.getLayoutlibCallback().getResourceId(ResourceType.ID, idName); } return idValue == null ? defValue : idValue; } @@ -666,7 +666,7 @@ public final class BridgeTypedArray extends TypedArray { idValue = Bridge.getResourceId(resValue.getResourceType(), resValue.getName()); } else { - idValue = mContext.getProjectCallback().getResourceId( + idValue = mContext.getLayoutlibCallback().getResourceId( resValue.getResourceType(), resValue.getName()); } diff --git a/tools/layoutlib/bridge/src/android/util/BridgeXmlPullAttributes.java b/tools/layoutlib/bridge/src/android/util/BridgeXmlPullAttributes.java index 691339e2d2ed9..138b2d5fca3d0 100644 --- a/tools/layoutlib/bridge/src/android/util/BridgeXmlPullAttributes.java +++ b/tools/layoutlib/bridge/src/android/util/BridgeXmlPullAttributes.java @@ -69,8 +69,8 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes { // this is not an attribute in the android namespace, we query the customviewloader, if // the namespaces match. - if (mContext.getProjectCallback().getNamespace().equals(ns)) { - Integer v = mContext.getProjectCallback().getResourceId(ResourceType.ATTR, name); + if (mContext.getLayoutlibCallback().getNamespace().equals(ns)) { + Integer v = mContext.getLayoutlibCallback().getResourceId(ResourceType.ATTR, name); if (v != null) { return v.intValue(); } @@ -273,7 +273,7 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes { if (mPlatformFile || resource.isFramework()) { id = Bridge.getResourceId(resource.getResourceType(), resource.getName()); } else { - id = mContext.getProjectCallback().getResourceId( + id = mContext.getLayoutlibCallback().getResourceId( resource.getResourceType(), resource.getName()); } diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java index 4acbd1cded0ad..5db9556d91d4c 100644 --- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java +++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java @@ -16,7 +16,7 @@ package android.view; -import com.android.ide.common.rendering.api.IProjectCallback; +import com.android.ide.common.rendering.api.LayoutlibCallback; import com.android.ide.common.rendering.api.LayoutLog; import com.android.ide.common.rendering.api.MergeCookie; import com.android.ide.common.rendering.api.ResourceReference; @@ -46,7 +46,7 @@ import static com.android.layoutlib.bridge.android.BridgeContext.getBaseContext; */ public final class BridgeInflater extends LayoutInflater { - private final IProjectCallback mProjectCallback; + private final LayoutlibCallback mLayoutlibCallback; private boolean mIsInMerge = false; private ResourceReference mResourceReference; @@ -64,21 +64,21 @@ public final class BridgeInflater extends LayoutInflater { super(original, newContext); newContext = getBaseContext(newContext); if (newContext instanceof BridgeContext) { - mProjectCallback = ((BridgeContext) newContext).getProjectCallback(); + mLayoutlibCallback = ((BridgeContext) newContext).getLayoutlibCallback(); } else { - mProjectCallback = null; + mLayoutlibCallback = null; } } /** - * Instantiate a new BridgeInflater with an {@link IProjectCallback} object. + * Instantiate a new BridgeInflater with an {@link LayoutlibCallback} object. * * @param context The Android application context. - * @param projectCallback the {@link IProjectCallback} object. + * @param layoutlibCallback the {@link LayoutlibCallback} object. */ - public BridgeInflater(Context context, IProjectCallback projectCallback) { + public BridgeInflater(Context context, LayoutlibCallback layoutlibCallback) { super(context); - mProjectCallback = projectCallback; + mLayoutlibCallback = layoutlibCallback; mConstructorArgs[0] = context; } @@ -167,12 +167,13 @@ public final class BridgeInflater extends LayoutInflater { ResourceValue value = null; + @SuppressWarnings("deprecation") Pair layoutInfo = Bridge.resolveResourceId(resource); if (layoutInfo != null) { value = bridgeContext.getRenderResources().getFrameworkResource( ResourceType.LAYOUT, layoutInfo.getSecond()); } else { - layoutInfo = mProjectCallback.resolveResourceId(resource); + layoutInfo = mLayoutlibCallback.resolveResourceId(resource); if (layoutInfo != null) { value = bridgeContext.getRenderResources().getProjectResource( @@ -203,7 +204,7 @@ public final class BridgeInflater extends LayoutInflater { } private View loadCustomView(String name, AttributeSet attrs) throws Exception { - if (mProjectCallback != null) { + if (mLayoutlibCallback != null) { // first get the classname in case it's not the node name if (name.equals("view")) { name = attrs.getAttributeValue(null, "class"); @@ -211,7 +212,7 @@ public final class BridgeInflater extends LayoutInflater { mConstructorArgs[1] = attrs; - Object customView = mProjectCallback.loadView(name, mConstructorSignature, + Object customView = mLayoutlibCallback.loadView(name, mConstructorSignature, mConstructorArgs); if (customView instanceof View) { diff --git a/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java b/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java index 0100dc5910396..6558b6aa503ee 100644 --- a/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java +++ b/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java @@ -43,7 +43,7 @@ public class PolicyManager { } public static LayoutInflater makeNewLayoutInflater(Context context) { - return new BridgeInflater(context, RenderAction.getCurrentContext().getProjectCallback()); + return new BridgeInflater(context, RenderAction.getCurrentContext().getLayoutlibCallback()); } public static WindowManagerPolicy makeNewWindowManager() { diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 868529ee4344a..3f553e7a2c3ed 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -20,8 +20,8 @@ import android.os.IBinder; import com.android.annotations.Nullable; import com.android.ide.common.rendering.api.AssetRepository; import com.android.ide.common.rendering.api.ILayoutPullParser; -import com.android.ide.common.rendering.api.IProjectCallback; import com.android.ide.common.rendering.api.LayoutLog; +import com.android.ide.common.rendering.api.LayoutlibCallback; import com.android.ide.common.rendering.api.RenderResources; import com.android.ide.common.rendering.api.ResourceReference; import com.android.ide.common.rendering.api.ResourceValue; @@ -113,7 +113,7 @@ public final class BridgeContext extends Context { private final RenderResources mRenderResources; private final Configuration mConfig; private final ApplicationInfo mApplicationInfo; - private final IProjectCallback mProjectCallback; + private final LayoutlibCallback mLayoutlibCallback; private final WindowManager mWindowManager; private final DisplayManager mDisplayManager; @@ -147,13 +147,13 @@ public final class BridgeContext extends Context { public BridgeContext(Object projectKey, DisplayMetrics metrics, RenderResources renderResources, AssetRepository assets, - IProjectCallback projectCallback, + LayoutlibCallback layoutlibCallback, Configuration config, int targetSdkVersion, boolean hasRtlSupport) { mProjectKey = projectKey; mMetrics = metrics; - mProjectCallback = projectCallback; + mLayoutlibCallback = layoutlibCallback; mRenderResources = renderResources; mConfig = config; @@ -172,7 +172,7 @@ public final class BridgeContext extends Context { /** * Initializes the {@link Resources} singleton to be linked to this {@link Context}, its - * {@link DisplayMetrics}, {@link Configuration}, and {@link IProjectCallback}. + * {@link DisplayMetrics}, {@link Configuration}, and {@link LayoutlibCallback}. * * @see #disposeResources() */ @@ -184,7 +184,7 @@ public final class BridgeContext extends Context { assetManager, mMetrics, mConfig, - mProjectCallback); + mLayoutlibCallback); mTheme = mSystemResources.newTheme(); } @@ -223,8 +223,8 @@ public final class BridgeContext extends Context { return mMetrics; } - public IProjectCallback getProjectCallback() { - return mProjectCallback; + public LayoutlibCallback getLayoutlibCallback() { + return mLayoutlibCallback; } public RenderResources getRenderResources() { @@ -283,7 +283,7 @@ public final class BridgeContext extends Context { Pair resourceInfo = Bridge.resolveResourceId(resid); boolean isFrameworkRes = true; if (resourceInfo == null) { - resourceInfo = mProjectCallback.resolveResourceId(resid); + resourceInfo = mLayoutlibCallback.resolveResourceId(resid); isFrameworkRes = false; } @@ -339,8 +339,8 @@ public final class BridgeContext extends Context { } // didn't find a match in the framework? look in the project. - if (mProjectCallback != null) { - resourceInfo = mProjectCallback.resolveResourceId(id); + if (mLayoutlibCallback != null) { + resourceInfo = mLayoutlibCallback.resolveResourceId(id); if (resourceInfo != null) { return new ResourceReference(resourceInfo.getSecond(), false); @@ -438,9 +438,9 @@ public final class BridgeContext extends Context { private ILayoutPullParser getParser(ResourceReference resource) { ILayoutPullParser parser; if (resource instanceof ResourceValue) { - parser = mProjectCallback.getParser((ResourceValue) resource); + parser = mLayoutlibCallback.getParser((ResourceValue) resource); } else { - parser = mProjectCallback.getParser(resource.getName()); + parser = mLayoutlibCallback.getParser(resource.getName()); } return parser; } @@ -665,7 +665,7 @@ public final class BridgeContext extends Context { boolean isFrameworkRes = true; Pair value = Bridge.resolveResourceId(defStyleRes); if (value == null) { - value = mProjectCallback.resolveResourceId(defStyleRes); + value = mLayoutlibCallback.resolveResourceId(defStyleRes); isFrameworkRes = false; } @@ -703,7 +703,7 @@ public final class BridgeContext extends Context { } } - String appNamespace = mProjectCallback.getNamespace(); + String appNamespace = mLayoutlibCallback.getNamespace(); if (attributeList != null) { for (int index = 0 ; index < attributeList.size() ; index++) { @@ -846,7 +846,7 @@ public final class BridgeContext extends Context { if (resolvedResource != null) { isFramework = true; } else { - resolvedResource = mProjectCallback.resolveResourceId(attr); + resolvedResource = mLayoutlibCallback.resolveResourceId(attr); } if (resolvedResource != null) { @@ -872,7 +872,7 @@ public final class BridgeContext extends Context { return Pair.of(info.getSecond(), Boolean.TRUE); } - info = mProjectCallback.resolveResourceId(attr); + info = mLayoutlibCallback.resolveResourceId(attr); if (info != null) { return Pair.of(info.getSecond(), Boolean.FALSE); } @@ -924,8 +924,8 @@ public final class BridgeContext extends Context { // getResourceId creates a new resource id if an existing resource id isn't found. So, we // check for the existence of the resource before calling it. if (getRenderResources().getProjectResource(resType, resName) != null) { - if (mProjectCallback != null) { - Integer value = mProjectCallback.getResourceId(resType, resName); + if (mLayoutlibCallback != null) { + Integer value = mLayoutlibCallback.getResourceId(resType, resName); if (value != null) { return value; } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java index 1d47333c06fd3..aac5d33e365f8 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java @@ -18,8 +18,8 @@ package com.android.layoutlib.bridge.android.support; import com.android.annotations.NonNull; import com.android.annotations.Nullable; -import com.android.ide.common.rendering.api.IProjectCallback; import com.android.ide.common.rendering.api.LayoutLog; +import com.android.ide.common.rendering.api.LayoutlibCallback; import com.android.ide.common.rendering.api.SessionParams; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.android.BridgeContext; @@ -30,7 +30,6 @@ import android.view.View; import android.widget.LinearLayout; import java.lang.reflect.Method; -import java.util.HashMap; import static com.android.layoutlib.bridge.util.ReflectionUtils.*; @@ -61,7 +60,7 @@ public class RecyclerViewUtil { public static void setAdapter(@NonNull View recyclerView, @NonNull BridgeContext context, @NonNull SessionParams params) { try { - setLayoutManager(recyclerView, context, params.getProjectCallback()); + setLayoutManager(recyclerView, context, params.getLayoutlibCallback()); Object adapter = createAdapter(params); setProperty(recyclerView, CN_ADAPTER, adapter, "setAdapter"); } catch (ReflectionException e) { @@ -71,7 +70,7 @@ public class RecyclerViewUtil { } private static void setLayoutManager(@NonNull View recyclerView, @NonNull BridgeContext context, - @NonNull IProjectCallback callback) throws ReflectionException { + @NonNull LayoutlibCallback callback) throws ReflectionException { Object cookie = context.getCookie(recyclerView); assert cookie == null || cookie instanceof LayoutManagerType || cookie instanceof String; if (!(cookie instanceof LayoutManagerType)) { @@ -90,7 +89,7 @@ public class RecyclerViewUtil { @Nullable private static Object createLayoutManager(@Nullable LayoutManagerType type, - @NonNull Context context, @NonNull IProjectCallback callback) + @NonNull Context context, @NonNull LayoutlibCallback callback) throws ReflectionException { if (type == null) { type = LayoutManagerType.getDefault(); @@ -109,7 +108,7 @@ public class RecyclerViewUtil { return null; } try { - return params.getProjectCallback().loadView(CN_ADAPTER, new Class[0], new Object[0]); + return params.getLayoutlibCallback().loadView(CN_ADAPTER, new Class[0], new Object[0]); } catch (Exception e) { throw new ReflectionException(e); } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java index ee57067007d16..dd1f661a276bc 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java @@ -70,7 +70,7 @@ public class AppCompatActionBar extends BridgeActionBar { try { Class[] constructorParams = {View.class}; Object[] constructorArgs = {getDecorContent()}; - mWindowDecorActionBar = params.getProjectCallback().loadView(WINDOW_ACTION_BAR_CLASS, + mWindowDecorActionBar = params.getLayoutlibCallback().loadView(WINDOW_ACTION_BAR_CLASS, constructorParams, constructorArgs); mWindowActionBarClass = mWindowDecorActionBar == null ? null : diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java index 2a83ea165ab05..3d1a9b9f0804f 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java @@ -51,7 +51,7 @@ public abstract class BridgeActionBar { @NonNull ViewGroup parentView) { mBridgeContext = context; mParams = params; - mCallback = params.getProjectCallback().getActionBarCallback(); + mCallback = params.getLayoutlibCallback().getActionBarCallback(); ResourceValue layoutName = getLayoutResource(context); if (layoutName == null) { throw new RuntimeException("Unable to find the layout for Action Bar."); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java index 127cb72a0440b..c708316cec1f9 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java @@ -16,10 +16,6 @@ package com.android.layoutlib.bridge.impl; -import static com.android.ide.common.rendering.api.Result.Status.ERROR_LOCK_INTERRUPTED; -import static com.android.ide.common.rendering.api.Result.Status.ERROR_TIMEOUT; -import static com.android.ide.common.rendering.api.Result.Status.SUCCESS; - import com.android.ide.common.rendering.api.HardwareConfig; import com.android.ide.common.rendering.api.LayoutLog; import com.android.ide.common.rendering.api.RenderParams; @@ -43,6 +39,10 @@ import android.view.inputmethod.InputMethodManager_Accessor; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; +import static com.android.ide.common.rendering.api.Result.Status.ERROR_LOCK_INTERRUPTED; +import static com.android.ide.common.rendering.api.Result.Status.ERROR_TIMEOUT; +import static com.android.ide.common.rendering.api.Result.Status.SUCCESS; + /** * Base class for rendering action. * @@ -120,7 +120,7 @@ public abstract class RenderAction extends FrameworkReso // build the context mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources, - mParams.getAssets(), mParams.getProjectCallback(), getConfiguration(), + mParams.getAssets(), mParams.getLayoutlibCallback(), getConfiguration(), mParams.getTargetSdkVersion(), mParams.isRtlSupported()); setUp(); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index ff67f65cc8eb6..95576ef9120b0 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -16,20 +16,13 @@ package com.android.layoutlib.bridge.impl; -import static com.android.ide.common.rendering.api.Result.Status.ERROR_ANIM_NOT_FOUND; -import static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION; -import static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED; -import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN; -import static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN; -import static com.android.ide.common.rendering.api.Result.Status.SUCCESS; - import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.ide.common.rendering.api.AdapterBinding; import com.android.ide.common.rendering.api.HardwareConfig; import com.android.ide.common.rendering.api.IAnimationListener; import com.android.ide.common.rendering.api.ILayoutPullParser; -import com.android.ide.common.rendering.api.IProjectCallback; +import com.android.ide.common.rendering.api.LayoutlibCallback; import com.android.ide.common.rendering.api.RenderResources; import com.android.ide.common.rendering.api.RenderSession; import com.android.ide.common.rendering.api.ResourceReference; @@ -54,13 +47,13 @@ import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes; import com.android.layoutlib.bridge.android.BridgeXmlBlockParser; import com.android.layoutlib.bridge.android.SessionParamsFlags; import com.android.layoutlib.bridge.android.support.RecyclerViewUtil; -import com.android.layoutlib.bridge.bars.BridgeActionBar; import com.android.layoutlib.bridge.bars.AppCompatActionBar; +import com.android.layoutlib.bridge.bars.BridgeActionBar; import com.android.layoutlib.bridge.bars.Config; +import com.android.layoutlib.bridge.bars.FrameworkActionBar; import com.android.layoutlib.bridge.bars.NavigationBar; import com.android.layoutlib.bridge.bars.StatusBar; import com.android.layoutlib.bridge.bars.TitleBar; -import com.android.layoutlib.bridge.bars.FrameworkActionBar; import com.android.layoutlib.bridge.impl.binding.FakeAdapter; import com.android.layoutlib.bridge.impl.binding.FakeExpandableAdapter; import com.android.resources.Density; @@ -116,6 +109,13 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import static com.android.ide.common.rendering.api.Result.Status.ERROR_ANIM_NOT_FOUND; +import static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION; +import static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED; +import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN; +import static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN; +import static com.android.ide.common.rendering.api.Result.Status.SUCCESS; + /** * Class implementing the render session. *

@@ -219,7 +219,7 @@ public class RenderSessionImpl extends RenderAction { WindowManagerGlobal_Delegate.setWindowManagerService(iwm); // build the inflater and parser. - mInflater = new BridgeInflater(context, params.getProjectCallback()); + mInflater = new BridgeInflater(context, params.getLayoutlibCallback()); context.setBridgeInflater(mInflater); mBlockParser = new BridgeXmlBlockParser( @@ -401,7 +401,7 @@ public class RenderSessionImpl extends RenderAction { // Sets the project callback (custom view loader) to the fragment delegate so that // it can instantiate the custom Fragment. - Fragment_Delegate.setProjectCallback(params.getProjectCallback()); + Fragment_Delegate.setLayoutlibCallback(params.getLayoutlibCallback()); String rootTag = params.getFlag(SessionParamsFlags.FLAG_KEY_ROOT_TAG); boolean isPreference = "PreferenceScreen".equals(rootTag); @@ -416,13 +416,13 @@ public class RenderSessionImpl extends RenderAction { // done with the parser, pop it. context.popParser(); - Fragment_Delegate.setProjectCallback(null); + Fragment_Delegate.setLayoutlibCallback(null); // set the AttachInfo on the root view. AttachInfo_Accessor.setAttachInfo(mViewRoot); // post-inflate process. For now this supports TabHost/TabWidget - postInflateProcess(view, params.getProjectCallback(), isPreference ? view : null); + postInflateProcess(view, params.getLayoutlibCallback(), isPreference ? view : null); // get the background drawable if (mWindowBackground != null) { @@ -675,7 +675,7 @@ public class RenderSessionImpl extends RenderAction { animationResource = context.getRenderResources().getProjectResource( ResourceType.ANIMATOR, animationName); if (animationResource != null) { - animationId = context.getProjectCallback().getResourceId( + animationId = context.getLayoutlibCallback().getResourceId( ResourceType.ANIMATOR, animationName); } } @@ -1246,17 +1246,17 @@ public class RenderSessionImpl extends RenderAction { * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically * based on the content of the {@link FrameLayout}. * @param view the root view to process. - * @param projectCallback callback to the project. + * @param layoutlibCallback callback to the project. * @param skip the view and it's children are not processed. */ @SuppressWarnings("deprecation") // For the use of Pair - private void postInflateProcess(View view, IProjectCallback projectCallback, View skip) + private void postInflateProcess(View view, LayoutlibCallback layoutlibCallback, View skip) throws PostInflateException { if (view == skip) { return; } if (view instanceof TabHost) { - setupTabHost((TabHost) view, projectCallback); + setupTabHost((TabHost) view, layoutlibCallback); } else if (view instanceof QuickContactBadge) { QuickContactBadge badge = (QuickContactBadge) view; badge.setImageToDefault(); @@ -1275,8 +1275,8 @@ public class RenderSessionImpl extends RenderAction { // if there was no adapter binding, trying to get it from the call back. if (binding == null) { - binding = params.getProjectCallback().getAdapterBinding(listRef, - context.getViewKey(view), view); + binding = layoutlibCallback.getAdapterBinding( + listRef, context.getViewKey(view), view); } if (binding != null) { @@ -1292,7 +1292,7 @@ public class RenderSessionImpl extends RenderAction { for (int i = 0; i < count; i++) { Pair pair = context.inflateView( binding.getHeaderAt(i), - list, false /*attachToRoot*/, skipCallbackParser); + list, false, skipCallbackParser); if (pair.getFirst() != null) { list.addHeaderView(pair.getFirst()); } @@ -1304,7 +1304,7 @@ public class RenderSessionImpl extends RenderAction { for (int i = 0; i < count; i++) { Pair pair = context.inflateView( binding.getFooterAt(i), - list, false /*attachToRoot*/, skipCallbackParser); + list, false, skipCallbackParser); if (pair.getFirst() != null) { list.addFooterView(pair.getFirst()); } @@ -1315,17 +1315,14 @@ public class RenderSessionImpl extends RenderAction { if (view instanceof ExpandableListView) { ((ExpandableListView) view).setAdapter( - new FakeExpandableAdapter( - listRef, binding, params.getProjectCallback())); + new FakeExpandableAdapter(listRef, binding, layoutlibCallback)); } else { ((AbsListView) view).setAdapter( - new FakeAdapter( - listRef, binding, params.getProjectCallback())); + new FakeAdapter(listRef, binding, layoutlibCallback)); } } else if (view instanceof AbsSpinner) { ((AbsSpinner) view).setAdapter( - new FakeAdapter( - listRef, binding, params.getProjectCallback())); + new FakeAdapter(listRef, binding, layoutlibCallback)); } } } @@ -1336,7 +1333,7 @@ public class RenderSessionImpl extends RenderAction { final int count = group.getChildCount(); for (int c = 0; c < count; c++) { View child = group.getChildAt(c); - postInflateProcess(child, projectCallback, skip); + postInflateProcess(child, layoutlibCallback, skip); } } } @@ -1360,10 +1357,10 @@ public class RenderSessionImpl extends RenderAction { /** * Sets up a {@link TabHost} object. * @param tabHost the TabHost to setup. - * @param projectCallback The project callback object to access the project R class. + * @param layoutlibCallback The project callback object to access the project R class. * @throws PostInflateException */ - private void setupTabHost(TabHost tabHost, IProjectCallback projectCallback) + private void setupTabHost(TabHost tabHost, LayoutlibCallback layoutlibCallback) throws PostInflateException { // look for the TabWidget, and the FrameLayout. They have their own specific names View v = tabHost.findViewById(android.R.id.tabs); @@ -1424,7 +1421,7 @@ public class RenderSessionImpl extends RenderAction { @SuppressWarnings("ConstantConditions") // child cannot be null. int id = child.getId(); @SuppressWarnings("deprecation") - Pair resource = projectCallback.resolveResourceId(id); + Pair resource = layoutlibCallback.resolveResourceId(id); String name; if (resource != null) { name = resource.getSecond(); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java index 6c998afaa0acd..9aab340909fd7 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java @@ -17,7 +17,7 @@ package com.android.layoutlib.bridge.impl.binding; import com.android.ide.common.rendering.api.DataBindingItem; -import com.android.ide.common.rendering.api.IProjectCallback; +import com.android.ide.common.rendering.api.LayoutlibCallback; import com.android.ide.common.rendering.api.LayoutLog; import com.android.ide.common.rendering.api.ResourceReference; import com.android.ide.common.rendering.api.IProjectCallback.ViewAttribute; @@ -40,7 +40,7 @@ import android.widget.TextView; public class AdapterHelper { static Pair getView(AdapterItem item, AdapterItem parentItem, ViewGroup parent, - IProjectCallback callback, ResourceReference adapterRef, boolean skipCallbackParser) { + LayoutlibCallback callback, ResourceReference adapterRef, boolean skipCallbackParser) { // we don't care about recycling here because we never scroll. DataBindingItem dataBindingItem = item.getDataBindingItem(); @@ -65,7 +65,7 @@ public class AdapterHelper { } private static void fillView(BridgeContext context, View view, AdapterItem item, - AdapterItem parentItem, IProjectCallback callback, ResourceReference adapterRef) { + AdapterItem parentItem, LayoutlibCallback callback, ResourceReference adapterRef) { if (view instanceof ViewGroup) { ViewGroup group = (ViewGroup) view; final int count = group.getChildCount(); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java index 9a13f5a36a894..142eac172502b 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java @@ -18,7 +18,7 @@ package com.android.layoutlib.bridge.impl.binding; import com.android.ide.common.rendering.api.AdapterBinding; import com.android.ide.common.rendering.api.DataBindingItem; -import com.android.ide.common.rendering.api.IProjectCallback; +import com.android.ide.common.rendering.api.LayoutlibCallback; import com.android.ide.common.rendering.api.ResourceReference; import com.android.util.Pair; @@ -37,18 +37,17 @@ import java.util.List; * and {@link SpinnerAdapter}. * */ -@SuppressWarnings("deprecation") public class FakeAdapter extends BaseAdapter { // don't use a set because the order is important. private final List mTypes = new ArrayList(); - private final IProjectCallback mCallback; + private final LayoutlibCallback mCallback; private final ResourceReference mAdapterRef; private final List mItems = new ArrayList(); private boolean mSkipCallbackParser = false; public FakeAdapter(ResourceReference adapterRef, AdapterBinding binding, - IProjectCallback callback) { + LayoutlibCallback callback) { mAdapterRef = adapterRef; mCallback = callback; @@ -111,11 +110,11 @@ public class FakeAdapter extends BaseAdapter { public View getView(int position, View convertView, ViewGroup parent) { // we don't care about recycling here because we never scroll. AdapterItem item = mItems.get(position); - Pair pair = AdapterHelper.getView(item, null /*parentGroup*/, parent, - mCallback, mAdapterRef, mSkipCallbackParser); + @SuppressWarnings("deprecation") + Pair pair = AdapterHelper.getView(item, null, parent, mCallback, + mAdapterRef, mSkipCallbackParser); mSkipCallbackParser = pair.getSecond(); return pair.getFirst(); - } @Override diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java index e539579fb0ab5..344b17eab039c 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java @@ -18,7 +18,7 @@ package com.android.layoutlib.bridge.impl.binding; import com.android.ide.common.rendering.api.AdapterBinding; import com.android.ide.common.rendering.api.DataBindingItem; -import com.android.ide.common.rendering.api.IProjectCallback; +import com.android.ide.common.rendering.api.LayoutlibCallback; import com.android.ide.common.rendering.api.ResourceReference; import com.android.util.Pair; @@ -34,7 +34,7 @@ import java.util.List; @SuppressWarnings("deprecation") public class FakeExpandableAdapter implements ExpandableListAdapter, HeterogeneousExpandableList { - private final IProjectCallback mCallback; + private final LayoutlibCallback mCallback; private final ResourceReference mAdapterRef; private boolean mSkipCallbackParser = false; @@ -45,7 +45,7 @@ public class FakeExpandableAdapter implements ExpandableListAdapter, Heterogeneo private final List mChildrenTypes = new ArrayList(); public FakeExpandableAdapter(ResourceReference adapterRef, AdapterBinding binding, - IProjectCallback callback) { + LayoutlibCallback callback) { mAdapterRef = adapterRef; mCallback = callback; diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java index 565e8815a987d..0a5e7984a336e 100644 --- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java @@ -20,7 +20,7 @@ import com.android.SdkConstants; import com.android.ide.common.rendering.api.ActionBarCallback; import com.android.ide.common.rendering.api.AdapterBinding; import com.android.ide.common.rendering.api.ILayoutPullParser; -import com.android.ide.common.rendering.api.IProjectCallback; +import com.android.ide.common.rendering.api.LayoutlibCallback; import com.android.ide.common.rendering.api.ResourceReference; import com.android.ide.common.rendering.api.ResourceValue; import com.android.resources.ResourceType; @@ -28,10 +28,7 @@ import com.android.ide.common.resources.IntArrayWrapper; import com.android.util.Pair; import com.android.utils.ILogger; -import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.IOException; -import java.io.InputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -40,7 +37,7 @@ import java.util.Map; import com.google.android.collect.Maps; @SuppressWarnings("deprecation") // For Pair -public class LayoutLibTestCallback extends ClassLoader implements IProjectCallback { +public class LayoutLibTestCallback extends LayoutlibCallback { private static final String PROJECT_CLASSES_LOCATION = "/testApp/MyApplication/build/intermediates/classes/debug/"; private static final String PACKAGE_NAME = "com.android.layoutlib.test.myapplication"; @@ -48,16 +45,16 @@ public class LayoutLibTestCallback extends ClassLoader implements IProjectCallba private final Map> mProjectResources = Maps.newHashMap(); private final Map mStyleableValueToNameMap = Maps.newHashMap(); private final Map> mResources = Maps.newHashMap(); - private final Map> mClasses = Maps.newHashMap(); private final ILogger mLog; private final ActionBarCallback mActionBarCallback = new ActionBarCallback(); + private final ClassLoader mModuleClassLoader = new ModuleClassLoader(PROJECT_CLASSES_LOCATION); public LayoutLibTestCallback(ILogger logger) { mLog = logger; } public void initResources() throws ClassNotFoundException { - Class rClass = loadClass(PACKAGE_NAME + ".R"); + Class rClass = mModuleClassLoader.loadClass(PACKAGE_NAME + ".R"); Class[] nestedClasses = rClass.getDeclaredClasses(); for (Class resClass : nestedClasses) { final ResourceType resType = ResourceType.getEnum(resClass.getSimpleName()); @@ -91,40 +88,11 @@ public class LayoutLibTestCallback extends ClassLoader implements IProjectCallba } } - @Override - protected Class findClass(String name) throws ClassNotFoundException { - Class aClass = mClasses.get(name); - if (aClass != null) { - return aClass; - } - String pathName = PROJECT_CLASSES_LOCATION.concat(name.replace('.', '/')).concat(".class"); - InputStream classInputStream = getClass().getResourceAsStream(pathName); - if (classInputStream == null) { - throw new ClassNotFoundException("Unable to find class " + name + " at " + pathName); - } - byte[] data; - try { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - int nRead; - data = new byte[16384]; - while ((nRead = classInputStream.read(data, 0, data.length)) != -1) { - buffer.write(data, 0, nRead); - } - buffer.flush(); - data = buffer.toByteArray(); - } catch (IOException e) { - // Wrap the exception with ClassNotFoundException so that caller can deal with it. - throw new ClassNotFoundException("Unable to load class " + name, e); - } - aClass = defineClass(name, data, 0, data.length); - mClasses.put(name, aClass); - return aClass; - } @Override public Object loadView(String name, Class[] constructorSignature, Object[] constructorArgs) throws Exception { - Class viewClass = findClass(name); + Class viewClass = mModuleClassLoader.loadClass(name); Constructor viewConstructor = viewClass.getConstructor(constructorSignature); viewConstructor.setAccessible(true); return viewConstructor.newInstance(constructorArgs); @@ -180,4 +148,9 @@ public class LayoutLibTestCallback extends ClassLoader implements IProjectCallba public ActionBarCallback getActionBarCallback() { return mActionBarCallback; } + + @Override + public boolean supports(int ideFeature) { + return false; + } } diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ModuleClassLoader.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ModuleClassLoader.java new file mode 100644 index 0000000000000..110f4c8b97951 --- /dev/null +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ModuleClassLoader.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2015 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.layoutlib.bridge.intensive.setup; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +import com.google.android.collect.Maps; + +/** + * The ClassLoader to load the project's classes. + */ +public class ModuleClassLoader extends ClassLoader { + + private final Map> mClasses = Maps.newHashMap(); + private final String mClassLocation; + + public ModuleClassLoader(String classLocation) { + mClassLocation = classLocation; + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + Class aClass = mClasses.get(name); + if (aClass != null) { + return aClass; + } + String pathName = mClassLocation.concat(name.replace('.', '/')).concat(".class"); + InputStream classInputStream = getClass().getResourceAsStream(pathName); + if (classInputStream == null) { + throw new ClassNotFoundException("Unable to find class " + name + " at " + pathName); + } + byte[] data; + try { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int nRead; + data = new byte[16384]; // 16k + while ((nRead = classInputStream.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + buffer.flush(); + data = buffer.toByteArray(); + } catch (IOException e) { + // Wrap the exception with ClassNotFoundException so that caller can deal with it. + throw new ClassNotFoundException("Unable to load class " + name, e); + } + aClass = defineClass(name, data, 0, data.length); + mClasses.put(name, aClass); + return aClass; + } +} From 54862febaf519281ac61ebe31caf49c69820449a Mon Sep 17 00:00:00 2001 From: Deepanshu Gupta Date: Tue, 14 Apr 2015 17:26:09 -0700 Subject: [PATCH 4/4] Update golden image for tests. Change-Id: If07edcbfb7016a6b80f4bd00cffab494f74bfc03 --- .../testApp/MyApplication/golden/activity.png | Bin 8075 -> 7991 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png index e38f437a0ce43a5f64f126046232b83f9bb55669..9bf302ad690691f2b428fe827099d812d41ef28f 100644 GIT binary patch delta 7740 zcmV-C9>d{_Kes-RBYz(LNkloZKx)(wcigx;)S!-mo1$$yjSrI%i!M;>{^wiyqvYgdx_b30>E8+p3h32WUlnC0O`1eHolca=&CR7h|M|}h zOn=qt)vHPCW^ZpV%6$6irvesP{{H^T`)ALdO+i6HqU?|%L&R$nCr+e@hzOc7V+IWz zIFS7O{3swGfPbb7j=nQjVJg=7}es zpobrRSik^a=r{LgV2Bxp*v46)Nqqep-x^m?TJ^Spl2FJ_+ zvw8Dodj0j+DLg!!#*Q6J6DCYB0Or95AEe00NSZZk7H!|Yoq_2~dj9$6Y0jKECa;?V z2G-T$#f#~M7ha$dBSz3Gue>5&M_2Up(@%@XIQHIq@6phqLm8OIj!Se?~?l9Cc)u{x^( zmoHx?7OS&jU|0+ci-BP=Fsyz9OkG_a)z;SD^hNdGdn@N*^&nuPqoe8k`SarO*|TR2 zjv*rva-ZGoMUgvAevI?v=jT&iULIFSZwDqZF_Cg|azt9I`1p8{kqGxPFpZ6kf8v;r zkB>-~h4&%RURYQd6&4nXa(SXjeEQ=G&Gc=qM`&0C?6OYC|>vV^%bwlEsXpa=fQgc4Od7X>XK0T zAt526WsresYHAWNd3$?PYip}0e~T6*EiH{spFT|u4Gol#kRTw6iHR`)29O|y7SeuV zOoXyrA#5eF7#J1TnvN(6)d96%*@`~ zf}jO$Z>4iB%?7GyZldjpf6)RGV~w!4ro#HVz6%Um3{*HO7A*p-ALOwIJg|~rN~7YD zNgDUCs?dsDkbYq@F!0j=I_df2O8JbV=ybF+S?8 zUs`o*t12+*Rh2aG=x$A5rU!YmmDC?q*Vd*AOm1~0-Fs}WCNQ%@&oVImQ5U5ax2m

oCuzXJtvyoZ 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 W&7$wRR^0#q002ovPDHLk0$_p~E!ZCb