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

Commit 7d409b07 authored by Tiger's avatar Tiger
Browse files

Let action bar background extend into system insets

This CL makes action bar background extend into system insets if the
content view doesn't fit any insets.

Bug: 343131420
Bug: 309578419
Flag: com.android.window.flags.enforce_edge_to_edge
Test: atest ActionBarOverlayLayoutTest
Change-Id: I266e55fce8e5a387ae0b56f7c22756d9ec153611
parent 2767bf3c
Loading
Loading
Loading
Loading
+8 −10
Original line number Original line Diff line number Diff line
@@ -93,8 +93,7 @@ public class ActionBarContainer extends FrameLayout {
        if (bg != null) {
        if (bg != null) {
            bg.setCallback(this);
            bg.setCallback(this);
            if (mActionBarView != null) {
            if (mActionBarView != null) {
                mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(),
                bg.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
                        mActionBarView.getRight(), mActionBarView.getBottom());
            }
            }
        }
        }
        setWillNotDraw(mIsSplit ? mSplitBackground == null :
        setWillNotDraw(mIsSplit ? mSplitBackground == null :
@@ -293,6 +292,7 @@ public class ActionBarContainer extends FrameLayout {
        if (mActionBarView == null) return;
        if (mActionBarView == null) return;


        if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
        if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
            final int verticalPadding = getPaddingTop() + getPaddingBottom();
            int nonTabMaxHeight = 0;
            int nonTabMaxHeight = 0;
            final int childCount = getChildCount();
            final int childCount = getChildCount();
            for (int i = 0; i < childCount; i++) {
            for (int i = 0; i < childCount; i++) {
@@ -307,7 +307,9 @@ public class ActionBarContainer extends FrameLayout {
            final int maxHeight = mode == MeasureSpec.AT_MOST ?
            final int maxHeight = mode == MeasureSpec.AT_MOST ?
                    MeasureSpec.getSize(heightMeasureSpec) : Integer.MAX_VALUE;
                    MeasureSpec.getSize(heightMeasureSpec) : Integer.MAX_VALUE;
            setMeasuredDimension(getMeasuredWidth(),
            setMeasuredDimension(getMeasuredWidth(),
                    Math.min(nonTabMaxHeight + getMeasuredHeightWithMargins(mTabContainer),
                    Math.min(
                            verticalPadding + nonTabMaxHeight
                                    + getMeasuredHeightWithMargins(mTabContainer),
                            maxHeight));
                            maxHeight));
        }
        }
    }
    }
@@ -335,13 +337,9 @@ public class ActionBarContainer extends FrameLayout {
            }
            }
        } else {
        } else {
            if (mBackground != null) {
            if (mBackground != null) {
                if (mActionBarView.getVisibility() == View.VISIBLE) {
                if ((mActionBarView.getVisibility() == View.VISIBLE) || (mActionContextView != null
                    mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(),
                        && mActionContextView.getVisibility() == View.VISIBLE)) {
                            mActionBarView.getRight(), mActionBarView.getBottom());
                    mBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
                } else if (mActionContextView != null &&
                        mActionContextView.getVisibility() == View.VISIBLE) {
                    mBackground.setBounds(mActionContextView.getLeft(), mActionContextView.getTop(),
                            mActionContextView.getRight(), mActionContextView.getBottom());
                } else {
                } else {
                    mBackground.setBounds(0, 0, 0, 0);
                    mBackground.setBounds(0, 0, 0, 0);
                }
                }
+98 −26
Original line number Original line Diff line number Diff line
@@ -24,6 +24,7 @@ import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Canvas;
import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Build;
@@ -77,10 +78,13 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
    private final Rect mBaseContentInsets = new Rect();
    private final Rect mBaseContentInsets = new Rect();
    private final Rect mLastBaseContentInsets = new Rect();
    private final Rect mLastBaseContentInsets = new Rect();
    private final Rect mContentInsets = new Rect();
    private final Rect mContentInsets = new Rect();
    private final Rect mSystemInsets = new Rect();
    private WindowInsets mBaseInnerInsets = WindowInsets.CONSUMED;
    private WindowInsets mBaseInnerInsets = WindowInsets.CONSUMED;
    private WindowInsets mLastBaseInnerInsets = WindowInsets.CONSUMED;
    private WindowInsets mLastBaseInnerInsets = WindowInsets.CONSUMED;
    private WindowInsets mInnerInsets = WindowInsets.CONSUMED;
    private WindowInsets mInnerInsets = WindowInsets.CONSUMED;
    private WindowInsets mLastInnerInsets = WindowInsets.CONSUMED;
    private WindowInsets mLastInnerInsets = WindowInsets.CONSUMED;
    private boolean mDecorFitsSystemWindows = true;
    private boolean mActionBarExtendsIntoSystemInsets = false;


    private ActionBarVisibilityCallback mActionBarVisibilityCallback;
    private ActionBarVisibilityCallback mActionBarVisibilityCallback;


@@ -268,7 +272,8 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
            // We want the bar to be visible if it is not being hidden,
            // We want the bar to be visible if it is not being hidden,
            // or the app has not turned on a stable UI mode (meaning they
            // or the app has not turned on a stable UI mode (meaning they
            // are performing explicit layout around the action bar).
            // are performing explicit layout around the action bar).
            mActionBarVisibilityCallback.enableContentAnimations(!stable);
            mActionBarVisibilityCallback.enableContentAnimations(
                    !stable && !mActionBarExtendsIntoSystemInsets);
            if (barVisible || !stable) mActionBarVisibilityCallback.showForSystem();
            if (barVisible || !stable) mActionBarVisibilityCallback.showForSystem();
            else mActionBarVisibilityCallback.hideForSystem();
            else mActionBarVisibilityCallback.hideForSystem();
        }
        }
@@ -288,25 +293,56 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
        }
        }
    }
    }


    private boolean applyInsets(View view, Rect insets, boolean left, boolean top,
    private boolean applyInsets(View view, Rect insets, boolean toPadding,
            boolean bottom, boolean right) {
            boolean left, boolean top, boolean bottom, boolean right) {
        boolean changed = false;
        boolean changed;
        if (toPadding) {
            changed = setMargin(view, left, top, bottom, right, 0, 0, 0, 0);
            changed |= setPadding(view, left, top, bottom, right,
                    insets.left, insets.top, insets.right, insets.bottom);
        } else {
            changed = setPadding(view, left, top, bottom, right, 0, 0, 0, 0);
            changed |= setMargin(view, left, top, bottom, right,
                    insets.left, insets.top, insets.right, insets.bottom);
        }
        return changed;
    }

    private boolean setPadding(View view, boolean left, boolean top, boolean bottom, boolean right,
            int l, int t, int r, int b) {
        if ((left && view.getPaddingLeft() != l)
                || (top && view.getPaddingTop() != t)
                || (right && view.getPaddingRight() != r)
                || (bottom && view.getPaddingBottom() != b)) {
            view.setPadding(
                    left ? l : view.getPaddingLeft(),
                    top ? t : view.getPaddingTop(),
                    right ? r : view.getPaddingRight(),
                    bottom ? b : view.getPaddingBottom());
            return true;
        }
        return false;
    }

    private boolean setMargin(View view, boolean left, boolean top, boolean bottom, boolean right,
            int l, int t, int r, int b) {
        LayoutParams lp = (LayoutParams) view.getLayoutParams();
        LayoutParams lp = (LayoutParams) view.getLayoutParams();
        if (left && lp.leftMargin != insets.left) {
        boolean changed = false;
        if (left && lp.leftMargin != l) {
            changed = true;
            changed = true;
            lp.leftMargin = insets.left;
            lp.leftMargin = l;
        }
        }
        if (top && lp.topMargin != insets.top) {
        if (top && lp.topMargin != t) {
            changed = true;
            changed = true;
            lp.topMargin = insets.top;
            lp.topMargin = t;
        }
        }
        if (right && lp.rightMargin != insets.right) {
        if (right && lp.rightMargin != r) {
            changed = true;
            changed = true;
            lp.rightMargin = insets.right;
            lp.rightMargin = r;
        }
        }
        if (bottom && lp.bottomMargin != insets.bottom) {
        if (bottom && lp.bottomMargin != b) {
            changed = true;
            changed = true;
            lp.bottomMargin = insets.bottom;
            lp.bottomMargin = b;
        }
        }
        return changed;
        return changed;
    }
    }
@@ -316,12 +352,28 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
        pullChildren();
        pullChildren();


        final int vis = getWindowSystemUiVisibility();
        final int vis = getWindowSystemUiVisibility();
        final Rect systemInsets = insets.getSystemWindowInsetsAsRect();
        final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
        final boolean layoutIntoSystemInsets = (vis & SYSTEM_UI_LAYOUT_FLAGS) != 0;
        mDecorFitsSystemWindows = hasContentOnApplyWindowInsetsListener();

        // Only extend action bar into system insets area if the app doesn't fit system insets.
        mActionBarExtendsIntoSystemInsets =
                !mDecorFitsSystemWindows || (stable && layoutIntoSystemInsets);

        if (mActionBarVisibilityCallback != null) {
            mActionBarVisibilityCallback.enableContentAnimations(
                    !stable && !mActionBarExtendsIntoSystemInsets);
        }

        final Insets sysInsets = insets.getSystemWindowInsets();
        mSystemInsets.set(sysInsets.left, sysInsets.top, sysInsets.right, sysInsets.bottom);


        // The top and bottom action bars are always within the content area.
        // The top and bottom action bars are always within the content area.
        boolean changed = applyInsets(mActionBarTop, systemInsets, true, true, false, true);
        boolean changed = applyInsets(mActionBarTop, mSystemInsets,
                mActionBarExtendsIntoSystemInsets, true, true, false, true);
        if (mActionBarBottom != null) {
        if (mActionBarBottom != null) {
            changed |= applyInsets(mActionBarBottom, systemInsets, true, false, true, true);
            changed |= applyInsets(mActionBarBottom, mSystemInsets,
                    mActionBarExtendsIntoSystemInsets, true, false, true, true);
        }
        }


        // Cannot use the result of computeSystemWindowInsets, because that consumes the
        // Cannot use the result of computeSystemWindowInsets, because that consumes the
@@ -406,6 +458,9 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
            // This is the standard space needed for the action bar.  For stable measurement,
            // This is the standard space needed for the action bar.  For stable measurement,
            // we can't depend on the size currently reported by it -- this must remain constant.
            // we can't depend on the size currently reported by it -- this must remain constant.
            topInset = mActionBarHeight;
            topInset = mActionBarHeight;
            if (mActionBarExtendsIntoSystemInsets) {
                topInset += mSystemInsets.top;
            }
            if (mHasNonEmbeddedTabs) {
            if (mHasNonEmbeddedTabs) {
                final View tabs = mActionBarTop.getTabContainer();
                final View tabs = mActionBarTop.getTabContainer();
                if (tabs != null) {
                if (tabs != null) {
@@ -424,6 +479,9 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
            if (mActionBarBottom != null) {
            if (mActionBarBottom != null) {
                if (stable) {
                if (stable) {
                    bottomInset = mActionBarHeight;
                    bottomInset = mActionBarHeight;
                    if (mActionBarExtendsIntoSystemInsets) {
                        bottomInset += mSystemInsets.bottom;
                    }
                } else {
                } else {
                    bottomInset = mActionBarBottom.getMeasuredHeight();
                    bottomInset = mActionBarBottom.getMeasuredHeight();
                }
                }
@@ -436,13 +494,26 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
        // overlay.
        // overlay.
        mContentInsets.set(mBaseContentInsets);
        mContentInsets.set(mBaseContentInsets);
        mInnerInsets = mBaseInnerInsets;
        mInnerInsets = mBaseInnerInsets;
        if (!mOverlayMode && !stable && hasContentOnApplyWindowInsetsListener()) {
        if (!mOverlayMode && !stable && mDecorFitsSystemWindows) {
            if (mActionBarExtendsIntoSystemInsets) {
                mContentInsets.top = Math.max(mContentInsets.top, topInset);
                mContentInsets.bottom = Math.max(mContentInsets.bottom, bottomInset);
            } else {
                mContentInsets.top += topInset;
                mContentInsets.top += topInset;
                mContentInsets.bottom += bottomInset;
                mContentInsets.bottom += bottomInset;
            }
            // Content view has been shrunk, shrink all insets to match.
            // Content view has been shrunk, shrink all insets to match.
            mInnerInsets = mInnerInsets.inset(0 /* left */, topInset, 0 /* right */, bottomInset);
            mInnerInsets = mInnerInsets.inset(0 /* left */, topInset, 0 /* right */, bottomInset);
        } else {
        } else {
            // Add ActionBar to system window inset, but leave other insets untouched.
            // Add ActionBar to system window inset, but leave other insets untouched.
            if (mActionBarExtendsIntoSystemInsets) {
                mInnerInsets = mInnerInsets.replaceSystemWindowInsets(
                        mInnerInsets.getSystemWindowInsetLeft(),
                        Math.max(mInnerInsets.getSystemWindowInsetTop(), topInset),
                        mInnerInsets.getSystemWindowInsetRight(),
                        Math.max(mInnerInsets.getSystemWindowInsetBottom(), bottomInset)
                );
            } else {
                mInnerInsets = mInnerInsets.replaceSystemWindowInsets(
                mInnerInsets = mInnerInsets.replaceSystemWindowInsets(
                        mInnerInsets.getSystemWindowInsetLeft(),
                        mInnerInsets.getSystemWindowInsetLeft(),
                        mInnerInsets.getSystemWindowInsetTop() + topInset,
                        mInnerInsets.getSystemWindowInsetTop() + topInset,
@@ -450,7 +521,8 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
                        mInnerInsets.getSystemWindowInsetBottom() + bottomInset
                        mInnerInsets.getSystemWindowInsetBottom() + bottomInset
                );
                );
            }
            }
        applyInsets(mContent, mContentInsets, true, true, true, true);
        }
        applyInsets(mContent, mContentInsets, false /* toPadding */, true, true, true, true);


        if (!mLastInnerInsets.equals(mInnerInsets)) {
        if (!mLastInnerInsets.equals(mInnerInsets)) {
            // If the inner insets have changed, we need to dispatch this down to
            // If the inner insets have changed, we need to dispatch this down to
+14 −5
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.view.DisplayCutout.NO_CUTOUT;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.makeMeasureSpec;
import static android.view.View.MeasureSpec.makeMeasureSpec;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;


import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.is;
@@ -69,6 +70,7 @@ public class ActionBarOverlayLayoutTest {


    private ViewGroup mContent;
    private ViewGroup mContent;
    private ViewGroup mActionBarTop;
    private ViewGroup mActionBarTop;
    private ViewGroup mActionBarView;
    private Toolbar mToolbar;
    private Toolbar mToolbar;
    private FakeOnApplyWindowListener mContentInsetsListener;
    private FakeOnApplyWindowListener mContentInsetsListener;


@@ -86,15 +88,22 @@ public class ActionBarOverlayLayoutTest {
        mContentInsetsListener = new FakeOnApplyWindowListener();
        mContentInsetsListener = new FakeOnApplyWindowListener();
        mContent.setOnApplyWindowInsetsListener(mContentInsetsListener);
        mContent.setOnApplyWindowInsetsListener(mContentInsetsListener);


        // mActionBarView and mToolbar are supposed to be the same view. Here makes mToolbar a child
        // of mActionBarView is to control the height of mActionBarView. In this way, the child
        // views of mToolbar won't affect the measurement of mActionBarView or mActionBarTop.
        mActionBarView = new FrameLayout(mContext);
        mActionBarView.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, 20));

        mToolbar = new Toolbar(mContext);
        mToolbar.setId(com.android.internal.R.id.action_bar);
        mActionBarView.addView(mToolbar);

        mActionBarTop = new ActionBarContainer(mContext);
        mActionBarTop = new ActionBarContainer(mContext);
        mActionBarTop.setId(com.android.internal.R.id.action_bar_container);
        mActionBarTop.setId(com.android.internal.R.id.action_bar_container);
        mActionBarTop.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, 20));
        mActionBarTop.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
        mActionBarTop.addView(mActionBarView);
        mLayout.addView(mActionBarTop);
        mLayout.addView(mActionBarTop);
        mLayout.setActionBarHeight(20);
        mLayout.setActionBarHeight(20);

        mToolbar = new Toolbar(mContext);
        mToolbar.setId(com.android.internal.R.id.action_bar);
        mActionBarTop.addView(mToolbar);
    }
    }


    @Test
    @Test