Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a4546b0e authored by Deepanshu Gupta's avatar Deepanshu Gupta Committed by Android (Google) Code Review
Browse files

Merge "Implement tools:list_item for RecyclerView." into mnc-dev

parents 0c784ffa 61f23e9b
Loading
Loading
Loading
Loading
+23 −8
Original line number Diff line number Diff line
@@ -25,7 +25,9 @@ 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.impl.ParserFactory;
import com.android.layoutlib.bridge.util.ReflectionUtils;
import com.android.resources.ResourceType;
import com.android.util.Pair;

@@ -112,15 +114,9 @@ public final class BridgeInflater extends LayoutInflater {
            }

            // 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;
            }
        } catch (Exception e) {
            // Wrap the real exception in a ClassNotFoundException, so that the calling method
            // can deal with it.
@@ -242,6 +238,25 @@ public final class BridgeInflater extends LayoutInflater {
                    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);
            }
        }
    }

+2 −1
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ public class BridgeConstants {

    /** 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 class BridgeConstants {
    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";
}
+37 −23
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.layoutlib.bridge.android.support;

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 @@ import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke;
/**
 * 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,15 +55,24 @@ public class RecyclerViewUtil {
     * 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);
            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,
@@ -73,9 +80,11 @@ public class RecyclerViewUtil {
        if (getLayoutManager(recyclerView) == null) {
            // Only set the layout manager if not already set by the recycler view.
            Object layoutManager = createLayoutManager(context, callback);
            if (layoutManager != null) {
                setProperty(recyclerView, CN_LAYOUT_MANAGER, layoutManager, "setLayoutManager");
            }
        }
    }

    /** Creates a LinearLayoutManager using the provided context. */
    @Nullable
@@ -91,34 +100,39 @@ public class RecyclerViewUtil {
    }

    @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,
            @Nullable Object propertyValue, @NonNull String propertySetter)
    private static void setProperty(@NonNull Object object, @NonNull String propertyClassName,
      @NonNull 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);
        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 {
        Method setter = getMethod(object.getClass(), propertySetter, propertyClass);
        if (setter != null) {
            invoke(setter, object, propertyValue);
        }
    }

+1 −19
Original line number Diff line number Diff line
@@ -45,7 +45,6 @@ import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
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_NOT_INFLA
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.
@@ -1341,8 +1341,6 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
                    }
                }
            }
        } 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();
@@ -1446,22 +1444,6 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
        }
    }

    /**
     * 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.
+16 −0
Original line number Diff line number Diff line
@@ -51,6 +51,22 @@ public class ReflectionUtils {
        throw new ReflectionException(ex);
    }

    /**
     * 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