summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/content/pm/ActivityInfo.java20
-rw-r--r--services/core/java/com/android/server/wm/LetterboxUiController.java49
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java56
3 files changed, 107 insertions, 18 deletions
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index bd04634ac4f1..535cebb1d1af 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1280,6 +1280,26 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
264301586L; // buganizer id
/**
+ * Excludes the packages the override is applied to from the camera compatibility treatment
+ * in free-form windowing mode for fixed-orientation apps.
+ *
+ * <p>In free-form windowing mode, the compatibility treatment emulates running on a portrait
+ * device by letterboxing the app window and changing the camera characteristics to what apps
+ * commonly expect in a portrait device: 90 and 270 degree sensor rotation for back and front
+ * cameras, respectively, and setting display rotation to 0.
+ *
+ * <p>Use this flag to disable the compatibility treatment for apps that do not respond well to
+ * the treatment.
+ *
+ * @hide
+ */
+ @ChangeId
+ @Overridable
+ @Disabled
+ public static final long OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT =
+ 314961188L;
+
+ /**
* This change id forces the packages it is applied to sandbox {@link android.view.View} API to
* an activity bounds for:
*
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 5d613cf45643..a24c02a3b677 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -22,6 +22,7 @@ import static android.content.pm.ActivityInfo.FORCE_RESIZE_APP;
import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION_TO_USER;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
@@ -131,6 +132,7 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.LetterboxDetails;
import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
+import com.android.window.flags.Flags;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -194,7 +196,8 @@ final class LetterboxUiController {
private final boolean mIsOverrideCameraCompatDisableRefreshEnabled;
// Corresponds to OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE
private final boolean mIsOverrideCameraCompatEnableRefreshViaPauseEnabled;
-
+ // Corresponds to OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT
+ private final boolean mIsOverrideCameraCompatDisableFreeformWindowingTreatmentEnabled;
// Corresponds to OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION
private final boolean mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled;
// Corresponds to OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED
@@ -321,15 +324,15 @@ final class LetterboxUiController {
PROPERTY_COMPAT_ENABLE_FAKE_FOCUS);
mBooleanPropertyCameraCompatAllowForceRotation =
readComponentProperty(packageManager, mActivityRecord.packageName,
- () -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled(),
+ mLetterboxConfiguration::isCameraCompatTreatmentEnabled,
PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION);
mBooleanPropertyCameraCompatAllowRefresh =
readComponentProperty(packageManager, mActivityRecord.packageName,
- () -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled(),
+ mLetterboxConfiguration::isCameraCompatTreatmentEnabled,
PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH);
mBooleanPropertyCameraCompatEnableRefreshViaPause =
readComponentProperty(packageManager, mActivityRecord.packageName,
- () -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled(),
+ mLetterboxConfiguration::isCameraCompatTreatmentEnabled,
PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE);
mBooleanPropertyAllowOrientationOverride =
@@ -351,11 +354,11 @@ final class LetterboxUiController {
mBooleanPropertyAllowUserAspectRatioOverride =
readComponentProperty(packageManager, mActivityRecord.packageName,
- () -> mLetterboxConfiguration.isUserAppAspectRatioSettingsEnabled(),
+ mLetterboxConfiguration::isUserAppAspectRatioSettingsEnabled,
PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE);
mBooleanPropertyAllowUserAspectRatioFullscreenOverride =
readComponentProperty(packageManager, mActivityRecord.packageName,
- () -> mLetterboxConfiguration.isUserAppAspectRatioFullscreenEnabled(),
+ mLetterboxConfiguration::isUserAppAspectRatioFullscreenEnabled,
PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE);
mIsOverrideAnyOrientationEnabled = isCompatChangeEnabled(OVERRIDE_ANY_ORIENTATION);
@@ -380,6 +383,8 @@ final class LetterboxUiController {
isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH);
mIsOverrideCameraCompatEnableRefreshViaPauseEnabled =
isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE);
+ mIsOverrideCameraCompatDisableFreeformWindowingTreatmentEnabled =
+ isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT);
mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled =
isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION);
@@ -759,8 +764,7 @@ final class LetterboxUiController {
*/
boolean shouldRefreshActivityForCameraCompat() {
return shouldEnableWithOptOutOverrideAndProperty(
- /* gatingCondition */ () -> mLetterboxConfiguration
- .isCameraCompatTreatmentEnabled(),
+ /* gatingCondition */ mLetterboxConfiguration::isCameraCompatTreatmentEnabled,
mIsOverrideCameraCompatDisableRefreshEnabled,
mBooleanPropertyCameraCompatAllowRefresh);
}
@@ -781,8 +785,7 @@ final class LetterboxUiController {
*/
boolean shouldRefreshActivityViaPauseForCameraCompat() {
return shouldEnableWithOverrideAndProperty(
- /* gatingCondition */ () -> mLetterboxConfiguration
- .isCameraCompatTreatmentEnabled(),
+ /* gatingCondition */ mLetterboxConfiguration::isCameraCompatTreatmentEnabled,
mIsOverrideCameraCompatEnableRefreshViaPauseEnabled,
mBooleanPropertyCameraCompatEnableRefreshViaPause);
}
@@ -800,12 +803,34 @@ final class LetterboxUiController {
*/
boolean shouldForceRotateForCameraCompat() {
return shouldEnableWithOptOutOverrideAndProperty(
- /* gatingCondition */ () -> mLetterboxConfiguration
- .isCameraCompatTreatmentEnabled(),
+ /* gatingCondition */ mLetterboxConfiguration::isCameraCompatTreatmentEnabled,
mIsOverrideCameraCompatDisableForceRotationEnabled,
mBooleanPropertyCameraCompatAllowForceRotation);
}
+ /**
+ * Whether activity is eligible for camera compatibility free-form treatment.
+ *
+ * <p>The treatment is applied to a fixed-orientation camera activity in free-form windowing
+ * mode. The treatment letterboxes or pillarboxes the activity to the expected orientation and
+ * provides changes to the camera and display orientation signals to match those expected on a
+ * portrait device in that orientation (for example, on a standard phone).
+ *
+ * <p>The treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Property gating the camera compatibility free-form treatment is enabled.
+ * <li>Activity isn't opted out by the device manufacturer with override or by the app
+ * developers with the component property.
+ * </ul>
+ */
+ boolean shouldApplyFreeformTreatmentForCameraCompat() {
+ return shouldEnableWithOptOutOverrideAndProperty(
+ /* gatingCondition */ ()-> Flags.cameraCompatForFreeform(),
+ mIsOverrideCameraCompatDisableFreeformWindowingTreatmentEnabled,
+ // TODO(b/328616176): add a manifest override for developers.
+ null);
+ }
+
private boolean isCameraCompatTreatmentActive() {
DisplayContent displayContent = mActivityRecord.mDisplayContent;
if (displayContent == null) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index 4e4bbfe6371d..0290f0f5bd0f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -21,6 +21,7 @@ import static android.content.pm.ActivityInfo.FORCE_RESIZE_APP;
import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION_TO_USER;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
@@ -63,6 +64,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.LetterboxUiController.MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP;
import static com.android.server.wm.LetterboxUiController.SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS;
+import static com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_FOR_FREEFORM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -81,6 +83,7 @@ import android.content.pm.PackageManager.Property;
import android.content.res.Resources;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.RoundedCorner;
@@ -101,11 +104,11 @@ import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
- /**
+/**
* Test class for {@link LetterboxUiControllerTest}.
*
* Build/Install/Run:
- * atest WmTests:LetterboxUiControllerTest
+ * atest WmTests:LetterboxUiControllerTest
*/
@SmallTest
@Presubmit
@@ -122,6 +125,8 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
@Rule
public TestRule compatChangeRule = new PlatformCompatChangeRule();
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private ActivityRecord mActivity;
private Task mTask;
@@ -466,10 +471,48 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
assertTrue(mController.shouldForceRotateForCameraCompat());
}
+ // shouldApplyFreeformTreatmentForCameraCompat
+
+ @Test
+ public void testShouldApplyCameraCompatFreeformTreatment_flagIsDisabled_returnsFalse() {
+ mSetFlagsRule.disableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);
+
+ assertFalse(mController.shouldApplyFreeformTreatmentForCameraCompat());
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
+ public void testShouldApplyCameraCompatFreeformTreatment_overrideEnabled_returnsFalse() {
+ mSetFlagsRule.enableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);
+
+ assertFalse(mController.shouldApplyFreeformTreatmentForCameraCompat());
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
+ public void testShouldApplyCameraCompatFreeformTreatment_disabledByOverride_returnsFalse()
+ throws Exception {
+ mSetFlagsRule.enableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);
+
+ mController = new LetterboxUiController(mWm, mActivity);
+
+ assertFalse(mController.shouldApplyFreeformTreatmentForCameraCompat());
+ }
+
+ @Test
+ public void testShouldApplyCameraCompatFreeformTreatment_notDisabledByOverride_returnsTrue()
+ throws Exception {
+ mSetFlagsRule.enableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);
+
+ mController = new LetterboxUiController(mWm, mActivity);
+
+ assertTrue(mController.shouldApplyFreeformTreatmentForCameraCompat());
+ }
+
@Test
public void testGetCropBoundsIfNeeded_handleCropForTransparentActivityBasedOnOpaqueBounds() {
final InsetsSource taskbar = new InsetsSource(/*id=*/ 0,
- WindowInsets.Type.navigationBars());
+ WindowInsets.Type.navigationBars());
taskbar.setFlags(FLAG_INSETS_ROUNDED_CORNER, FLAG_INSETS_ROUNDED_CORNER);
final WindowState mainWindow = mockForGetCropBoundsAndRoundedCorners(taskbar);
final Rect opaqueBounds = new Rect(0, 0, 500, 300);
@@ -726,7 +769,7 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
throws Exception {
mDisplayContent.setIgnoreOrientationRequest(false);
assertEquals(SCREEN_ORIENTATION_PORTRAIT, mController.overrideOrientationIfNeeded(
- /* candidate */ SCREEN_ORIENTATION_PORTRAIT));
+ /* candidate */ SCREEN_ORIENTATION_PORTRAIT));
}
@Test
@@ -736,7 +779,7 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
prepareActivityThatShouldApplyUserMinAspectRatioOverride();
assertEquals(SCREEN_ORIENTATION_PORTRAIT, mController.overrideOrientationIfNeeded(
- /* candidate */ SCREEN_ORIENTATION_PORTRAIT));
+ /* candidate */ SCREEN_ORIENTATION_PORTRAIT));
}
@Test
@@ -859,6 +902,7 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
assertEquals(SCREEN_ORIENTATION_USER, mController.overrideOrientationIfNeeded(
/* candidate */ SCREEN_ORIENTATION_UNSPECIFIED));
}
+
@Test
public void testOverrideOrientationIfNeeded_respectOrientationRequestOverUserFullScreen() {
spyOn(mController);
@@ -1380,7 +1424,7 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
private void mockThatProperty(String propertyName, boolean value) throws Exception {
Property property = new Property(propertyName, /* value */ value, /* packageName */ "",
- /* className */ "");
+ /* className */ "");
PackageManager pm = mWm.mContext.getPackageManager();
spyOn(pm);
doReturn(property).when(pm).getProperty(eq(propertyName), anyString());