diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 3d7fb16bb846b..334a7275ebe28 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -469,6 +469,18 @@ "group": "WM_DEBUG_TASKS", "at": "com\/android\/server\/wm\/RecentTasks.java" }, + "-1643780158": { + "message": "Saving original orientation before camera compat, last orientation is %d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" + }, + "-1639406696": { + "message": "NOSENSOR override detected", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java" + }, "-1638958146": { "message": "Removing activity %s from task=%s adding to task=%s Callers=%s", "level": "INFO", @@ -751,6 +763,12 @@ "group": "WM_DEBUG_IME", "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" }, + "-1397175017": { + "message": "Other orientation overrides are in place: not reverting", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java" + }, "-1394745488": { "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s", "level": "INFO", @@ -1669,6 +1687,12 @@ "group": "WM_DEBUG_WINDOW_TRANSITIONS", "at": "com\/android\/server\/wm\/Transition.java" }, + "-529187878": { + "message": "Reverting orientation after camera compat force rotation", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" + }, "-521613870": { "message": "App died during pause, not stopping: %s", "level": "VERBOSE", @@ -2365,6 +2389,12 @@ "group": "WM_DEBUG_FOCUS_LIGHT", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "138097009": { + "message": "NOSENSOR override is absent: reverting", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java" + }, "140319294": { "message": "IME target changed within ActivityRecord", "level": "DEBUG", diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 99b0645df6ac9..8934ff9a31005 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -746,6 +746,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp */ DisplayWindowPolicyControllerHelper mDwpcHelper; + private final DisplayRotationReversionController mRotationReversionController; + private final Consumer mUpdateWindowsForAnimator = w -> { WindowStateAnimator winAnimator = w.mWinAnimator; final ActivityRecord activity = w.mActivityRecord; @@ -1170,6 +1172,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mWmService.mLetterboxConfiguration.isCameraCompatTreatmentEnabled( /* checkDeviceConfig */ false) ? new DisplayRotationCompatPolicy(this) : null; + mRotationReversionController = new DisplayRotationReversionController(this); mInputMonitor = new InputMonitor(mWmService, this); mInsetsPolicy = new InsetsPolicy(mInsetsStateController, this); @@ -1283,6 +1286,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp .show(mOverlayLayer); } + DisplayRotationReversionController getRotationReversionController() { + return mRotationReversionController; + } + boolean isReady() { // The display is ready when the system and the individual display are both ready. return mWmService.mDisplayReady && mDisplayReady; @@ -1665,9 +1672,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } private boolean updateOrientation(boolean forceUpdate) { + final WindowContainer prevOrientationSource = mLastOrientationSource; final int orientation = getOrientation(); // The last orientation source is valid only after getOrientation. final WindowContainer orientationSource = getLastOrientationSource(); + if (orientationSource != prevOrientationSource + && mRotationReversionController.isRotationReversionEnabled()) { + mRotationReversionController.updateForNoSensorOverride(); + } final ActivityRecord r = orientationSource != null ? orientationSource.asActivityRecord() : null; if (r != null) { diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 248d89b49a670..0a1e29ace045e 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -34,6 +34,9 @@ import static com.android.server.wm.DisplayRotationProto.IS_FIXED_TO_USER_ROTATI import static com.android.server.wm.DisplayRotationProto.LAST_ORIENTATION; import static com.android.server.wm.DisplayRotationProto.ROTATION; import static com.android.server.wm.DisplayRotationProto.USER_ROTATION; +import static com.android.server.wm.DisplayRotationReversionController.REVERSION_TYPE_CAMERA_COMPAT; +import static com.android.server.wm.DisplayRotationReversionController.REVERSION_TYPE_HALF_FOLD; +import static com.android.server.wm.DisplayRotationReversionController.REVERSION_TYPE_NOSENSOR; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_ACTIVE; @@ -106,6 +109,9 @@ public class DisplayRotation { int mExit; } + @Nullable + final FoldController mFoldController; + private final WindowManagerService mService; private final DisplayContent mDisplayContent; private final DisplayPolicy mDisplayPolicy; @@ -127,8 +133,6 @@ public class DisplayRotation { private OrientationListener mOrientationListener; private StatusBarManagerInternal mStatusBarManagerInternal; private SettingsObserver mSettingsObserver; - @Nullable - private FoldController mFoldController; @NonNull private final DeviceStateController mDeviceStateController; @@ -279,7 +283,11 @@ public class DisplayRotation { if (mSupportAutoRotation && mContext.getResources().getBoolean( R.bool.config_windowManagerHalfFoldAutoRotateOverride)) { mFoldController = new FoldController(); + } else { + mFoldController = null; } + } else { + mFoldController = null; } } @@ -337,6 +345,11 @@ public class DisplayRotation { return -1; } + @VisibleForTesting + boolean useDefaultSettingsProvider() { + return isDefaultDisplay; + } + /** * Updates the configuration which may have different values depending on current user, e.g. * runtime resource overlay. @@ -870,7 +883,7 @@ public class DisplayRotation { @VisibleForTesting void setUserRotation(int userRotationMode, int userRotation) { mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; - if (isDefaultDisplay) { + if (useDefaultSettingsProvider()) { // We'll be notified via settings listener, so we don't need to update internal values. final ContentResolver res = mContext.getContentResolver(); final int accelerometerRotation = @@ -1814,7 +1827,7 @@ public class DisplayRotation { return false; } if (mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED) { - return !(isTabletop ^ mTabletopRotations.contains(mRotation)); + return isTabletop == mTabletopRotations.contains(mRotation); } return true; } @@ -1838,14 +1851,17 @@ public class DisplayRotation { return mDeviceState == DeviceStateController.DeviceState.OPEN && !mShouldIgnoreSensorRotation // Ignore if the hinge angle still moving && mInHalfFoldTransition - && mHalfFoldSavedRotation != -1 // Ignore if we've already reverted. + && mDisplayContent.getRotationReversionController().isOverrideActive( + REVERSION_TYPE_HALF_FOLD) && mUserRotationMode - == WindowManagerPolicy.USER_ROTATION_LOCKED; // Ignore if we're unlocked. + == WindowManagerPolicy.USER_ROTATION_LOCKED; // Ignore if we're unlocked. } int revertOverriddenRotation() { int savedRotation = mHalfFoldSavedRotation; mHalfFoldSavedRotation = -1; + mDisplayContent.getRotationReversionController() + .revertOverride(REVERSION_TYPE_HALF_FOLD); mInHalfFoldTransition = false; return savedRotation; } @@ -1865,6 +1881,8 @@ public class DisplayRotation { && mDeviceState != DeviceStateController.DeviceState.HALF_FOLDED) { // The device has transitioned to HALF_FOLDED state: save the current rotation and // update the device rotation. + mDisplayContent.getRotationReversionController().beforeOverrideApplied( + REVERSION_TYPE_HALF_FOLD); mHalfFoldSavedRotation = mRotation; mDeviceState = newState; // Now mFoldState is set to HALF_FOLDED, the overrideFrozenRotation function will @@ -2069,6 +2087,8 @@ public class DisplayRotation { final int mHalfFoldSavedRotation; final boolean mInHalfFoldTransition; final DeviceStateController.DeviceState mDeviceState; + @Nullable final boolean[] mRotationReversionSlots; + @Nullable final String mDisplayRotationCompatPolicySummary; Record(DisplayRotation dr, int fromRotation, int toRotation) { @@ -2109,6 +2129,8 @@ public class DisplayRotation { ? null : dc.mDisplayRotationCompatPolicy .getSummaryForDisplayRotationHistoryRecord(); + mRotationReversionSlots = + dr.mDisplayContent.getRotationReversionController().getSlotsCopy(); } void dump(String prefix, PrintWriter pw) { @@ -2134,6 +2156,12 @@ public class DisplayRotation { if (mDisplayRotationCompatPolicySummary != null) { pw.println(prefix + mDisplayRotationCompatPolicySummary); } + if (mRotationReversionSlots != null) { + pw.println(prefix + " reversionSlots= NOSENSOR " + + mRotationReversionSlots[REVERSION_TYPE_NOSENSOR] + ", CAMERA " + + mRotationReversionSlots[REVERSION_TYPE_CAMERA_COMPAT] + " HALF_FOLD " + + mRotationReversionSlots[REVERSION_TYPE_HALF_FOLD]); + } } } diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java index fb72d6c6b56d3..ae93a9496f7c1 100644 --- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java @@ -33,6 +33,7 @@ import static android.view.Display.TYPE_INTERNAL; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES; +import static com.android.server.wm.DisplayRotationReversionController.REVERSION_TYPE_CAMERA_COMPAT; import android.annotation.NonNull; import android.annotation.Nullable; @@ -156,6 +157,11 @@ final class DisplayRotationCompatPolicy { @ScreenOrientation int getOrientation() { mLastReportedOrientation = getOrientationInternal(); + if (mLastReportedOrientation != SCREEN_ORIENTATION_UNSPECIFIED) { + rememberOverriddenOrientationIfNeeded(); + } else { + restoreOverriddenOrientationIfNeeded(); + } return mLastReportedOrientation; } @@ -277,6 +283,34 @@ final class DisplayRotationCompatPolicy { + " }"; } + private void restoreOverriddenOrientationIfNeeded() { + if (!isOrientationOverridden()) { + return; + } + if (mDisplayContent.getRotationReversionController().revertOverride( + REVERSION_TYPE_CAMERA_COMPAT)) { + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Reverting orientation after camera compat force rotation"); + // Reset last orientation source since we have reverted the orientation. + mDisplayContent.mLastOrientationSource = null; + } + } + + private boolean isOrientationOverridden() { + return mDisplayContent.getRotationReversionController().isOverrideActive( + REVERSION_TYPE_CAMERA_COMPAT); + } + + private void rememberOverriddenOrientationIfNeeded() { + if (!isOrientationOverridden()) { + mDisplayContent.getRotationReversionController().beforeOverrideApplied( + REVERSION_TYPE_CAMERA_COMPAT); + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Saving original orientation before camera compat, last orientation is %d", + mDisplayContent.getLastOrientation()); + } + } + // Refreshing only when configuration changes after rotation. private boolean shouldRefreshActivity(ActivityRecord activity, Configuration newConfig, Configuration lastReportedConfig) { diff --git a/services/core/java/com/android/server/wm/DisplayRotationReversionController.java b/services/core/java/com/android/server/wm/DisplayRotationReversionController.java new file mode 100644 index 0000000000000..d3a8a82f8f871 --- /dev/null +++ b/services/core/java/com/android/server/wm/DisplayRotationReversionController.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2023 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.WINDOWING_MODE_FULLSCREEN; + +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; + +import android.annotation.Nullable; +import android.app.WindowConfiguration; +import android.content.ActivityInfoProto; +import android.view.Surface; + +import com.android.internal.protolog.common.ProtoLog; +import com.android.server.policy.WindowManagerPolicy; + +/** + * Defines the behavior of reversion from device rotation overrides. + * + *

There are 3 override types: + *

    + *
  1. The top application has {@link SCREEN_ORIENTATION_NOSENSOR} set and is rotated to + * {@link ROTATION_0}. + *
  2. Camera compat treatment has rotated the app {@link DisplayRotationCompatPolicy}. + *
  3. The device is half-folded and has auto-rotate is temporarily enabled. + *
+ * + *

Before an override is enabled, a component should call {@code beforeOverrideApplied}. When + * it wishes to revert, it should call {@code revertOverride}. The user rotation will be restored + * if there are no other overrides present. + */ +final class DisplayRotationReversionController { + + static final int REVERSION_TYPE_NOSENSOR = 0; + static final int REVERSION_TYPE_CAMERA_COMPAT = 1; + static final int REVERSION_TYPE_HALF_FOLD = 2; + private static final int NUM_SLOTS = 3; + + @Surface.Rotation + private int mUserRotationOverridden = WindowConfiguration.ROTATION_UNDEFINED; + @WindowManagerPolicy.UserRotationMode + private int mUserRotationModeOverridden; + + private final boolean[] mSlots = new boolean[NUM_SLOTS]; + private final DisplayContent mDisplayContent; + + DisplayRotationReversionController(DisplayContent content) { + mDisplayContent = content; + } + + boolean isRotationReversionEnabled() { + return mDisplayContent.mDisplayRotationCompatPolicy != null + || mDisplayContent.getDisplayRotation().mFoldController != null + || mDisplayContent.getIgnoreOrientationRequest(); + } + + void beforeOverrideApplied(int slotIndex) { + if (mSlots[slotIndex]) return; + maybeSaveUserRotation(); + mSlots[slotIndex] = true; + } + + boolean isOverrideActive(int slotIndex) { + return mSlots[slotIndex]; + } + + @Nullable + boolean[] getSlotsCopy() { + return isRotationReversionEnabled() ? mSlots.clone() : null; + } + + void updateForNoSensorOverride() { + if (!mSlots[REVERSION_TYPE_NOSENSOR]) { + if (isTopFullscreenActivityNoSensor()) { + ProtoLog.v(WM_DEBUG_ORIENTATION, "NOSENSOR override detected"); + beforeOverrideApplied(REVERSION_TYPE_NOSENSOR); + } + } else { + if (!isTopFullscreenActivityNoSensor()) { + ProtoLog.v(WM_DEBUG_ORIENTATION, "NOSENSOR override is absent: reverting"); + revertOverride(REVERSION_TYPE_NOSENSOR); + } + } + } + + boolean isAnyOverrideActive() { + for (int i = 0; i < NUM_SLOTS; ++i) { + if (mSlots[i]) { + return true; + } + } + return false; + } + + boolean revertOverride(int slotIndex) { + if (!mSlots[slotIndex]) return false; + mSlots[slotIndex] = false; + if (isAnyOverrideActive()) { + ProtoLog.v(WM_DEBUG_ORIENTATION, + "Other orientation overrides are in place: not reverting"); + return false; + } + // Only override if the rotation is frozen and there are no other active slots. + if (mDisplayContent.getDisplayRotation().isRotationFrozen()) { + mDisplayContent.getDisplayRotation().setUserRotation( + mUserRotationModeOverridden, + mUserRotationOverridden); + return true; + } else { + return false; + } + } + + private void maybeSaveUserRotation() { + if (!isAnyOverrideActive()) { + mUserRotationModeOverridden = + mDisplayContent.getDisplayRotation().getUserRotationMode(); + mUserRotationOverridden = mDisplayContent.getDisplayRotation().getUserRotation(); + } + } + + private boolean isTopFullscreenActivityNoSensor() { + final Task topFullscreenTask = + mDisplayContent.getTask( + t -> t.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); + if (topFullscreenTask != null) { + final ActivityRecord topActivity = + topFullscreenTask.topRunningActivity(); + return topActivity != null && topActivity.getOrientation() + == ActivityInfoProto.SCREEN_ORIENTATION_NOSENSOR; + } + return false; + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index dc12469960ff2..4d7f37c97a4a1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -24,6 +24,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; @@ -1061,6 +1062,51 @@ public class DisplayContentTests extends WindowTestsBase { assertEquals(SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation()); } + private void updateAllDisplayContentAndRotation(DisplayContent dc) { + // NB updateOrientation will not revert the user orientation until a settings change + // takes effect. + dc.updateOrientation(); + dc.onDisplayChanged(dc); + dc.mWmService.updateRotation(true /* alwaysSendConfiguration */, + false /* forceRelayout */); + waitUntilHandlersIdle(); + } + + @Test + public void testNoSensorRevert() { + final DisplayContent dc = mDisplayContent; + spyOn(dc); + doReturn(true).when(dc).getIgnoreOrientationRequest(); + final DisplayRotation dr = dc.getDisplayRotation(); + spyOn(dr); + doReturn(false).when(dr).useDefaultSettingsProvider(); + final ActivityRecord app = new ActivityBuilder(mAtm).setCreateTask(true).build(); + app.setOrientation(SCREEN_ORIENTATION_LANDSCAPE, app); + + assertFalse(dc.getRotationReversionController().isAnyOverrideActive()); + dc.getDisplayRotation().setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, + ROTATION_90); + updateAllDisplayContentAndRotation(dc); + assertEquals(ROTATION_90, dc.getDisplayRotation() + .rotationForOrientation(SCREEN_ORIENTATION_UNSPECIFIED, ROTATION_90)); + + app.setOrientation(SCREEN_ORIENTATION_NOSENSOR); + updateAllDisplayContentAndRotation(dc); + assertTrue(dc.getRotationReversionController().isAnyOverrideActive()); + assertEquals(ROTATION_0, dc.getRotation()); + + app.setOrientation(SCREEN_ORIENTATION_UNSPECIFIED); + updateAllDisplayContentAndRotation(dc); + assertFalse(dc.getRotationReversionController().isAnyOverrideActive()); + assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, + dc.getDisplayRotation().getUserRotationMode()); + assertEquals(ROTATION_90, dc.getDisplayRotation().getUserRotation()); + assertEquals(ROTATION_90, dc.getDisplayRotation() + .rotationForOrientation(SCREEN_ORIENTATION_UNSPECIFIED, ROTATION_0)); + dc.getDisplayRotation().setUserRotation(WindowManagerPolicy.USER_ROTATION_FREE, + ROTATION_0); + } + @Test public void testOnDescendantOrientationRequestChanged() { final DisplayContent dc = createNewDisplay(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java index c2b3783b7311c..a3117269eb01a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java @@ -364,6 +364,23 @@ public final class DisplayRotationCompatPolicyTests extends WindowTestsBase { assertActivityRefreshRequested(/* refreshRequested */ true); } + @Test + public void testCameraDisconnected_revertRotationAndRefresh() throws Exception { + configureActivityAndDisplay(SCREEN_ORIENTATION_PORTRAIT, ORIENTATION_LANDSCAPE); + // Open camera and test for compat treatment + mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1); + callOnActivityConfigurationChanging(mActivity, /* isDisplayRotationChanging */ true); + assertEquals(mDisplayRotationCompatPolicy.getOrientation(), + SCREEN_ORIENTATION_LANDSCAPE); + assertActivityRefreshRequested(/* refreshRequested */ true); + // Close camera and test for revert + mCameraAvailabilityCallback.onCameraClosed(CAMERA_ID_1); + callOnActivityConfigurationChanging(mActivity, /* isDisplayRotationChanging */ true); + assertEquals(mDisplayRotationCompatPolicy.getOrientation(), + SCREEN_ORIENTATION_UNSPECIFIED); + assertActivityRefreshRequested(/* refreshRequested */ true); + } + @Test public void testGetOrientation_cameraConnectionClosed_returnUnspecified() { configureActivity(SCREEN_ORIENTATION_PORTRAIT); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java index 131ff7b2ab04f..950e9e4848b0d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java @@ -112,6 +112,7 @@ public class DisplayRotationTests { private static WindowManagerService sMockWm; private DisplayContent mMockDisplayContent; + private DisplayRotationReversionController mMockDisplayRotationReversionController; private DisplayPolicy mMockDisplayPolicy; private DisplayAddress mMockDisplayAddress; private Context mMockContext; @@ -1367,6 +1368,10 @@ public class DisplayRotationTests { when(mMockContext.getResources().getBoolean( com.android.internal.R.bool.config_windowManagerHalfFoldAutoRotateOverride)) .thenReturn(mSupportHalfFoldAutoRotateOverride); + mMockDisplayRotationReversionController = + mock(DisplayRotationReversionController.class); + when(mMockDisplayContent.getRotationReversionController()) + .thenReturn(mMockDisplayRotationReversionController); mMockResolver = mock(ContentResolver.class); when(mMockContext.getContentResolver()).thenReturn(mMockResolver);