diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 60ab83aa2264b..95c5612aeee47 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -1363,7 +1363,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { public boolean alwaysSandboxDisplayApis() { return CompatChanges.isChangeEnabled(ALWAYS_SANDBOX_DISPLAY_APIS, applicationInfo.packageName, - UserHandle.getUserHandleForUid(applicationInfo.uid)); + UserHandle.getUserHandleForUid(applicationInfo.uid)) + || ConstrainDisplayApisConfig.alwaysConstrainDisplayApis(applicationInfo); } /** @hide */ diff --git a/core/java/android/content/pm/ConstrainDisplayApisConfig.java b/core/java/android/content/pm/ConstrainDisplayApisConfig.java index 1337347cdaf02..11ba3d4ba9a29 100644 --- a/core/java/android/content/pm/ConstrainDisplayApisConfig.java +++ b/core/java/android/content/pm/ConstrainDisplayApisConfig.java @@ -46,6 +46,14 @@ public final class ConstrainDisplayApisConfig { private static final String FLAG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES = "never_constrain_display_apis_all_packages"; + /** + * A string flag whose value holds a comma separated list of package entries in the format + * ':?:?' for which Display APIs should + * always be constrained. + */ + private static final String FLAG_ALWAYS_CONSTRAIN_DISPLAY_APIS = + "always_constrain_display_apis"; + /** * Returns true if either the flag 'never_constrain_display_apis_all_packages' is true or the * flag 'never_constrain_display_apis' contains a package entry that matches the given {@code @@ -58,8 +66,30 @@ public final class ConstrainDisplayApisConfig { FLAG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES, /* defaultValue= */ false)) { return true; } + + return flagHasMatchingPackageEntry(FLAG_NEVER_CONSTRAIN_DISPLAY_APIS, applicationInfo); + } + + /** + * Returns true if the flag 'always_constrain_display_apis' contains a package entry that + * matches the given {@code applicationInfo}. + * + * @param applicationInfo Information about the application/package. + */ + public static boolean alwaysConstrainDisplayApis(ApplicationInfo applicationInfo) { + return flagHasMatchingPackageEntry(FLAG_ALWAYS_CONSTRAIN_DISPLAY_APIS, applicationInfo); + } + + /** + * Returns true if the flag with the given {@code flagName} contains a package entry that + * matches the given {@code applicationInfo}. + * + * @param applicationInfo Information about the application/package. + */ + private static boolean flagHasMatchingPackageEntry(String flagName, + ApplicationInfo applicationInfo) { String configStr = DeviceConfig.getString(NAMESPACE_CONSTRAIN_DISPLAY_APIS, - FLAG_NEVER_CONSTRAIN_DISPLAY_APIS, /* defaultValue= */ ""); + flagName, /* defaultValue= */ ""); // String#split returns a non-empty array given an empty string. if (configStr.isEmpty()) { diff --git a/core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java b/core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java index 1dfbfcd85a736..0456029f45a04 100644 --- a/core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java +++ b/core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java @@ -48,7 +48,8 @@ public final class ConstrainDisplayApisConfigTest { public void setUp() throws Exception { mInitialConstrainDisplayApisFlags = DeviceConfig.getProperties( NAMESPACE_CONSTRAIN_DISPLAY_APIS); - clearConstrainDisplayApisFlags(); + DeviceConfig.setProperties( + new Properties.Builder(NAMESPACE_CONSTRAIN_DISPLAY_APIS).build()); } @After @@ -120,6 +121,29 @@ public final class ConstrainDisplayApisConfigTest { testNeverConstrainDisplayApis("com.android.test5", /* version= */ 5, /* expected= */ true); } + @Test + public void alwaysConstrainDisplayApis_flagsNoSet_returnsFalse() { + testAlwaysConstrainDisplayApis("com.android.test", /* version= */ 1, /* expected= */ false); + } + + @Test + public void alwaysConstrainDisplayApis_flagHasEntries_returnsTrueForPackagesWithinRange() { + setAlwaysConstrainDisplayApisFlag("com.android.test1::,com.android.test2:1:2"); + + // Package 'com.android.other' + testAlwaysConstrainDisplayApis("com.android.other", /* version= */ 5, /* expected= */ + false); + // Package 'com.android.test1' + testAlwaysConstrainDisplayApis("com.android.test1", /* version= */ 5, /* expected= */ true); + // Package 'com.android.test2' + testAlwaysConstrainDisplayApis("com.android.test2", /* version= */ 0, /* expected= */ + false); + testAlwaysConstrainDisplayApis("com.android.test2", /* version= */ 1, /* expected= */ true); + testAlwaysConstrainDisplayApis("com.android.test2", /* version= */ 2, /* expected= */ true); + testAlwaysConstrainDisplayApis("com.android.test2", /* version= */ 3, /* expected= */ + false); + } + private static void testNeverConstrainDisplayApis(String packageName, long version, boolean expected) { boolean result = ConstrainDisplayApisConfig.neverConstrainDisplayApis( @@ -131,6 +155,17 @@ public final class ConstrainDisplayApisConfigTest { } } + private static void testAlwaysConstrainDisplayApis(String packageName, long version, + boolean expected) { + boolean result = ConstrainDisplayApisConfig.alwaysConstrainDisplayApis( + buildApplicationInfo(packageName, version)); + if (expected) { + assertTrue(result); + } else { + assertFalse(result); + } + } + private static ApplicationInfo buildApplicationInfo(String packageName, long version) { ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.packageName = packageName; @@ -149,8 +184,8 @@ public final class ConstrainDisplayApisConfigTest { value, /* makeDefault= */ false); } - private static void clearConstrainDisplayApisFlags() { - setNeverConstrainDisplayApisFlag(null); - setNeverConstrainDisplayApisAllPackagesFlag(null); + private static void setAlwaysConstrainDisplayApisFlag(@Nullable String value) { + DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, "always_constrain_display_apis", + value, /* makeDefault= */ false); } } 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 574a85469ba06..59894973521df 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -107,7 +107,8 @@ public class SizeCompatTests extends WindowTestsBase { public void setUp() throws Exception { mInitialConstrainDisplayApisFlags = DeviceConfig.getProperties( NAMESPACE_CONSTRAIN_DISPLAY_APIS); - clearConstrainDisplayApisFlags(); + DeviceConfig.setProperties( + new Properties.Builder(NAMESPACE_CONSTRAIN_DISPLAY_APIS).build()); } @After @@ -921,7 +922,7 @@ public class SizeCompatTests extends WindowTestsBase { @Test @DisableCompatChanges({ActivityInfo.ALWAYS_SANDBOX_DISPLAY_APIS}) - public void testAlwaysSandboxDisplayApis_configDisabled_sandboxingNotApplied() { + public void testAlwaysSandboxDisplayApis_configDisabled_sandboxingApplied() { setUpDisplaySizeWithApp(1000, 1200); // Make the task root resizable. @@ -933,7 +934,7 @@ public class SizeCompatTests extends WindowTestsBase { activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); - // Activity max bounds be sandboxed due to letterbox and the config being disabled. + // Activity max bounds should be sandboxed due to letterbox and the config being disabled. assertActivityMaxBoundsSandboxed(activity); } @@ -962,6 +963,27 @@ public class SizeCompatTests extends WindowTestsBase { assertActivityMaxBoundsSandboxed(activity); } + @Test + public void testAlwaysConstrainDisplayApisDeviceConfig_packageInRange_sandboxingApplied() { + setUpDisplaySizeWithApp(1000, 1200); + + setAlwaysConstrainDisplayApisFlag( + "com.android.frameworks.wmtests:20:,com.android.other::," + + "com.android.frameworks.wmtests:0:10"); + + // Make the task root resizable. + mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; + + // Create an activity with a max aspect ratio on the same task. + final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, + RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); + activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); + + // Resizable activity is sandboxed due to match with flag. + assertActivityMaxBoundsSandboxed(activity); + } + @Test @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) @@ -2142,8 +2164,8 @@ public class SizeCompatTests extends WindowTestsBase { value, /* makeDefault= */ false); } - private static void clearConstrainDisplayApisFlags() { - setNeverConstrainDisplayApisFlag(null); - setNeverConstrainDisplayApisAllPackagesFlag(null); + private static void setAlwaysConstrainDisplayApisFlag(@Nullable String value) { + DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, "always_constrain_display_apis", + value, /* makeDefault= */ false); } }