am 8bfc5a9d: am b1e21330: Implement tools:list_item for RecyclerView. [DO NOT MERGE]
* commit '8bfc5a9d14000a436e54350099bd460f55418f27':
Implement tools:list_item for RecyclerView. [DO NOT MERGE]
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 72d660c..cbbc463 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -25,7 +25,9 @@
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.impl.ParserFactory;
+import com.android.layoutlib.bridge.util.ReflectionUtils;
import com.android.resources.ResourceType;
import com.android.util.Pair;
@@ -112,14 +114,8 @@
}
// Finally try again using the custom view loader
- try {
- if (view == null) {
- view = loadCustomView(name, attrs);
- }
- } catch (ClassNotFoundException e) {
- // If the class was not found, we throw the exception directly, because this
- // method is already expected to throw it.
- throw e;
+ if (view == null) {
+ view = loadCustomView(name, attrs);
}
} catch (Exception e) {
// Wrap the real exception in a ClassNotFoundException, so that the calling method
@@ -242,6 +238,25 @@
bc.setScrollYPos(view, value);
}
}
+ if (ReflectionUtils.isInstanceOf(view, RecyclerViewUtil.CN_RECYCLER_VIEW)) {
+ Integer resourceId = null;
+ String attrVal = attrs.getAttributeValue(BridgeConstants.NS_TOOLS_URI,
+ BridgeConstants.ATTR_LIST_ITEM);
+ if (attrVal != null && !attrVal.isEmpty()) {
+ ResourceValue resValue = bc.getRenderResources().findResValue(attrVal, false);
+ if (resValue.isFramework()) {
+ resourceId = Bridge.getResourceId(resValue.getResourceType(),
+ resValue.getName());
+ } else {
+ resourceId = mLayoutlibCallback.getResourceId(resValue.getResourceType(),
+ resValue.getName());
+ }
+ }
+ if (resourceId == null) {
+ resourceId = 0;
+ }
+ RecyclerViewUtil.setAdapter(view, bc, mLayoutlibCallback, resourceId);
+ }
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
index 1af6998..661c08b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
@@ -41,6 +41,7 @@
/** App auto namespace */
public final static String NS_APP_RES_AUTO = "http://schemas.android.com/apk/res-auto";
+ public final static String NS_TOOLS_URI = "http://schemas.android.com/tools";
public final static String R = "com.android.internal.R";
@@ -50,5 +51,5 @@
public final static String WRAP_CONTENT = "wrap_content";
/** Attribute in the tools namespace used to specify layout manager for RecyclerView. */
- public static final String ATTR_LAYOUT_MANAGER_TYPE = "layoutManager";
+ public static final String ATTR_LIST_ITEM = "list_item";
}
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 5e5b3c9..4182cd9 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,7 +18,6 @@
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;
import com.android.layoutlib.bridge.android.RenderParamsFlags;
@@ -37,7 +36,6 @@
/**
* Utility class for working with android.support.v7.widget.RecyclerView
*/
-@SuppressWarnings("SpellCheckingInspection") // for "recycler".
public class RecyclerViewUtil {
private static final String RV_PKG_PREFIX = "android.support.v7.widget.";
@@ -57,23 +55,34 @@
* Any exceptions thrown during the process are logged in {@link Bridge#getLog()}
*/
public static void setAdapter(@NonNull View recyclerView, @NonNull BridgeContext context,
- @NonNull SessionParams params) {
+ @NonNull LayoutlibCallback layoutlibCallback, int adapterLayout) {
try {
- setLayoutManager(recyclerView, context, params.getLayoutlibCallback());
- Object adapter = createAdapter(params);
- setProperty(recyclerView, CN_ADAPTER, adapter, "setAdapter");
+ setLayoutManager(recyclerView, context, layoutlibCallback);
+ Object adapter = createAdapter(layoutlibCallback);
+ if (adapter != null) {
+ setProperty(recyclerView, CN_ADAPTER, adapter, "setAdapter");
+ setProperty(adapter, int.class, adapterLayout, "setLayoutId");
+ }
} catch (ReflectionException e) {
+ Throwable cause = getCause(e);
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
- "Error occured while trying to setup RecyclerView.", e, null);
+ "Error occurred while trying to setup RecyclerView.", cause, null);
}
}
+ private static Throwable getCause(Throwable throwable) {
+ Throwable cause = throwable.getCause();
+ return cause == null ? throwable : cause;
+ }
+
private static void setLayoutManager(@NonNull View recyclerView, @NonNull BridgeContext context,
@NonNull LayoutlibCallback callback) throws ReflectionException {
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");
+ if (layoutManager != null) {
+ setProperty(recyclerView, CN_LAYOUT_MANAGER, layoutManager, "setLayoutManager");
+ }
}
}
@@ -84,41 +93,46 @@
throws ReflectionException {
try {
return callback.loadView(CN_LINEAR_LAYOUT_MANAGER, LLM_CONSTRUCTOR_SIGNATURE,
- new Object[]{ context});
+ 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;
+ 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);
+ private static Object createAdapter(@NonNull LayoutlibCallback layoutlibCallback)
+ throws ReflectionException {
+ Boolean ideSupport =
+ layoutlibCallback.getFlag(RenderParamsFlags.FLAG_KEY_RECYCLER_VIEW_SUPPORT);
if (ideSupport != Boolean.TRUE) {
return null;
}
try {
- return params.getLayoutlibCallback().loadView(CN_ADAPTER, new Class[0], new Object[0]);
+ return layoutlibCallback.loadClass(CN_ADAPTER, new Class[0], new Object[0]);
} catch (Exception e) {
throw new ReflectionException(e);
}
}
- private static void setProperty(@NonNull View recyclerView, @NonNull String propertyClassName,
+ private static void setProperty(@NonNull Object object, @NonNull String propertyClassName,
+ @NonNull Object propertyValue, @NonNull String propertySetter)
+ throws ReflectionException {
+ Class<?> propertyClass = getClassInstance(propertyValue, propertyClassName);
+ setProperty(object, propertyClass, propertyValue, propertySetter);
+ }
+
+ private static void setProperty(@NonNull Object object, @NonNull Class<?> propertyClass,
@Nullable Object propertyValue, @NonNull String propertySetter)
throws ReflectionException {
- if (propertyValue != null) {
- Class<?> layoutManagerClass = getClassInstance(propertyValue, propertyClassName);
- Method setLayoutManager = getMethod(recyclerView.getClass(),
- propertySetter, layoutManagerClass);
- if (setLayoutManager != null) {
- invoke(setLayoutManager, recyclerView, propertyValue);
- }
+ Method setter = getMethod(object.getClass(), propertySetter, propertyClass);
+ if (setter != null) {
+ invoke(setter, object, propertyValue);
}
}
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 9ef5156..e6d8ae9 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
@@ -45,7 +45,6 @@
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.layoutlib.bridge.android.RenderParamsFlags;
import com.android.layoutlib.bridge.android.support.DesignLibUtil;
-import com.android.layoutlib.bridge.android.support.RecyclerViewUtil;
import com.android.layoutlib.bridge.bars.AppCompatActionBar;
import com.android.layoutlib.bridge.bars.BridgeActionBar;
import com.android.layoutlib.bridge.bars.Config;
@@ -116,6 +115,7 @@
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 static com.android.layoutlib.bridge.util.ReflectionUtils.isInstanceOf;
/**
* Class implementing the render session.
@@ -1351,8 +1351,6 @@
}
}
}
- } else if (isInstanceOf(view, RecyclerViewUtil.CN_RECYCLER_VIEW)) {
- RecyclerViewUtil.setAdapter(view, getContext(), getParams());
} else if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
final int count = group.getChildCount();
@@ -1457,22 +1455,6 @@
}
/**
- * Check if the object is an instance of a class named {@code className}. This doesn't work
- * for interfaces.
- */
- public static boolean isInstanceOf(Object object, String className) {
- Class superClass = object.getClass();
- while (superClass != null) {
- String name = superClass.getName();
- if (name.equals(className)) {
- return true;
- }
- superClass = superClass.getSuperclass();
- }
- return false;
- }
-
- /**
* Sets up a {@link TabHost} object.
* @param tabHost the TabHost to setup.
* @param layoutlibCallback The project callback object to access the project R class.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
index b324451..b78b613 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
@@ -52,6 +52,22 @@
}
/**
+ * Check if the object is an instance of a class named {@code className}. This doesn't work
+ * for interfaces.
+ */
+ public static boolean isInstanceOf(Object object, String className) {
+ Class superClass = object.getClass();
+ while (superClass != null) {
+ String name = superClass.getName();
+ if (name.equals(className)) {
+ return true;
+ }
+ superClass = superClass.getSuperclass();
+ }
+ return false;
+ }
+
+ /**
* Wraps all reflection related exceptions. Created since ReflectiveOperationException was
* introduced in 1.7 and we are still on 1.6
*/