diff --git a/api/test-current.txt b/api/test-current.txt index 0d8471c9299e0..a3ef9c41d5d21 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -2312,6 +2312,7 @@ package android.provider { } 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 920eb4b517759..e30ba38c127fa 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -325,6 +325,17 @@ public final class DeviceConfig { */ @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 3c29e5d84becd..8ce6810497c32 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -5188,15 +5188,19 @@ class DisplayContent extends WindowContainer { 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 006c8939de936..0470d95e42781 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.PowerManager.DRAW_WAKE_LOCK; 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.Point; 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; @@ -667,6 +670,15 @@ class WindowState extends WindowContainer implements WindowManagerP 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 f49a575349387..f2e7dc6fecae0 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.Display.DEFAULT_DISPLAY; 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; @@ -788,6 +793,34 @@ public class DisplayContentTests extends WindowTestsBase { assertEquals(expected, dc.calculateSystemGestureExclusion()); } + @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); 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 1c9e504258415..2e5ce69a8564c 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 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { int mRotationToReport = 0; boolean mKeyguardShowingAndNotOccluded = false; + boolean mOkToAnimate = true; private Runnable mRunnableWhenAddingSplashScreen; @@ -222,7 +223,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { @Override public boolean okToAnimate() { - return true; + return mOkToAnimate; } @Override