From 4674792ad663d1db723ad1a1dfc882eb9a515602 Mon Sep 17 00:00:00 2001 From: tomnatan Date: Fri, 15 Oct 2021 15:15:49 +0000 Subject: [PATCH] Apply min aspect ratio override only for portrait only activities This only affects the min aspect ratio override, developers can still set min aspect ratio in the manifest regadless of whether the app is fixed to portrait. This change is needed since applying the override on activities that aren't fixed to portrait results in unintended behavior (see bug for more context). Fix: 202842551 Test: atest WmTests:SizeCompatTests Change-Id: Iebd8edf1fc43ee892aea78715c9b217950df5a3b --- .../java/android/content/pm/ActivityInfo.java | 26 ++++-- .../com/android/server/wm/ActivityRecord.java | 31 +++++-- .../server/wm/TaskLaunchParamsModifier.java | 2 +- .../parsing/AndroidPackageParsingTestBase.kt | 2 - .../android/server/wm/SizeCompatTests.java | 92 +++++++++++++++++++ 5 files changed, 132 insertions(+), 21 deletions(-) diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 95c5612aeee47..e28e4ad9ae9f4 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -994,9 +994,10 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { * OVERRIDE_MIN_ASPECT_RATIO_MEDIUM * OVERRIDE_MIN_ASPECT_RATIO_LARGE * - * If OVERRIDE_MIN_ASPECT_RATIO is applied, the min aspect ratio given in the app's - * manifest will be overridden to the largest enabled aspect ratio treatment unless the app's - * manifest value is higher. + * If OVERRIDE_MIN_ASPECT_RATIO is applied, and the activity's orientation is fixed to + * portrait, the min aspect ratio given in the app's manifest will be overridden to the + * largest enabled aspect ratio treatment unless the app's manifest value is higher. + * TODO(b/203647190): add OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY instead of portrait by default * @hide */ @ChangeId @@ -1232,8 +1233,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { * Returns true if the activity has maximum or minimum aspect ratio. * @hide */ - public boolean hasFixedAspectRatio() { - return getMaxAspectRatio() != 0 || getMinAspectRatio() != 0; + public boolean hasFixedAspectRatio(@ScreenOrientation int orientation) { + return getMaxAspectRatio() != 0 || getMinAspectRatio(orientation) != 0; } /** @@ -1392,10 +1393,14 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { * {@code getManifestMinAspectRatio}. * @hide */ - public float getMinAspectRatio() { + public float getMinAspectRatio(@ScreenOrientation int orientation) { + // TODO(b/203647190): check orientation only if OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY + // In case the activity's orientation isn't fixed to portrait, OVERRIDE_MIN_ASPECT_RATIO + // shouldn't be applied. if (applicationInfo == null || !CompatChanges.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO, applicationInfo.packageName, - UserHandle.getUserHandleForUid(applicationInfo.uid))) { + UserHandle.getUserHandleForUid(applicationInfo.uid)) + || !isFixedOrientationPortrait(orientation)) { return mMinAspectRatio; } @@ -1521,9 +1526,10 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { if (getMaxAspectRatio() != 0) { pw.println(prefix + "maxAspectRatio=" + getMaxAspectRatio()); } - if (getMinAspectRatio() != 0) { - pw.println(prefix + "minAspectRatio=" + getMinAspectRatio()); - if (getManifestMinAspectRatio() != getMinAspectRatio()) { + final float minAspectRatio = getMinAspectRatio(screenOrientation); + if (minAspectRatio != 0) { + pw.println(prefix + "minAspectRatio=" + minAspectRatio); + if (getManifestMinAspectRatio() != minAspectRatio) { pw.println(prefix + "getManifestMinAspectRatio=" + getManifestMinAspectRatio()); } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 95f96066010df..7dd165b75bfc9 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1145,10 +1145,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (info.getMaxAspectRatio() != 0) { pw.println(prefix + "maxAspectRatio=" + info.getMaxAspectRatio()); } - if (info.getMinAspectRatio() != 0) { - pw.println(prefix + "minAspectRatio=" + info.getMinAspectRatio()); + final float minAspectRatio = getMinAspectRatio(); + if (minAspectRatio != 0) { + pw.println(prefix + "minAspectRatio=" + minAspectRatio); } - if (info.getMinAspectRatio() != info.getManifestMinAspectRatio()) { + if (minAspectRatio != info.getManifestMinAspectRatio()) { // Log the fact that we've overridden the min aspect ratio from the manifest pw.println(prefix + "manifestMinAspectRatio=" + info.getManifestMinAspectRatio()); @@ -7272,7 +7273,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return false; } } - return !isResizeable() && (info.isFixedOrientation() || info.hasFixedAspectRatio()) + return !isResizeable() && (info.isFixedOrientation() || hasFixedAspectRatio()) // The configuration of non-standard type should be enforced by system. // {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} is set when this activity is // added to a task, but this function is called when resolving the launch params, at @@ -7940,13 +7941,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return false; } } - if (info.getMinAspectRatio() > 0) { + final float minAspectRatio = getMinAspectRatio(); + if (minAspectRatio > 0) { // The activity should have at least the min aspect ratio, so this checks if the // container still has available space to provide larger aspect ratio. final float containerAspectRatio = (0.5f + Math.max(containerAppWidth, containerAppHeight)) / Math.min(containerAppWidth, containerAppHeight); - if (containerAspectRatio <= info.getMinAspectRatio()) { + if (containerAspectRatio <= minAspectRatio) { // The long side has reached the parent. return false; } @@ -8157,8 +8159,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A Rect containingBounds, float desiredAspectRatio, boolean fixedOrientationLetterboxed) { final float maxAspectRatio = info.getMaxAspectRatio(); final Task rootTask = getRootTask(); - final float minAspectRatio = info.getMinAspectRatio(); - + final float minAspectRatio = getMinAspectRatio(); if (task == null || rootTask == null || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets() && !fixedOrientationLetterboxed) @@ -8261,6 +8262,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return true; } + /** + * Returns the min aspect ratio of this activity. + */ + private float getMinAspectRatio() { + return info.getMinAspectRatio(getRequestedOrientation()); + } + + /** + * Returns true if the activity has maximum or minimum aspect ratio. + */ + private boolean hasFixedAspectRatio() { + return info.hasFixedAspectRatio(getRequestedOrientation()); + } + /** * Returns the aspect ratio of the given {@code rect}. */ diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index d543c1f756c94..b8ceb4a4f421b 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -818,7 +818,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { final int layoutMinHeight = (layout == null) ? -1 : layout.minHeight; // Aspect ratio requirements. - final float minAspectRatio = info.getMinAspectRatio(); + final float minAspectRatio = info.getMinAspectRatio(orientation); final float maxAspectRatio = info.getMaxAspectRatio(); final int width = Math.min(defaultWidth, Math.max(phoneWidth, layoutMinWidth)); diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt index 581ff5472e92e..9099bb5153611 100644 --- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt @@ -341,10 +341,8 @@ open class AndroidPackageParsingTestBase { launchToken=${this.launchToken} lockTaskLaunchMode=${this.lockTaskLaunchMode} logo=${this.logo} - maxAspectRatio=${this.maxAspectRatio} maxRecents=${this.maxRecents} metaData=${this.metaData.dumpToString()} - minAspectRatio=${this.minAspectRatio} name=${this.name} nonLocalizedLabel=${ // Per b/184574333, v1 mistakenly trimmed the label. v2 fixed this, but for 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 6407c92ee2aa8..95ca4565440db 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -1118,6 +1118,98 @@ public class SizeCompatTests extends WindowTestsBase { activity.getBounds().width(), 0.5); } + @Test + @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, + ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) + public void testOverrideMinAspectRatioScreenOrientationNotSetThenChangedToPortrait() { + // In this test, the activity's orientation isn't fixed to portrait, therefore the override + // isn't applied. + + setUpDisplaySizeWithApp(1000, 1200); + + // Create a size compat activity on the same task. + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setTask(mTask) + .setComponent(ComponentName.createRelative(mContext, + SizeCompatTests.class.getName())) + .setUid(android.os.Process.myUid()) + .build(); + + // The per-package override should have no effect + assertEquals(1200, activity.getBounds().height()); + assertEquals(1000, activity.getBounds().width()); + + // After changing the orientation to portrait the override should be applied. + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + activity.clearSizeCompatMode(); + + // The per-package override forces the activity into a 3:2 aspect ratio + assertEquals(1200, activity.getBounds().height()); + assertEquals(1200 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE, + activity.getBounds().width(), 0.5); + } + + @Test + @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, + ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) + public void testOverrideMinAspectRatioScreenOrientationLandscapeThenChangedToPortrait() { + // In this test, the activity's orientation isn't fixed to portrait, therefore the override + // isn't applied. + + setUpDisplaySizeWithApp(1000, 1200); + + // Create a size compat activity on the same task. + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setTask(mTask) + .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) + .setComponent(ComponentName.createRelative(mContext, + SizeCompatTests.class.getName())) + .setUid(android.os.Process.myUid()) + .build(); + + // The per-package override should have no effect + assertEquals(1200, activity.getBounds().height()); + assertEquals(1000, activity.getBounds().width()); + + // After changing the orientation to portrait the override should be applied. + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + activity.clearSizeCompatMode(); + + // The per-package override forces the activity into a 3:2 aspect ratio + assertEquals(1200, activity.getBounds().height()); + assertEquals(1200 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE, + activity.getBounds().width(), 0.5); + } + + @Test + @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, + ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) + public void testOverrideMinAspectRatioScreenOrientationPortraitThenChangedToUnspecified() { + setUpDisplaySizeWithApp(1000, 1200); + + // Create a size compat activity on the same task. + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setTask(mTask) + .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) + .setComponent(ComponentName.createRelative(mContext, + SizeCompatTests.class.getName())) + .setUid(android.os.Process.myUid()) + .build(); + + // The per-package override forces the activity into a 3:2 aspect ratio + assertEquals(1200, activity.getBounds().height()); + assertEquals(1200 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE, + activity.getBounds().width(), 0.5); + + // After changing the orientation to landscape the override shouldn't be applied. + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); + activity.clearSizeCompatMode(); + + // The per-package override should have no effect + assertEquals(1200, activity.getBounds().height()); + assertEquals(1000, activity.getBounds().width()); + } + @Test @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) public void testOverrideMinAspectRatioWithoutGlobalOverride() {