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

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

Prevent causing insets if the system bar is shown forcibly

Forcibly-shown system bars are usually transient. Prevent them from
causing insets can reduce the UI shakiness, and can be compatible with
the behavior in the legacy insets mode.

Fix: 150582388
Test: atest InsetsSourceProviderTest InsetsStateControllerTest
            InsetsPolicyTest
Change-Id: I3c0fa4fb7555b2f63e1c4849db7b169489ab64e4
parent 35886c0d
Loading
Loading
Loading
Loading
+14 −0
Original line number Original line Diff line number Diff line
@@ -342,6 +342,20 @@ public class InsetsState implements Parcelable {
        }
        }
    }
    }


    /**
     * A shortcut for setting the visibility of the source.
     *
     * @param type The {@link InternalInsetsType} of the source to set the visibility
     * @param referenceState The {@link InsetsState} for reference
     */
    public void setSourceVisible(@InternalInsetsType int type, InsetsState referenceState) {
        InsetsSource source = mSources.get(type);
        InsetsSource referenceSource = referenceState.mSources.get(type);
        if (source != null && referenceSource != null) {
            source.setVisible(referenceSource.isVisible());
        }
    }

    public void set(InsetsState other) {
    public void set(InsetsState other) {
        set(other, false /* copySources */);
        set(other, false /* copySources */);
    }
    }
+6 −1
Original line number Original line Diff line number Diff line
@@ -23,7 +23,12 @@ import android.view.WindowInsets.Type.InsetsType;
 * Generalization of an object that can control insets state.
 * Generalization of an object that can control insets state.
 */
 */
interface InsetsControlTarget {
interface InsetsControlTarget {
    void notifyInsetsControlChanged();

    /**
     * Notifies the control target that the insets control has changed.
     */
    default void notifyInsetsControlChanged() {
    };


    /**
    /**
     * @return {@link WindowState} of this target, if any.
     * @return {@link WindowState} of this target, if any.
+42 −44
Original line number Original line Diff line number Diff line
@@ -57,9 +57,11 @@ class InsetsPolicy {
    private final InsetsStateController mStateController;
    private final InsetsStateController mStateController;
    private final DisplayContent mDisplayContent;
    private final DisplayContent mDisplayContent;
    private final DisplayPolicy mPolicy;
    private final DisplayPolicy mPolicy;
    private final TransientControlTarget mTransientControlTarget = new TransientControlTarget();
    private final IntArray mShowingTransientTypes = new IntArray();
    private final IntArray mShowingTransientTypes = new IntArray();


    /** For resetting visibilities of insets sources. */
    private final InsetsControlTarget mDummyControlTarget = new InsetsControlTarget() { };

    private WindowState mFocusedWin;
    private WindowState mFocusedWin;
    private BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
    private BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
    private BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR);
    private BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR);
@@ -143,12 +145,15 @@ class InsetsPolicy {
     */
     */
    InsetsState getInsetsForDispatch(WindowState target) {
    InsetsState getInsetsForDispatch(WindowState target) {
        InsetsState state = mStateController.getInsetsForDispatch(target);
        InsetsState state = mStateController.getInsetsForDispatch(target);
        if (mShowingTransientTypes.size() == 0) {
            return state;
        }
        for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) {
        for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) {
            state.setSourceVisible(mShowingTransientTypes.get(i), false);
            state.setSourceVisible(mShowingTransientTypes.get(i), false);
        }
        }
        if (mFocusedWin != null && getStatusControlTarget(mFocusedWin) == mDummyControlTarget) {
            state.setSourceVisible(ITYPE_STATUS_BAR, mFocusedWin.getRequestedInsetsState());
        }
        if (mFocusedWin != null && getNavControlTarget(mFocusedWin) == mDummyControlTarget) {
            state.setSourceVisible(ITYPE_NAVIGATION_BAR, mFocusedWin.getRequestedInsetsState());
        }
        return state;
        return state;
    }
    }


@@ -194,71 +199,71 @@ class InsetsPolicy {


    private @Nullable InsetsControlTarget getFakeStatusControlTarget(
    private @Nullable InsetsControlTarget getFakeStatusControlTarget(
            @Nullable WindowState focused) {
            @Nullable WindowState focused) {
        if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1) {
        return getStatusControlTarget(focused) == mDummyControlTarget ? focused : null;
            return focused;
        }
        return null;
    }
    }


    private @Nullable InsetsControlTarget getFakeNavControlTarget(@Nullable WindowState focused) {
    private @Nullable InsetsControlTarget getFakeNavControlTarget(@Nullable WindowState focused) {
        if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1) {
        return getNavControlTarget(focused) == mDummyControlTarget ? focused : null;
            return focused;
        }
        return null;
    }
    }


    private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin) {
    private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin) {
        if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1) {
        if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1) {
            return mTransientControlTarget;
            return mDummyControlTarget;
        }
        }
        if (focusedWin == mPolicy.getNotificationShade()) {
        if (focusedWin == mPolicy.getNotificationShade()) {
            // Notification shade has control anyways, no reason to force anything.
            // Notification shade has control anyways, no reason to force anything.
            return focusedWin;
            return focusedWin;
        }
        }
        if (areSystemBarsForciblyVisible() || isKeyguardOrStatusBarForciblyVisible()) {
        if (forceShowsSystemBarsForWindowingMode()) {
            // Status bar is forcibly shown for the windowing mode which is a steady state.
            // We don't want the client to control the status bar, and we will dispatch the real
            // visibility of status bar to the client.
            return null;
            return null;
        }
        }
        if (forceShowsStatusBarTransiently()) {
            // Status bar is forcibly shown transiently, and its new visibility won't be
            // dispatched to the client so that we can keep the layout stable. We will dispatch the
            // fake control to the client, so that it can re-show the bar during this scenario.
            return mDummyControlTarget;
        }
        return focusedWin;
        return focusedWin;
    }
    }


    private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin) {
    private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin) {
        if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1) {
        if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1) {
            return mTransientControlTarget;
            return mDummyControlTarget;
        }
        }
        if (focusedWin == mPolicy.getNotificationShade()) {
        if (focusedWin == mPolicy.getNotificationShade()) {
            // Notification shade has control anyways, no reason to force anything.
            // Notification shade has control anyways, no reason to force anything.
            return focusedWin;
            return focusedWin;
        }
        }
        if (areSystemBarsForciblyVisible() || isNavBarForciblyVisible()) {
        if (forceShowsSystemBarsForWindowingMode()) {
            // Navigation bar is forcibly shown for the windowing mode which is a steady state.
            // We don't want the client to control the navigation bar, and we will dispatch the real
            // visibility of navigation bar to the client.
            return null;
            return null;
        }
        }
        if (forceShowsNavigationBarTransiently()) {
            // Navigation bar is forcibly shown transiently, and its new visibility won't be
            // dispatched to the client so that we can keep the layout stable. We will dispatch the
            // fake control to the client, so that it can re-show the bar during this scenario.
            return mDummyControlTarget;
        }
        return focusedWin;
        return focusedWin;
    }
    }


    private boolean isKeyguardOrStatusBarForciblyVisible() {
    private boolean forceShowsStatusBarTransiently() {
        final WindowState statusBar = mPolicy.getStatusBar();
        final WindowState win = mPolicy.getStatusBar();
        if (statusBar != null) {
        return win != null && (win.mAttrs.privateFlags & PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0;
            // TODO(b/118118435): Pretend to the app that it's still able to control it?
            if ((statusBar.mAttrs.privateFlags & PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0) {
                return true;
            }
        }
        return false;
    }
    }


    private boolean isNavBarForciblyVisible() {
    private boolean forceShowsNavigationBarTransiently() {
        final WindowState notificationShade = mPolicy.getNotificationShade();
        final WindowState win = mPolicy.getNotificationShade();
        if (notificationShade == null) {
        return win != null
            return false;
                && (win.mAttrs.privateFlags & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
        }
        if ((notificationShade.mAttrs.privateFlags
                & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0) {
            return true;
        }
        return false;
    }
    }


    private boolean areSystemBarsForciblyVisible() {
    private boolean forceShowsSystemBarsForWindowingMode() {
        final boolean isDockedStackVisible =
        final boolean isDockedStackVisible =
                mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
                mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
        final boolean isFreeformStackVisible =
        final boolean isFreeformStackVisible =
@@ -279,7 +284,7 @@ class InsetsPolicy {
        for (int i = showingTransientTypes.size() - 1; i >= 0; i--) {
        for (int i = showingTransientTypes.size() - 1; i >= 0; i--) {
            InsetsSourceProvider provider =
            InsetsSourceProvider provider =
                    mStateController.getSourceProvider(showingTransientTypes.get(i));
                    mStateController.getSourceProvider(showingTransientTypes.get(i));
            InsetsSourceControl control = provider.getControl(mTransientControlTarget);
            InsetsSourceControl control = provider.getControl(mDummyControlTarget);
            if (control == null || control.getLeash() == null) {
            if (control == null || control.getLeash() == null) {
                continue;
                continue;
            }
            }
@@ -412,11 +417,4 @@ class InsetsPolicy {
            }
            }
        }
        }
    }
    }

    private class TransientControlTarget implements InsetsControlTarget {

        @Override
        public void notifyInsetsControlChanged() {
        }
    }
}
}
+1 −2
Original line number Original line Diff line number Diff line
@@ -61,8 +61,7 @@ class InsetsStateController {
            w.notifyInsetsChanged();
            w.notifyInsetsChanged();
        }
        }
    };
    };
    private final InsetsControlTarget mEmptyImeControlTarget = () -> {
    private final InsetsControlTarget mEmptyImeControlTarget = new InsetsControlTarget() { };
    };


    InsetsStateController(DisplayContent displayContent) {
    InsetsStateController(DisplayContent displayContent) {
        mDisplayContent = displayContent;
        mDisplayContent = displayContent;
+4 −5
Original line number Original line Diff line number Diff line
@@ -120,7 +120,6 @@ public class InsetsPolicyTest extends WindowTestsBase {
        assertNull(controls);
        assertNull(controls);
    }
    }


    // TODO: adjust this test if we pretend to the app that it's still able to control it.
    @Test
    @Test
    public void testControlsForDispatch_forceStatusBarVisible() {
    public void testControlsForDispatch_forceStatusBarVisible() {
        addWindow(TYPE_STATUS_BAR, "statusBar").mAttrs.privateFlags |=
        addWindow(TYPE_STATUS_BAR, "statusBar").mAttrs.privateFlags |=
@@ -129,9 +128,9 @@ public class InsetsPolicyTest extends WindowTestsBase {


        final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
        final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();


        // The app must not control the status bar.
        // The focused app window can control both system bars.
        assertNotNull(controls);
        assertNotNull(controls);
        assertEquals(1, controls.length);
        assertEquals(2, controls.length);
    }
    }


    @Test
    @Test
@@ -143,9 +142,9 @@ public class InsetsPolicyTest extends WindowTestsBase {


        final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
        final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();


        // The app must not control the navigation bar.
        // The focused app window can control both system bars.
        assertNotNull(controls);
        assertNotNull(controls);
        assertEquals(1, controls.length);
        assertEquals(2, controls.length);
    }
    }


    @Test
    @Test