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
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3acd171..66689ca 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5176,6 +5176,12 @@
<!-- Whether displaying letterbox education is enabled for letterboxed fullscreen apps. -->
<bool name="config_letterboxIsEducationEnabled">false</bool>
+ <!-- Default min aspect ratio for unresizable apps which is used when an app doesn't specify
+ android:minAspectRatio in accordance with CDD 7.1.1.2 requirement:
+ https://source.android.com/compatibility/12/android-12-cdd#7112_screen_aspect_ratio.
+ An exception will be thrown if the given aspect ratio < 4:3. -->
+ <item name="config_letterboxDefaultMinAspectRatioForUnresizableApps" format="float" type="dimen">1.5</item>
+
<!-- Whether a camera compat controller is enabled to allow the user to apply or revert
treatment for stretched issues in camera viewfinder. -->
<bool name="config_isCameraCompatControlForStretchedIssuesEnabled">false</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3c03b41..49be0b8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4395,6 +4395,7 @@
<java-symbol type="integer" name="config_letterboxDefaultPositionForHorizontalReachability" />
<java-symbol type="integer" name="config_letterboxDefaultPositionForVerticalReachability" />
<java-symbol type="bool" name="config_letterboxIsEducationEnabled" />
+ <java-symbol type="dimen" name="config_letterboxDefaultMinAspectRatioForUnresizableApps" />
<java-symbol type="bool" name="config_isCameraCompatControlForStretchedIssuesEnabled" />
<java-symbol type="bool" name="config_hideDisplayCutoutWithDisplayArea" />
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index e700103..328f55f 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 @@
// 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 @@
return mLetterboxBoundsForFixedOrientationAndAspectRatio != null;
}
+ boolean isAspectRatioApplied() {
+ return mIsAspectRatioApplied;
+ }
+
/**
* Whether this activity is eligible for letterbox eduction.
*
@@ -8632,7 +8635,18 @@
* 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 2c7540b..b931f79 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 @@
*/
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 @@
// 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 @@
mLetterboxPositionForVerticalReachability = mDefaultPositionForVerticalReachability;
mIsEducationEnabled = mContext.getResources().getBoolean(
R.bool.config_letterboxIsEducationEnabled);
+ setDefaultMinAspectRatioForUnresizableApps(mContext.getResources().getFloat(
+ R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps));
}
/**
@@ -233,6 +245,43 @@
}
/**
+ * 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
* com.android.internal.R.integer.config_letterboxActivityCornersRadius} will be ignored and
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 2015206..9dbc477 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 @@
pw.println(prefix + " fixedOrientationLetterboxAspectRatio="
+ getFixedOrientationLetterboxAspectRatio(
mActivityRecord.getParent().getConfiguration()));
+ pw.println(prefix + " defaultMinAspectRatioForUnresizableApps="
+ + mLetterboxConfiguration.getDefaultMinAspectRatioForUnresizableApps());
}
/**
@@ -556,6 +558,9 @@
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 8a6a4df..79c6ee7 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 @@
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 @@
case "--aspectRatio":
runSetFixedOrientationLetterboxAspectRatio(pw);
break;
+ case "--minAspectRatioForUnresizable":
+ runSetDefaultMinAspectRatioForUnresizableApps(pw);
+ break;
case "--cornerRadius":
runSetLetterboxActivityCornersRadius(pw);
break;
@@ -998,6 +1021,9 @@
case "aspectRatio":
mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio();
break;
+ case "minAspectRatioForUnresizable":
+ mLetterboxConfiguration.resetDefaultMinAspectRatioForUnresizableApps();
+ break;
case "cornerRadius":
mLetterboxConfiguration.resetLetterboxActivityCornersRadius();
break;
@@ -1121,6 +1147,7 @@
private void resetLetterboxStyle() {
synchronized (mInternal.mGlobalLock) {
mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio();
+ mLetterboxConfiguration.resetDefaultMinAspectRatioForUnresizableApps();
mLetterboxConfiguration.resetLetterboxActivityCornersRadius();
mLetterboxConfiguration.resetLetterboxBackgroundType();
mLetterboxConfiguration.resetLetterboxBackgroundColor();
@@ -1145,6 +1172,8 @@
+ 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 @@
+ 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 dbb7fae..db3a51c 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.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 @@
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 @@
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 @@
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 0240cc3..624dcbc 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 @@
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());
@@ -1455,6 +1453,37 @@
}
@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() {
// Set up a display in landscape and ignoring orientation request.
@@ -1928,7 +1957,7 @@
}
@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 @@
// 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