Allow remote inset transient bar configuration

Allow an OEM to configure the show transient behavior when using a
RemoteInsetsControlTarget.

Bug: 231351266
Test: manual, atest
com.android.server.wm.DisplayPolicyTests#testCanSystemBarsBeShownByUser

Change-Id: I2555b437ed62ea26f85dade6faa9c3a3cbc24593
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 622414e..abcee9d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -757,6 +757,15 @@
          bar for all apps. -->
     <bool name="config_remoteInsetsControllerControlsSystemBars">false</bool>
 
+    <!-- Control whether the system bars can be requested when using a remote insets control target.
+         This allows for specifying whether or not system bars can be shown by the user (via swipe
+         or other means) when they are hidden by the logic defined by the remote insets controller.
+         This is useful for cases where the system provides alternative affordances for showing and
+         hiding the bars or for cases in which it's desired the bars not be shown for any reason.
+         This configuration will only apply when config_remoteInsetsControllerControlsSystemBars.
+         is set to true. -->
+    <bool name="config_remoteInsetsControllerSystemBarsCanBeShownByUserAction">false</bool>
+
     <!-- HDMI behavior -->
 
     <!-- The number of degrees to rotate the display when the device has HDMI connected
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 872da62..bc2c62c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1726,6 +1726,7 @@
   <java-symbol type="bool" name="config_enableLockBeforeUnlockScreen" />
   <java-symbol type="bool" name="config_enableLockScreenRotation" />
   <java-symbol type="bool" name="config_remoteInsetsControllerControlsSystemBars" />
+  <java-symbol type="bool" name="config_remoteInsetsControllerSystemBarsCanBeShownByUserAction" />
   <java-symbol type="bool" name="config_lidControlsScreenLock" />
   <java-symbol type="bool" name="config_lidControlsSleep" />
   <java-symbol type="bool" name="config_lockDayNightMode" />
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7ffa55f..a70282e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -228,6 +228,7 @@
 import android.window.IDisplayAreaOrganizer;
 import android.window.TransitionRequestInfo;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -1074,7 +1075,7 @@
         mDisplayPolicy = new DisplayPolicy(mWmService, this);
         mDisplayRotation = new DisplayRotation(mWmService, this);
         mCloseToSquareMaxAspectRatio = mWmService.mContext.getResources().getFloat(
-                com.android.internal.R.dimen.config_closeToSquareDisplayMaxAspectRatio);
+                R.dimen.config_closeToSquareDisplayMaxAspectRatio);
         if (isDefaultDisplay) {
             // The policy may be invoked right after here, so it requires the necessary default
             // fields of this display content.
@@ -1566,7 +1567,7 @@
                 mAtmService.mContext.createConfigurationContext(getConfiguration());
         final float minimalSize =
                 displayConfigurationContext.getResources().getDimension(
-                                com.android.internal.R.dimen.default_minimal_size_resizable_task);
+                        R.dimen.default_minimal_size_resizable_task);
         if (Double.compare(mDisplayMetrics.density, 0.0) == 0) {
             throw new IllegalArgumentException("Display with ID=" + getDisplayId() + "has invalid "
                 + "DisplayMetrics.density= 0.0");
@@ -4550,9 +4551,9 @@
         // if the wallpaper service is disabled on the device, we're never going to have
         // wallpaper, don't bother waiting for it
         boolean wallpaperEnabled = mWmService.mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_enableWallpaperService)
+                R.bool.config_enableWallpaperService)
                 && mWmService.mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_checkWallpaperAtBoot);
+                R.bool.config_checkWallpaperAtBoot);
 
         final boolean haveBootMsg = drawnWindowTypes.get(TYPE_BOOT_PROGRESS);
         final boolean haveApp = drawnWindowTypes.get(TYPE_BASE_APPLICATION);
@@ -6505,9 +6506,12 @@
     class RemoteInsetsControlTarget implements InsetsControlTarget {
         private final IDisplayWindowInsetsController mRemoteInsetsController;
         private final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
+        private final boolean mCanShowTransient;
 
         RemoteInsetsControlTarget(IDisplayWindowInsetsController controller) {
             mRemoteInsetsController = controller;
+            mCanShowTransient = mWmService.mContext.getResources().getBoolean(
+                    R.bool.config_remoteInsetsControllerSystemBarsCanBeShownByUserAction);
         }
 
         /**
@@ -6563,6 +6567,11 @@
         }
 
         @Override
+        public boolean canShowTransient() {
+            return mCanShowTransient;
+        }
+
+        @Override
         public boolean getRequestedVisibility(@InternalInsetsType int type) {
             if (type == ITYPE_IME) {
                 return getInsetsStateController().getImeSourceProvider().isImeShowing();
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 98a51a9..e5282f7 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -219,6 +219,7 @@
     @Px
     private int mRightGestureInset;
 
+    private boolean mCanSystemBarsBeShownByUser;
     private boolean mNavButtonForcedVisible;
 
     StatusBarManagerInternal getStatusBarManagerInternal() {
@@ -424,6 +425,9 @@
         final Resources r = mContext.getResources();
         mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
         mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer);
+        mCanSystemBarsBeShownByUser = !r.getBoolean(
+                R.bool.config_remoteInsetsControllerControlsSystemBars) || r.getBoolean(
+                R.bool.config_remoteInsetsControllerSystemBarsCanBeShownByUserAction);
 
         mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(
                 Context.ACCESSIBILITY_SERVICE);
@@ -616,7 +620,7 @@
         displayContent.mAppTransition.registerListenerLocked(mAppTransitionListener);
         displayContent.mTransitionController.registerLegacyListener(mAppTransitionListener);
         mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
-                mService.mVrModeEnabled);
+                mService.mVrModeEnabled, mCanSystemBarsBeShownByUser);
 
         // TODO: Make it can take screenshot on external display
         mScreenshotHelper = displayContent.isDefaultDisplay
@@ -2019,6 +2023,11 @@
         return lp.width;
     }
 
+    @VisibleForTesting
+    void setCanSystemBarsBeShownByUser(boolean canBeShown) {
+        mCanSystemBarsBeShownByUser = canBeShown;
+    }
+
     void notifyDisplayReady() {
         mHandler.post(() -> {
             final int displayId = getDisplayId();
@@ -2256,11 +2265,17 @@
         updateSystemBarAttributes();
     }
 
-    private void requestTransientBars(WindowState swipeTarget, boolean isGestureOnSystemBar) {
+    @VisibleForTesting
+    void requestTransientBars(WindowState swipeTarget, boolean isGestureOnSystemBar) {
         if (swipeTarget == null || !mService.mPolicy.isUserSetupComplete()) {
             // Swipe-up for navigation bar is disabled during setup
             return;
         }
+        if (!mCanSystemBarsBeShownByUser) {
+            Slog.d(TAG, "Remote insets controller disallows showing system bars - ignoring "
+                    + "request");
+            return;
+        }
         final InsetsSourceProvider provider = swipeTarget.getControllableInsetProvider();
         final InsetsControlTarget controlTarget = provider != null
                 ? provider.getControlTarget() : null;
diff --git a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
index 93bdf16..4c18d0b 100644
--- a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
@@ -99,9 +99,11 @@
     // Local copy of vr mode enabled state, to avoid calling into VrManager with
     // the lock held.
     private boolean mVrModeEnabled;
+    private boolean mCanSystemBarsBeShownByUser;
     private int mLockTaskState = LOCK_TASK_MODE_NONE;
 
-    ImmersiveModeConfirmation(Context context, Looper looper, boolean vrModeEnabled) {
+    ImmersiveModeConfirmation(Context context, Looper looper, boolean vrModeEnabled,
+            boolean canSystemBarsBeShownByUser) {
         final Display display = context.getDisplay();
         final Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
         mContext = display.getDisplayId() == DEFAULT_DISPLAY
@@ -111,6 +113,7 @@
         mPanicThresholdMs = context.getResources()
                 .getInteger(R.integer.config_immersive_mode_confirmation_panic);
         mVrModeEnabled = vrModeEnabled;
+        mCanSystemBarsBeShownByUser = canSystemBarsBeShownByUser;
     }
 
     private long getNavBarExitDuration() {
@@ -171,6 +174,7 @@
             if ((DEBUG_SHOW_EVERY_TIME || !sConfirmed)
                     && userSetupComplete
                     && !mVrModeEnabled
+                    && mCanSystemBarsBeShownByUser
                     && !navBarEmpty
                     && !UserManager.isDeviceInDemoMode(mContext)
                     && (mLockTaskState != LOCK_TASK_MODE_LOCKED)) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 2b131e1..8f2e9b4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -45,7 +45,12 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.graphics.PixelFormat;
@@ -344,4 +349,24 @@
         final InsetsSource navBarSource = state.peekSource(ITYPE_NAVIGATION_BAR);
         assertEquals(attrs.height - 10, navBarSource.getFrame().height());
     }
+
+    @Test
+    public void testCanSystemBarsBeShownByUser() {
+        ((TestWindowManagerPolicy) mWm.mPolicy).mIsUserSetupComplete = true;
+        final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
+        final WindowState windowState = mock(WindowState.class);
+        final InsetsSourceProvider provider = mock(InsetsSourceProvider.class);
+        final InsetsControlTarget controlTarget = mock(InsetsControlTarget.class);
+        when(provider.getControlTarget()).thenReturn(controlTarget);
+        when(windowState.getControllableInsetProvider()).thenReturn(provider);
+        when(controlTarget.getRequestedVisibility(anyInt())).thenReturn(true);
+
+        displayPolicy.setCanSystemBarsBeShownByUser(false);
+        displayPolicy.requestTransientBars(windowState, true);
+        verify(controlTarget, never()).showInsets(anyInt(), anyBoolean());
+
+        displayPolicy.setCanSystemBarsBeShownByUser(true);
+        displayPolicy.requestTransientBars(windowState, true);
+        verify(controlTarget).showInsets(anyInt(), anyBoolean());
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 92457c7..851be9d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -40,6 +40,7 @@
 
     boolean mKeyguardShowingAndNotOccluded = false;
     boolean mOkToAnimate = true;
+    boolean mIsUserSetupComplete = false;
 
     TestWindowManagerPolicy() {
     }
@@ -284,7 +285,7 @@
 
     @Override
     public boolean isUserSetupComplete() {
-        return false;
+        return mIsUserSetupComplete;
     }
 
     @Override