diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java index 9eea66338402e..87762a63a0584 100644 --- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java +++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java @@ -16,19 +16,15 @@ package android.view; -import com.android.ide.common.rendering.api.LayoutlibCallback; import com.android.ide.common.rendering.api.LayoutLog; +import com.android.ide.common.rendering.api.LayoutlibCallback; import com.android.ide.common.rendering.api.MergeCookie; import com.android.ide.common.rendering.api.ResourceReference; import com.android.ide.common.rendering.api.ResourceValue; import com.android.layoutlib.bridge.Bridge; -import com.android.layoutlib.bridge.BridgeConstants; import com.android.layoutlib.bridge.android.BridgeContext; import com.android.layoutlib.bridge.android.BridgeXmlBlockParser; -import com.android.layoutlib.bridge.android.support.RecyclerViewUtil; -import com.android.layoutlib.bridge.android.support.RecyclerViewUtil.LayoutManagerType; import com.android.layoutlib.bridge.impl.ParserFactory; -import com.android.layoutlib.bridge.impl.RenderSessionImpl; import com.android.resources.ResourceType; import com.android.util.Pair; @@ -233,22 +229,6 @@ public final class BridgeInflater extends LayoutInflater { if (viewKey != null) { bc.addViewKey(view, viewKey); } - if (RenderSessionImpl.isInstanceOf(view, RecyclerViewUtil.CN_RECYCLER_VIEW)) { - String type = attrs.getAttributeValue(BridgeConstants.NS_RESOURCES, - BridgeConstants.ATTR_LAYOUT_MANAGER_TYPE); - if (type != null) { - LayoutManagerType layoutManagerType = LayoutManagerType.getByLogicalName(type); - if (layoutManagerType == null) { - layoutManagerType = LayoutManagerType.getByClassName(type); - } - if (layoutManagerType == null) { - // add the classname itself. - bc.addCookie(view, type); - } else { - bc.addCookie(view, layoutManagerType); - } - } - } } } 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 094778d2b4a54..eb5f59733ebfb 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 @@ -93,6 +93,8 @@ import java.util.IdentityHashMap; import java.util.List; import java.util.Map; +import static com.android.layoutlib.bridge.android.RenderParamsFlags.FLAG_KEY_APPLICATION_PACKAGE; + /** * Custom implementation of Context/Activity to handle non compiled resources. */ @@ -306,7 +308,7 @@ public final class BridgeContext extends Context { // check if this is a style resource if (value instanceof StyleResourceValue) { // get the id that will represent this style. - outValue.resourceId = getDynamicIdByStyle((StyleResourceValue)value); + outValue.resourceId = getDynamicIdByStyle((StyleResourceValue) value); return true; } @@ -812,6 +814,14 @@ public final class BridgeContext extends Context { } + @Override + public String getPackageName() { + if (mApplicationInfo.packageName == null) { + mApplicationInfo.packageName = mLayoutlibCallback.getFlag(FLAG_KEY_APPLICATION_PACKAGE); + } + return mApplicationInfo.packageName; + } + // ------------- private new methods /** @@ -1224,12 +1234,6 @@ public final class BridgeContext extends Context { return null; } - @Override - public String getPackageName() { - // pass - return null; - } - @Override public String getBasePackageName() { // pass diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java index 2f45473bf53b7..b98f96f27c916 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java @@ -16,6 +16,7 @@ package com.android.layoutlib.bridge.android; +import com.android.ide.common.rendering.api.RenderParams; import com.android.ide.common.rendering.api.SessionParams.Key; /** @@ -31,10 +32,21 @@ public final class RenderParamsFlags { new Key("rootTag", String.class); public static final Key FLAG_KEY_DISABLE_BITMAP_CACHING = new Key("disableBitmapCaching", Boolean.class); - public static final Key FLAG_KEY_RECYCLER_VIEW_SUPPORT = - new Key("recyclerViewSupport", Boolean.class); public static final Key FLAG_KEY_RENDER_ALL_DRAWABLE_STATES = new Key("renderAllDrawableStates", Boolean.class); + /** + * To tell LayoutLib that the IDE supports RecyclerView. + *

+ * Default is false. + */ + public static final Key FLAG_KEY_RECYCLER_VIEW_SUPPORT = + new Key("recyclerViewSupport", Boolean.class); + /** + * The application package name. Used via + * {@link com.android.ide.common.rendering.api.LayoutlibCallback#getFlag(Key)} + */ + public static final Key FLAG_KEY_APPLICATION_PACKAGE = + new Key("applicationPackage", String.class); // Disallow instances. private RenderParamsFlags() {} 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 9273ac248a133..e4c7288422754 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 @@ -27,11 +27,12 @@ import com.android.layoutlib.bridge.android.RenderParamsFlags; import android.content.Context; import android.view.View; -import android.widget.LinearLayout; import java.lang.reflect.Method; -import static com.android.layoutlib.bridge.util.ReflectionUtils.*; +import static com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException; +import static com.android.layoutlib.bridge.util.ReflectionUtils.getMethod; +import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke; /** * Utility class for working with android.support.v7.widget.RecyclerView @@ -39,17 +40,15 @@ import static com.android.layoutlib.bridge.util.ReflectionUtils.*; @SuppressWarnings("SpellCheckingInspection") // for "recycler". public class RecyclerViewUtil { - /** - * Used by {@link LayoutManagerType}. - *

- * Not declared inside the enum, since it needs to be accessible in the constructor. - */ - private static final Object CONTEXT = new Object(); - - public static final String CN_RECYCLER_VIEW = "android.support.v7.widget.RecyclerView"; + private static final String RV_PKG_PREFIX = "android.support.v7.widget."; + public static final String CN_RECYCLER_VIEW = RV_PKG_PREFIX + "RecyclerView"; private static final String CN_LAYOUT_MANAGER = CN_RECYCLER_VIEW + "$LayoutManager"; private static final String CN_ADAPTER = CN_RECYCLER_VIEW + "$Adapter"; + // LinearLayoutManager related constants. + private static final String CN_LINEAR_LAYOUT_MANAGER = RV_PKG_PREFIX + "LinearLayoutManager"; + private static final Class[] LLM_CONSTRUCTOR_SIGNATURE = new Class[]{Context.class}; + /** * Tries to create an Adapter ({@code android.support.v7.widget.RecyclerView.Adapter} and a * LayoutManager {@code RecyclerView.LayoutManager} and assign these to the {@code RecyclerView} @@ -71,36 +70,32 @@ public class RecyclerViewUtil { private static void setLayoutManager(@NonNull View recyclerView, @NonNull BridgeContext context, @NonNull LayoutlibCallback callback) throws ReflectionException { - Object cookie = context.getCookie(recyclerView); - assert cookie == null || cookie instanceof LayoutManagerType || cookie instanceof String; - if (!(cookie instanceof LayoutManagerType)) { - if (cookie != null) { - // TODO: When layoutlib API is updated, try to load the class with a null - // constructor or a constructor taking one argument - the context. - Bridge.getLog().warning(LayoutLog.TAG_UNSUPPORTED, - "LayoutManager (" + cookie + ") not found, falling back to " + - "LinearLayoutManager", null); - } - cookie = LayoutManagerType.getDefault(); + if (getLayoutManager(recyclerView) == null) { + // Only set the layout manager if not already set by the recycler view. + Object layoutManager = createLayoutManager(context, callback); + setProperty(recyclerView, CN_LAYOUT_MANAGER, layoutManager, "setLayoutManager"); } - Object layoutManager = createLayoutManager((LayoutManagerType) cookie, context, callback); - setProperty(recyclerView, CN_LAYOUT_MANAGER, layoutManager, "setLayoutManager"); } + /** Creates a LinearLayoutManager using the provided context. */ @Nullable - private static Object createLayoutManager(@Nullable LayoutManagerType type, - @NonNull Context context, @NonNull LayoutlibCallback callback) + private static Object createLayoutManager(@NonNull Context context, + @NonNull LayoutlibCallback callback) throws ReflectionException { - if (type == null) { - type = LayoutManagerType.getDefault(); - } try { - return callback.loadView(type.getClassName(), type.getSignature(), type.getArgs(context)); + return callback.loadView(CN_LINEAR_LAYOUT_MANAGER, LLM_CONSTRUCTOR_SIGNATURE, + new Object[]{ context}); } catch (Exception e) { throw new ReflectionException(e); } } + @Nullable + private static Object getLayoutManager(View recyclerview) throws ReflectionException { + Method getLayoutManager = getMethod(recyclerview.getClass(), "getLayoutManager"); + return getLayoutManager != null ? invoke(getLayoutManager, recyclerview) : null; + } + @Nullable private static Object createAdapter(@NonNull SessionParams params) throws ReflectionException { Boolean ideSupport = params.getFlag(RenderParamsFlags.FLAG_KEY_RECYCLER_VIEW_SUPPORT); @@ -145,74 +140,4 @@ public class RecyclerViewUtil { } throw new RuntimeException("invalid object/classname combination."); } - - /** Supported LayoutManagers. */ - public enum LayoutManagerType { - LINEAR_LAYOUT_MANGER("Linear", - "android.support.v7.widget.LinearLayoutManager", - new Class[]{Context.class}, new Object[]{CONTEXT}), - GRID_LAYOUT_MANAGER("Grid", - "android.support.v7.widget.GridLayoutManager", - new Class[]{Context.class, int.class}, new Object[]{CONTEXT, 2}), - STAGGERED_GRID_LAYOUT_MANAGER("StaggeredGrid", - "android.support.v7.widget.StaggeredGridLayoutManager", - new Class[]{int.class, int.class}, new Object[]{2, LinearLayout.VERTICAL}); - - private String mLogicalName; - private String mClassName; - private Class[] mSignature; - private Object[] mArgs; - - LayoutManagerType(String logicalName, String className, Class[] signature, Object[] args) { - mLogicalName = logicalName; - mClassName = className; - mSignature = signature; - mArgs = args; - } - - String getClassName() { - return mClassName; - } - - Class[] getSignature() { - return mSignature; - } - - @NonNull - Object[] getArgs(Context context) { - Object[] args = new Object[mArgs.length]; - System.arraycopy(mArgs, 0, args, 0, mArgs.length); - for (int i = 0; i < args.length; i++) { - if (args[i] == CONTEXT) { - args[i] = context; - } - } - return args; - } - - @NonNull - public static LayoutManagerType getDefault() { - return LINEAR_LAYOUT_MANGER; - } - - @Nullable - public static LayoutManagerType getByLogicalName(@NonNull String logicalName) { - for (LayoutManagerType type : values()) { - if (logicalName.equals(type.mLogicalName)) { - return type; - } - } - return null; - } - - @Nullable - public static LayoutManagerType getByClassName(@NonNull String className) { - for (LayoutManagerType type : values()) { - if (className.equals(type.mClassName)) { - return type; - } - } - return null; - } - } }