From 4c996a74e05c94196c984411c8e04cf52ef2cbd5 Mon Sep 17 00:00:00 2001 From: Mariia Sandrikova Date: Mon, 16 May 2022 20:43:41 +0000 Subject: [PATCH] Set min aspect ratio for unresizable apps to 3:2. Also, allow to override it via a config overlay. Bug: 230757107 Test: atest WmTests:SizeCompatTests Change-Id: I750b8fd464b041f16bf18c3bdbfb1a28a2132902 --- core/res/res/values/config.xml | 6 +++ core/res/res/values/symbols.xml | 1 + .../com/android/server/wm/ActivityRecord.java | 18 ++++++- .../server/wm/LetterboxConfiguration.java | 49 +++++++++++++++++++ .../server/wm/LetterboxUiController.java | 5 ++ .../server/wm/WindowManagerShellCommand.java | 34 +++++++++++++ .../wm/DualDisplayAreaGroupPolicyTest.java | 15 ++++-- .../android/server/wm/SizeCompatTests.java | 44 +++++++++++++++-- 8 files changed, 160 insertions(+), 12 deletions(-) diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 3acd171439254..66689ca568e96 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -5176,6 +5176,12 @@ false + + 1.5 + false diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 3c03b41b87882..49be0b87dc9f9 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4395,6 +4395,7 @@ + diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index e700103bf0d26..328f55f9192c3 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -7860,7 +7860,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Vertical position int offsetY = 0; if (parentBounds.height() != screenResolvedBounds.height()) { - if (screenResolvedBounds.height() >= parentAppBounds.height()) { // If resolved bounds overlap with insets, center within app bounds. offsetY = getCenterOffset( @@ -7908,6 +7907,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return mLetterboxBoundsForFixedOrientationAndAspectRatio != null; } + boolean isAspectRatioApplied() { + return mIsAspectRatioApplied; + } + /** * Whether this activity is eligible for letterbox eduction. * @@ -8632,7 +8635,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * Returns the min aspect ratio of this activity. */ private float getMinAspectRatio() { - return info.getMinAspectRatio(getRequestedOrientation()); + float infoAspectRatio = info.getMinAspectRatio(getRequestedOrientation()); + // Complying with the CDD 7.1.1.2 requirement for unresizble apps: + // https://source.android.com/compatibility/12/android-12-cdd#7112_screen_aspect_ratio + return infoAspectRatio < 1f && info.resizeMode == RESIZE_MODE_UNRESIZEABLE + // TODO(233582832): Consider removing fixed-orientation condition. + // Some apps switching from tablet to phone layout at the certain size + // threshold. This may lead to flickering on tablets in landscape orientation + // if an app sets orientation to portrait dynamically because of aspect ratio + // restriction applied here. + && getRequestedConfigurationOrientation() != ORIENTATION_UNDEFINED + ? mWmService.mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps() + : infoAspectRatio; } /** diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java index 2c7540b8bc0a4..b931f7902e43b 100644 --- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java +++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java @@ -37,6 +37,11 @@ final class LetterboxConfiguration { */ static final float MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO = 1.0f; + // Min allowed aspect ratio for unresizable apps which is used when an app doesn't specify + // android:minAspectRatio in accordance with the CDD 7.1.1.2 requirement: + // https://source.android.com/compatibility/12/android-12-cdd#7112_screen_aspect_ratio + static final float MIN_UNRESIZABLE_ASPECT_RATIO = 4 / 3f; + /** Enum for Letterbox background type. */ @Retention(RetentionPolicy.SOURCE) @IntDef({LETTERBOX_BACKGROUND_SOLID_COLOR, LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND, @@ -104,6 +109,11 @@ final class LetterboxConfiguration { // MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO will be ignored. private float mFixedOrientationLetterboxAspectRatio; + // Default min aspect ratio for unresizable apps which is used when an app doesn't specify + // android:minAspectRatio in accordance with the CDD 7.1.1.2 requirement: + // https://source.android.com/compatibility/12/android-12-cdd#7112_screen_aspect_ratio + private float mDefaultMinAspectRatioForUnresizableApps; + // Corners radius for activities presented in the letterbox mode, values < 0 will be ignored. private int mLetterboxActivityCornersRadius; @@ -204,6 +214,8 @@ final class LetterboxConfiguration { mLetterboxPositionForVerticalReachability = mDefaultPositionForVerticalReachability; mIsEducationEnabled = mContext.getResources().getBoolean( R.bool.config_letterboxIsEducationEnabled); + setDefaultMinAspectRatioForUnresizableApps(mContext.getResources().getFloat( + R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps)); } /** @@ -232,6 +244,43 @@ final class LetterboxConfiguration { return mFixedOrientationLetterboxAspectRatio; } + /** + * Resets the min aspect ratio for unresizable apps which is used when an app doesn't specify + * {@code android:minAspectRatio} to {@link + * R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps}. + * + * @throws AssertionError if {@link + * R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps} is < {@link + * #MIN_UNRESIZABLE_ASPECT_RATIO}. + */ + void resetDefaultMinAspectRatioForUnresizableApps() { + setDefaultMinAspectRatioForUnresizableApps(mContext.getResources().getFloat( + R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps)); + } + + /** + * Gets the min aspect ratio for unresizable apps which is used when an app doesn't specify + * {@code android:minAspectRatio}. + */ + float getDefaultMinAspectRatioForUnresizableApps() { + return mDefaultMinAspectRatioForUnresizableApps; + } + + /** + * Overrides the min aspect ratio for unresizable apps which is used when an app doesn't + * specify {@code android:minAspectRatio}. + * + * @throws AssertionError if given value is < {@link #MIN_UNRESIZABLE_ASPECT_RATIO}. + */ + void setDefaultMinAspectRatioForUnresizableApps(float aspectRatio) { + if (aspectRatio < MIN_UNRESIZABLE_ASPECT_RATIO) { + throw new AssertionError( + "Unexpected min aspect ratio for unresizable apps, it should be <= " + + MIN_UNRESIZABLE_ASPECT_RATIO + " but was " + aspectRatio); + } + mDefaultMinAspectRatioForUnresizableApps = aspectRatio; + } + /** * Overrides corners raidus for activities presented in the letterbox mode. If given value < 0, * both it and a value of {@link diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index 201520677b26d..9dbc477151863 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -540,6 +540,8 @@ final class LetterboxUiController { pw.println(prefix + " fixedOrientationLetterboxAspectRatio=" + getFixedOrientationLetterboxAspectRatio( mActivityRecord.getParent().getConfiguration())); + pw.println(prefix + " defaultMinAspectRatioForUnresizableApps=" + + mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps()); } /** @@ -556,6 +558,9 @@ final class LetterboxUiController { if (mainWin.isLetterboxedForDisplayCutout()) { return "DISPLAY_CUTOUT"; } + if (mActivityRecord.isAspectRatioApplied()) { + return "ASPECT_RATIO"; + } return "UNKNOWN_REASON"; } diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 8a6a4df0fd421..79c6ee7ff91d7 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -629,6 +629,26 @@ public class WindowManagerShellCommand extends ShellCommand { return 0; } + private int runSetDefaultMinAspectRatioForUnresizableApps(PrintWriter pw) + throws RemoteException { + final float aspectRatio; + try { + String arg = getNextArgRequired(); + aspectRatio = Float.parseFloat(arg); + } catch (NumberFormatException e) { + getErrPrintWriter().println("Error: bad aspect ratio format " + e); + return -1; + } catch (IllegalArgumentException e) { + getErrPrintWriter().println( + "Error: aspect ratio should be provided as an argument " + e); + return -1; + } + synchronized (mInternal.mGlobalLock) { + mLetterboxConfiguration.setDefaultMinAspectRatioForUnresizableApps(aspectRatio); + } + return 0; + } + private int runSetLetterboxActivityCornersRadius(PrintWriter pw) throws RemoteException { final int cornersRadius; try { @@ -939,6 +959,9 @@ public class WindowManagerShellCommand extends ShellCommand { case "--aspectRatio": runSetFixedOrientationLetterboxAspectRatio(pw); break; + case "--minAspectRatioForUnresizable": + runSetDefaultMinAspectRatioForUnresizableApps(pw); + break; case "--cornerRadius": runSetLetterboxActivityCornersRadius(pw); break; @@ -998,6 +1021,9 @@ public class WindowManagerShellCommand extends ShellCommand { case "aspectRatio": mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio(); break; + case "minAspectRatioForUnresizable": + mLetterboxConfiguration.resetDefaultMinAspectRatioForUnresizableApps(); + break; case "cornerRadius": mLetterboxConfiguration.resetLetterboxActivityCornersRadius(); break; @@ -1121,6 +1147,7 @@ public class WindowManagerShellCommand extends ShellCommand { private void resetLetterboxStyle() { synchronized (mInternal.mGlobalLock) { mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio(); + mLetterboxConfiguration.resetDefaultMinAspectRatioForUnresizableApps(); mLetterboxConfiguration.resetLetterboxActivityCornersRadius(); mLetterboxConfiguration.resetLetterboxBackgroundType(); mLetterboxConfiguration.resetLetterboxBackgroundColor(); @@ -1145,6 +1172,8 @@ public class WindowManagerShellCommand extends ShellCommand { + mLetterboxConfiguration.getLetterboxVerticalPositionMultiplier()); pw.println("Aspect ratio: " + mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio()); + pw.println("Default min aspect ratio for unresizable apps: " + + mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps()); pw.println("Is horizontal reachability enabled: " + mLetterboxConfiguration.getIsHorizontalReachabilityEnabled()); pw.println("Is vertical reachability enabled: " @@ -1261,6 +1290,11 @@ public class WindowManagerShellCommand extends ShellCommand { + LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO); pw.println(" both it and R.dimen.config_fixedOrientationLetterboxAspectRatio will"); pw.println(" be ignored and framework implementation will determine aspect ratio."); + pw.println(" --minAspectRatioForUnresizable aspectRatio"); + pw.println(" Default min aspect ratio for unresizable apps which is used when an"); + pw.println(" app doesn't specify android:minAspectRatio. An exception will be"); + pw.println(" thrown if aspectRatio < " + + LetterboxConfiguration.MIN_UNRESIZABLE_ASPECT_RATIO); pw.println(" --cornerRadius radius"); pw.println(" Corners radius for activities in the letterbox mode. If radius < 0,"); pw.println(" both it and R.integer.config_letterboxActivityCornersRadius will be"); diff --git a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java index dbb7fae548b75..db3a51ca4791e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java @@ -39,6 +39,7 @@ import static com.android.server.wm.SizeCompatTests.rotateDisplay; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -168,7 +169,8 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase { mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda); - prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_PORTRAIT); + prepareLimitedBounds(mFirstActivity, SCREEN_ORIENTATION_PORTRAIT, + false /* isUnresizable */); final Rect dagBounds = new Rect(mFirstRoot.getBounds()); final Rect taskBounds = new Rect(mFirstTask.getBounds()); final Rect activityBounds = new Rect(mFirstActivity.getBounds()); @@ -209,8 +211,10 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase { assertThat(activityConfigBounds.width()).isEqualTo(activityBounds.width()); assertThat(activityConfigBounds.height()).isEqualTo(activityBounds.height()); assertThat(activitySizeCompatBounds.height()).isEqualTo(newTaskBounds.height()); - assertThat(activitySizeCompatBounds.width()).isEqualTo( - newTaskBounds.height() * newTaskBounds.height() / newTaskBounds.width()); + final float defaultAspectRatio = mFirstActivity.mWmService.mLetterboxConfiguration + .getDefaultMinAspectRatioForUnresizableApps(); + assertEquals(activitySizeCompatBounds.width(), + newTaskBounds.height() / defaultAspectRatio, 0.5); } @Test @@ -230,8 +234,9 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase { assertThat(mFirstActivity.inSizeCompatMode()).isFalse(); assertThat(taskBounds).isEqualTo(dagBounds); assertThat(activityBounds.width()).isEqualTo(dagBounds.width()); - assertThat(activityBounds.height()) - .isEqualTo(dagBounds.width() * dagBounds.width() / dagBounds.height()); + final float defaultAspectRatio = mFirstActivity.mWmService.mLetterboxConfiguration + .getDefaultMinAspectRatioForUnresizableApps(); + assertEquals(activityBounds.height(), dagBounds.width() / defaultAspectRatio, 0.5); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 0240cc315e7b6..624dcbca39dbb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -1429,12 +1429,10 @@ public class SizeCompatTests extends WindowTestsBase { setUpDisplaySizeWithApp(2800, 1400); mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - // Portrait fixed app with min aspect ratio higher that aspect ratio override for fixed - // orientation letterbox. final float fixedOrientationLetterboxAspectRatio = 1.1f; mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio( fixedOrientationLetterboxAspectRatio); - prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); + prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_PORTRAIT, /* isUnresizable= */ false); final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds()); final Rect activityBounds = new Rect(mActivity.getBounds()); @@ -1454,6 +1452,37 @@ public class SizeCompatTests extends WindowTestsBase { activityBounds.width()); } + @Test + public void testDisplayIgnoreOrientationRequest_unresizableWithCorrespondingMinAspectRatio() { + // Set up a display in landscape and ignoring orientation request. + setUpDisplaySizeWithApp(2800, 1400); + mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + + final float fixedOrientationLetterboxAspectRatio = 1.1f; + mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio( + fixedOrientationLetterboxAspectRatio); + prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); + + final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds()); + final Rect activityBounds = new Rect(mActivity.getBounds()); + + // Display shouldn't be rotated. + assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, + mActivity.mDisplayContent.getLastOrientation()); + assertTrue(displayBounds.width() > displayBounds.height()); + + // App should launch in fixed orientation letterbox. + assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); + assertFalse(mActivity.inSizeCompatMode()); + + // Letterbox logic should use config_letterboxDefaultMinAspectRatioForUnresizableApps over + // config_fixedOrientationLetterboxAspectRatio. + assertEquals(displayBounds.height(), activityBounds.height()); + final float defaultAspectRatio = mActivity.mWmService.mLetterboxConfiguration + .getDefaultMinAspectRatioForUnresizableApps(); + assertEquals(displayBounds.height() / defaultAspectRatio, activityBounds.width(), 0.5); + } + @Test public void testDisplayIgnoreOrientationRequest_orientationLetterboxBecameSizeCompatAfterRotate() { @@ -1928,7 +1957,7 @@ public class SizeCompatTests extends WindowTestsBase { } @Test - public void testSupportsNonResizableInSplitScreen_fillTaskForSameOrientation() { + public void testSupportsNonResizableInSplitScreen_aspectRatioLetterboxInSameOrientation() { // Support non resizable in multi window mAtm.mDevEnableNonResizableMultiWindow = true; setUpDisplaySizeWithApp(1000, 2800); @@ -1966,7 +1995,12 @@ public class SizeCompatTests extends WindowTestsBase { // Activity bounds fill split screen. final Rect primarySplitBounds = new Rect(organizer.mPrimary.getBounds()); final Rect letterboxedBounds = new Rect(mActivity.getBounds()); - assertEquals(primarySplitBounds, letterboxedBounds); + // Activity is letterboxed for aspect ratio. + assertEquals(primarySplitBounds.height(), letterboxedBounds.height()); + final float defaultAspectRatio = mActivity.mWmService.mLetterboxConfiguration + .getDefaultMinAspectRatioForUnresizableApps(); + assertEquals(primarySplitBounds.height() / defaultAspectRatio, + letterboxedBounds.width(), 0.5); } @Test