Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e473c3f2 authored by Mina Karadzic's avatar Mina Karadzic Committed by Android (Google) Code Review
Browse files

Merge "Allow camera compat (simulate requested orientation) for landscape cameras." into main

parents df773253 fa068dd8
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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;
    }

+18 −12
Original line number Diff line number Diff line
@@ -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.
@@ -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) {
@@ -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) {
@@ -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.
     *
+27 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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,