diff --git a/api/test-current.txt b/api/test-current.txt index 14c70e30cea48..874c2162e42c1 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -2320,6 +2320,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 48faf114d2d74..d226716cdd491 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -333,6 +333,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 4d548bf5ea630..697948a1d961e 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -5178,15 +5178,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 bf874be41c5b5..81e458496385b 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