Loading tools/layoutlib/bridge/src/android/view/BridgeInflater.java +1 −21 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } } } } } Loading tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +11 −7 Original line number Diff line number Diff line Loading @@ -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. */ Loading Loading @@ -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 /** Loading Loading @@ -1224,12 +1234,6 @@ public final class BridgeContext extends Context { return null; } @Override public String getPackageName() { // pass return null; } @Override public String getBasePackageName() { // pass Loading tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java +14 −2 Original line number Diff line number Diff line Loading @@ -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; /** Loading @@ -31,10 +32,21 @@ public final class RenderParamsFlags { new Key<String>("rootTag", String.class); public static final Key<Boolean> FLAG_KEY_DISABLE_BITMAP_CACHING = new Key<Boolean>("disableBitmapCaching", Boolean.class); public static final Key<Boolean> FLAG_KEY_RECYCLER_VIEW_SUPPORT = new Key<Boolean>("recyclerViewSupport", Boolean.class); public static final Key<Boolean> FLAG_KEY_RENDER_ALL_DRAWABLE_STATES = new Key<Boolean>("renderAllDrawableStates", Boolean.class); /** * To tell LayoutLib that the IDE supports RecyclerView. * <p/> * Default is false. */ public static final Key<Boolean> FLAG_KEY_RECYCLER_VIEW_SUPPORT = new Key<Boolean>("recyclerViewSupport", Boolean.class); /** * The application package name. Used via * {@link com.android.ide.common.rendering.api.LayoutlibCallback#getFlag(Key)} */ public static final Key<String> FLAG_KEY_APPLICATION_PACKAGE = new Key<String>("applicationPackage", String.class); // Disallow instances. private RenderParamsFlags() {} Loading tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java +24 −99 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -39,17 +40,15 @@ import static com.android.layoutlib.bridge.util.ReflectionUtils.*; @SuppressWarnings("SpellCheckingInspection") // for "recycler". public class RecyclerViewUtil { /** * Used by {@link LayoutManagerType}. * <p/> * 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} Loading @@ -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(); } Object layoutManager = createLayoutManager((LayoutManagerType) cookie, context, callback); 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"); } } /** 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); Loading Loading @@ -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; } } } Loading
tools/layoutlib/bridge/src/android/view/BridgeInflater.java +1 −21 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } } } } } Loading
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +11 −7 Original line number Diff line number Diff line Loading @@ -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. */ Loading Loading @@ -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 /** Loading Loading @@ -1224,12 +1234,6 @@ public final class BridgeContext extends Context { return null; } @Override public String getPackageName() { // pass return null; } @Override public String getBasePackageName() { // pass Loading
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java +14 −2 Original line number Diff line number Diff line Loading @@ -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; /** Loading @@ -31,10 +32,21 @@ public final class RenderParamsFlags { new Key<String>("rootTag", String.class); public static final Key<Boolean> FLAG_KEY_DISABLE_BITMAP_CACHING = new Key<Boolean>("disableBitmapCaching", Boolean.class); public static final Key<Boolean> FLAG_KEY_RECYCLER_VIEW_SUPPORT = new Key<Boolean>("recyclerViewSupport", Boolean.class); public static final Key<Boolean> FLAG_KEY_RENDER_ALL_DRAWABLE_STATES = new Key<Boolean>("renderAllDrawableStates", Boolean.class); /** * To tell LayoutLib that the IDE supports RecyclerView. * <p/> * Default is false. */ public static final Key<Boolean> FLAG_KEY_RECYCLER_VIEW_SUPPORT = new Key<Boolean>("recyclerViewSupport", Boolean.class); /** * The application package name. Used via * {@link com.android.ide.common.rendering.api.LayoutlibCallback#getFlag(Key)} */ public static final Key<String> FLAG_KEY_APPLICATION_PACKAGE = new Key<String>("applicationPackage", String.class); // Disallow instances. private RenderParamsFlags() {} Loading
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java +24 −99 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -39,17 +40,15 @@ import static com.android.layoutlib.bridge.util.ReflectionUtils.*; @SuppressWarnings("SpellCheckingInspection") // for "recycler". public class RecyclerViewUtil { /** * Used by {@link LayoutManagerType}. * <p/> * 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} Loading @@ -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(); } Object layoutManager = createLayoutManager((LayoutManagerType) cookie, context, callback); 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"); } } /** 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); Loading Loading @@ -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; } } }