From 06bb87d8fec3550f15d6617f9dc67c1cffe72402 Mon Sep 17 00:00:00 2001 From: Benjamin Franz Date: Mon, 16 Nov 2020 16:56:13 +0000 Subject: [PATCH] Per-app configuration for force resizing We're defining a new compat framework change id that indicates whether a given app should be force resized. This is treated the same as supportsSizeChanges metadata. Bug: 174042936 Test: atest WmTests:SizeCompatTests Change-Id: I6ef3ec11171140ca5a244f2185a3710d9fec7ae9 --- .../java/android/content/pm/ActivityInfo.java | 78 +++++++++++++++++++ .../com/android/server/wm/ActivityRecord.java | 7 +- services/tests/wmtests/Android.bp | 1 + .../android/server/wm/SizeCompatTests.java | 29 +++++++ 4 files changed, 111 insertions(+), 4 deletions(-) diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index ddcfb92ee4dff..b1ca12cde8577 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -18,6 +18,9 @@ package android.content.pm; import android.annotation.IntDef; import android.annotation.TestApi; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.Disabled; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Intent; @@ -27,6 +30,7 @@ import android.content.res.TypedArray; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import android.os.UserHandle; import android.util.Printer; import java.lang.annotation.Retention; @@ -865,6 +869,47 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { Configuration.NATIVE_CONFIG_COLOR_MODE, // COLOR_MODE }; + /** + * This change id forces the packages it is applied to to be resizable. We only allow resizing + * in fullscreen windowing mode, but not forcing the app into resizable multi-windowing mode. + * @hide + */ + @ChangeId + @Disabled + public static final long FORCE_RESIZE_APP = 174042936L; // number refers to buganizer id + + /** + * Return value for {@link #supportsSizeChanges()} indicating that this activity does not + * support size changes. + * @hide + */ + public static final int SIZE_CHANGES_UNSUPPORTED = 0; + + /** + * Return value for {@link #supportsSizeChanges()} indicating that this activity supports size + * changes due to the android.supports_size_changes metadata flag being set either on + * application or on activity level. + * @hide + */ + public static final int SIZE_CHANGES_SUPPORTED_METADATA = 1; + + /** + * Return value for {@link #supportsSizeChanges()} indicating that this activity has been + * overridden to support size changes through the compat framework change id + * {@link #FORCE_RESIZE_APP}. + * @hide + */ + public static final int SIZE_CHANGES_SUPPORTED_OVERRIDE = 2; + + /** @hide */ + @IntDef(prefix = { "SIZE_CHANGES_" }, value = { + SIZE_CHANGES_UNSUPPORTED, + SIZE_CHANGES_SUPPORTED_METADATA, + SIZE_CHANGES_SUPPORTED_OVERRIDE, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SizeChangesSupportMode {} + /** * Convert Java change bits to native. * @@ -1146,6 +1191,25 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { return (flags & FLAG_SUPPORTS_PICTURE_IN_PICTURE) != 0; } + /** + * Returns whether the activity supports size changes. + * @hide + */ + @SizeChangesSupportMode + public int supportsSizeChanges() { + if (supportsSizeChanges) { + return SIZE_CHANGES_SUPPORTED_METADATA; + } + + if (CompatChanges.isChangeEnabled(FORCE_RESIZE_APP, + applicationInfo.packageName, + UserHandle.getUserHandleForUid(applicationInfo.uid))) { + return SIZE_CHANGES_SUPPORTED_OVERRIDE; + } + + return SIZE_CHANGES_UNSUPPORTED; + } + /** @hide */ @UnsupportedAppUsage public static boolean isResizeableMode(int mode) { @@ -1186,6 +1250,20 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { } } + /** @hide */ + public static String sizeChangesSupportModeToString(@SizeChangesSupportMode int mode) { + switch (mode) { + case SIZE_CHANGES_UNSUPPORTED: + return "SIZE_CHANGES_UNSUPPORTED"; + case SIZE_CHANGES_SUPPORTED_METADATA: + return "SIZE_CHANGES_SUPPORTED_METADATA"; + case SIZE_CHANGES_SUPPORTED_OVERRIDE: + return "SIZE_CHANGES_SUPPORTED_OVERRIDE"; + default: + return "unknown=" + mode; + } + } + public void dump(Printer pw, String prefix) { dump(pw, prefix, DUMP_FLAG_ALL); } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index ef845c843c5f7..74e8b86ef046f 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1009,9 +1009,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (info.minAspectRatio != 0) { pw.println(prefix + "minAspectRatio=" + info.minAspectRatio); } - if (info.supportsSizeChanges) { - pw.println(prefix + "supportsSizeChanges=true"); - } + pw.println(prefix + "supportsSizeChanges=" + + ActivityInfo.sizeChangesSupportModeToString(info.supportsSizeChanges())); if (info.configChanges != 0) { pw.println(prefix + "configChanges=0x" + Integer.toHexString(info.configChanges)); } @@ -6539,7 +6538,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * aspect ratio. */ boolean shouldUseSizeCompatMode() { - if (info.supportsSizeChanges) { + if (info.supportsSizeChanges() != ActivityInfo.SIZE_CHANGES_UNSUPPORTED) { return false; } if (inMultiWindowMode() || getWindowConfiguration().hasWindowDecorCaption()) { diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp index 1ecf850adb1fc..cf977b4a18dba 100644 --- a/services/tests/wmtests/Android.bp +++ b/services/tests/wmtests/Android.bp @@ -47,6 +47,7 @@ android_test { "testables", "ub-uiautomator", "hamcrest-library", + "platform-compat-test-rules", ], libs: [ 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 c7175a0c424d6..e19024825b382 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -49,6 +49,8 @@ import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.TaskStackListener; import android.app.WindowConfiguration; +import android.compat.testing.PlatformCompatChangeRule; +import android.content.ComponentName; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Rect; @@ -58,7 +60,11 @@ import android.view.WindowManager; import androidx.test.filters.MediumTest; +import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; + +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TestRule; import org.junit.runner.RunWith; import java.util.ArrayList; @@ -73,6 +79,9 @@ import java.util.ArrayList; @Presubmit @RunWith(WindowTestRunner.class) public class SizeCompatTests extends WindowTestsBase { + @Rule + public TestRule compatChangeRule = new PlatformCompatChangeRule(); + private Task mTask; private ActivityRecord mActivity; @@ -534,6 +543,26 @@ public class SizeCompatTests extends WindowTestsBase { assertFalse(activity.shouldUseSizeCompatMode()); } + @Test + @EnableCompatChanges({ActivityInfo.FORCE_RESIZE_APP}) + public void testNoSizeCompatWhenPerAppOverrideSet() { + setUpDisplaySizeWithApp(1000, 2500); + + // Make the task root resizable. + mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE; + + // Create a size compat activity on the same task. + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setTask(mTask) + .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) + .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) + .setComponent(ComponentName.createRelative(mContext, + SizeCompatTests.class.getName())) + .setUid(android.os.Process.myUid()) + .build(); + assertFalse(activity.shouldUseSizeCompatMode()); + } + @Test public void testLaunchWithFixedRotationTransform() { final int dw = 1000;