Adjust smallestScreenWidthDp for letterbox

By definition, smallestScreenWidthDp is the smallest value of both screenWidthDp and screenHeightDp. When a different value is reported in smallestScreenWidthDp, the app can load incorrect layout.

Test: atest WmTests:SizeCompatTests
Fix: 232406936
Change-Id: Ie0d7767fba03cc07e21e3624d9d8c5b0ea13dff1
This commit is contained in:
Mariia Sandrikova
2022-07-06 16:22:43 +00:00
parent 91079f446e
commit ea12f9a7a1
4 changed files with 101 additions and 18 deletions

View File

@@ -7737,9 +7737,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// relatively fixed.
overrideConfig.colorMode = fullConfig.colorMode;
overrideConfig.densityDpi = fullConfig.densityDpi;
// The smallest screen width is the short side of screen bounds. Because the bounds
// and density won't be changed, smallestScreenWidthDp is also fixed.
overrideConfig.smallestScreenWidthDp = fullConfig.smallestScreenWidthDp;
if (info.isFixedOrientation()) {
// lock rotation too. When in size-compat, onConfigurationChanged will watch for and
// apply runtime rotation changes.
@@ -7836,7 +7833,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// computed accordingly.
if (!matchParentBounds()) {
getTaskFragment().computeConfigResourceOverrides(resolvedConfig,
newParentConfiguration);
newParentConfiguration, areBoundsLetterboxed());
}
// If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
// are already calculated in resolveFixedOrientationConfiguration.
@@ -8007,7 +8004,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
// Since bounds has changed, the configuration needs to be computed accordingly.
getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
areBoundsLetterboxed());
}
void recomputeConfiguration() {
@@ -8223,7 +8221,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Calculate app bounds using fixed orientation bounds because they will be needed later
// for comparison with size compat app bounds in {@link resolveSizeCompatModeConfiguration}.
getTaskFragment().computeConfigResourceOverrides(getResolvedOverrideConfiguration(),
newParentConfig);
newParentConfig, mCompatDisplayInsets, areBoundsLetterboxed());
mLetterboxBoundsForFixedOrientationAndAspectRatio = new Rect(resolvedBounds);
}
@@ -8251,7 +8249,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Compute the configuration based on the resolved bounds. If aspect ratio doesn't
// restrict, the bounds should be the requested override bounds.
getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
getFixedRotationTransformDisplayInfo());
getFixedRotationTransformDisplayInfo(), areBoundsLetterboxed());
}
}
@@ -8315,7 +8313,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// are calculated in compat container space. The actual position on screen will be applied
// later, so the calculation is simpler that doesn't need to involve offset from parent.
getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
mCompatDisplayInsets);
mCompatDisplayInsets, areBoundsLetterboxed());
// Use current screen layout as source because the size of app is independent to parent.
resolvedConfig.screenLayout = TaskFragment.computeScreenLayoutOverride(
getConfiguration().screenLayout, resolvedConfig.screenWidthDp,

View File

@@ -1957,29 +1957,37 @@ class TaskFragment extends WindowContainer<WindowContainer> {
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@NonNull Configuration parentConfig) {
computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
null /* compatInsets */);
null /* compatInsets */, false /* areBoundsLetterboxed */);
}
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo) {
@NonNull Configuration parentConfig, boolean areBoundsLetterboxed) {
computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
null /* compatInsets */, areBoundsLetterboxed);
}
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
boolean areBoundsLetterboxed) {
if (overrideDisplayInfo != null) {
// Make sure the screen related configs can be computed by the provided display info.
inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
invalidateAppBoundsConfig(inOutConfig);
}
computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo,
null /* compatInsets */);
null /* compatInsets */, areBoundsLetterboxed);
}
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@NonNull Configuration parentConfig,
@Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
@Nullable ActivityRecord.CompatDisplayInsets compatInsets,
boolean areBoundsLetterboxed) {
if (compatInsets != null) {
// Make sure the app bounds can be computed by the compat insets.
invalidateAppBoundsConfig(inOutConfig);
}
computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
compatInsets);
compatInsets, areBoundsLetterboxed);
}
/**
@@ -2006,7 +2014,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
**/
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
@Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
@Nullable ActivityRecord.CompatDisplayInsets compatInsets,
boolean areBoundsLetterboxed) {
int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
if (windowingMode == WINDOWING_MODE_UNDEFINED) {
windowingMode = parentConfig.windowConfiguration.getWindowingMode();
@@ -2113,6 +2122,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
: overrideScreenHeightDp;
}
// TODO(b/238331848): Consider simplifying logic that computes smallestScreenWidthDp.
if (inOutConfig.smallestScreenWidthDp
== Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
// When entering to or exiting from Pip, the PipTaskOrganizer will set the
@@ -2128,9 +2138,10 @@ class TaskFragment extends WindowContainer<WindowContainer> {
// task, because they should not be affected by insets.
inOutConfig.smallestScreenWidthDp = (int) (0.5f
+ Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
} else if (isEmbedded()) {
// For embedded TFs, the smallest width should be updated. Otherwise, inherit
// from the parent task would result in applications loaded wrong resource.
} else if (isEmbedded() || areBoundsLetterboxed || customContainerPolicy) {
// For embedded TFs and activities that are letteboxed or eligible for size
// compat mode, the smallest width should be updated. Otherwise, inherit from
// the parent task would result in applications loaded wrong resource.
inOutConfig.smallestScreenWidthDp =
Math.min(inOutConfig.screenWidthDp, inOutConfig.screenHeightDp);
}

View File

@@ -1495,6 +1495,79 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(displayBounds.height() / defaultAspectRatio, activityBounds.width(), 0.5);
}
@Test
public void testComputeConfigResourceOverrides_unresizableApp() {
// Set up a display in landscape and ignoring orientation request.
setUpDisplaySizeWithApp(2800, 1400);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
final Rect activityBounds = new Rect(mActivity.getBounds());
int originalScreenWidthDp = mActivity.getConfiguration().screenWidthDp;
int originalScreenHeighthDp = mActivity.getConfiguration().screenHeightDp;
// App should launch in fixed orientation letterbox.
// Activity bounds should be 700x1400 with the ratio as the display.
assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFitted();
assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
assertTrue(originalScreenWidthDp < originalScreenHeighthDp);
// Rotate display to portrait.
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
// After we rotate, the activity should go in the size-compat mode and report the same
// configuration values.
assertScaled();
assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
assertEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp);
assertEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp);
// Restart activity
mActivity.restartProcessIfVisible();
// Now configuration should be updated
assertFitted();
assertNotEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp);
assertNotEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp);
assertEquals(mActivity.getConfiguration().screenWidthDp,
mActivity.getConfiguration().smallestScreenWidthDp);
}
@Test
public void testComputeConfigResourceOverrides_resizableFixedOrientationActivity() {
// Set up a display in landscape and ignoring orientation request.
setUpDisplaySizeWithApp(2800, 1400);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
// Portrait fixed app without max aspect.
prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_PORTRAIT, false /* isUnresizable */);
final Rect activityBounds = new Rect(mActivity.getBounds());
int originalScreenWidthDp = mActivity.getConfiguration().screenWidthDp;
int originalScreenHeighthDp = mActivity.getConfiguration().screenHeightDp;
// App should launch in fixed orientation letterbox.
// Activity bounds should be 700x1400 with the ratio as the display.
assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFitted();
assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
assertTrue(originalScreenWidthDp < originalScreenHeighthDp);
// Rotate display to portrait.
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
// Now configuration should be updated
assertFitted();
assertNotEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp);
assertNotEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp);
assertEquals(mActivity.getConfiguration().screenWidthDp,
mActivity.getConfiguration().smallestScreenWidthDp);
}
@Test
public void testSplitAspectRatioForUnresizablePortraitApps() {
// Set up a display in landscape and ignoring orientation request.

View File

@@ -691,7 +691,8 @@ public class TaskTests extends WindowTestsBase {
final ActivityRecord.CompatDisplayInsets compatInsets =
new ActivityRecord.CompatDisplayInsets(
display, activity, /* fixedOrientationBounds= */ null);
task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatInsets);
task.computeConfigResourceOverrides(
inOutConfig, parentConfig, compatInsets, /* areBoundsLetterboxed */ true);
assertEquals(largerLandscapeBounds, inOutConfig.windowConfiguration.getAppBounds());
final float density = parentConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;