Merge "Let top-fullscreen-app window keep controlling status bar" into rvc-dev
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 2f18a0d..e244b55 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2756,19 +2756,22 @@
      * @return Whether the top app should hide the statusbar based on the top fullscreen opaque
      *         window.
      */
-    private boolean topAppHidesStatusBar() {
+    boolean topAppHidesStatusBar() {
         if (mTopFullscreenOpaqueWindowState == null || mForceShowSystemBars) {
             return false;
         }
-        final int fl = PolicyControl.getWindowFlags(null,
-                mTopFullscreenOpaqueWindowState.getAttrs());
+        final LayoutParams attrs = mTopFullscreenOpaqueWindowState.getAttrs();
+        final int fl = PolicyControl.getWindowFlags(null, attrs);
+        final int sysui = PolicyControl.getSystemUiVisibility(null, attrs);
+        final InsetsSource request = mTopFullscreenOpaqueWindowState.getRequestedInsetsState()
+                .peekSource(ITYPE_STATUS_BAR);
         if (WindowManagerDebugConfig.DEBUG) {
             Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
-            Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
-                    + " lp.flags=0x" + Integer.toHexString(fl));
+            Slog.d(TAG, "attr: " + attrs + " request: " + request);
         }
         return (fl & LayoutParams.FLAG_FULLSCREEN) != 0
-                || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
+                || (sysui & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0
+                || (request != null && !request.isVisible());
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index d02be88..035f201 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -117,13 +117,8 @@
         if (ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL) {
             return;
         }
-        mStatusBar.setVisible(focusedWin == null
-                || focusedWin != getStatusControlTarget(focusedWin)
-                || focusedWin.getRequestedInsetsState().getSource(ITYPE_STATUS_BAR).isVisible());
-        mNavBar.setVisible(focusedWin == null
-                || focusedWin != getNavControlTarget(focusedWin)
-                || focusedWin.getRequestedInsetsState().getSource(ITYPE_NAVIGATION_BAR)
-                        .isVisible());
+        mStatusBar.updateVisibility(getStatusControlTarget(focusedWin), ITYPE_STATUS_BAR);
+        mNavBar.updateVisibility(getNavControlTarget(focusedWin), ITYPE_NAVIGATION_BAR);
         mPolicy.updateHideNavInputEventReceiver();
     }
 
@@ -215,16 +210,7 @@
     void onInsetsModified(WindowState windowState, InsetsState state) {
         mStateController.onInsetsModified(windowState, state);
         checkAbortTransient(windowState, state);
-        if (ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL) {
-            return;
-        }
-        if (windowState == getStatusControlTarget(mFocusedWin)) {
-            mStatusBar.setVisible(state.getSource(ITYPE_STATUS_BAR).isVisible());
-        }
-        if (windowState == getNavControlTarget(mFocusedWin)) {
-            mNavBar.setVisible(state.getSource(ITYPE_NAVIGATION_BAR).isVisible());
-        }
-        mPolicy.updateHideNavInputEventReceiver();
+        updateBarControlTarget(mFocusedWin);
     }
 
     /**
@@ -248,7 +234,6 @@
             if (abortTypes.size() > 0) {
                 mPolicy.getStatusBarManagerInternal().abortTransient(mDisplayContent.getDisplayId(),
                         abortTypes.toArray());
-                updateBarControlTarget(mFocusedWin);
             }
         }
     }
@@ -289,6 +274,11 @@
             // fake control to the client, so that it can re-show the bar during this scenario.
             return mDummyControlTarget;
         }
+        if (mPolicy.topAppHidesStatusBar()) {
+            // Non-fullscreen focused window should not break the state that the top-fullscreen-app
+            // window hides status bar.
+            return mPolicy.getTopFullscreenOpaqueWindow();
+        }
         return focusedWin;
     }
 
@@ -378,6 +368,14 @@
             mId = id;
         }
 
+        private void updateVisibility(InsetsControlTarget controlTarget,
+                @InternalInsetsType int type) {
+            final WindowState controllingWin =
+                    controlTarget instanceof WindowState ? (WindowState) controlTarget : null;
+            setVisible(controllingWin == null
+                    || controllingWin.getRequestedInsetsState().getSource(type).isVisible());
+        }
+
         private void setVisible(boolean visible) {
             final int state = visible ? WINDOW_STATE_SHOWING : WINDOW_STATE_HIDDEN;
             if (mState != state) {
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 2444c24..c794e1a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -21,6 +21,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
@@ -183,6 +184,47 @@
     }
 
     @Test
+    public void testControlsForDispatch_topAppHidesStatusBar() {
+        addWindow(TYPE_STATUS_BAR, "statusBar");
+        addWindow(TYPE_NAVIGATION_BAR, "navBar");
+
+        // Add a fullscreen (MATCH_PARENT x MATCH_PARENT) app window which hides status bar.
+        final WindowState fullscreenApp = addWindow(TYPE_APPLICATION, "fullscreenApp");
+        final InsetsState requestedState = new InsetsState();
+        requestedState.getSource(ITYPE_STATUS_BAR).setVisible(false);
+        fullscreenApp.updateRequestedInsetsState(requestedState);
+
+        // Add a non-fullscreen dialog window.
+        final WindowState dialog = addWindow(TYPE_APPLICATION, "dialog");
+        dialog.mAttrs.width = WRAP_CONTENT;
+        dialog.mAttrs.height = WRAP_CONTENT;
+
+        // Let fullscreenApp be mTopFullscreenOpaqueWindowState.
+        final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
+        displayPolicy.beginPostLayoutPolicyLw();
+        displayPolicy.applyPostLayoutPolicyLw(dialog, dialog.mAttrs, fullscreenApp, null);
+        displayPolicy.applyPostLayoutPolicyLw(fullscreenApp, fullscreenApp.mAttrs, null, null);
+        displayPolicy.finishPostLayoutPolicyLw();
+        mDisplayContent.getInsetsPolicy().updateBarControlTarget(dialog);
+
+        assertEquals(fullscreenApp, displayPolicy.getTopFullscreenOpaqueWindow());
+
+        // dialog is the focused window, but it can only control navigation bar.
+        final InsetsSourceControl[] dialogControls =
+                mDisplayContent.getInsetsStateController().getControlsForDispatch(dialog);
+        assertNotNull(dialogControls);
+        assertEquals(1, dialogControls.length);
+        assertEquals(ITYPE_NAVIGATION_BAR, dialogControls[0].getType());
+
+        // fullscreenApp is hiding status bar, and it can keep controlling status bar.
+        final InsetsSourceControl[] fullscreenAppControls =
+                mDisplayContent.getInsetsStateController().getControlsForDispatch(fullscreenApp);
+        assertNotNull(fullscreenAppControls);
+        assertEquals(1, fullscreenAppControls.length);
+        assertEquals(ITYPE_STATUS_BAR, fullscreenAppControls[0].getType());
+    }
+
+    @Test
     public void testShowTransientBars_bothCanBeTransient_appGetsBothFakeControls() {
         addNonFocusableWindow(TYPE_STATUS_BAR, "statusBar")
                 .getControllableInsetProvider().getSource().setVisible(false);