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
This commit is contained in:
Mariia Sandrikova
2022-05-16 20:43:41 +00:00
parent c46e9f6947
commit 4c996a74e0
8 changed files with 160 additions and 12 deletions

View File

@@ -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>

View File

@@ -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" />

View File

@@ -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;
}
/**

View File

@@ -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

View File

@@ -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";
}

View File

@@ -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");

View File

@@ -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

View File

@@ -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