Per-app config for split screen aspect ratio
We're defining a new compat framework change id that indicates whether a given app should use the split screen aspect ratio. Test: As manual testing use 'adb shell am compat disable/enable 208648326 <package-name>'. For the unit tests run 'atest WmTests:SizeCompatTests'. Fixes: 208648326 Change-Id: I0232d6d98b10e546b840c08ffbf6e7be9c465965 Merged-In: I0232d6d98b10e546b840c08ffbf6e7be9c465965
This commit is contained in:
@@ -1108,6 +1108,16 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
|
||||
@TestApi
|
||||
public static final float OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE = 16 / 9f;
|
||||
|
||||
/**
|
||||
* Enables the use of split screen aspect ratio. This allows an app to use all the available
|
||||
* space in split mode avoiding letterboxing.
|
||||
* @hide
|
||||
*/
|
||||
@ChangeId
|
||||
@Disabled
|
||||
@Overridable
|
||||
public static final long OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN = 208648326L;
|
||||
|
||||
/**
|
||||
* Compares activity window layout min width/height with require space for multi window to
|
||||
* determine if it can be put into multi window mode.
|
||||
@@ -1317,8 +1327,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
|
||||
* Returns true if the activity has maximum or minimum aspect ratio.
|
||||
* @hide
|
||||
*/
|
||||
public boolean hasFixedAspectRatio(@ScreenOrientation int orientation) {
|
||||
return getMaxAspectRatio() != 0 || getMinAspectRatio(orientation) != 0;
|
||||
public boolean hasFixedAspectRatio() {
|
||||
return getMaxAspectRatio() != 0 || getMinAspectRatio() != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1460,30 +1470,10 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the min aspect ratio of this activity.
|
||||
*
|
||||
* This takes into account the minimum aspect ratio as defined in the app's manifest and
|
||||
* possible overrides as per OVERRIDE_MIN_ASPECT_RATIO.
|
||||
*
|
||||
* In the rare cases where the manifest minimum aspect ratio is required, use
|
||||
* {@code getManifestMinAspectRatio}.
|
||||
* Returns the min aspect ratio of this activity as defined in the manifest file.
|
||||
* @hide
|
||||
*/
|
||||
public float getMinAspectRatio(@ScreenOrientation int orientation) {
|
||||
if (applicationInfo == null || !isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO) || (
|
||||
isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
|
||||
&& !isFixedOrientationPortrait(orientation))) {
|
||||
return mMinAspectRatio;
|
||||
}
|
||||
|
||||
if (isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_LARGE)) {
|
||||
return Math.max(OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, mMinAspectRatio);
|
||||
}
|
||||
|
||||
if (isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_MEDIUM)) {
|
||||
return Math.max(OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE, mMinAspectRatio);
|
||||
}
|
||||
|
||||
public float getMinAspectRatio() {
|
||||
return mMinAspectRatio;
|
||||
}
|
||||
|
||||
@@ -1512,7 +1502,13 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isChangeEnabled(long changeId) {
|
||||
/**
|
||||
* Checks if a changeId is enabled for the current user
|
||||
* @param changeId The changeId to verify
|
||||
* @return True of the changeId is enabled
|
||||
* @hide
|
||||
*/
|
||||
public boolean isChangeEnabled(long changeId) {
|
||||
return CompatChanges.isChangeEnabled(changeId, applicationInfo.packageName,
|
||||
UserHandle.getUserHandleForUid(applicationInfo.uid));
|
||||
}
|
||||
@@ -1633,12 +1629,9 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
|
||||
if (getMaxAspectRatio() != 0) {
|
||||
pw.println(prefix + "maxAspectRatio=" + getMaxAspectRatio());
|
||||
}
|
||||
final float minAspectRatio = getMinAspectRatio(screenOrientation);
|
||||
final float minAspectRatio = getMinAspectRatio();
|
||||
if (minAspectRatio != 0) {
|
||||
pw.println(prefix + "minAspectRatio=" + minAspectRatio);
|
||||
if (getManifestMinAspectRatio() != minAspectRatio) {
|
||||
pw.println(prefix + "getManifestMinAspectRatio=" + getManifestMinAspectRatio());
|
||||
}
|
||||
}
|
||||
if (supportsSizeChanges) {
|
||||
pw.println(prefix + "supportsSizeChanges=true");
|
||||
|
||||
@@ -78,6 +78,11 @@ import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
|
||||
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
|
||||
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
|
||||
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY;
|
||||
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN;
|
||||
import static android.content.pm.ActivityInfo.PERSIST_ACROSS_REBOOTS;
|
||||
import static android.content.pm.ActivityInfo.PERSIST_ROOT_ONLY;
|
||||
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
|
||||
@@ -8759,15 +8764,35 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
/**
|
||||
* Returns the min aspect ratio of this activity.
|
||||
*/
|
||||
private float getMinAspectRatio() {
|
||||
return info.getMinAspectRatio(getRequestedOrientation());
|
||||
float getMinAspectRatio() {
|
||||
if (info.applicationInfo == null || !info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO) || (
|
||||
info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
|
||||
&& !ActivityInfo.isFixedOrientationPortrait(getRequestedOrientation()))) {
|
||||
return info.getMinAspectRatio();
|
||||
}
|
||||
|
||||
if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN)) {
|
||||
return Math.max(mLetterboxUiController.getSplitScreenAspectRatio(),
|
||||
info.getMinAspectRatio());
|
||||
}
|
||||
|
||||
if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_LARGE)) {
|
||||
return Math.max(ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
|
||||
info.getMinAspectRatio());
|
||||
}
|
||||
|
||||
if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_MEDIUM)) {
|
||||
return Math.max(ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE,
|
||||
info.getMinAspectRatio());
|
||||
}
|
||||
return info.getMinAspectRatio();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the activity has maximum or minimum aspect ratio.
|
||||
*/
|
||||
private boolean hasFixedAspectRatio() {
|
||||
return info.hasFixedAspectRatio(getRequestedOrientation());
|
||||
return info.getMaxAspectRatio() != 0 || getMinAspectRatio() != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -257,6 +257,10 @@ final class LetterboxUiController {
|
||||
: mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
|
||||
}
|
||||
|
||||
return getSplitScreenAspectRatio();
|
||||
}
|
||||
|
||||
float getSplitScreenAspectRatio() {
|
||||
int dividerWindowWidth =
|
||||
getResources().getDimensionPixelSize(R.dimen.docked_stack_divider_thickness);
|
||||
int dividerInsets =
|
||||
|
||||
@@ -731,7 +731,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
|
||||
}
|
||||
|
||||
// First we get the default size we want.
|
||||
getDefaultFreeformSize(root.info, displayArea, layout, orientation, mTmpBounds);
|
||||
getDefaultFreeformSize(root, displayArea, layout, orientation, mTmpBounds);
|
||||
if (hasInitialBounds || sizeMatches(inOutBounds, mTmpBounds)) {
|
||||
// We're here because either input parameters specified initial bounds, or the suggested
|
||||
// bounds have the same size of the default freeform size. We should use the suggested
|
||||
@@ -799,7 +799,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
|
||||
return orientation;
|
||||
}
|
||||
|
||||
private void getDefaultFreeformSize(@NonNull ActivityInfo info,
|
||||
private void getDefaultFreeformSize(@NonNull ActivityRecord activityRecord,
|
||||
@NonNull TaskDisplayArea displayArea,
|
||||
@NonNull ActivityInfo.WindowLayout layout, int orientation, @NonNull Rect bounds) {
|
||||
// Default size, which is letterboxing/pillarboxing in displayArea. That's to say the large
|
||||
@@ -807,6 +807,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
|
||||
// dimension of default size is calculated to keep the same aspect ratio as the
|
||||
// displayArea's. Here we use stable bounds of displayArea because that indicates the area
|
||||
// that isn't occupied by system widgets (e.g. sysbar and navbar).
|
||||
final ActivityInfo info = activityRecord.info;
|
||||
final Rect stableBounds = mTmpStableBounds;
|
||||
displayArea.getStableRect(stableBounds);
|
||||
final int portraitHeight = Math.min(stableBounds.width(), stableBounds.height());
|
||||
@@ -832,7 +833,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
|
||||
final int layoutMinHeight = (layout == null) ? -1 : layout.minHeight;
|
||||
|
||||
// Aspect ratio requirements.
|
||||
final float minAspectRatio = info.getMinAspectRatio(orientation);
|
||||
final float minAspectRatio = activityRecord.getMinAspectRatio();
|
||||
final float maxAspectRatio = info.getMaxAspectRatio();
|
||||
|
||||
final int width = Math.min(defaultWidth, Math.max(phoneWidth, layoutMinWidth));
|
||||
|
||||
@@ -97,12 +97,12 @@ import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
|
||||
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
/**
|
||||
* Tests for Size Compatibility mode.
|
||||
@@ -663,7 +663,7 @@ public class SizeCompatTests extends WindowTestsBase {
|
||||
final ActivityRecord activity = new ActivityBuilder(mAtm)
|
||||
.setTask(mTask)
|
||||
.setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
|
||||
.setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
|
||||
.setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
|
||||
.build();
|
||||
assertFalse(activity.shouldCreateCompatDisplayInsets());
|
||||
|
||||
@@ -1537,6 +1537,108 @@ public class SizeCompatTests extends WindowTestsBase {
|
||||
assertFitted();
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
|
||||
ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN})
|
||||
public void testOverrideSplitScreenAspectRatioForUnresizablePortraitApps() {
|
||||
final int displayWidth = 1400;
|
||||
final int displayHeight = 1600;
|
||||
setUpDisplaySizeWithApp(displayWidth, displayHeight);
|
||||
final ActivityRecord activity = new ActivityBuilder(mAtm)
|
||||
.setTask(mTask)
|
||||
.setComponent(ComponentName.createRelative(mContext,
|
||||
SizeCompatTests.class.getName()))
|
||||
.setMinAspectRatio(1.1f)
|
||||
.setUid(android.os.Process.myUid())
|
||||
.build();
|
||||
// Setup Letterbox Configuration
|
||||
activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
|
||||
activity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.5f);
|
||||
// Non-resizable portrait activity
|
||||
prepareUnresizable(activity, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
float expectedAspectRatio = 1f * displayWidth / getExpectedSplitSize(displayHeight);
|
||||
final Rect afterBounds = activity.getBounds();
|
||||
final float afterAspectRatio = (float) (afterBounds.height()) / afterBounds.width();
|
||||
Assert.assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
|
||||
ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN})
|
||||
public void testOverrideSplitScreenAspectRatioForUnresizablePortraitAppsFromLandscape() {
|
||||
final int displayWidth = 1600;
|
||||
final int displayHeight = 1400;
|
||||
setUpDisplaySizeWithApp(displayWidth, displayHeight);
|
||||
final ActivityRecord activity = new ActivityBuilder(mAtm)
|
||||
.setTask(mTask)
|
||||
.setComponent(ComponentName.createRelative(mContext,
|
||||
SizeCompatTests.class.getName()))
|
||||
.setMinAspectRatio(1.1f)
|
||||
.setUid(android.os.Process.myUid())
|
||||
.build();
|
||||
// Setup Letterbox Configuration
|
||||
activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
|
||||
activity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.5f);
|
||||
// Non-resizable portrait activity
|
||||
prepareUnresizable(activity, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
float expectedAspectRatio = 1f * displayHeight / getExpectedSplitSize(displayWidth);
|
||||
final Rect afterBounds = activity.getBounds();
|
||||
final float afterAspectRatio = (float) (afterBounds.height()) / afterBounds.width();
|
||||
Assert.assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
|
||||
ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN})
|
||||
@DisableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY})
|
||||
public void testOverrideSplitScreenAspectRatioForUnresizableLandscapeApps() {
|
||||
final int displayWidth = 1400;
|
||||
final int displayHeight = 1600;
|
||||
setUpDisplaySizeWithApp(displayWidth, displayHeight);
|
||||
final ActivityRecord activity = new ActivityBuilder(mAtm)
|
||||
.setTask(mTask)
|
||||
.setComponent(ComponentName.createRelative(mContext,
|
||||
SizeCompatTests.class.getName()))
|
||||
.setMinAspectRatio(1.1f)
|
||||
.setUid(android.os.Process.myUid())
|
||||
.build();
|
||||
// Setup Letterbox Configuration
|
||||
activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
|
||||
activity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.5f);
|
||||
// Non-resizable portrait activity
|
||||
prepareUnresizable(activity, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
float expectedAspectRatio = 1f * displayWidth / getExpectedSplitSize(displayHeight);
|
||||
final Rect afterBounds = activity.getBounds();
|
||||
final float afterAspectRatio = (float) (afterBounds.width()) / afterBounds.height();
|
||||
Assert.assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
|
||||
ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN})
|
||||
@DisableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY})
|
||||
public void testOverrideSplitScreenAspectRatioForUnresizableLandscapeAppsFromLandscape() {
|
||||
final int displayWidth = 1600;
|
||||
final int displayHeight = 1400;
|
||||
setUpDisplaySizeWithApp(displayWidth, displayHeight);
|
||||
final ActivityRecord activity = new ActivityBuilder(mAtm)
|
||||
.setTask(mTask)
|
||||
.setComponent(ComponentName.createRelative(mContext,
|
||||
SizeCompatTests.class.getName()))
|
||||
.setMinAspectRatio(1.1f)
|
||||
.setUid(android.os.Process.myUid())
|
||||
.build();
|
||||
// Setup Letterbox Configuration
|
||||
activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
|
||||
activity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.5f);
|
||||
// Non-resizable portrait activity
|
||||
prepareUnresizable(activity, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
float expectedAspectRatio = 1f * displayHeight / getExpectedSplitSize(displayWidth);
|
||||
final Rect afterBounds = activity.getBounds();
|
||||
final float afterAspectRatio = (float) (afterBounds.width()) / afterBounds.height();
|
||||
Assert.assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitAspectRatioForUnresizableLandscapeApps() {
|
||||
// Set up a display in portrait and ignoring orientation request.
|
||||
|
||||
Reference in New Issue
Block a user