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

Commit ced5cb66 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[CameraCompat] Use device sensor rotation when app is on external display." into main

parents bf1bac52 c83f22af
Loading
Loading
Loading
Loading
+167 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.wm;

import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.view.Display;
import android.view.OrientationEventListener;
import android.view.Surface;
import android.window.DesktopExperienceFlags;

import com.android.internal.annotations.VisibleForTesting;

/**
 * Provider for the camera rotation and sensor orientation info used to setup camera compat mode.
 *
 * <p>{@link AppCompatCameraRotationState} monitors whether the app currently using the camera is
 * on a built-in display (rotates with the built-in camera) or an external display, and returns the
 * display rotation apps should use to keep the preview upright:
 * <ul>
 *     <li>If running on a built-in display, relevant rotation is {@link Display#getRotation()}.
 *     <li>If running on an external display, only the sensor rotation matters, received from
 *     {@link OrientationEventListener}.
 * </ul>
 */
class AppCompatCameraRotationState {
    @Nullable
    @VisibleForTesting
    OrientationEventListener mOrientationEventListener;

    @NonNull
    private final DisplayContent mDisplayContent;

    private int mDisplayRotationIfExternal = ROTATION_UNDEFINED;

    AppCompatCameraRotationState(@NonNull DisplayContent displayContent) {
        mDisplayContent = displayContent;
    }

    /** Sets up listening to the orientation of the primary device if on an external display. */
    void start() {
        if (isExternalDisplay()) {
            // Listen to orientation changes of the host device.
            setupSensorOrientationListener();
        }
    }

    /** Disables {@link OrientationEventListener} if set up. */
    void dispose() {
        if (mOrientationEventListener != null) {
            mOrientationEventListener.disable();
            mOrientationEventListener = null;
        }
    }


    /** Creates and enables {@link OrientationEventListener}.  */
    void setupSensorOrientationListener() {
        mOrientationEventListener = new OrientationEventListener(
                mDisplayContent.mWmService.mContext) {
            @Override
            public void onOrientationChanged(int orientation) {
                synchronized (mDisplayContent.mWmService.mGlobalLock) {
                    mDisplayRotationIfExternal = transformSensorOrientationToDisplayRotation(
                            orientation);
                }
            }
        };

        mOrientationEventListener.enable();
    }

    /**
     * Whether the natural orientation (not the current rotation) of the camera is portrait.
     *
     * <p>This orientation is equal to the natural orientation of the display it is tied to
     * (built-in display).
     */
    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).
        return getDisplayContentTiedToCamera().getNaturalOrientation() == ORIENTATION_PORTRAIT;
    }

    /**
     * Returns relevant rotation of the relevant "device", whether it is a camera or display.
     *
     *<p>This is the offset that apps should use to rotate the camera preview. Difference in this
     * value and what the app expects given their requested orientation informs camera compat setup.
     */
    @Surface.Rotation
    int getCameraDeviceRotation() {
        return isExternalDisplay() ? mDisplayRotationIfExternal : mDisplayContent.getRotation();
    }

    // TODO(b/425599049): support external cameras.
    /**
     * Whether the device relevant for camera is in portrait orientation.
     *
     * <p>This is either the display rotation when running on an internal display, or the camera
     * rotation when running on an external display.
     */
    boolean isCameraDeviceOrientationPortrait() {
        final int cameraDisplayRotation = getCameraDeviceRotation();
        final boolean isDisplayInItsNaturalOrientation = (cameraDisplayRotation == ROTATION_0
                || cameraDisplayRotation == ROTATION_180);
        // Display is in portrait if and only if: portrait device is in its natural orientation,
        // or landscape device is not in its natural orientation.
        // `isPortraitCamera <=> isDisplayInItsNaturalOrientation` is equivalent to
        // `isPortraitCamera XOR !isDisplayInItsNaturalOrientation`.
        return isCameraDeviceNaturalOrientationPortrait() ^ !isDisplayInItsNaturalOrientation;
    }

    @Surface.Rotation
    private int transformSensorOrientationToDisplayRotation(int orientation) {
        // Sensor rotation is continuous, and counted in the opposite direction from display
        // rotation.
        final int displayRotationInt = ((360 - orientation) + 360) % 360;
        // Choose the closest display rotation. When using the `OrientationEventListener`, this is
        // the recommended way in developer documentation for apps to orient the preview or a
        // captured image.
        if (displayRotationInt > 45 && displayRotationInt <= 135) {
            return ROTATION_90;
        } else if (displayRotationInt > 135 && displayRotationInt <= 225) {
            return ROTATION_180;
        } else if (displayRotationInt > 225 && displayRotationInt <= 315) {
            return ROTATION_270;
        } else {
            return ROTATION_0;
        }
    }

    @NonNull
    private DisplayContent getDisplayContentTiedToCamera() {
        return isExternalDisplay()
                // If camera app is on the external display, the display rotation should be
                // overridden to use the primary device rotation which the camera sensor is tied to.
                ? mDisplayContent.mWmService.getDefaultDisplayContentLocked()
                : mDisplayContent;
    }

    private boolean isExternalDisplay() {
        return DesktopExperienceFlags.ENABLE_CAMERA_COMPAT_EXTERNAL_DISPLAY_ROTATION_BUGFIX.isTrue()
                && mDisplayContent.getDisplay().getType() == Display.TYPE_EXTERNAL;
    }
}
+30 −31
Original line number Diff line number Diff line
@@ -30,8 +30,6 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;

import static com.android.server.wm.AppCompatConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -44,7 +42,6 @@ import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.os.RemoteException;
import android.util.Slog;
import android.view.DisplayInfo;
import android.view.Surface;

import com.android.internal.annotations.VisibleForTesting;
@@ -72,6 +69,8 @@ final class CameraCompatFreeformPolicy implements AppCompatCameraStatePolicy,
    private final AppCompatCameraStateSource mCameraStateNotifier;
    @NonNull
    private final CameraStateMonitor mCameraStateMonitor;
    @NonNull
    private final AppCompatCameraRotationState mCameraDisplayRotationProvider;

    // TODO(b/380840084): Clean up after flag is launched.
    @Nullable
@@ -90,23 +89,21 @@ final class CameraCompatFreeformPolicy implements AppCompatCameraStatePolicy,
        mCameraStateMonitor = cameraStateMonitor;
        mCameraStateNotifier = cameraStateNotifier;
        mActivityRefresher = activityRefresher;
        mCameraDisplayRotationProvider = new AppCompatCameraRotationState(displayContent);
    }

    void start() {
        mCameraStateNotifier.addCameraStatePolicy(this);
        mActivityRefresher.addEvaluator(this);
        mCameraDisplayRotationProvider.start();
        mIsRunning = true;
    }

    int getCameraDeviceRotation() {
        // TODO(b/276432441): Check device orientation when running on an external display.
        return mDisplayContent.getRotation();
    }

    /** Releases camera callback listener. */
    void dispose() {
        mCameraStateNotifier.removeCameraStatePolicy(this);
        mActivityRefresher.removeEvaluator(this);
        mCameraDisplayRotationProvider.dispose();
        mIsRunning = false;
    }

@@ -115,6 +112,11 @@ final class CameraCompatFreeformPolicy implements AppCompatCameraStatePolicy,
        return mIsRunning;
    }

    @Surface.Rotation
    int getCameraDeviceRotation() {
        return mCameraDisplayRotationProvider.getCameraDeviceRotation();
    }

    // Refreshing only when configuration changes after applying camera compat treatment.
    @Override
    public boolean shouldRefreshActivity(@NonNull ActivityRecord activity,
@@ -297,37 +299,34 @@ final class CameraCompatFreeformPolicy implements AppCompatCameraStatePolicy,
        if (!isTreatmentEnabledForActivity(topActivity, /* shouldCheckOrientation= */ true)) {
            return CAMERA_COMPAT_FREEFORM_NONE;
        }
        final int appOrientation = topActivity.getRequestedConfigurationOrientation();
        // It is very important to check the original (actual) display rotation, and not the
        // sandboxed rotation that camera compat treatment sets.
        final DisplayInfo displayInfo = topActivity.mWmService.mDisplayManagerInternal
                .getDisplayInfo(topActivity.getDisplayId());

        // This treatment targets only devices with portrait natural orientation, which most tablets
        // have.
        if (!mCameraDisplayRotationProvider.isCameraDeviceNaturalOrientationPortrait()) {
            // TODO(b/365725400): handle landscape natural orientation.
        if (displayInfo.getNaturalHeight() > displayInfo.getNaturalWidth()) {
            return CAMERA_COMPAT_FREEFORM_NONE;
        }

        final int appOrientation = topActivity.getRequestedConfigurationOrientation();
        final boolean isDisplayRotationPortrait = mCameraDisplayRotationProvider
                .isCameraDeviceOrientationPortrait();
        if (appOrientation == ORIENTATION_PORTRAIT) {
                if (isDisplayRotationPortrait(displayInfo.rotation)) {
            if (isDisplayRotationPortrait) {
                return CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT;
            } else {
                return CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE;
            }
        } else if (appOrientation == ORIENTATION_LANDSCAPE) {
                if (isDisplayRotationPortrait(displayInfo.rotation)) {
            if (isDisplayRotationPortrait) {
                return CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT;
            } else {
                return CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE;
            }
        }
        }

        return CAMERA_COMPAT_FREEFORM_NONE;
    }

    private static boolean isDisplayRotationPortrait(@Surface.Rotation int displayRotation) {
        return displayRotation == ROTATION_0 || displayRotation == ROTATION_180;
    }

    /**
     * Whether camera compat treatment is applicable for the given activity, ignoring its windowing
     * mode.
+16 −2
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.pm.ApplicationInfo.CATEGORY_GAME;
import static android.content.pm.ApplicationInfo.CATEGORY_UNDEFINED;
import static android.view.Display.TYPE_INTERNAL;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -136,7 +137,11 @@ class AppCompatActivityRobot {
    }

    void createActivityWithComponentInNewTaskAndDisplay() {
        createActivityWithComponentInNewTask(/* inNewTask */ true, /* inNewDisplay */ true);
        createActivityWithComponentInNewTaskAndDisplay(TYPE_INTERNAL);
    }
    void createActivityWithComponentInNewTaskAndDisplay(int displayType) {
        createActivityWithComponentInNewTask(/* inNewTask */ true, /* inNewDisplay */ true,
                displayType);
    }

    void configureTopActivity(float minAspect, float maxAspect, int screenOrientation,
@@ -358,7 +363,11 @@ class AppCompatActivityRobot {
    }

    void createNewDisplay() {
        createNewDisplay(TYPE_INTERNAL);
    }
    void createNewDisplay(int type) {
        mDisplayContent = new TestDisplayContent.Builder(mAtm, mDisplayWidth, mDisplayHeight)
                .setType(type)
                .build();
        onPostDisplayContentCreation(mDisplayContent);
    }
@@ -569,8 +578,13 @@ class AppCompatActivityRobot {
    }

    private void createActivityWithComponentInNewTask(boolean inNewTask, boolean inNewDisplay) {
        createActivityWithComponentInNewTask(inNewTask, inNewDisplay, TYPE_INTERNAL);
    }

    private void createActivityWithComponentInNewTask(boolean inNewTask, boolean inNewDisplay,
            int displayType) {
        if (inNewDisplay) {
            createNewDisplay();
            createNewDisplay(displayType);
        }
        if (inNewTask) {
            createNewTask();
+246 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.wm;

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;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_90;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.window.flags.Flags.FLAG_ENABLE_CAMERA_COMPAT_EXTERNAL_DISPLAY_ROTATION_BUGFIX;
import static com.android.window.flags.Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING;

import static org.junit.Assert.assertEquals;

import android.annotation.NonNull;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.res.Configuration;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.view.Surface;

import androidx.test.filters.SmallTest;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;

import java.util.function.Consumer;

/**
 * Tests for {@link AppCompatCameraRotationState}.
 *
 * Build/Install/Run:
 *  atest WmTests:AppCompatCameraInfoProviderTests
 */
@SmallTest
@Presubmit
@RunWith(WindowTestRunner.class)
public class AppCompatCameraRotationStateTests extends WindowTestsBase {
    @Rule
    public TestRule compatChangeRule = new PlatformCompatChangeRule();

    @Test
    @DisableFlags(FLAG_ENABLE_CAMERA_COMPAT_EXTERNAL_DISPLAY_ROTATION_BUGFIX)
    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
    public void testFeatureDisabled_returnsCurrentDisplayRotation() {
        runTestScenario((robot) -> {
            robot.configureActivityAndDisplay(ROTATION_90, ORIENTATION_PORTRAIT, TYPE_INTERNAL);
            robot.makeCurrentDisplayDefault();
            // The last created display is 'current'.
            robot.configureActivityAndDisplay(ROTATION_0, ORIENTATION_LANDSCAPE, TYPE_EXTERNAL);

            robot.checkOrientationEventListenerSetUp(/* expected= */ false);
            robot.checkDisplayRotation(/* expected= */ Surface.ROTATION_0);
        });
    }

    @Test
    @EnableFlags({FLAG_ENABLE_CAMERA_COMPAT_EXTERNAL_DISPLAY_ROTATION_BUGFIX,
            FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING})
    public void testFeatureEnabled_internalDisplay_returnsCurrentDisplayRotation() {
        runTestScenario((robot) -> {
            robot.configureActivityAndDisplay(ROTATION_0, ORIENTATION_PORTRAIT, TYPE_INTERNAL);
            robot.makeCurrentDisplayDefault();
            // The last created display is 'current'.
            robot.configureActivityAndDisplay(ROTATION_90, ORIENTATION_PORTRAIT, TYPE_INTERNAL);

            robot.checkOrientationEventListenerSetUp(/* expected= */ false);
            robot.checkDisplayRotation(/* expected= */ Surface.ROTATION_90);
        });
    }

    @Test
    @EnableFlags({FLAG_ENABLE_CAMERA_COMPAT_EXTERNAL_DISPLAY_ROTATION_BUGFIX,
            FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING})
    public void testFeatureEnabled_externalDisplay_returnsSensorRotation() {
        runTestScenario((robot) -> {
            robot.configureActivityAndDisplay(ROTATION_90, ORIENTATION_PORTRAIT, TYPE_INTERNAL);
            robot.makeCurrentDisplayDefault();
            robot.configureActivityAndDisplay(ROTATION_0, ORIENTATION_LANDSCAPE, TYPE_EXTERNAL);
            robot.checkOrientationEventListenerSetUp(/* expected= */ true);

            // Sensor rotation is continuous, and counted in the opposite direction from display
            // rotation: 360 - 100 = 260, and 260 is closest to ROTATION_270.
            robot.setSensorOrientation(100);

            // Sensor rotation should be returned on external displays, even if built-in display has
            // different rotation (for example from disabled auto-rotation).
            robot.checkDisplayRotation(/* expected= */ Surface.ROTATION_270);
        });
    }

    @Test
    @EnableFlags({FLAG_ENABLE_CAMERA_COMPAT_EXTERNAL_DISPLAY_ROTATION_BUGFIX,
            FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING})
    public void testIsCameraDeviceOrientationPortrait_rotatesToLandscape_returnsFalse() {
        runTestScenario((robot) -> {
            robot.configureActivityAndDisplay(ROTATION_0, ORIENTATION_PORTRAIT, TYPE_INTERNAL);
            robot.makeCurrentDisplayDefault();
            // The last created display is 'current'.
            robot.configureActivityAndDisplay(ROTATION_0, ORIENTATION_LANDSCAPE, TYPE_EXTERNAL);
            robot.checkOrientationEventListenerSetUp(/* expected= */ true);

            // Sensor rotation is continuous, and counted in the opposite direction from display
            // rotation: 360 - 100 = 260, and 260 is closest to ROTATION_270.
            robot.setSensorOrientation(100);

            // Sensor rotation should be returned on external displays, even if built-in display has
            // different rotation (for example from disabled auto-rotation).
            robot.checkIsCameraDisplayRotationPortrait(/* expected= */ false);
        });
    }

    @Test
    @EnableFlags({FLAG_ENABLE_CAMERA_COMPAT_EXTERNAL_DISPLAY_ROTATION_BUGFIX,
            FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING})
    public void testIsPortraitCamera_portraitInnerDisplay_rotatesToLandscape_true() {
        runTestScenario((robot) -> {
            robot.configureActivityAndDisplay(ROTATION_0, ORIENTATION_PORTRAIT, TYPE_INTERNAL);
            robot.makeCurrentDisplayDefault();
            robot.configureActivityAndDisplay(ROTATION_0, ORIENTATION_LANDSCAPE, TYPE_EXTERNAL);
            robot.checkOrientationEventListenerSetUp(/* expected= */ true);

            // Sensor rotation is continuous, and counted in the opposite direction from display
            // rotation: 360 - 100 = 260, and 260 is closest to ROTATION_270.
            robot.setSensorOrientation(100);

            // Current rotation does not affect whether camera sensor is portrait or landscape.
            robot.checkIsPortraitCamera(/* expected= */ true);
        });
    }

    @Test
    @EnableFlags({FLAG_ENABLE_CAMERA_COMPAT_EXTERNAL_DISPLAY_ROTATION_BUGFIX,
            FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING})
    public void testIsCamera_DeviceNaturalOrientationPortrait_landscapeDisplay_returnsFalse() {
        runTestScenario((robot) -> {
            robot.configureActivityAndDisplay(ROTATION_0, ORIENTATION_LANDSCAPE, TYPE_INTERNAL);

            // Current rotation does not affect whether camera sensor is portrait or landscape.
            robot.checkIsPortraitCamera(/* expected= */ false);
        });
    }

    /**
     * Runs a test scenario providing a Robot.
     */
    void runTestScenario(@NonNull Consumer<AppCompatCameraInfoProviderRobotTests> consumer) {
        final AppCompatCameraInfoProviderRobotTests robot =
                new AppCompatCameraInfoProviderRobotTests(mWm, mAtm, mSupervisor);
        consumer.accept(robot);
    }

    private static class AppCompatCameraInfoProviderRobotTests extends AppCompatRobotBase {
        private AppCompatCameraRotationState mCameraInfoProvider;
        private final WindowManagerService mWm;

        AppCompatCameraInfoProviderRobotTests(@NonNull WindowManagerService wm,
                @NonNull ActivityTaskManagerService atm,
                @NonNull ActivityTaskSupervisor supervisor) {
            super(wm, atm, supervisor);
            mWm = wm;
            setupAppCompatConfiguration();
        }

        @Override
        void onPostDisplayContentCreation(@NonNull DisplayContent displayContent) {
            super.onPostDisplayContentCreation(displayContent);
        }

        @Override
        void onPostActivityCreation(@NonNull ActivityRecord activity) {
            super.onPostActivityCreation(activity);
            mCameraInfoProvider = new AppCompatCameraRotationState(activity.mDisplayContent);
            mCameraInfoProvider.start();
        }

        private void setupAppCompatConfiguration() {
            applyOnConf((c) -> {
                c.enableCameraCompatForceRotateTreatment(true);
                c.enableCameraCompatForceRotateTreatmentAtBuildTime(true);
            });
        }

        private void configureActivityAndDisplay(
                @Surface.Rotation int displayRotation,
                @Configuration.Orientation int naturalOrientation,
                int displayType) {
            applyOnActivity(a -> {
                dw().allowEnterDesktopMode(true);
                a.createActivityWithComponentInNewTaskAndDisplay(displayType);
                a.setIgnoreOrientationRequest(true);
                a.rotateDisplayForTopActivity(displayRotation);
                a.setDisplayNaturalOrientation(naturalOrientation);
                spyOn(a.top().mAppCompatController.getCameraOverrides());
                spyOn(a.top().info);
                doReturn(a.displayContent().getDisplayInfo()).when(
                        a.displayContent().mWmService.mDisplayManagerInternal).getDisplayInfo(
                        a.displayContent().mDisplayId);
            });
        }

        void makeCurrentDisplayDefault() {
            doReturn(activity().displayContent()).when(mWm).getDefaultDisplayContentLocked();
        }

        void checkDisplayRotation(@Surface.Rotation int expected) {
            assertEquals(expected, mCameraInfoProvider.getCameraDeviceRotation());
        }

        void checkIsPortraitCamera(boolean expected) {
            assertEquals(expected, mCameraInfoProvider.isCameraDeviceNaturalOrientationPortrait());
        }

        void checkIsCameraDisplayRotationPortrait(boolean expected) {
            assertEquals(expected, mCameraInfoProvider.isCameraDeviceOrientationPortrait());
        }

        void checkOrientationEventListenerSetUp(boolean expected) {
            assertEquals(expected, mCameraInfoProvider.mOrientationEventListener != null);
        }
        void setSensorOrientation(int orientation) {
            mCameraInfoProvider.mOrientationEventListener.onOrientationChanged(orientation);
        }
    }
}