Merge "WM: implicitly exclude all edges for pre-Q immersive sticky apps" into qt-dev
am: 8ef731c232

Change-Id: Ie23184e62d410cff170232d15720b22d53f7e6df
diff --git a/api/test-current.txt b/api/test-current.txt
index d2dbacb..fa018a3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2313,6 +2313,7 @@
   }
 
   public static interface DeviceConfig.WindowManager {
+    field public static final String KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE = "system_gestures_excluded_by_pre_q_sticky_immersive";
     field public static final String KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP = "system_gesture_exclusion_limit_dp";
   }
 
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 920eb4b..e30ba38 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -325,6 +325,17 @@
          */
         @TestApi
         String KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP = "system_gesture_exclusion_limit_dp";
+
+        /**
+         * Key for controlling whether system gestures are implicitly excluded by windows requesting
+         * sticky immersive mode from apps that are targeting an SDK prior to Q.
+         *
+         * @see android.provider.DeviceConfig#NAMESPACE_WINDOW_MANAGER
+         * @hide
+         */
+        @TestApi
+        String KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE =
+                "system_gestures_excluded_by_pre_q_sticky_immersive";
     }
 
     private static final Object sLock = new Object();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 1659131..c069b2e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -5158,15 +5158,19 @@
             w.getTouchableRegion(touchableRegion);
             touchableRegion.op(unhandled, Op.INTERSECT);
 
-            rectListToRegion(w.getSystemGestureExclusion(), local);
+            if (w.isImplicitlyExcludingAllSystemGestures()) {
+                local.set(touchableRegion);
+            } else {
+                rectListToRegion(w.getSystemGestureExclusion(), local);
 
-            // Transform to display coordinates
-            local.scale(w.mGlobalScale);
-            final Rect frame = w.getWindowFrames().mFrame;
-            local.translate(frame.left, frame.top);
+                // Transform to display coordinates
+                local.scale(w.mGlobalScale);
+                final Rect frame = w.getWindowFrames().mFrame;
+                local.translate(frame.left, frame.top);
 
-            // A window can only exclude system gestures where it is actually touchable
-            local.op(touchableRegion, Op.INTERSECT);
+                // A window can only exclude system gestures where it is actually touchable
+                local.op(touchableRegion, Op.INTERSECT);
+            }
 
             // Apply restriction if necessary.
             if (needsGestureExclusionRestrictions(w, mLastDispatchedSystemUiVisibility)) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2db0131..fb57d73 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -32,6 +32,7 @@
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Process.myPid;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE;
 import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -844,6 +845,7 @@
     boolean mWindowsChanged = false;
 
     int mSystemGestureExclusionLimitDp;
+    boolean mSystemGestureExcludedByPreQStickyImmersive;
 
     public interface WindowChangeListener {
         public void windowsChanged();
@@ -1142,13 +1144,21 @@
         mSystemGestureExclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP,
                 DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
                         KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0));
+        mSystemGestureExcludedByPreQStickyImmersive =
+                DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+                        KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false);
         DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
                 new HandlerExecutor(mH), properties -> {
                     synchronized (mGlobalLock) {
                         final int exclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP,
                                 properties.getInt(KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0));
-                        if (mSystemGestureExclusionLimitDp != exclusionLimitDp) {
+                        final boolean excludedByPreQSticky = DeviceConfig.getBoolean(
+                                DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+                                KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false);
+                        if (mSystemGestureExcludedByPreQStickyImmersive != excludedByPreQSticky
+                                || mSystemGestureExclusionLimitDp != exclusionLimitDp) {
                             mSystemGestureExclusionLimitDp = exclusionLimitDp;
+                            mSystemGestureExcludedByPreQStickyImmersive = excludedByPreQSticky;
                             mRoot.forAllDisplays(DisplayContent::updateSystemGestureExclusionLimit);
                         }
                     }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c6c9e1b..b5586bf 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -24,6 +24,8 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.SurfaceControl.Transaction;
+import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
@@ -155,6 +157,7 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Debug;
 import android.os.IBinder;
 import android.os.PowerManager;
@@ -657,6 +660,15 @@
         return true;
     }
 
+    boolean isImplicitlyExcludingAllSystemGestures() {
+        final int immersiveStickyFlags =
+                SYSTEM_UI_FLAG_HIDE_NAVIGATION | SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+        final boolean immersiveSticky =
+                (mSystemUiVisibility & immersiveStickyFlags) == immersiveStickyFlags;
+        return immersiveSticky && mWmService.mSystemGestureExcludedByPreQStickyImmersive
+                && mAppToken != null && mAppToken.mTargetSdk < Build.VERSION_CODES.Q;
+    }
+
     interface PowerManagerWrapper {
         void wakeUp(long time, @WakeReason int reason, String details);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index f49a575..f2e7dc6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -26,8 +26,13 @@
 import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
 import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
 import static android.view.DisplayCutout.fromBoundingRect;
+import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
+import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
@@ -789,6 +794,34 @@
     }
 
     @Test
+    public void testCalculateSystemGestureExclusion_immersiveStickyLegacyWindow() throws Exception {
+        synchronized (mWm.mGlobalLock) {
+            mWm.mSystemGestureExcludedByPreQStickyImmersive = true;
+
+            final DisplayContent dc = createNewDisplay();
+            final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
+            win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+            win.getAttrs().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+            win.getAttrs().privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
+            win.getAttrs().subtreeSystemUiVisibility = win.mSystemUiVisibility =
+                    SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_HIDE_NAVIGATION
+                            | SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+            win.mAppToken.mTargetSdk = P;
+
+            dc.setLayoutNeeded();
+            dc.performLayout(true /* initial */, false /* updateImeWindows */);
+
+            win.setHasSurface(true);
+
+            final Region expected = Region.obtain();
+            expected.set(dc.getBounds());
+            assertEquals(expected, dc.calculateSystemGestureExclusion());
+
+            win.setHasSurface(false);
+        }
+    }
+
+    @Test
     public void testOrientationChangeLogging() {
         MetricsLogger mockLogger = mock(MetricsLogger.class);
         Configuration oldConfig = new Configuration();
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 c3561f4..d034f27 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -49,6 +49,7 @@
 
     int mRotationToReport = 0;
     boolean mKeyguardShowingAndNotOccluded = false;
+    boolean mOkToAnimate = true;
 
     private Runnable mRunnableWhenAddingSplashScreen;
 
@@ -222,7 +223,7 @@
 
     @Override
     public boolean okToAnimate() {
-        return true;
+        return mOkToAnimate;
     }
 
     @Override