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

Commit 102a1812 authored by Tiger's avatar Tiger
Browse files

Let fake control target override visibility received by other windows

Previously, the fake control target could only override the insets
visibility in its own client. But since it was the real target
overriding the real visibility affect all other windows before the
transient control target becomes the real target, it should keep
overriding the visibility when it becomes the fake control target.
Otherwise, that may cause the layout change, and the screen may look
flicker.

Fix: 281740543
Test: atest InsetsPolicyTest
Test: Show Gboard in landscape fullscreen mode on an immersive app,
      press the voice input button, see if the IME layout is changed by
      status bar.
Change-Id: I0bc0c470d0572cd9115ea09c4402580e98db6182
parent 0cb3e5c4
Loading
Loading
Loading
Loading
+54 −26
Original line number Diff line number Diff line
@@ -75,6 +75,18 @@ class InsetsPolicy {
    /** Used to show system bars permanently. This will affect the layout. */
    private final InsetsControlTarget mPermanentControlTarget;

    /**
     * Used to override the visibility of {@link Type#statusBars()} when dispatching insets to
     * clients.
     */
    private InsetsControlTarget mFakeStatusControlTarget;

    /**
     * Used to override the visibility of {@link Type#navigationBars()} when dispatching insets to
     * clients.
     */
    private InsetsControlTarget mFakeNavControlTarget;

    private WindowState mFocusedWin;
    private final BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
    private final BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR);
@@ -101,25 +113,25 @@ class InsetsPolicy {
            abortTransient();
        }
        mFocusedWin = focusedWin;
        final InsetsControlTarget statusControlTarget =
                getStatusControlTarget(focusedWin, false /* fake */);
        final InsetsControlTarget navControlTarget =
                getNavControlTarget(focusedWin, false /* fake */);
        final WindowState notificationShade = mPolicy.getNotificationShade();
        final WindowState topApp = mPolicy.getTopFullscreenOpaqueWindow();
        mStateController.onBarControlTargetChanged(
                statusControlTarget,
                statusControlTarget == mTransientControlTarget
        final InsetsControlTarget statusControlTarget =
                getStatusControlTarget(focusedWin, false /* fake */);
        mFakeStatusControlTarget = statusControlTarget == mTransientControlTarget
                ? getStatusControlTarget(focusedWin, true /* fake */)
                : statusControlTarget == notificationShade
                        ? getStatusControlTarget(topApp, true /* fake */)
                                : null,
                navControlTarget,
                navControlTarget == mTransientControlTarget
                        : null;
        final InsetsControlTarget navControlTarget =
                getNavControlTarget(focusedWin, false /* fake */);
        mFakeNavControlTarget = navControlTarget == mTransientControlTarget
                ? getNavControlTarget(focusedWin, true /* fake */)
                : navControlTarget == notificationShade
                        ? getNavControlTarget(topApp, true /* fake */)
                                : null);
                        : null;
        mStateController.onBarControlTargetChanged(
                statusControlTarget, mFakeStatusControlTarget,
                navControlTarget, mFakeNavControlTarget);
        mStatusBar.updateVisibility(statusControlTarget, Type.statusBars());
        mNavBar.updateVisibility(navControlTarget, Type.navigationBars());
    }
@@ -204,7 +216,7 @@ class InsetsPolicy {
            boolean includesTransient) {
        InsetsState state;
        if (!includesTransient) {
            state = adjustVisibilityForTransientTypes(originalState);
            state = adjustVisibilityForFakeControllingSources(originalState);
        } else {
            state = originalState;
        }
@@ -319,21 +331,37 @@ class InsetsPolicy {
        return state;
    }

    private InsetsState adjustVisibilityForTransientTypes(InsetsState originalState) {
    private InsetsState adjustVisibilityForFakeControllingSources(InsetsState originalState) {
        if (mFakeStatusControlTarget == null && mFakeNavControlTarget == null) {
            return originalState;
        }
        InsetsState state = originalState;
        for (int i = state.sourceSize() - 1; i >= 0; i--) {
            final InsetsSource source = state.sourceAt(i);
            if (isTransient(source.getType()) && source.isVisible()) {
                if (state == originalState) {
                    // The source will be modified, create a non-deep copy to store the new one.
                    state = new InsetsState(originalState);
            state = adjustVisibilityForFakeControllingSource(state, Type.statusBars(), source,
                    mFakeStatusControlTarget);
            state = adjustVisibilityForFakeControllingSource(state, Type.navigationBars(), source,
                    mFakeNavControlTarget);
        }
                // Replace the source with a copy in invisible state.
                final InsetsSource outSource = new InsetsSource(source);
                outSource.setVisible(false);
                state.addSource(outSource);
        return state;
    }

    private static InsetsState adjustVisibilityForFakeControllingSource(InsetsState originalState,
            @InsetsType int type, InsetsSource source, InsetsControlTarget target) {
        if (source.getType() != type || target == null) {
            return originalState;
        }
        final boolean isRequestedVisible = target.isRequestedVisible(type);
        if (source.isVisible() == isRequestedVisible) {
            return originalState;
        }
        // The source will be modified, create a non-deep copy to store the new one.
        final InsetsState state = new InsetsState(originalState);

        // Replace the source with a copy with the overridden visibility.
        final InsetsSource outSource = new InsetsSource(source);
        outSource.setVisible(isRequestedVisible);
        state.addSource(outSource);
        return state;
    }

+1 −1
Original line number Diff line number Diff line
@@ -108,7 +108,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
    private final ArraySet<WindowSurfaceController> mAlertWindowSurfaces = new ArraySet<>();
    private final DragDropController mDragDropController;
    final boolean mCanAddInternalSystemWindow;
    final boolean mCanForceShowingInsets;
    boolean mCanForceShowingInsets;
    private final boolean mCanStartTasksFromRecents;

    final boolean mCanCreateSystemApplicationOverlay;
+45 −0
Original line number Diff line number Diff line
@@ -327,6 +327,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
                addNavigationBar().getControllableInsetProvider().getSource();
        statusBarSource.setVisible(false);
        navBarSource.setVisible(false);
        mAppWindow.setRequestedVisibleTypes(0, navigationBars() | statusBars());
        mAppWindow.mAboveInsetsState.addSource(navBarSource);
        mAppWindow.mAboveInsetsState.addSource(statusBarSource);
        final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
@@ -387,6 +388,50 @@ public class InsetsPolicyTest extends WindowTestsBase {
        assertFalse(policy.isTransient(navigationBars()));
    }

    @Test
    public void testFakeControlTarget_overrideVisibilityReceivedByWindows() {
        final WindowState statusBar = addStatusBar();
        final InsetsSourceProvider statusBarProvider = statusBar.getControllableInsetProvider();
        statusBar.mSession.mCanForceShowingInsets = true;
        statusBar.setHasSurface(true);
        statusBarProvider.setServerVisible(true);

        final InsetsSource statusBarSource = statusBarProvider.getSource();
        final int statusBarId = statusBarSource.getId();
        assertTrue(statusBarSource.isVisible());

        final WindowState app1 = addWindow(TYPE_APPLICATION, "app1");
        app1.mAboveInsetsState.addSource(statusBarSource);
        assertTrue(app1.getInsetsState().peekSource(statusBarId).isVisible());

        final WindowState app2 = addWindow(TYPE_APPLICATION, "app2");
        app2.mAboveInsetsState.addSource(statusBarSource);
        assertTrue(app2.getInsetsState().peekSource(statusBarId).isVisible());

        app2.setRequestedVisibleTypes(0, navigationBars() | statusBars());
        mDisplayContent.getInsetsPolicy().updateBarControlTarget(app2);
        waitUntilWindowAnimatorIdle();

        // app2 is the real control target now. It can override the visibility of all sources that
        // it controls.
        assertFalse(statusBarSource.isVisible());
        assertFalse(app1.getInsetsState().peekSource(statusBarId).isVisible());
        assertFalse(app2.getInsetsState().peekSource(statusBarId).isVisible());

        statusBar.mAttrs.forciblyShownTypes = statusBars();
        mDisplayContent.getDisplayPolicy().applyPostLayoutPolicyLw(
                statusBar, statusBar.mAttrs, null, null);
        mDisplayContent.getInsetsPolicy().updateBarControlTarget(app2);
        waitUntilWindowAnimatorIdle();

        // app2 is the fake control target now. It can only override the visibility of sources
        // received by windows, but not the raw source.
        assertTrue(statusBarSource.isVisible());
        assertFalse(app1.getInsetsState().peekSource(statusBarId).isVisible());
        assertFalse(app2.getInsetsState().peekSource(statusBarId).isVisible());

    }

    private WindowState addNavigationBar() {
        final Binder owner = new Binder();
        final WindowState win = createWindow(null, TYPE_NAVIGATION_BAR, "navBar");
+3 −1
Original line number Diff line number Diff line
@@ -367,9 +367,11 @@ public class InsetsStateControllerTest extends WindowTestsBase {
        doReturn(rotatedState).when(app.mToken).getFixedRotationTransformInsetsState();
        assertTrue(rotatedState.isSourceOrDefaultVisible(ID_STATUS_BAR, statusBars()));

        provider.getSource().setVisible(false);
        app.setRequestedVisibleTypes(0, statusBars());
        mDisplayContent.getInsetsPolicy().updateBarControlTarget(app);
        mDisplayContent.getInsetsPolicy().showTransient(statusBars(),
                true /* isGestureOnSystemBar */);
        waitUntilWindowAnimatorIdle();

        assertTrue(mDisplayContent.getInsetsPolicy().isTransient(statusBars()));
        assertFalse(app.getInsetsState().isSourceOrDefaultVisible(ID_STATUS_BAR, statusBars()));