Refine system bar position restoring

The previous logic restores the system bar as long as its insets source
is visible. There can be a timing issue that if the user swipes to show
transient bars while an immersive app just becomes the control target
but the hide-bar info haven't sent to WM yet, WM will re-show the bar
incorrectly.

This CL uses the requested visibility and the behavior to decide if we
should restore the postion and the visibility.

This CL also refines and caches the arguments of showTransient. In this
way, we don't have to create the array every time while invoking that
method.

Fix: 161247175
Test: atest InsetsPolicyTest
Merged-In: Idef314dfe6625399b88b3dacb4c74c7071453497
Change-Id: Idef314dfe6625399b88b3dacb4c74c7071453497
(cherry picked from commit 533682ebb39456df26097753d1f5172bff0e3d5d)
(cherry picked from commit 444e8dc6ce224f87b4d062d697a6db5a62e11183)
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 6b0b509..593b37a 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -60,6 +60,8 @@
  */
 public class InsetsState implements Parcelable {
 
+    public static final InsetsState EMPTY = new InsetsState();
+
     /**
      * Internal representation of inset source types. This is different from the public API in
      * {@link WindowInsets.Type} as one type from the public API might indicate multiple windows
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 0d467c50..7f827e4 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -241,6 +241,9 @@
                     | View.STATUS_BAR_TRANSPARENT
                     | View.NAVIGATION_BAR_TRANSPARENT;
 
+    private static final int[] SHOW_TYPES_FOR_SWIPE = {ITYPE_NAVIGATION_BAR, ITYPE_STATUS_BAR};
+    private static final int[] SHOW_TYPES_FOR_PANIC = {ITYPE_NAVIGATION_BAR};
+
     private final WindowManagerService mService;
     private final Context mContext;
     private final Context mUiContext;
@@ -3215,8 +3218,15 @@
                 return;
             }
 
+            final InsetsState requestedState = controlTarget.getRequestedInsetsState();
+            final @InsetsType int restorePositionTypes =
+                    (requestedState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)
+                            ? Type.navigationBars() : 0)
+                    | (requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR)
+                            ? Type.statusBars() : 0);
+
             if (swipeTarget == mNavigationBar
-                    && !getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)) {
+                    && (restorePositionTypes & Type.navigationBars()) != 0) {
                 // Don't show status bar when swiping on already visible navigation bar.
                 // But restore the position of navigation bar if it has been moved by the control
                 // target.
@@ -3224,14 +3234,13 @@
                 return;
             }
 
-            int insetsTypesToShow = Type.systemBars();
-
             if (controlTarget.canShowTransient()) {
-                insetsTypesToShow &= ~mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
-                        new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
-            }
-            if (insetsTypesToShow != 0) {
-                controlTarget.showInsets(insetsTypesToShow, false);
+                // Show transient bars if they are hidden; restore position if they are visible.
+                mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_SWIPE);
+                controlTarget.showInsets(restorePositionTypes, false);
+            } else {
+                // Restore visibilities and positions of system bars.
+                controlTarget.showInsets(Type.statusBars() | Type.navigationBars(), false);
             }
         } else {
             boolean sb = mStatusBarController.checkShowTransientBarLw();
@@ -3809,8 +3818,7 @@
                 mPendingPanicGestureUptime = SystemClock.uptimeMillis();
                 if (!isNavBarEmpty(mLastSystemUiFlags)) {
                     mNavigationBarController.showTransient();
-                    mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
-                            new int[] {ITYPE_NAVIGATION_BAR}));
+                    mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_PANIC);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
index 3ffc26a..5e7ed3f 100644
--- a/services/core/java/com/android/server/wm/InsetsControlTarget.java
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import android.inputmethodservice.InputMethodService;
+import android.view.InsetsState;
 import android.view.WindowInsets.Type.InsetsType;
 
 /**
@@ -38,6 +39,13 @@
     }
 
     /**
+     * @return The requested {@link InsetsState} of this target.
+     */
+    default InsetsState getRequestedInsetsState() {
+        return InsetsState.EMPTY;
+    }
+
+    /**
      * Instructs the control target to show inset sources.
      *
      * @param types to specify which types of insets source window should be shown.
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 254356d..a145be0 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -42,7 +42,6 @@
 import android.view.SurfaceControl;
 import android.view.SyncRtSurfaceTransactionApplier;
 import android.view.ViewRootImpl;
-import android.view.WindowInsets.Type.InsetsType;
 import android.view.WindowInsetsAnimation;
 import android.view.WindowInsetsAnimation.Bounds;
 import android.view.WindowInsetsAnimationControlListener;
@@ -133,15 +132,13 @@
         return provider != null && provider.hasWindow() && !provider.getSource().isVisible();
     }
 
-    @InsetsType int showTransient(IntArray types) {
-        @InsetsType int showingTransientTypes = 0;
+    void showTransient(@InternalInsetsType int[] types) {
         boolean changed = false;
-        for (int i = types.size() - 1; i >= 0; i--) {
-            final int type = types.get(i);
+        for (int i = types.length - 1; i >= 0; i--) {
+            final @InternalInsetsType int type = types[i];
             if (!isHidden(type)) {
                 continue;
             }
-            showingTransientTypes |= InsetsState.toPublicType(type);
             if (mShowingTransientTypes.indexOf(type) != -1) {
                 continue;
             }
@@ -169,7 +166,6 @@
                 }
             });
         }
-        return showingTransientTypes;
     }
 
     void hideTransient() {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 11db705..6a2c54e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -725,7 +725,8 @@
      * @return The insets state as requested by the client, i.e. the dispatched insets state
      *         for which the visibilities are overridden with what the client requested.
      */
-    InsetsState getRequestedInsetsState() {
+    @Override
+    public InsetsState getRequestedInsetsState() {
         return mRequestedInsetsState;
     }
 
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 c794e1a..da36ba9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -43,7 +43,6 @@
 import static org.mockito.Mockito.spy;
 
 import android.platform.test.annotations.Presubmit;
-import android.util.IntArray;
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.test.InsetsModeSession;
@@ -240,8 +239,7 @@
         }).when(policy).startAnimation(anyBoolean(), any(), any());
 
         policy.updateBarControlTarget(mAppWindow);
-        policy.showTransient(
-                IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+        policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
         waitUntilWindowAnimatorIdle();
         final InsetsSourceControl[] controls =
                 mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow);
@@ -268,8 +266,7 @@
         final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
         doNothing().when(policy).startAnimation(anyBoolean(), any(), any());
         policy.updateBarControlTarget(mAppWindow);
-        policy.showTransient(
-                IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+        policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
         waitUntilWindowAnimatorIdle();
         final InsetsSourceControl[] controls =
                 mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow);
@@ -297,8 +294,7 @@
         final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
         doNothing().when(policy).startAnimation(anyBoolean(), any(), any());
         policy.updateBarControlTarget(mAppWindow);
-        policy.showTransient(
-                IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+        policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
         waitUntilWindowAnimatorIdle();
         InsetsSourceControl[] controls =
                 mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow);
@@ -336,8 +332,7 @@
         final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy());
         doNothing().when(policy).startAnimation(anyBoolean(), any(), any());
         policy.updateBarControlTarget(app);
-        policy.showTransient(
-                IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+        policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
         final InsetsSourceControl[] controls =
                 mDisplayContent.getInsetsStateController().getControlsForDispatch(app);
         policy.updateBarControlTarget(app2);