Merge "Let fake control target override visibility received by other windows" into udc-qpr-dev am: 697946aead

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/24690212

Change-Id: Id3198ae6448da1a1129d39e193b29d76d34f8bf3
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 03f025b..d0d7f49 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 @@
     /** 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 @@
             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();
+        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 */);
+        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 @@
             boolean includesTransient) {
         InsetsState state;
         if (!includesTransient) {
-            state = adjustVisibilityForTransientTypes(originalState);
+            state = adjustVisibilityForFakeControllingSources(originalState);
         } else {
             state = originalState;
         }
@@ -319,24 +331,40 @@
         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;
+    }
+
     private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState,
             boolean copyState) {
         if (w.mIsImWindow) {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index d9881c7..2bc7010 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 @@
     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 411712e..ffa1ed9 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 @@
                 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 @@
         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 114796d..2085d61 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 @@
         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()));