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

Commit e16645a9 authored by Tiger Huang's avatar Tiger Huang
Browse files

Make display cutout can produce insets

This CL creates InsetsType and InternalInsetsType for display cutout.
With this CL, WindowInsets.getSystemWindowInsets() can be compatible
with the legacy insets mode.

Fix: 149932355
Test: Open an app which has LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
      and hides navigation bar on the display which has double display
      cutout. And check if the app can get the correct result from
      WindowInsets.getSystemWindowInsets().

Change-Id: I381a083d8c30e1678c835eaf5341e941139aa0d7
parent 6a9cd118
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -58,6 +58,10 @@ public class InsetsSource implements Parcelable {
                : null;
    }

    public void setFrame(int left, int top, int right, int bottom) {
        mFrame.set(left, top, right, bottom);
    }

    public void setFrame(Rect frame) {
        mFrame.set(frame);
    }
+32 −3
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.view.ViewRootImpl.sNewInsetsMode;
import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.SIZE;
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.displayCutout;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.indexOf;
import static android.view.WindowInsets.Type.isVisibleInsetsType;
@@ -71,6 +72,10 @@ public class InsetsState implements Parcelable {
            ITYPE_RIGHT_GESTURES,
            ITYPE_TOP_TAPPABLE_ELEMENT,
            ITYPE_BOTTOM_TAPPABLE_ELEMENT,
            ITYPE_LEFT_DISPLAY_CUTOUT,
            ITYPE_TOP_DISPLAY_CUTOUT,
            ITYPE_RIGHT_DISPLAY_CUTOUT,
            ITYPE_BOTTOM_DISPLAY_CUTOUT,
            ITYPE_IME
    })
    public @interface InternalInsetsType {}
@@ -88,8 +93,13 @@ public class InsetsState implements Parcelable {
    public static final int ITYPE_TOP_TAPPABLE_ELEMENT = 7;
    public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT = 8;

    public static final int ITYPE_LEFT_DISPLAY_CUTOUT = 9;
    public static final int ITYPE_TOP_DISPLAY_CUTOUT = 10;
    public static final int ITYPE_RIGHT_DISPLAY_CUTOUT = 11;
    public static final int ITYPE_BOTTOM_DISPLAY_CUTOUT = 12;

    /** Input method window. */
    public static final int ITYPE_IME = 9;
    public static final int ITYPE_IME = 13;

    static final int LAST_TYPE = ITYPE_IME;

@@ -185,8 +195,8 @@ public class InsetsState implements Parcelable {
        final int softInputAdjustMode = legacySoftInputMode & SOFT_INPUT_MASK_ADJUST;
        return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound,
                alwaysConsumeSystemBars, cutout, softInputAdjustMode == SOFT_INPUT_ADJUST_RESIZE
                        ? systemBars() | ime()
                        : systemBars(),
                        ? systemBars() | displayCutout() | ime()
                        : systemBars() | displayCutout(),
                sNewInsetsMode == NEW_INSETS_MODE_FULL
                        && (legacySystemUiFlags & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0);
    }
@@ -358,6 +368,12 @@ public class InsetsState implements Parcelable {
        if ((types & Type.CAPTION_BAR) != 0) {
            result.add(ITYPE_CAPTION_BAR);
        }
        if ((types & Type.DISPLAY_CUTOUT) != 0) {
            result.add(ITYPE_LEFT_DISPLAY_CUTOUT);
            result.add(ITYPE_TOP_DISPLAY_CUTOUT);
            result.add(ITYPE_RIGHT_DISPLAY_CUTOUT);
            result.add(ITYPE_BOTTOM_DISPLAY_CUTOUT);
        }
        if ((types & Type.IME) != 0) {
            result.add(ITYPE_IME);
        }
@@ -388,6 +404,11 @@ public class InsetsState implements Parcelable {
            case ITYPE_TOP_TAPPABLE_ELEMENT:
            case ITYPE_BOTTOM_TAPPABLE_ELEMENT:
                return Type.TAPPABLE_ELEMENT;
            case ITYPE_LEFT_DISPLAY_CUTOUT:
            case ITYPE_TOP_DISPLAY_CUTOUT:
            case ITYPE_RIGHT_DISPLAY_CUTOUT:
            case ITYPE_BOTTOM_DISPLAY_CUTOUT:
                return Type.DISPLAY_CUTOUT;
            default:
                throw new IllegalArgumentException("Unknown type: " + type);
        }
@@ -437,6 +458,14 @@ public class InsetsState implements Parcelable {
                return "ITYPE_TOP_TAPPABLE_ELEMENT";
            case ITYPE_BOTTOM_TAPPABLE_ELEMENT:
                return "ITYPE_BOTTOM_TAPPABLE_ELEMENT";
            case ITYPE_LEFT_DISPLAY_CUTOUT:
                return "ITYPE_LEFT_DISPLAY_CUTOUT";
            case ITYPE_TOP_DISPLAY_CUTOUT:
                return "ITYPE_TOP_DISPLAY_CUTOUT";
            case ITYPE_RIGHT_DISPLAY_CUTOUT:
                return "ITYPE_RIGHT_DISPLAY_CUTOUT";
            case ITYPE_BOTTOM_DISPLAY_CUTOUT:
                return "ITYPE_BOTTOM_DISPLAY_CUTOUT";
            case ITYPE_IME:
                return "ITYPE_IME";
            default:
+26 −4
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@

package android.view;

import static android.view.WindowInsets.Type.DISPLAY_CUTOUT;
import static android.view.WindowInsets.Type.FIRST;
import static android.view.WindowInsets.Type.IME;
import static android.view.WindowInsets.Type.LAST;
@@ -1209,6 +1210,13 @@ public final class WindowInsets {
        @NonNull
        public Builder setDisplayCutout(@Nullable DisplayCutout displayCutout) {
            mDisplayCutout = displayCutout != null ? displayCutout : DisplayCutout.NO_CUTOUT;
            if (!mDisplayCutout.isEmpty()) {
                final Insets safeInsets = Insets.of(mDisplayCutout.getSafeInsets());
                final int index = indexOf(DISPLAY_CUTOUT);
                mTypeInsetsMap[index] = safeInsets;
                mTypeMaxInsetsMap[index] = safeInsets;
                mTypeVisibilityMap[index] = true;
            }
            return this;
        }

@@ -1256,8 +1264,10 @@ public final class WindowInsets {
        static final int MANDATORY_SYSTEM_GESTURES = 1 << 5;
        static final int TAPPABLE_ELEMENT = 1 << 6;

        static final int LAST = 1 << 7;
        static final int SIZE = 8;
        static final int DISPLAY_CUTOUT = 1 << 7;

        static final int LAST = 1 << 8;
        static final int SIZE = 9;
        static final int WINDOW_DECOR = LAST;

        static int indexOf(@InsetsType int type) {
@@ -1276,8 +1286,10 @@ public final class WindowInsets {
                    return 5;
                case TAPPABLE_ELEMENT:
                    return 6;
                case WINDOW_DECOR:
                case DISPLAY_CUTOUT:
                    return 7;
                case WINDOW_DECOR:
                    return 8;
                default:
                    throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST,"
                            + " type=" + type);
@@ -1290,7 +1302,7 @@ public final class WindowInsets {
        /** @hide */
        @Retention(RetentionPolicy.SOURCE)
        @IntDef(flag = true, value = {STATUS_BARS, NAVIGATION_BARS, CAPTION_BAR, IME, WINDOW_DECOR,
                SYSTEM_GESTURES, MANDATORY_SYSTEM_GESTURES, TAPPABLE_ELEMENT})
                SYSTEM_GESTURES, MANDATORY_SYSTEM_GESTURES, TAPPABLE_ELEMENT, DISPLAY_CUTOUT})
        public @interface InsetsType {
        }

@@ -1357,6 +1369,16 @@ public final class WindowInsets {
            return TAPPABLE_ELEMENT;
        }

        /**
         * @return An insets type representing the area that avoids the display cutout.
         *
         * @see DisplayCutout#getSafeInsetTop
         * @hide
         */
        public static @InsetsType int displayCutout() {
            return DISPLAY_CUTOUT;
        }

        /**
         * @return All system bars. Includes {@link #statusBars()}, {@link #captionBar()} as well as
         *         {@link #navigationBars()}, but not {@link #ime()}.
+24 −0
Original line number Diff line number Diff line
@@ -25,12 +25,16 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECOND
import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
import static android.view.Display.TYPE_INTERNAL;
import static android.view.InsetsState.ITYPE_BOTTOM_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES;
import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_RIGHT_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_RIGHT_GESTURES;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_TOP_GESTURES;
import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
@@ -1430,6 +1434,7 @@ public class DisplayPolicy {
     */
    void simulateLayoutDisplay(DisplayFrames displayFrames, InsetsState insetsState, int uiMode) {
        displayFrames.onBeginLayout();
        updateInsetsStateForDisplayCutout(displayFrames, insetsState);
        insetsState.setDisplayFrame(displayFrames.mUnrestricted);
        final WindowFrames simulatedWindowFrames = new WindowFrames();
        if (mNavigationBar != null) {
@@ -1458,6 +1463,8 @@ public class DisplayPolicy {
     */
    public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
        displayFrames.onBeginLayout();
        updateInsetsStateForDisplayCutout(displayFrames,
                mDisplayContent.getInsetsStateController().getRawInsetsState());
        mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
        mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();

@@ -1524,6 +1531,23 @@ public class DisplayPolicy {
        mLastNotificationShadeForcesShowingNavigation = notificationShadeForcesShowingNavigation;
    }

    private static void updateInsetsStateForDisplayCutout(DisplayFrames displayFrames,
            InsetsState state) {
        if (displayFrames.mDisplayCutout.getDisplayCutout().isEmpty()) {
            state.removeSource(ITYPE_LEFT_DISPLAY_CUTOUT);
            state.removeSource(ITYPE_TOP_DISPLAY_CUTOUT);
            state.removeSource(ITYPE_RIGHT_DISPLAY_CUTOUT);
            state.removeSource(ITYPE_BOTTOM_DISPLAY_CUTOUT);
            return;
        }
        final Rect u = displayFrames.mUnrestricted;
        final Rect s = displayFrames.mDisplayCutoutSafe;
        state.getSource(ITYPE_LEFT_DISPLAY_CUTOUT).setFrame(u.left, u.top, s.left, u.bottom);
        state.getSource(ITYPE_TOP_DISPLAY_CUTOUT).setFrame(u.left, u.top, u.right, s.top);
        state.getSource(ITYPE_RIGHT_DISPLAY_CUTOUT).setFrame(s.right, u.top, u.right, u.bottom);
        state.getSource(ITYPE_BOTTOM_DISPLAY_CUTOUT).setFrame(u.left, s.bottom, u.right, u.bottom);
    }

    /** Enforces the last layout policy for display frames. */
    private void postAdjustDisplayFrames(DisplayFrames displayFrames) {
        if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
+20 −0
Original line number Diff line number Diff line
@@ -269,6 +269,26 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
    }

    @Test
    public void layoutWindowLw_fitDisplayCutout() {
        assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
        addDisplayCutout();

        mWindow.mAttrs.setFitInsetsTypes(Type.displayCutout());
        mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
        addWindow(mWindow);

        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);

        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0);
        assertInsetByTopBottom(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0);
        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
    }

    // TODO(b/118118435): remove after migration
    @Test
    public void layoutWindowLw_appDrawsBarsLegacy() {