Loading services/core/java/com/android/server/wm/AppCompatCameraRotationState.java +4 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,10 @@ class AppCompatCameraRotationState { boolean isCameraDeviceNaturalOrientationPortrait() { // Per CDD (7.5.5 C-1-1), camera sensor orientation and display natural orientation have to // be the same (portrait or landscape). // TODO(b/444213250): this is not always correct, for example for some landscape foldables, // natural orientation of some displays and camera sensors may differ. Instead, query the // camera sensors for their natural orientation. Also make sure no camera sensor sandboxing // affects that. return getDisplayContentTiedToCamera().getNaturalOrientation() == ORIENTATION_PORTRAIT; } Loading services/core/java/com/android/server/wm/AppCompatCameraSimReqOrientationPolicy.java +18 −12 Original line number Diff line number Diff line Loading @@ -276,8 +276,7 @@ final class AppCompatCameraSimReqOrientationPolicy implements AppCompatCameraSta .setShouldLetterboxForCameraCompat(displayRotation != ROTATION_UNDEFINED) .setRotateAndCropRotation(getCameraRotationFromSandboxedDisplayRotation( displayRotation)) // TODO(b/365725400): support landscape cameras. .setShouldOverrideSensorOrientation(false) .setShouldOverrideSensorOrientation(shouldOverrideSensorOrientation()) .setShouldAllowTransformInverseDisplay(false); } else if (isExternalDisplaySandboxEnabledForActivity(activityRecord)) { // Sandbox only display rotation if needed, for external display. Loading Loading @@ -311,8 +310,9 @@ final class AppCompatCameraSimReqOrientationPolicy implements AppCompatCameraSta * Calculates the angle for camera feed rotate-and-crop. * * <p>Camera apps most commonly calculate the preview rotation with the formula (simplified): * {code rotation = cameraSensorRotation - displayRotation}. When display rotation is sandboxed, * camera preview needs to be rotated by the same amount to keep the preview upright. * {code rotation = cameraSensorRotation - displayRotation}. When display rotation or sensor * orientation is sandboxed, camera feed needs to be rotated by the same amount to keep the * preview upright. */ private int getCameraRotationFromSandboxedDisplayRotation(@Surface.Rotation int displayRotation) { Loading @@ -320,17 +320,19 @@ final class AppCompatCameraSimReqOrientationPolicy implements AppCompatCameraSta return ROTATION_UNDEFINED; } int realCameraRotation = mCameraDisplayRotationProvider.getCameraDeviceRotation(); if (displayRotation == realCameraRotation) { // No need to rotate and crop, display rotation is unchanged. return ROTATION_UNDEFINED; } // Most apps that assume camera sensor orientation expect portrait camera orientation. // If sensor orientation is changed (currently only landscape to portrait is supported), // this will affect rotate and crop; otherwise sensorRotationOffset should be 0. // The value of sensorRotationOffset is calculated by the difference between the real // sensor orientation and sandboxed: 0 for landscape cameras, and 90 for portrait cameras. // Camera Framework flips this value based on whether the camera is front or back. final int sensorRotationOffset = shouldOverrideSensorOrientation() ? 270 : 0; final int displayRotationInDegrees = getRotationToDegrees(displayRotation); final int realCameraRotationInDegrees = getRotationToDegrees(realCameraRotation); // Feed needs to be rotated by the same amount as the display sandboxing difference, in // order to keep the preview upright. // Feed needs to be rotated by the same amount as the display sandboxing difference and the // camera sensor sandboxing difference, in order to keep the preview upright. return getRotationDegreesToEnum((displayRotationInDegrees - realCameraRotationInDegrees + 360) % 360); + sensorRotationOffset + 360) % 360); } private static int getRotationToDegrees(@Surface.Rotation int rotation) { Loading Loading @@ -374,6 +376,10 @@ final class AppCompatCameraSimReqOrientationPolicy implements AppCompatCameraSta } } private boolean shouldOverrideSensorOrientation() { return Flags.cameraCompatLandscapeCameraSupport() && !mCameraDisplayRotationProvider.isCameraDeviceNaturalOrientationPortrait(); } /** * Returns true if letterboxing should be allowed for camera apps, even if otherwise it isn't. * Loading services/tests/wmtests/src/com/android/server/wm/AppCompatCameraSimReqOrientationPolicyTests.java +27 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_NONE; import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_PORTRAIT_DEVICE_IN_LANDSCAPE; import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_PORTRAIT_DEVICE_IN_PORTRAIT; import static android.app.CameraCompatTaskInfo.CameraCompatMode; import static android.app.WallpaperManager.ORIENTATION_LANDSCAPE; import static android.app.WindowConfiguration.ROTATION_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; Loading @@ -34,6 +33,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_FULL_USER; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.Display.TYPE_EXTERNAL; import static android.view.Display.TYPE_INTERNAL; Loading @@ -46,6 +46,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.AppCompatCameraOverrides.REQUESTED; import static com.android.server.wm.AppCompatConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO; import static com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_LANDSCAPE_CAMERA_SUPPORT; import static com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_UNIFY_CAMERA_POLICIES; import static com.android.window.flags.Flags.FLAG_ENABLE_CAMERA_COMPAT_COMPATIBILITY_INFO_ROTATE_AND_CROP_BUGFIX; import static com.android.window.flags.Flags.FLAG_ENABLE_CAMERA_COMPAT_EXTERNAL_DISPLAY_ROTATION_BUGFIX; Loading Loading @@ -637,6 +638,31 @@ public class AppCompatCameraSimReqOrientationPolicyTests extends WindowTestsBase }); } @Test @EnableFlags({FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING, FLAG_CAMERA_COMPAT_LANDSCAPE_CAMERA_SUPPORT}) @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT}) public void testOnCameraOpened_landscapeDisplay_sandboxedToPortrait() { runTestScenario((robot) -> { robot.configureActivityAndDisplay(SCREEN_ORIENTATION_PORTRAIT, ORIENTATION_LANDSCAPE, WINDOWING_MODE_FREEFORM); robot.activity().rotateDisplayForTopActivity(ROTATION_0); robot.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1); // Display rotation for fixed-orientation portrait apps should always be 0. robot.assertCompatibilityInfoSentWithDisplayRotation(ROTATION_0); // Sensor orientation should change from landscape to portrait. robot.assertCompatibilityInfoSentWithSensorOverride(true); robot.assertCompatibilityInfoSentWithLetterbox(true); // Default is true, and should be disabled (false) for camera compat. robot.assertCompatibilityInfoSentWithInverseTransformAllowed(false); // Rotate and crop value should offset by the change in sensor orientation: // (0 - 90) % 360 = 270. robot.assertCompatibilityInfoSentWithRotateAndCrop(ROTATION_270); }); } @Test @EnableFlags({FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING, FLAG_ENABLE_CAMERA_COMPAT_EXTERNAL_DISPLAY_ROTATION_BUGFIX, Loading Loading
services/core/java/com/android/server/wm/AppCompatCameraRotationState.java +4 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,10 @@ class AppCompatCameraRotationState { boolean isCameraDeviceNaturalOrientationPortrait() { // Per CDD (7.5.5 C-1-1), camera sensor orientation and display natural orientation have to // be the same (portrait or landscape). // TODO(b/444213250): this is not always correct, for example for some landscape foldables, // natural orientation of some displays and camera sensors may differ. Instead, query the // camera sensors for their natural orientation. Also make sure no camera sensor sandboxing // affects that. return getDisplayContentTiedToCamera().getNaturalOrientation() == ORIENTATION_PORTRAIT; } Loading
services/core/java/com/android/server/wm/AppCompatCameraSimReqOrientationPolicy.java +18 −12 Original line number Diff line number Diff line Loading @@ -276,8 +276,7 @@ final class AppCompatCameraSimReqOrientationPolicy implements AppCompatCameraSta .setShouldLetterboxForCameraCompat(displayRotation != ROTATION_UNDEFINED) .setRotateAndCropRotation(getCameraRotationFromSandboxedDisplayRotation( displayRotation)) // TODO(b/365725400): support landscape cameras. .setShouldOverrideSensorOrientation(false) .setShouldOverrideSensorOrientation(shouldOverrideSensorOrientation()) .setShouldAllowTransformInverseDisplay(false); } else if (isExternalDisplaySandboxEnabledForActivity(activityRecord)) { // Sandbox only display rotation if needed, for external display. Loading Loading @@ -311,8 +310,9 @@ final class AppCompatCameraSimReqOrientationPolicy implements AppCompatCameraSta * Calculates the angle for camera feed rotate-and-crop. * * <p>Camera apps most commonly calculate the preview rotation with the formula (simplified): * {code rotation = cameraSensorRotation - displayRotation}. When display rotation is sandboxed, * camera preview needs to be rotated by the same amount to keep the preview upright. * {code rotation = cameraSensorRotation - displayRotation}. When display rotation or sensor * orientation is sandboxed, camera feed needs to be rotated by the same amount to keep the * preview upright. */ private int getCameraRotationFromSandboxedDisplayRotation(@Surface.Rotation int displayRotation) { Loading @@ -320,17 +320,19 @@ final class AppCompatCameraSimReqOrientationPolicy implements AppCompatCameraSta return ROTATION_UNDEFINED; } int realCameraRotation = mCameraDisplayRotationProvider.getCameraDeviceRotation(); if (displayRotation == realCameraRotation) { // No need to rotate and crop, display rotation is unchanged. return ROTATION_UNDEFINED; } // Most apps that assume camera sensor orientation expect portrait camera orientation. // If sensor orientation is changed (currently only landscape to portrait is supported), // this will affect rotate and crop; otherwise sensorRotationOffset should be 0. // The value of sensorRotationOffset is calculated by the difference between the real // sensor orientation and sandboxed: 0 for landscape cameras, and 90 for portrait cameras. // Camera Framework flips this value based on whether the camera is front or back. final int sensorRotationOffset = shouldOverrideSensorOrientation() ? 270 : 0; final int displayRotationInDegrees = getRotationToDegrees(displayRotation); final int realCameraRotationInDegrees = getRotationToDegrees(realCameraRotation); // Feed needs to be rotated by the same amount as the display sandboxing difference, in // order to keep the preview upright. // Feed needs to be rotated by the same amount as the display sandboxing difference and the // camera sensor sandboxing difference, in order to keep the preview upright. return getRotationDegreesToEnum((displayRotationInDegrees - realCameraRotationInDegrees + 360) % 360); + sensorRotationOffset + 360) % 360); } private static int getRotationToDegrees(@Surface.Rotation int rotation) { Loading Loading @@ -374,6 +376,10 @@ final class AppCompatCameraSimReqOrientationPolicy implements AppCompatCameraSta } } private boolean shouldOverrideSensorOrientation() { return Flags.cameraCompatLandscapeCameraSupport() && !mCameraDisplayRotationProvider.isCameraDeviceNaturalOrientationPortrait(); } /** * Returns true if letterboxing should be allowed for camera apps, even if otherwise it isn't. * Loading
services/tests/wmtests/src/com/android/server/wm/AppCompatCameraSimReqOrientationPolicyTests.java +27 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_NONE; import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_PORTRAIT_DEVICE_IN_LANDSCAPE; import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_PORTRAIT_DEVICE_IN_PORTRAIT; import static android.app.CameraCompatTaskInfo.CameraCompatMode; import static android.app.WallpaperManager.ORIENTATION_LANDSCAPE; import static android.app.WindowConfiguration.ROTATION_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; Loading @@ -34,6 +33,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_FULL_USER; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.Display.TYPE_EXTERNAL; import static android.view.Display.TYPE_INTERNAL; Loading @@ -46,6 +46,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.AppCompatCameraOverrides.REQUESTED; import static com.android.server.wm.AppCompatConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO; import static com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_LANDSCAPE_CAMERA_SUPPORT; import static com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_UNIFY_CAMERA_POLICIES; import static com.android.window.flags.Flags.FLAG_ENABLE_CAMERA_COMPAT_COMPATIBILITY_INFO_ROTATE_AND_CROP_BUGFIX; import static com.android.window.flags.Flags.FLAG_ENABLE_CAMERA_COMPAT_EXTERNAL_DISPLAY_ROTATION_BUGFIX; Loading Loading @@ -637,6 +638,31 @@ public class AppCompatCameraSimReqOrientationPolicyTests extends WindowTestsBase }); } @Test @EnableFlags({FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING, FLAG_CAMERA_COMPAT_LANDSCAPE_CAMERA_SUPPORT}) @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT}) public void testOnCameraOpened_landscapeDisplay_sandboxedToPortrait() { runTestScenario((robot) -> { robot.configureActivityAndDisplay(SCREEN_ORIENTATION_PORTRAIT, ORIENTATION_LANDSCAPE, WINDOWING_MODE_FREEFORM); robot.activity().rotateDisplayForTopActivity(ROTATION_0); robot.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1); // Display rotation for fixed-orientation portrait apps should always be 0. robot.assertCompatibilityInfoSentWithDisplayRotation(ROTATION_0); // Sensor orientation should change from landscape to portrait. robot.assertCompatibilityInfoSentWithSensorOverride(true); robot.assertCompatibilityInfoSentWithLetterbox(true); // Default is true, and should be disabled (false) for camera compat. robot.assertCompatibilityInfoSentWithInverseTransformAllowed(false); // Rotate and crop value should offset by the change in sensor orientation: // (0 - 90) % 360 = 270. robot.assertCompatibilityInfoSentWithRotateAndCrop(ROTATION_270); }); } @Test @EnableFlags({FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING, FLAG_ENABLE_CAMERA_COMPAT_EXTERNAL_DISPLAY_ROTATION_BUGFIX, Loading