diff options
3 files changed, 100 insertions, 4 deletions
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 93eed370004b..24647f459ab5 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1199,6 +1199,43 @@ public interface WindowManager extends ViewManager { "android.window.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE"; /** + * Application-level [PackageManager][android.content.pm.PackageManager.Property] tag that (when + * set to false) informs the system the app has opted out of the camera compatibility treatment + * for fixed-orientation apps, which simulates running on a portrait device, in the orientation + * requested by the app. + * + * <p>This treatment aims to mitigate camera issues on large screens, like stretched or sideways + * previews. It simulates running on a portrait device by: + * <ul> + * <li>Letterboxing the app window, + * <li>Cropping the camera buffer to match the app's requested orientation, + * <li>Setting the camera sensor orientation to portrait. + * <li>Setting the display rotation to match the app's requested orientation, given portrait + * natural orientation, + * <li>Refreshes the activity to trigger new camera setup, with sandboxed values. + * </ul> + * + * <p>To opt out of the camera compatibility treatment, add this property to your app manifest + * and set the value to {@code false}. + * + * <p>Not setting this property at all, or setting this property to {@code true} has no effect. + * + * <p><b>Syntax:</b> + * <pre> + * <application> + * <property + * android:name="android.window.PROPERTY_CAMERA_COMPAT_ALLOW_SIMULATE_REQUESTED_ORIENTATION" + * android:value="true|false"/> + * </application> + * </pre> + * + * @hide + */ + //TODO(b/394590412): Make this property public. + String PROPERTY_CAMERA_COMPAT_ALLOW_SIMULATE_REQUESTED_ORIENTATION = + "android.window.PROPERTY_CAMERA_COMPAT_ALLOW_SIMULATE_REQUESTED_ORIENTATION"; + + /** * Application level {@link android.content.pm.PackageManager.Property PackageManager.Property} * for an app to inform the system that the app should be excluded from the compatibility * override for orientation set by the device manufacturer. When the orientation override is diff --git a/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java b/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java index 47d30c98120c..5eed54704f36 100644 --- a/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java +++ b/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java @@ -23,6 +23,7 @@ import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFR import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA; import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA; import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION; +import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_SIMULATE_REQUESTED_ORIENTATION; import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH; import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE; @@ -32,6 +33,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS import static com.android.server.wm.AppCompatUtils.isChangeEnabled; import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.server.wm.utils.OptPropFactory; import com.android.window.flags.Flags; @@ -60,6 +62,8 @@ class AppCompatCameraOverrides { private final OptPropFactory.OptProp mCameraCompatEnableRefreshViaPauseOptProp; @NonNull private final OptPropFactory.OptProp mCameraCompatAllowForceRotationOptProp; + @Nullable + private final OptPropFactory.OptProp mCameraCompatAllowOrientationTreatmentOptProp; AppCompatCameraOverrides(@NonNull ActivityRecord activityRecord, @NonNull AppCompatConfiguration appCompatConfiguration, @@ -80,6 +84,10 @@ class AppCompatCameraOverrides { mCameraCompatAllowForceRotationOptProp = optPropBuilder.create( PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION, isCameraCompatTreatmentEnabled); + mCameraCompatAllowOrientationTreatmentOptProp = + Flags.enableCameraCompatForDesktopWindowingOptOut() ? optPropBuilder.create( + PROPERTY_CAMERA_COMPAT_ALLOW_SIMULATE_REQUESTED_ORIENTATION, + isCameraCompatTreatmentEnabled) : null; } /** @@ -168,10 +176,31 @@ class AppCompatCameraOverrides { * </ul> */ boolean shouldApplyFreeformTreatmentForCameraCompat() { - return Flags.enableCameraCompatForDesktopWindowing() && (isChangeEnabled(mActivityRecord, - OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT) - || mActivityRecord.mWmService.mAppCompatConfiguration - .isCameraCompatFreeformWindowingTreatmentEnabled()); + return Flags.enableCameraCompatForDesktopWindowing() + && (shouldEnableCameraCompatFreeformTreatmentForApp() + || shouldEnableCameraCompatFreeformTreatmentForAllApps()); + } + + private boolean shouldEnableCameraCompatFreeformTreatmentForApp() { + if (mCameraCompatAllowOrientationTreatmentOptProp != null) { + return mCameraCompatAllowOrientationTreatmentOptProp + .shouldEnableWithOptOutOverrideAndProperty(isChangeEnabled(mActivityRecord, + OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT)); + } else { + return isChangeEnabled(mActivityRecord, + OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT); + } + } + + /** + * Returns whether camera compat treatment should be enabled for all apps targeted for treatment + * (usually fixed-orientation apps). + * + * <p>This can be enabled via adb only. + */ + private boolean shouldEnableCameraCompatFreeformTreatmentForAllApps() { + return mActivityRecord.mWmService.mAppCompatConfiguration + .isCameraCompatFreeformWindowingTreatmentEnabled(); } boolean isOverrideOrientationOnlyForCameraEnabled() { diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java index 4ad1cd192eb6..d4be7f812cb5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java @@ -23,12 +23,14 @@ import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFR import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA; import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA; import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION; +import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_SIMULATE_REQUESTED_ORIENTATION; import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH; import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.window.flags.Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING; +import static com.android.window.flags.Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING_OPT_OUT; import android.compat.testing.PlatformCompatChangeRule; import android.platform.test.annotations.DisableFlags; @@ -239,6 +241,34 @@ public class AppCompatCameraOverridesTest extends WindowTestsBase { @Test @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT}) + @EnableFlags({FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING, + FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING_OPT_OUT}) + public void testShouldApplyCameraCompatFreeformTreatment_propertyFalse_returnsFalse() { + runTestScenario((robot) -> { + robot.activity().createActivityWithComponentInNewTask(); + + robot.prop().disable(PROPERTY_CAMERA_COMPAT_ALLOW_SIMULATE_REQUESTED_ORIENTATION); + + robot.checkShouldApplyFreeformTreatmentForCameraCompat(false); + }); + } + + @Test + @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT}) + @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING) + @DisableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING_OPT_OUT) + public void testShouldApplyCameraCompatFreeformTreatment_optOutFlagNotEnabled_optOutIgnored() { + runTestScenario((robot) -> { + robot.activity().createActivityWithComponentInNewTask(); + + robot.prop().disable(PROPERTY_CAMERA_COMPAT_ALLOW_SIMULATE_REQUESTED_ORIENTATION); + + robot.checkShouldApplyFreeformTreatmentForCameraCompat(true); + }); + } + + @Test + @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT}) @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING) public void testShouldApplyCameraCompatFreeformTreatment_overrideAndFlagEnabled_returnsTrue() { runTestScenario((robot) -> { |