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

Commit b4bdd38d authored by Yunfan Chen's avatar Yunfan Chen
Browse files

Migrate status bar to the flexible insets API

This CL removes the hard-coded logic in the frameworks and use the new
flexible insets way to implement the status bar related insets. This
moved the display cutout touchable region related calculation from the
DisplayPolicy in the system core to the StatusBarWindowController.

Test: DisplayPolicyInsetsTests
Bug: 239145252
Change-Id: I9911597e6522625e22857821f4c8f0b1dc5b17f4
parent fa42e5b6
Loading
Loading
Loading
Loading
+42 −5
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ public class InsetsFrameProvider implements Parcelable {
    private static final int HAS_INSETS_SIZE_OVERRIDE = 2;

    private static Rect sTmpRect = new Rect();
    private static Rect sTmpRect2 = new Rect();

    /**
     * The type of insets to provide.
@@ -88,6 +89,18 @@ public class InsetsFrameProvider implements Parcelable {
     */
    public InsetsSizeOverride[] insetsSizeOverrides = null;

    /**
     * This field, if set, is indicating the insets needs to be at least the given size inside the
     * display cutout safe area. This will be compared to the insets size calculated based on other
     * attributes, and will be applied when this is larger. This is independent of the
     * PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT in LayoutParams, as this is not going to change
     * the layout of the window, but only change the insets frame. This can be applied to insets
     * calculated based on all three source frames.
     *
     * Be cautious, this will not be in effect for the window types whose insets size is overridden.
     */
    public Insets minimalInsetsSizeInDisplayCutoutSafe = null;

    public InsetsFrameProvider(int type) {
        this(type, SOURCE_FRAME, null, null);
    }
@@ -202,7 +215,8 @@ public class InsetsFrameProvider implements Parcelable {

    public static void calculateInsetsFrame(Rect displayFrame, Rect containerBounds,
            Rect displayCutoutSafe, Rect inOutFrame, int source, Insets insetsSize,
            @WindowManager.LayoutParams.PrivateFlags int privateFlags) {
            @WindowManager.LayoutParams.PrivateFlags int privateFlags,
            Insets displayCutoutSafeInsetsSize) {
        boolean extendByCutout = false;
        if (source == InsetsFrameProvider.SOURCE_DISPLAY) {
            inOutFrame.set(displayFrame);
@@ -214,6 +228,33 @@ public class InsetsFrameProvider implements Parcelable {
        if (insetsSize == null) {
            return;
        }
        if (displayCutoutSafeInsetsSize != null) {
            sTmpRect2.set(inOutFrame);
        }
        calculateInsetsFrame(inOutFrame, insetsSize);

        if (extendByCutout) {
            WindowLayout.extendFrameByCutout(displayCutoutSafe, displayFrame, inOutFrame, sTmpRect);
        }

        if (displayCutoutSafeInsetsSize != null) {
            // The insets is at least with the given size within the display cutout safe area.
            // Calculate the smallest size.
            calculateInsetsFrame(sTmpRect2, displayCutoutSafeInsetsSize);
            WindowLayout.extendFrameByCutout(displayCutoutSafe, displayFrame, sTmpRect2, sTmpRect);
            // If it's larger than previous calculation, use it.
            if (sTmpRect2.contains(inOutFrame)) {
                inOutFrame.set(sTmpRect2);
            }
        }
    }

    /**
     * Calculate the insets frame given the insets size and the source frame.
     * @param inOutFrame the source frame.
     * @param insetsSize the insets size. Only the first non-zero value will be taken.
     */
    private static void calculateInsetsFrame(Rect inOutFrame, Insets insetsSize) {
        // Only one side of the provider shall be applied. Check in the order of left - top -
        // right - bottom, only the first non-zero value will be applied.
        if (insetsSize.left != 0) {
@@ -227,10 +268,6 @@ public class InsetsFrameProvider implements Parcelable {
        } else {
            inOutFrame.setEmpty();
        }

        if (extendByCutout) {
            WindowLayout.extendFrameByCutout(displayCutoutSafe, displayFrame, inOutFrame, sTmpRect);
        }
    }

    /**
+18 −0
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.systemui.statusbar.window;

import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.InsetsState.ITYPE_TOP_MANDATORY_GESTURES;
import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
@@ -27,6 +30,7 @@ import static com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Binder;
@@ -36,6 +40,7 @@ import android.util.Log;
import android.view.DisplayCutout;
import android.view.Gravity;
import android.view.IWindowManager;
import android.view.InsetsFrameProvider;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
@@ -221,6 +226,19 @@ public class StatusBarWindowController {
        lp.setTitle("StatusBar");
        lp.packageName = mContext.getPackageName();
        lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
        final InsetsFrameProvider gestureInsetsProvider =
                new InsetsFrameProvider(ITYPE_TOP_MANDATORY_GESTURES);
        final int safeTouchRegionHeight = mContext.getResources().getDimensionPixelSize(
                com.android.internal.R.dimen.display_cutout_touchable_region_size);
        if (safeTouchRegionHeight > 0) {
            gestureInsetsProvider.minimalInsetsSizeInDisplayCutoutSafe =
                    Insets.of(0, safeTouchRegionHeight, 0, 0);
        }
        lp.providedInsets = new InsetsFrameProvider[] {
                new InsetsFrameProvider(ITYPE_STATUS_BAR),
                new InsetsFrameProvider(ITYPE_TOP_TAPPABLE_ELEMENT),
                gestureInsetsProvider
        };
        return lp;

    }
+77 −91
Original line number Diff line number Diff line
@@ -28,8 +28,6 @@ import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_RIGHT_GESTURES;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.InsetsState.ITYPE_TOP_MANDATORY_GESTURES;
import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
@@ -118,7 +116,6 @@ import android.util.ArraySet;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.InsetsFlags;
@@ -1150,24 +1147,6 @@ public class DisplayPolicy {
                break;
            case TYPE_STATUS_BAR:
                mStatusBar = win;
                final TriConsumer<DisplayFrames, WindowContainer, Rect> gestureFrameProvider =
                        (displayFrames, windowContainer, rect) -> {
                            rect.bottom = rect.top + getStatusBarHeight(displayFrames);
                            final DisplayCutout cutout =
                                    displayFrames.mInsetsState.getDisplayCutout();
                            if (cutout != null) {
                                final Rect top = cutout.getBoundingRectTop();
                                if (!top.isEmpty()) {
                                    rect.bottom = Math.max(rect.bottom,
                                            top.bottom + mDisplayCutoutTouchableRegionSize);
                                }
                            }
                        };
                mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, win, null);
                mDisplayContent.setInsetProvider(
                        ITYPE_TOP_MANDATORY_GESTURES, win, gestureFrameProvider);
                mDisplayContent.setInsetProvider(ITYPE_TOP_TAPPABLE_ELEMENT, win, null);
                mInsetsSourceWindowsExceptIme.add(win);
                break;
            case TYPE_NAVIGATION_BAR:
                mNavigationBar = win;
@@ -1185,7 +1164,8 @@ public class DisplayPolicy {
                                                displayFrames.mUnrestricted,
                                                win.getBounds(), displayFrames.mDisplayCutoutSafe,
                                                inOutFrame, provider.source,
                                                provider.insetsSize, lp.privateFlags);
                                                provider.insetsSize, lp.privateFlags,
                                                provider.minimalInsetsSizeInDisplayCutoutSafe);
                                    }
                                }
                                inOutFrame.inset(win.mGivenContentInsets);
@@ -1231,18 +1211,24 @@ public class DisplayPolicy {
                mInsetsSourceWindowsExceptIme.add(win);
                if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
                break;
            default:
                if (attrs.providedInsets != null) {
        }
        // TODO(b/239145252): Temporarily skip the navigation bar as it is still with the hard-coded
        // logic.
        if (attrs.providedInsets != null && attrs.type != TYPE_NAVIGATION_BAR) {
            for (int i = attrs.providedInsets.length - 1; i >= 0; i--) {
                final InsetsFrameProvider provider = attrs.providedInsets[i];
                switch (provider.type) {
                    case ITYPE_STATUS_BAR:
                        if (attrs.type != TYPE_STATUS_BAR) {
                            mStatusBarAlt = win;
                            mStatusBarAltPosition = getAltBarPosition(attrs);
                        }
                        break;
                    case ITYPE_NAVIGATION_BAR:
                        if (attrs.type != TYPE_NAVIGATION_BAR) {
                            mNavigationBarAlt = win;
                            mNavigationBarAltPosition = getAltBarPosition(attrs);
                        }
                        break;
                    case ITYPE_CLIMATE_BAR:
                        mClimateBarAlt = win;
@@ -1271,7 +1257,8 @@ public class DisplayPolicy {
                                            windowContainer.getBounds(),
                                            displayFrames.mDisplayCutoutSafe,
                                            inOutFrame, ifp.source,
                                                    ifp.insetsSize, lp.privateFlags);
                                            ifp.insetsSize, lp.privateFlags,
                                            ifp.minimalInsetsSizeInDisplayCutoutSafe);
                                } : null;
                final InsetsFrameProvider.InsetsSizeOverride[] overrides =
                        provider.insetsSizeOverrides;
@@ -1296,7 +1283,8 @@ public class DisplayPolicy {
                                                    inOutFrame, ifp.source,
                                                    ifp.insetsSizeOverrides[
                                                            overrideIndex].insetsSize,
                                                            lp.privateFlags);
                                                    lp.privateFlags,
                                                    null);
                                        };
                        overrideProviders.put(overrides[j].windowType,
                                overrideFrameProvider);
@@ -1309,8 +1297,6 @@ public class DisplayPolicy {
                mInsetsSourceWindowsExceptIme.add(win);
            }
        }
                break;
        }
    }

    @WindowManagerPolicy.AltBarPosition
+27 −15
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.InsetsState.ITYPE_TOP_MANDATORY_GESTURES;
import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
@@ -45,6 +47,7 @@ import static org.mockito.Mockito.verify;

import android.app.StatusBarManager;
import android.platform.test.annotations.Presubmit;
import android.view.InsetsFrameProvider;
import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
@@ -70,7 +73,7 @@ public class InsetsPolicyTest extends WindowTestsBase {

    @Test
    public void testControlsForDispatch_regular() {
        addWindow(TYPE_STATUS_BAR, "statusBar");
        addStatusBar();
        addWindow(TYPE_NAVIGATION_BAR, "navBar");

        final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
@@ -82,7 +85,7 @@ public class InsetsPolicyTest extends WindowTestsBase {

    @Test
    public void testControlsForDispatch_multiWindowTaskVisible() {
        addWindow(TYPE_STATUS_BAR, "statusBar");
        addStatusBar();
        addWindow(TYPE_NAVIGATION_BAR, "navBar");

        final WindowState win = createWindow(null, WINDOWING_MODE_MULTI_WINDOW,
@@ -95,7 +98,7 @@ public class InsetsPolicyTest extends WindowTestsBase {

    @Test
    public void testControlsForDispatch_freeformTaskVisible() {
        addWindow(TYPE_STATUS_BAR, "statusBar");
        addStatusBar();
        addWindow(TYPE_NAVIGATION_BAR, "navBar");

        final WindowState win = createWindow(null, WINDOWING_MODE_FREEFORM,
@@ -108,8 +111,7 @@ public class InsetsPolicyTest extends WindowTestsBase {

    @Test
    public void testControlsForDispatch_forceStatusBarVisible() {
        addWindow(TYPE_STATUS_BAR, "statusBar").mAttrs.privateFlags |=
                PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
        addStatusBar().mAttrs.privateFlags |= PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
        addWindow(TYPE_NAVIGATION_BAR, "navBar");

        final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
@@ -123,7 +125,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
    public void testControlsForDispatch_statusBarForceShowNavigation() {
        addWindow(TYPE_NOTIFICATION_SHADE, "notificationShade").mAttrs.privateFlags |=
                PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
        addWindow(TYPE_STATUS_BAR, "statusBar");
        addStatusBar();
        addWindow(TYPE_NAVIGATION_BAR, "navBar");

        final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
@@ -152,7 +154,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
    public void testControlsForDispatch_remoteInsetsControllerControlsBars_appHasNoControl() {
        mDisplayContent.setRemoteInsetsController(createDisplayWindowInsetsController());
        mDisplayContent.getInsetsPolicy().setRemoteInsetsControllerControlsSystemBars(true);
        addWindow(TYPE_STATUS_BAR, "statusBar");
        addStatusBar();
        addWindow(TYPE_NAVIGATION_BAR, "navBar");

        final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
@@ -163,7 +165,7 @@ public class InsetsPolicyTest extends WindowTestsBase {

    @Test
    public void testControlsForDispatch_topAppHidesStatusBar() {
        addWindow(TYPE_STATUS_BAR, "statusBar");
        addStatusBar();
        addWindow(TYPE_NAVIGATION_BAR, "navBar");

        // Add a fullscreen (MATCH_PARENT x MATCH_PARENT) app window which hides status bar.
@@ -256,7 +258,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
    @SetupWindows(addWindows = W_ACTIVITY)
    @Test
    public void testShowTransientBars_bothCanBeTransient_appGetsBothFakeControls() {
        final WindowState statusBar = addNonFocusableWindow(TYPE_STATUS_BAR, "statusBar");
        final WindowState statusBar = addStatusBar();
        statusBar.setHasSurface(true);
        statusBar.getControllableInsetProvider().setServerVisible(true);
        final WindowState navBar = addNonFocusableWindow(TYPE_NAVIGATION_BAR, "navBar");
@@ -298,8 +300,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
    @SetupWindows(addWindows = W_ACTIVITY)
    @Test
    public void testShowTransientBars_statusBarCanBeTransient_appGetsStatusBarFakeControl() {
        addNonFocusableWindow(TYPE_STATUS_BAR, "statusBar")
                .getControllableInsetProvider().getSource().setVisible(false);
        addStatusBar().getControllableInsetProvider().getSource().setVisible(false);
        addNonFocusableWindow(TYPE_NAVIGATION_BAR, "navBar")
                .getControllableInsetProvider().setServerVisible(true);

@@ -328,8 +329,8 @@ public class InsetsPolicyTest extends WindowTestsBase {
    @SetupWindows(addWindows = W_ACTIVITY)
    @Test
    public void testAbortTransientBars_bothCanBeAborted_appGetsBothRealControls() {
        final InsetsSource statusBarSource = addNonFocusableWindow(TYPE_STATUS_BAR, "statusBar")
                .getControllableInsetProvider().getSource();
        final InsetsSource statusBarSource =
                addStatusBar().getControllableInsetProvider().getSource();
        final InsetsSource navBarSource = addNonFocusableWindow(TYPE_NAVIGATION_BAR, "navBar")
                .getControllableInsetProvider().getSource();
        statusBarSource.setVisible(false);
@@ -381,8 +382,7 @@ public class InsetsPolicyTest extends WindowTestsBase {

    @Test
    public void testShowTransientBars_abortsWhenControlTargetChanges() {
        addNonFocusableWindow(TYPE_STATUS_BAR, "statusBar")
                .getControllableInsetProvider().getSource().setVisible(false);
        addStatusBar().getControllableInsetProvider().getSource().setVisible(false);
        addNonFocusableWindow(TYPE_NAVIGATION_BAR, "navBar")
                .getControllableInsetProvider().getSource().setVisible(false);
        final WindowState app = addWindow(TYPE_APPLICATION, "app");
@@ -406,6 +406,18 @@ public class InsetsPolicyTest extends WindowTestsBase {
        return win;
    }

    private WindowState addStatusBar() {
        final WindowState win = createWindow(null, TYPE_STATUS_BAR, "statusBar");
        win.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
        win.mAttrs.providedInsets = new InsetsFrameProvider[] {
                new InsetsFrameProvider(ITYPE_STATUS_BAR),
                new InsetsFrameProvider(ITYPE_TOP_TAPPABLE_ELEMENT),
                new InsetsFrameProvider(ITYPE_TOP_MANDATORY_GESTURES)
        };
        mDisplayContent.getDisplayPolicy().addWindowLw(win, win.mAttrs);
        return win;
    }

    private WindowState addWindow(int type, String name) {
        final WindowState win = createWindow(null, type, name);
        mDisplayContent.getDisplayPolicy().addWindowLw(win, win.mAttrs);
+8 −0
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.InsetsState.ITYPE_TOP_MANDATORY_GESTURES;
import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
@@ -84,6 +86,7 @@ import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
import android.view.InsetsFrameProvider;
import android.view.InsetsVisibilities;
import android.view.WindowManager;

@@ -3079,6 +3082,11 @@ public class SizeCompatTests extends WindowTestsBase {
        attrs.layoutInDisplayCutoutMode =
                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
        attrs.setFitInsetsTypes(0 /* types */);
        attrs.providedInsets = new InsetsFrameProvider[] {
                new InsetsFrameProvider(ITYPE_STATUS_BAR),
                new InsetsFrameProvider(ITYPE_TOP_TAPPABLE_ELEMENT),
                new InsetsFrameProvider(ITYPE_TOP_MANDATORY_GESTURES)
        };
        final TestWindowState statusBar = new TestWindowState(
                displayContent.mWmService, mock(Session.class), new TestIWindow(), attrs, token);
        token.addWindow(statusBar);
Loading