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

Commit 6a83815b authored by Tiger Huang's avatar Tiger Huang
Browse files

Make action mode view extend into system insets area

This CL makes the action mode view extend into system insets area if the
insets don't get consumed by its parent container. If the vertical
navigation bar is visible, the action mode view and the action bar will
fit navigation bar, which will align the width of the status bar color
view, and there won't be weird color blending in the corner.

This CL also removes StatusGuard since the status bar area will be be
filled with the action mode view.

Bug: 379783298
Fix: 397378527
Flag: Flag: EXEMPT bugfix
Test: Tested with an app which would start action mode under different
      conditions:
      - portrait and landscape
      - setDecorFitsSystemWindows with `true` and `false`
      - show or hide status bar
      - show or hide navigation bar
      - show or hide system bars
Change-Id: If86817e58f92c494ec0ff636702b2073c355fa02
parent 702244f2
Loading
Loading
Loading
Loading
+79 −51
Original line number Diff line number Diff line
@@ -120,6 +120,7 @@ import com.android.internal.view.menu.MenuHelper;
import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.BackgroundFallback;
import com.android.internal.widget.floatingtoolbar.FloatingToolbar;
import com.android.window.flags.Flags;

import java.util.List;
import java.util.concurrent.Executor;
@@ -1003,7 +1004,8 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
    public void onWindowSystemUiVisibilityChanged(int visible) {
        updateColorViews(null /* insets */, true /* animate */);

        if (mStatusGuard != null && mStatusGuard.getVisibility() == VISIBLE) {
        if (!Flags.actionModeEdgeToEdge()
                && mStatusGuard != null && mStatusGuard.getVisibility() == VISIBLE) {
            updateStatusGuardColor();
        }
    }
@@ -1040,7 +1042,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
        }
        mFrameOffsets.set(insets.getSystemWindowInsetsAsRect());
        insets = updateColorViews(insets, true /* animate */);
        insets = updateStatusGuard(insets);
        insets = updateActionModeInsets(insets);
        if (getForeground() != null) {
            drawableChanged();
        }
@@ -1592,7 +1594,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
        }
    }

    private WindowInsets updateStatusGuard(WindowInsets insets) {
    private WindowInsets updateActionModeInsets(WindowInsets insets) {
        boolean showStatusGuard = false;
        // Show the status guard when the non-overlay contextual action bar is showing
        if (mPrimaryActionModeView != null) {
@@ -1608,15 +1610,37 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
                    final Rect rect = mTempRect;

                    // Apply the insets that have not been applied by the contentParent yet.
                    WindowInsets innerInsets =
                    final WindowInsets innerInsets =
                            mWindow.mContentParent.computeSystemWindowInsets(insets, rect);
                    final boolean consumesSystemWindowInsetsTop;
                    if (Flags.actionModeEdgeToEdge()) {
                        final Insets newPadding = innerInsets.getSystemWindowInsets();
                        final Insets newMargin = innerInsets.getInsets(
                                WindowInsets.Type.navigationBars());

                        // Don't extend into navigation bar area so the width can align with status
                        // bar color view.
                        if (mlp.leftMargin != newMargin.left
                                || mlp.rightMargin != newMargin.right) {
                            mlpChanged = true;
                            mlp.leftMargin = newMargin.left;
                            mlp.rightMargin = newMargin.right;
                        }

                        mPrimaryActionModeView.setPadding(
                                newPadding.left - newMargin.left,
                                newPadding.top,
                                newPadding.right - newMargin.right,
                                0);
                        consumesSystemWindowInsetsTop = newPadding.top > 0;
                    } else {
                        int newTopMargin = innerInsets.getSystemWindowInsetTop();
                        int newLeftMargin = innerInsets.getSystemWindowInsetLeft();
                        int newRightMargin = innerInsets.getSystemWindowInsetRight();

                    // Must use root window insets for the guard, because the color views consume
                    // the navigation bar inset if the window does not request LAYOUT_HIDE_NAV - but
                    // the status guard is attached at the root.
                        // Must use root window insets for the guard, because the color views
                        // consume the navigation bar inset if the window does not request
                        // LAYOUT_HIDE_NAV - but the status guard is attached at the root.
                        WindowInsets rootInsets = getRootWindowInsets();
                        int newGuardLeftMargin = rootInsets.getSystemWindowInsetLeft();
                        int newGuardRightMargin = rootInsets.getSystemWindowInsetRight();
@@ -1657,6 +1681,8 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
                            // If it wasn't previously shown, the color may be stale
                            updateStatusGuardColor();
                        }
                        consumesSystemWindowInsetsTop = showStatusGuard;
                    }

                    // We only need to consume the insets if the action
                    // mode is overlaid on the app content (e.g. it's
@@ -1664,22 +1690,24 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
                    // screen_simple_overlay_action_mode.xml).
                    final boolean nonOverlay = (mWindow.getLocalFeaturesPrivate()
                            & (1 << Window.FEATURE_ACTION_MODE_OVERLAY)) == 0;
                    if (nonOverlay && showStatusGuard) {
                    if (nonOverlay && consumesSystemWindowInsetsTop) {
                        insets = insets.inset(0, insets.getSystemWindowInsetTop(), 0, 0);
                    }
                } else {
                    if (!Flags.actionModeEdgeToEdge()) {
                        // reset top margin
                        if (mlp.topMargin != 0 || mlp.leftMargin != 0 || mlp.rightMargin != 0) {
                            mlpChanged = true;
                            mlp.topMargin = 0;
                        }
                    }
                }
                if (mlpChanged) {
                    mPrimaryActionModeView.setLayoutParams(mlp);
                }
            }
        }
        if (mStatusGuard != null) {
        if (!Flags.actionModeEdgeToEdge() && mStatusGuard != null) {
            mStatusGuard.setVisibility(showStatusGuard ? VISIBLE : GONE);
        }
        return insets;
@@ -2183,7 +2211,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
        for (int i = getChildCount() - 1; i >= 0; i--) {
            View v = getChildAt(i);
            if (v != mStatusColorViewState.view && v != mNavigationColorViewState.view
                    && v != mStatusGuard) {
                    && (Flags.actionModeEdgeToEdge() || v != mStatusGuard)) {
                removeViewAt(i);
            }
        }
+8 −4
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.widget.TextView;

import com.android.internal.R;
import com.android.internal.view.menu.MenuBuilder;
import com.android.window.flags.Flags;

/**
 * @hide
@@ -315,12 +316,14 @@ public class ActionBarContextView extends AbsActionBarView {

        final int contentWidth = MeasureSpec.getSize(widthMeasureSpec);

        int maxHeight = mContentHeight > 0 ?
                mContentHeight : MeasureSpec.getSize(heightMeasureSpec);
        final int maxHeight = !Flags.actionModeEdgeToEdge() && mContentHeight > 0
                ? mContentHeight : MeasureSpec.getSize(heightMeasureSpec);

        final int verticalPadding = getPaddingTop() + getPaddingBottom();
        int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight();
        final int height = maxHeight - verticalPadding;
        final int height = Flags.actionModeEdgeToEdge()
                ? mContentHeight > 0 ? mContentHeight : maxHeight
                : maxHeight - verticalPadding;
        final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);

        if (mClose != null) {
@@ -376,7 +379,8 @@ public class ActionBarContextView extends AbsActionBarView {
            }
            setMeasuredDimension(contentWidth, measuredHeight);
        } else {
            setMeasuredDimension(contentWidth, maxHeight);
            setMeasuredDimension(contentWidth, Flags.actionModeEdgeToEdge()
                    ? mContentHeight + verticalPadding : maxHeight);
        }
    }

+39 −46
Original line number Diff line number Diff line
@@ -294,54 +294,24 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
        }
    }

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

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

    private boolean setMargin(View view,  Rect insets,
            boolean left, boolean top, boolean right, boolean bottom) {
    private boolean setMargin(View view, int left, int top, int right, int bottom) {
        final LayoutParams lp = (LayoutParams) view.getLayoutParams();
        boolean changed = false;
        if (left && lp.leftMargin != insets.left) {
        if (lp.leftMargin != left) {
            changed = true;
            lp.leftMargin = insets.left;
            lp.leftMargin = left;
        }
        if (top && lp.topMargin != insets.top) {
        if (lp.topMargin != top) {
            changed = true;
            lp.topMargin = insets.top;
            lp.topMargin = top;
        }
        if (right && lp.rightMargin != insets.right) {
        if (lp.rightMargin != right) {
            changed = true;
            lp.rightMargin = insets.right;
            lp.rightMargin = right;
        }
        if (bottom && lp.bottomMargin != insets.bottom) {
        if (lp.bottomMargin != bottom) {
            changed = true;
            lp.bottomMargin = insets.bottom;
            lp.bottomMargin = bottom;
        }
        return changed;
    }
@@ -367,12 +337,30 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
        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.
        boolean changed = applyInsets(mActionBarTop, mSystemInsets,
                mActionBarExtendsIntoSystemInsets, true, true, true, false);
        boolean changed = false;
        if (mActionBarExtendsIntoSystemInsets) {
            // Don't extend into navigation bar area so the width can align with status bar
            // color view.
            final Insets navBarInsets = insets.getInsets(WindowInsets.Type.navigationBars());
            final int paddingLeft = sysInsets.left - navBarInsets.left;
            final int paddingRight = sysInsets.right - navBarInsets.right;
            mActionBarTop.setPadding(paddingLeft, sysInsets.top, paddingRight, 0);
            changed |= setMargin(
                    mActionBarTop, navBarInsets.left, 0, navBarInsets.right, 0);
            if (mActionBarBottom != null) {
            changed |= applyInsets(mActionBarBottom, mSystemInsets,
                    mActionBarExtendsIntoSystemInsets, true, false, true, true);
                mActionBarBottom.setPadding(paddingLeft, 0, paddingRight, sysInsets.bottom);
                changed |= setMargin(
                        mActionBarBottom, navBarInsets.left, 0, navBarInsets.right, 0);
            }
        } else {
            mActionBarTop.setPadding(0, 0, 0, 0);
            changed |= setMargin(
                    mActionBarTop, sysInsets.left, sysInsets.top, sysInsets.right, 0);
            if (mActionBarBottom != null) {
                mActionBarBottom.setPadding(0, 0, 0, 0);
                changed |= setMargin(
                        mActionBarTop, sysInsets.left, 0, sysInsets.right, sysInsets.bottom);
            }
        }

        // Cannot use the result of computeSystemWindowInsets, because that consumes the
@@ -521,7 +509,12 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
                );
            }
        }
        setMargin(mContent, mContentInsets, true, true, true, true);
        setMargin(
                mContent,
                mContentInsets.left,
                mContentInsets.top,
                mContentInsets.right,
                mContentInsets.bottom);

        if (!mLastInnerInsets.equals(mInnerInsets)) {
            // If the inner insets have changed, we need to dispatch this down to