From b273845ecb243ce93ba014bcbb51f2e64b49bb0b Mon Sep 17 00:00:00 2001 From: Vali Calinescu Date: Fri, 28 Apr 2023 15:25:08 +0000 Subject: [PATCH] Add opt-out property for force resize override Bug: 278428984 Test: atest WmTests:LetterboxUiControllerTest Test: atest CtsWindowManagerDeviceTestCases:CompatChangeTests Change-Id: I8b5470b6989d1e82508db772de98076b0ce52ecf --- .../java/android/content/pm/ActivityInfo.java | 21 ---- core/java/android/view/WindowManager.java | 31 +++++ .../com/android/server/wm/ActivityRecord.java | 25 +++- .../server/wm/LetterboxUiController.java | 51 ++++++++ .../server/wm/LetterboxUiControllerTest.java | 115 ++++++++++++++++++ 5 files changed, 220 insertions(+), 23 deletions(-) diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index b5d2f2c9177a6..036a4eb22ba62 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -1697,27 +1697,6 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { return (flags & FLAG_SUPPORTS_PICTURE_IN_PICTURE) != 0; } - /** - * Returns whether the activity supports size changes. - * @hide - */ - @SizeChangesSupportMode - public int supportsSizeChanges() { - if (isChangeEnabled(FORCE_NON_RESIZE_APP)) { - return SIZE_CHANGES_UNSUPPORTED_OVERRIDE; - } - - if (supportsSizeChanges) { - return SIZE_CHANGES_SUPPORTED_METADATA; - } - - if (isChangeEnabled(FORCE_RESIZE_APP)) { - return SIZE_CHANGES_SUPPORTED_OVERRIDE; - } - - return SIZE_CHANGES_UNSUPPORTED_METADATA; - } - /** * Returns if the activity should never be sandboxed to the activity window bounds. * @hide diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 1850462221012..e95ba797a9858 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1215,6 +1215,37 @@ public interface WindowManager extends ViewManager { String PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE"; + /** + * Application level {@link android.content.pm.PackageManager.Property PackageManager + * .Property} for an app to inform the system that the app should be opted-out from the + * compatibility overrides that change the resizability of the app. + * + *

When these compat overrides are enabled they force the packages they are applied to to be + * resizable / unresizable. If the app is forced to be resizable this won't change whether + * the app can be put into multi-windowing mode, but allow the app to resize without going into + * size-compat mode when the window container resizes, such as display size change or screen + * rotation. + * + *

Setting this property to {@code false} informs the system that the app must be + * opted-out from the compatibility treatment even if the device manufacturer has opted the app + * into the treatment. + * + *

Not setting this property at all, or setting this property to {@code true} has no effect. + * + *

Syntax: + *

+     * <application>
+     *   <property
+     *     android:name="android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES"
+     *     android:value="true|false"/>
+     * </application>
+     * 
+ * @hide + */ + // TODO(b/280052089): Make this public API. + String PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES = + "android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES"; + /** * @hide */ diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index d93778e18748b..22dffe3ac504e 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -93,6 +93,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.pm.ActivityInfo.SIZE_CHANGES_SUPPORTED_METADATA; import static android.content.pm.ActivityInfo.SIZE_CHANGES_SUPPORTED_OVERRIDE; +import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_METADATA; import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_OVERRIDE; import static android.content.res.Configuration.ASSETS_SEQ_UNDEFINED; import static android.content.res.Configuration.EMPTY; @@ -1298,7 +1299,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A + info.getManifestMinAspectRatio()); } pw.println(prefix + "supportsSizeChanges=" - + ActivityInfo.sizeChangesSupportModeToString(info.supportsSizeChanges())); + + ActivityInfo.sizeChangesSupportModeToString(supportsSizeChanges())); if (info.configChanges != 0) { pw.println(prefix + "configChanges=0x" + Integer.toHexString(info.configChanges)); } @@ -8127,7 +8128,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * aspect ratio. */ boolean shouldCreateCompatDisplayInsets() { - switch (info.supportsSizeChanges()) { + switch (supportsSizeChanges()) { case SIZE_CHANGES_SUPPORTED_METADATA: case SIZE_CHANGES_SUPPORTED_OVERRIDE: return false; @@ -8154,6 +8155,26 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A && isActivityTypeStandardOrUndefined(); } + /** + * Returns whether the activity supports size changes. + */ + @ActivityInfo.SizeChangesSupportMode + private int supportsSizeChanges() { + if (mLetterboxUiController.shouldOverrideForceNonResizeApp()) { + return SIZE_CHANGES_UNSUPPORTED_OVERRIDE; + } + + if (info.supportsSizeChanges) { + return SIZE_CHANGES_SUPPORTED_METADATA; + } + + if (mLetterboxUiController.shouldOverrideForceResizeApp()) { + return SIZE_CHANGES_SUPPORTED_OVERRIDE; + } + + return SIZE_CHANGES_UNSUPPORTED_METADATA; + } + @Override boolean hasSizeCompatBounds() { return mSizeCompatBounds != null; diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index b557b2e1410fc..bd80b02b889f5 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -17,6 +17,8 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.content.pm.ActivityInfo.FORCE_NON_RESIZE_APP; +import static android.content.pm.ActivityInfo.FORCE_RESIZE_APP; import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION; import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION; import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH; @@ -52,6 +54,7 @@ import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATI import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE; +import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES; import static android.view.WindowManager.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS; import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION; @@ -189,6 +192,10 @@ final class LetterboxUiController { // Corresponds to OVERRIDE_MIN_ASPECT_RATIO private final boolean mIsOverrideMinAspectRatio; + // Corresponds to FORCE_RESIZE_APP + private final boolean mIsOverrideForceResizeApp; + // Corresponds to FORCE_NON_RESIZE_APP + private final boolean mIsOverrideForceNonResizeApp; @Nullable private final Boolean mBooleanPropertyAllowOrientationOverride; @@ -196,6 +203,8 @@ final class LetterboxUiController { private final Boolean mBooleanPropertyAllowDisplayOrientationOverride; @Nullable private final Boolean mBooleanPropertyAllowMinAspectRatioOverride; + @Nullable + private final Boolean mBooleanPropertyAllowForceResizeOverride; /* * WindowContainerListener responsible to make translucent activities inherit @@ -311,6 +320,10 @@ final class LetterboxUiController { readComponentProperty(packageManager, mActivityRecord.packageName, /* gatingCondition */ null, PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE); + mBooleanPropertyAllowForceResizeOverride = + readComponentProperty(packageManager, mActivityRecord.packageName, + /* gatingCondition */ null, + PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES); mIsOverrideAnyOrientationEnabled = isCompatChangeEnabled(OVERRIDE_ANY_ORIENTATION); mIsOverrideToPortraitOrientationEnabled = @@ -342,6 +355,8 @@ final class LetterboxUiController { mIsOverrideEnableCompatFakeFocusEnabled = isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS); mIsOverrideMinAspectRatio = isCompatChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO); + mIsOverrideForceResizeApp = isCompatChangeEnabled(FORCE_RESIZE_APP); + mIsOverrideForceNonResizeApp = isCompatChangeEnabled(FORCE_NON_RESIZE_APP); } /** @@ -532,6 +547,42 @@ final class LetterboxUiController { mBooleanPropertyAllowMinAspectRatioOverride); } + /** + * Whether we should apply the force resize per-app override. When this override is applied it + * forces the packages it is applied to to be resizable. It won't change whether the app can be + * put into multi-windowing mode, but allow the app to resize without going into size-compat + * mode when the window container resizes, such as display size change or screen rotation. + * + *

This method returns {@code true} when the following conditions are met: + *

+ */ + boolean shouldOverrideForceResizeApp() { + return shouldEnableWithOptInOverrideAndOptOutProperty( + /* gatingCondition */ () -> true, + mIsOverrideForceResizeApp, + mBooleanPropertyAllowForceResizeOverride); + } + + /** + * Whether we should apply the force non resize per-app override. When this override is applied + * it forces the packages it is applied to to be non-resizable. + * + *

This method returns {@code true} when the following conditions are met: + *

+ */ + boolean shouldOverrideForceNonResizeApp() { + return shouldEnableWithOptInOverrideAndOptOutProperty( + /* gatingCondition */ () -> true, + mIsOverrideForceNonResizeApp, + mBooleanPropertyAllowForceResizeOverride); + } + /** * Sets whether an activity is relaunching after the app has called {@link * android.app.Activity#setRequestedOrientation}. diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java index 81e0fb3c79961..0a5940c75a975 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import static android.content.pm.ActivityInfo.FORCE_NON_RESIZE_APP; +import static android.content.pm.ActivityInfo.FORCE_RESIZE_APP; import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION; import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION; import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH; @@ -43,6 +45,7 @@ import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATI import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE; +import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES; import static android.view.WindowManager.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS; import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION; @@ -918,6 +921,118 @@ public class LetterboxUiControllerTest extends WindowTestsBase { assertFalse(mController.shouldOverrideMinAspectRatio()); } + @Test + @EnableCompatChanges({FORCE_RESIZE_APP}) + public void testshouldOverrideForceResizeApp_overrideEnabled_returnsTrue() { + mController = new LetterboxUiController(mWm, mActivity); + + assertTrue(mController.shouldOverrideForceResizeApp()); + } + + @Test + @EnableCompatChanges({FORCE_RESIZE_APP}) + public void testshouldOverrideForceResizeApp_propertyTrue_overrideEnabled_returnsTrue() + throws Exception { + mockThatProperty(PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES, /* value */ true); + mController = new LetterboxUiController(mWm, mActivity); + + assertTrue(mController.shouldOverrideForceResizeApp()); + } + + @Test + @DisableCompatChanges({FORCE_RESIZE_APP}) + public void testshouldOverrideForceResizeApp_propertyTrue_overrideDisabled_returnsFalse() + throws Exception { + mockThatProperty(PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES, /* value */ true); + mController = new LetterboxUiController(mWm, mActivity); + + assertFalse(mController.shouldOverrideForceResizeApp()); + } + + @Test + @DisableCompatChanges({FORCE_RESIZE_APP}) + public void testshouldOverrideForceResizeApp_overrideDisabled_returnsFalse() { + mController = new LetterboxUiController(mWm, mActivity); + + assertFalse(mController.shouldOverrideForceResizeApp()); + } + + @Test + @EnableCompatChanges({FORCE_RESIZE_APP}) + public void testshouldOverrideForceResizeApp_propertyFalse_overrideEnabled_returnsFalse() + throws Exception { + mockThatProperty(PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES, /* value */ false); + mController = new LetterboxUiController(mWm, mActivity); + + assertFalse(mController.shouldOverrideForceResizeApp()); + } + + @Test + @DisableCompatChanges({FORCE_RESIZE_APP}) + public void testshouldOverrideForceResizeApp_propertyFalse_noOverride_returnsFalse() + throws Exception { + mockThatProperty(PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES, /* value */ false); + mController = new LetterboxUiController(mWm, mActivity); + + assertFalse(mController.shouldOverrideForceResizeApp()); + } + + @Test + @EnableCompatChanges({FORCE_NON_RESIZE_APP}) + public void testshouldOverrideForceNonResizeApp_overrideEnabled_returnsTrue() { + mController = new LetterboxUiController(mWm, mActivity); + + assertTrue(mController.shouldOverrideForceNonResizeApp()); + } + + @Test + @EnableCompatChanges({FORCE_NON_RESIZE_APP}) + public void testshouldOverrideForceNonResizeApp_propertyTrue_overrideEnabled_returnsTrue() + throws Exception { + mockThatProperty(PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES, /* value */ true); + mController = new LetterboxUiController(mWm, mActivity); + + assertTrue(mController.shouldOverrideForceNonResizeApp()); + } + + @Test + @DisableCompatChanges({FORCE_NON_RESIZE_APP}) + public void testshouldOverrideForceNonResizeApp_propertyTrue_overrideDisabled_returnsFalse() + throws Exception { + mockThatProperty(PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES, /* value */ true); + mController = new LetterboxUiController(mWm, mActivity); + + assertFalse(mController.shouldOverrideForceNonResizeApp()); + } + + @Test + @DisableCompatChanges({FORCE_NON_RESIZE_APP}) + public void testshouldOverrideForceNonResizeApp_overrideDisabled_returnsFalse() { + mController = new LetterboxUiController(mWm, mActivity); + + assertFalse(mController.shouldOverrideForceNonResizeApp()); + } + + @Test + @EnableCompatChanges({FORCE_NON_RESIZE_APP}) + public void testshouldOverrideForceNonResizeApp_propertyFalse_overrideEnabled_returnsFalse() + throws Exception { + mockThatProperty(PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES, /* value */ false); + mController = new LetterboxUiController(mWm, mActivity); + + assertFalse(mController.shouldOverrideForceNonResizeApp()); + } + + @Test + @DisableCompatChanges({FORCE_NON_RESIZE_APP}) + public void testshouldOverrideForceNonResizeApp_propertyFalse_noOverride_returnsFalse() + throws Exception { + mockThatProperty(PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES, /* value */ false); + mController = new LetterboxUiController(mWm, mActivity); + + assertFalse(mController.shouldOverrideForceNonResizeApp()); + } + @Test public void testgetFixedOrientationLetterboxAspectRatio_splitScreenAspectEnabled() { doReturn(true).when(mActivity.mWmService.mLetterboxConfiguration)