diff options
4 files changed, 103 insertions, 28 deletions
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index 03f025b1f0f4..d0d7f493b969 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -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 WindowState notificationShade = mPolicy.getNotificationShade(); + final WindowState topApp = mPolicy.getTopFullscreenOpaqueWindow(); final InsetsControlTarget statusControlTarget = getStatusControlTarget(focusedWin, false /* fake */); + mFakeStatusControlTarget = statusControlTarget == mTransientControlTarget + ? getStatusControlTarget(focusedWin, true /* fake */) + : statusControlTarget == notificationShade + ? getStatusControlTarget(topApp, true /* fake */) + : null; final InsetsControlTarget navControlTarget = getNavControlTarget(focusedWin, false /* fake */); - final WindowState notificationShade = mPolicy.getNotificationShade(); - final WindowState topApp = mPolicy.getTopFullscreenOpaqueWindow(); + mFakeNavControlTarget = navControlTarget == mTransientControlTarget + ? getNavControlTarget(focusedWin, true /* fake */) + : navControlTarget == notificationShade + ? getNavControlTarget(topApp, true /* fake */) + : null; mStateController.onBarControlTargetChanged( - statusControlTarget, - statusControlTarget == mTransientControlTarget - ? getStatusControlTarget(focusedWin, true /* fake */) - : statusControlTarget == notificationShade - ? getStatusControlTarget(topApp, true /* fake */) - : null, - navControlTarget, - navControlTarget == mTransientControlTarget - ? getNavControlTarget(focusedWin, true /* fake */) - : navControlTarget == notificationShade - ? getNavControlTarget(topApp, true /* fake */) - : null); + 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); - } - // Replace the source with a copy in invisible state. - final InsetsSource outSource = new InsetsSource(source); - outSource.setVisible(false); - state.addSource(outSource); - } + state = adjustVisibilityForFakeControllingSource(state, Type.statusBars(), source, + mFakeStatusControlTarget); + state = adjustVisibilityForFakeControllingSource(state, Type.navigationBars(), source, + mFakeNavControlTarget); + } + 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; } diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index d9881c7c46c5..2bc701000398 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -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; diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java index 411712e6b577..ffa1ed926766 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java @@ -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"); diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index 114796d17ef1..2085d6140f68 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -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())); |