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

Commit 3f6bd481 authored by Jens Ole Lauridsen's avatar Jens Ole Lauridsen Committed by Android (Google) Code Review
Browse files

Merge "Support AppBar from Material Design." into mnc-dev

parents 1c83a043 4dfe4d43
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ 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.impl.ParserFactory;
@@ -234,6 +235,13 @@ public final class BridgeInflater extends LayoutInflater {
            if (viewKey != null) {
                bc.addViewKey(view, viewKey);
            }
            String scrollPos = attrs.getAttributeValue(BridgeConstants.NS_RESOURCES, "scrollY");
            if (scrollPos != null) {
                if (scrollPos.endsWith("px")) {
                    int value = Integer.parseInt(scrollPos.substring(0, scrollPos.length() - 2));
                    bc.setScrollYPos(view, value);
                }
            }
        }
    }

+11 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.annotation.Nullable;
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -125,6 +126,7 @@ public final class BridgeContext extends Context {
    private final LayoutlibCallback mLayoutlibCallback;
    private final WindowManager mWindowManager;
    private final DisplayManager mDisplayManager;
    private final HashMap<View, Integer> mScrollYPos = new HashMap<View, Integer>();

    private Resources.Theme mTheme;

@@ -1738,4 +1740,13 @@ public final class BridgeContext extends Context {
        // pass
        return new File[0];
    }

    public void setScrollYPos(@NonNull View view, int scrollPos) {
        mScrollYPos.put(view, scrollPos);
    }

    public int getScrollYPos(@NonNull View view) {
        Integer pos = mScrollYPos.get(view);
        return pos != null ? pos : 0;
    }
}
+65 −0
Original line number Diff line number Diff line
/*
 * 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.android.support;

import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.view.View;

import java.lang.reflect.Method;

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 the design support lib.
 */
public class DesignLibUtil {

    private static final String PKG_PREFIX = "android.support.design.widget.";
    public static final String CN_COORDINATOR_LAYOUT = PKG_PREFIX + "CoordinatorLayout";
    public static final String CN_APPBAR_LAYOUT = PKG_PREFIX + "AppBarLayout";
    public static final String CN_COLLAPSING_TOOLBAR_LAYOUT =
            PKG_PREFIX + "CollapsingToolbarLayout";
    public static final String CN_TOOLBAR = "android.support.v7.widget.Toolbar";
    public static final int SCROLL_AXIS_VERTICAL = 1 << 1;

    /**
     * Tries to set the title of a view. This is used to set the title in a
     * CollapsingToolbarLayout.
     * <p/>
     * Any exceptions thrown during the process are logged in {@link Bridge#getLog()}
     */
    public static void setTitle(@NonNull View view, @Nullable String title) {
        if (title == null) {
            return;
        }
        try {
            Method setTitle = getMethod(view.getClass(), "setTitle", CharSequence.class);
            if (setTitle != null) {
                invoke(setTitle, view, title);
            }
        } catch (ReflectionException e) {
            Bridge.getLog().warning(LayoutLog.TAG_INFO,
                    "Error occurred while trying to set title.", e);
        }
    }
}
+98 −1
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import com.android.layoutlib.bridge.android.BridgeContext;
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;
@@ -148,7 +149,6 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
    private int mTitleBarSize;
    private int mActionBarSize;


    // information being returned through the API
    private BufferedImage mImage;
    private List<ViewInfo> mViewInfoList;
@@ -424,6 +424,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
            // post-inflate process. For now this supports TabHost/TabWidget
            postInflateProcess(view, params.getLayoutlibCallback(), isPreference ? view : null);

            setActiveToolbar(view, context, params);

            // get the background drawable
            if (mWindowBackground != null) {
                Drawable d = ResourceHelper.getDrawable(mWindowBackground, context);
@@ -544,6 +546,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
            // now do the layout.
            mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);

            handleScrolling(mViewRoot);

            if (params.isLayoutOnly()) {
                // delete the canvas and image to reset them on the next full rendering
                mImage = null;
@@ -1349,6 +1353,99 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
        }
    }

    /**
     * If the root layout is a CoordinatorLayout with an AppBar:
     * Set the title of the AppBar to the title of the activity context.
     */
    private void setActiveToolbar(View view, BridgeContext context, SessionParams params) {
        View coordinatorLayout = findChildView(view, DesignLibUtil.CN_COORDINATOR_LAYOUT);
        if (coordinatorLayout == null) {
            return;
        }
        View appBar = findChildView(coordinatorLayout, DesignLibUtil.CN_APPBAR_LAYOUT);
        if (appBar == null) {
            return;
        }
        ViewGroup collapsingToolbar =
                (ViewGroup) findChildView(appBar, DesignLibUtil.CN_COLLAPSING_TOOLBAR_LAYOUT);
        if (collapsingToolbar == null) {
            return;
        }
        if (!hasToolbar(collapsingToolbar)) {
            return;
        }
        RenderResources res = context.getRenderResources();
        String title = params.getAppLabel();
        ResourceValue titleValue = res.findResValue(title, false);
        if (titleValue != null && titleValue.getValue() != null) {
            title = titleValue.getValue();
        }
        DesignLibUtil.setTitle(collapsingToolbar, title);
    }

    private View findChildView(View view, String className) {
        if (!(view instanceof ViewGroup)) {
            return null;
        }
        ViewGroup group = (ViewGroup) view;
        for (int i = 0; i < group.getChildCount(); i++) {
            if (isInstanceOf(group.getChildAt(i), className)) {
                return group.getChildAt(i);
            }
        }
        return null;
    }

    private boolean hasToolbar(View collapsingToolbar) {
        if (!(collapsingToolbar instanceof ViewGroup)) {
            return false;
        }
        ViewGroup group = (ViewGroup) collapsingToolbar;
        for (int i = 0; i < group.getChildCount(); i++) {
            if (isInstanceOf(group.getChildAt(i), DesignLibUtil.CN_TOOLBAR)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Set the vertical scroll position on all the components with the "scrollY" attribute. If the
     * component supports nested scrolling attempt that first, then use the unconsumed scroll part
     * to scroll the content in the component.
     */
    private void handleScrolling(View view) {
        BridgeContext context = getContext();
        int scrollPos = context.getScrollYPos(view);
        if (scrollPos != 0) {
            if (view.isNestedScrollingEnabled()) {
                int[] consumed = new int[2];
                if (view.startNestedScroll(DesignLibUtil.SCROLL_AXIS_VERTICAL)) {
                    view.dispatchNestedPreScroll(0, scrollPos, consumed, null);
                    view.dispatchNestedScroll(consumed[0], consumed[1], 0, scrollPos, null);
                    view.stopNestedScroll();
                    scrollPos -= consumed[1];
                }
            }
            if (scrollPos != 0) {
                view.scrollBy(0, scrollPos);
            } else {
                view.scrollBy(0, scrollPos);
            }
        } else {
            view.scrollBy(0, scrollPos);
        }

        if (!(view instanceof ViewGroup)) {
            return;
        }
        ViewGroup group = (ViewGroup) view;
        for (int i = 0; i < group.getChildCount(); i++) {
            View child = group.getChildAt(i);
            handleScrolling(child);
        }
    }

    /**
     * Check if the object is an instance of a class named {@code className}. This doesn't work
     * for interfaces.