diff options
| author | 2023-03-21 16:15:43 +0000 | |
|---|---|---|
| committer | 2023-03-31 11:44:36 +0000 | |
| commit | f50f8dcb0c120f76ab6208e2b204440d19b25a47 (patch) | |
| tree | be4aac6db0ab654aef565899ede3cf70a0536a9d | |
| parent | 6a47399c9f5866f9fb59f0cf484533da397982bd (diff) | |
Prevent autorotation during hinge movement
Pauses autorotation when hinge angle sensor
reports values and display switch.
This reduces accidental rotation while
folding or unfolding a foldable device.
Bug: 233055896
Test: atest WmTests:DisplayRotationTests
Change-Id: I1b07e1e84ab1cafb0f2794d62d99e114908fe840
| -rw-r--r-- | core/res/res/values/config.xml | 14 | ||||
| -rw-r--r-- | core/res/res/values/symbols.xml | 4 | ||||
| -rw-r--r-- | services/core/java/com/android/server/wm/DisplayContent.java | 3 | ||||
| -rw-r--r-- | services/core/java/com/android/server/wm/DisplayRotation.java | 183 | ||||
| -rw-r--r-- | services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java | 214 |
5 files changed, 414 insertions, 4 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index ef19fc1f5360..639e54b7d23f 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -680,6 +680,20 @@ rotation. --> <bool name="config_windowManagerHalfFoldAutoRotateOverride">false</bool> + <!-- Indicates whether the window manager pauses autorotation when folding or unfolding + a foldable device based on hinge angle sensor events and physical display switch events. --> + <bool name="config_windowManagerPauseRotationWhenUnfolding">false</bool> + + <!-- Amount of time during which autorotation will be disabled since last hinge angle event --> + <integer name="config_pauseRotationWhenUnfolding_maxHingeAngle">0</integer> + + <!-- Maximum hinge angle event to be considered to disable autorotation when folding or + unfolding --> + <integer name="config_pauseRotationWhenUnfolding_hingeEventTimeout">0</integer> + + <!-- Amount of time during which autorotation will be disabled since last display switch --> + <integer name="config_pauseRotationWhenUnfolding_displaySwitchTimeout">0</integer> + <!-- When a device enters any of these states, it should be woken up. States are defined in device_state_configuration.xml. --> <integer-array name="config_deviceStatesOnWhichToWakeUp"> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 8855d5b3de25..5022e3237c4e 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4017,6 +4017,10 @@ <java-symbol type="array" name="config_halfFoldedDeviceStates" /> <java-symbol type="array" name="config_rearDisplayDeviceStates" /> <java-symbol type="bool" name="config_windowManagerHalfFoldAutoRotateOverride" /> + <java-symbol type="bool" name="config_windowManagerPauseRotationWhenUnfolding" /> + <java-symbol type="integer" name="config_pauseRotationWhenUnfolding_hingeEventTimeout" /> + <java-symbol type="integer" name="config_pauseRotationWhenUnfolding_maxHingeAngle" /> + <java-symbol type="integer" name="config_pauseRotationWhenUnfolding_displaySwitchTimeout" /> <java-symbol type="array" name="config_deviceStatesOnWhichToWakeUp" /> <java-symbol type="array" name="config_deviceStatesOnWhichToSleep" /> <java-symbol type="string" name="config_foldedArea" /> diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 89cb13a40f8d..ab109fcaa673 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -2921,6 +2921,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp /* includeRotationSettings */ false); mDisplaySwitchTransitionLauncher.requestDisplaySwitchTransitionIfNeeded(mDisplayId, mInitialDisplayWidth, mInitialDisplayHeight, newWidth, newHeight); + mDisplayRotation.physicalDisplayChanged(); } // If there is an override set for base values - use it, otherwise use new values. @@ -3291,7 +3292,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mTransitionController.unregisterLegacyListener(mFixedRotationTransitionListener); handleAnimatingStoppedAndTransition(); mWmService.stopFreezingDisplayLocked(); - mDisplayRotation.removeDefaultDisplayRotationChangedCallback(); mDeviceStateController.unregisterDeviceStateCallback(mDeviceStateConsumer); super.removeImmediately(); if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Removing display=" + this); @@ -3305,6 +3305,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mWindowingLayer.release(); mInputMonitor.onDisplayRemoved(); mWmService.mDisplayNotificationController.dispatchDisplayRemoved(this); + mDisplayRotation.onDisplayRemoved(); mWmService.mAccessibilityController.onDisplayRemoved(mDisplayId); mRootWindowContainer.mTaskSupervisor .getKeyguardController().onDisplayRemoved(mDisplayId); diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 6af1c7c9d656..628f4d3a85d6 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -51,8 +51,13 @@ import android.content.pm.ActivityInfo.ScreenOrientation; import android.content.pm.PackageManager; import android.content.res.Resources; import android.database.ContentObserver; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; import android.hardware.power.Boost; import android.os.Handler; +import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; @@ -1085,6 +1090,10 @@ public class DisplayRotation { return false; } + if (mFoldController != null && mFoldController.shouldDisableRotationSensor()) { + return false; + } + if (mSupportAutoRotation) { if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR @@ -1183,6 +1192,9 @@ public class DisplayRotation { int sensorRotation = mOrientationListener != null ? mOrientationListener.getProposedRotation() // may be -1 : -1; + if (mFoldController != null && mFoldController.shouldIgnoreSensorRotation()) { + sensorRotation = -1; + } if (mDeviceStateController.shouldReverseRotationDirectionAroundZAxis()) { sensorRotation = RotationUtils.reverseRotationDirectionAroundZAxis(sensorRotation); } @@ -1425,6 +1437,11 @@ public class DisplayRotation { return false; } + // Do not show rotation choice when fold controller blocks rotation sensor + if (mFoldController != null && mFoldController.shouldIgnoreSensorRotation()) { + return false; + } + // Don't show rotation choice if we are in tabletop or book modes. if (isTabletopAutoRotateOverrideEnabled()) return false; @@ -1527,6 +1544,13 @@ public class DisplayRotation { } } + void onDisplayRemoved() { + removeDefaultDisplayRotationChangedCallback(); + if (mFoldController != null) { + mFoldController.onDisplayRemoved(); + } + } + /** Return whether the rotation settings has changed. */ private boolean updateSettings() { final ContentResolver resolver = mContext.getContentResolver(); @@ -1622,6 +1646,22 @@ public class DisplayRotation { pw.println(prefix + " mLidOpenRotation=" + Surface.rotationToString(mLidOpenRotation)); pw.println(prefix + " mFixedToUserRotation=" + isFixedToUserRotation()); + if (mFoldController != null) { + pw.println(prefix + "FoldController"); + pw.println(prefix + " mPauseAutorotationDuringUnfolding=" + + mFoldController.mPauseAutorotationDuringUnfolding); + pw.println(prefix + " mShouldDisableRotationSensor=" + + mFoldController.mShouldDisableRotationSensor); + pw.println(prefix + " mShouldIgnoreSensorRotation=" + + mFoldController.mShouldIgnoreSensorRotation); + pw.println(prefix + " mLastDisplaySwitchTime=" + + mFoldController.mLastDisplaySwitchTime); + pw.println(prefix + " mLastHingeAngleEventTime=" + + mFoldController.mLastHingeAngleEventTime); + pw.println(prefix + " mDeviceState=" + + mFoldController.mDeviceState); + } + if (!mRotationHistory.mRecords.isEmpty()) { pw.println(); pw.println(prefix + " RotationHistory"); @@ -1663,13 +1703,37 @@ public class DisplayRotation { } } - private class FoldController { + /** + * Called by the DisplayContent when the physical display changes + */ + void physicalDisplayChanged() { + if (mFoldController != null) { + mFoldController.onPhysicalDisplayChanged(); + } + } + + @VisibleForTesting + long uptimeMillis() { + return SystemClock.uptimeMillis(); + } + + class FoldController { + private final boolean mPauseAutorotationDuringUnfolding; @Surface.Rotation private int mHalfFoldSavedRotation = -1; // No saved rotation private DeviceStateController.DeviceState mDeviceState = DeviceStateController.DeviceState.UNKNOWN; + private long mLastHingeAngleEventTime = 0; + private long mLastDisplaySwitchTime = 0; + private boolean mShouldIgnoreSensorRotation; + private boolean mShouldDisableRotationSensor; private boolean mInHalfFoldTransition = false; + private int mDisplaySwitchRotationBlockTimeMs; + private int mHingeAngleRotationBlockTimeMs; + private int mMaxHingeAngle; private final boolean mIsDisplayAlwaysSeparatingHinge; + private SensorManager mSensorManager; + private SensorEventListener mHingeAngleSensorEventListener; private final Set<Integer> mTabletopRotations; private final Runnable mActivityBoundsUpdateCallback; @@ -1726,6 +1790,48 @@ public class DisplayRotation { } } }; + + mPauseAutorotationDuringUnfolding = mContext.getResources().getBoolean( + R.bool.config_windowManagerPauseRotationWhenUnfolding); + + if (mPauseAutorotationDuringUnfolding) { + mDisplaySwitchRotationBlockTimeMs = mContext.getResources().getInteger( + R.integer.config_pauseRotationWhenUnfolding_displaySwitchTimeout); + mHingeAngleRotationBlockTimeMs = mContext.getResources().getInteger( + R.integer.config_pauseRotationWhenUnfolding_hingeEventTimeout); + mMaxHingeAngle = mContext.getResources().getInteger( + R.integer.config_pauseRotationWhenUnfolding_maxHingeAngle); + registerSensorManager(); + } + } + + private void registerSensorManager() { + mSensorManager = mContext.getSystemService(SensorManager.class); + if (mSensorManager != null) { + final Sensor hingeAngleSensor = mSensorManager + .getDefaultSensor(Sensor.TYPE_HINGE_ANGLE); + + if (hingeAngleSensor != null) { + mHingeAngleSensorEventListener = new SensorEventListener() { + @Override + public void onSensorChanged(SensorEvent event) { + onHingeAngleChanged(event.values[0]); + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + } + }; + mSensorManager.registerListener(mHingeAngleSensorEventListener, + hingeAngleSensor, SensorManager.SENSOR_DELAY_FASTEST, getHandler()); + } + } + } + + void onDisplayRemoved() { + if (mSensorManager != null && mHingeAngleSensorEventListener != null) { + mSensorManager.unregisterListener(mHingeAngleSensorEventListener); + } } boolean isDeviceInPosture(DeviceStateController.DeviceState state, boolean isTabletop) { @@ -1755,6 +1861,7 @@ public class DisplayRotation { boolean shouldRevertOverriddenRotation() { // When transitioning to open. return mDeviceState == DeviceStateController.DeviceState.OPEN + && !mShouldIgnoreSensorRotation // Ignore if the hinge angle still moving && mInHalfFoldTransition && mHalfFoldSavedRotation != -1 // Ignore if we've already reverted. && mUserRotationMode @@ -1801,6 +1908,80 @@ public class DisplayRotation { UiThread.getHandler().postDelayed(mActivityBoundsUpdateCallback, FOLDING_RECOMPUTE_CONFIG_DELAY_MS); } + + boolean shouldIgnoreSensorRotation() { + return mShouldIgnoreSensorRotation; + } + + boolean shouldDisableRotationSensor() { + return mShouldDisableRotationSensor; + } + + private void updateSensorRotationBlockIfNeeded() { + final long currentTime = uptimeMillis(); + final boolean newShouldIgnoreRotation = + currentTime - mLastDisplaySwitchTime < mDisplaySwitchRotationBlockTimeMs + || currentTime - mLastHingeAngleEventTime < mHingeAngleRotationBlockTimeMs; + + if (newShouldIgnoreRotation != mShouldIgnoreSensorRotation) { + mShouldIgnoreSensorRotation = newShouldIgnoreRotation; + + // Resuming the autorotation + if (!mShouldIgnoreSensorRotation) { + if (mShouldDisableRotationSensor) { + // Sensor was disabled, let's re-enable it + mShouldDisableRotationSensor = false; + updateOrientationListenerLw(); + } else { + // Sensor was not disabled, let's update the rotation in case if we received + // some rotation sensor updates when autorotate was disabled + updateRotationAndSendNewConfigIfChanged(); + } + } + } + } + + void onPhysicalDisplayChanged() { + if (!mPauseAutorotationDuringUnfolding) return; + + mLastDisplaySwitchTime = uptimeMillis(); + + final boolean isUnfolding = + mDeviceState == DeviceStateController.DeviceState.OPEN + || mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED; + + if (isUnfolding) { + // Temporary disable rotation sensor updates when unfolding + mShouldDisableRotationSensor = true; + updateOrientationListenerLw(); + } + + updateSensorRotationBlockIfNeeded(); + getHandler().postDelayed(() -> { + synchronized (mLock) { + updateSensorRotationBlockIfNeeded(); + }; + }, mDisplaySwitchRotationBlockTimeMs); + } + + void onHingeAngleChanged(float hingeAngle) { + if (hingeAngle < mMaxHingeAngle) { + mLastHingeAngleEventTime = uptimeMillis(); + + updateSensorRotationBlockIfNeeded(); + + getHandler().postDelayed(() -> { + synchronized (mLock) { + updateSensorRotationBlockIfNeeded(); + }; + }, mHingeAngleRotationBlockTimeMs); + } + } + } + + @VisibleForTesting + Handler getHandler() { + return mService.mH; } private class OrientationListener extends WindowOrientationListener implements Runnable { 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 146ed34204f5..495f868b1b11 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java @@ -62,6 +62,7 @@ import android.hardware.devicestate.DeviceStateManager; import android.os.IBinder; import android.os.PowerManagerInternal; import android.os.SystemClock; +import android.os.Handler; import android.platform.test.annotations.Presubmit; import android.provider.Settings; import android.view.DisplayAddress; @@ -76,6 +77,9 @@ import com.android.server.LocalServices; import com.android.server.UiThread; import com.android.server.policy.WindowManagerPolicy; import com.android.server.statusbar.StatusBarManagerInternal; +import com.android.server.testutils.OffsettableClock; +import com.android.server.testutils.TestHandler; +import com.android.server.wm.DisplayContent.FixedRotationTransitionListener; import org.junit.After; import org.junit.AfterClass; @@ -104,6 +108,9 @@ public class DisplayRotationTests { private static final long UI_HANDLER_WAIT_TIMEOUT_MS = 50; private StatusBarManagerInternal mPreviousStatusBarManagerInternal; + private static final OffsettableClock sClock = new OffsettableClock.Stopped(); + private static TestHandler sHandler; + private static long sCurrentUptimeMillis = 10_000; private static WindowManagerService sMockWm; private DisplayContent mMockDisplayContent; @@ -113,6 +120,7 @@ public class DisplayRotationTests { private Resources mMockRes; private SensorManager mMockSensorManager; private Sensor mFakeOrientationSensor; + private Sensor mFakeHingeAngleSensor; private DisplayWindowSettings mMockDisplayWindowSettings; private ContentResolver mMockResolver; private FakeSettingsProvider mFakeSettingsProvider; @@ -125,6 +133,9 @@ public class DisplayRotationTests { private ContentObserver mUserRotationObserver; private SensorEventListener mOrientationSensorListener; + ArgumentCaptor<SensorEventListener> mHingeAngleSensorListenerCaptor = ArgumentCaptor.forClass( + SensorEventListener.class); + private DisplayRotationBuilder mBuilder; private DeviceStateController mDeviceStateController; @@ -135,6 +146,7 @@ public class DisplayRotationTests { sMockWm = mock(WindowManagerService.class); sMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class); sMockWm.mPolicy = mock(WindowManagerPolicy.class); + sHandler = new TestHandler(null, sClock); } @AfterClass @@ -468,12 +480,16 @@ public class DisplayRotationTests { } private SensorEvent createSensorEvent(int rotation) throws Exception { + return createSensorEvent(mFakeOrientationSensor, rotation); + } + + private SensorEvent createSensorEvent(Sensor sensor, int value) throws Exception { final Constructor<SensorEvent> constructor = SensorEvent.class.getDeclaredConstructor(int.class); constructor.setAccessible(true); final SensorEvent event = constructor.newInstance(1); - event.sensor = mFakeOrientationSensor; - event.values[0] = rotation; + event.sensor = sensor; + event.values[0] = value; event.timestamp = SystemClock.elapsedRealtimeNanos(); return event; } @@ -943,6 +959,120 @@ public class DisplayRotationTests { Surface.ROTATION_0, Surface.ROTATION_90, false /* forceUpdate */)); } + @Test + public void testSensorRotationAfterDisplayChangeBeforeTimeout_ignoresSensor() throws Exception { + mBuilder.setSupportHalfFoldAutoRotateOverride(true) + .setPauseRotationWhenUnfolding(true) + .setDisplaySwitchRotationBlockTimeMs(1000) + .build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + thawRotation(); + enableOrientationSensor(); + + mTarget.physicalDisplayChanged(); + + moveTimeForward(900); + mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90)); + assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation( + SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); + } + + @Test + public void testSensorRotationAfterDisplayChangeAfterTimeout_usesSensor() throws Exception { + mBuilder.setSupportHalfFoldAutoRotateOverride(true) + .setPauseRotationWhenUnfolding(true) + .setDisplaySwitchRotationBlockTimeMs(1000) + .build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + thawRotation(); + enableOrientationSensor(); + + mTarget.physicalDisplayChanged(); + + moveTimeForward(1100); + mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90)); + assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation( + SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); + } + + @Test + public void testSensorRotationAfterHingeEventBeforeTimeout_ignoresSensor() throws Exception { + mBuilder.setSupportHalfFoldAutoRotateOverride(true) + .setPauseRotationWhenUnfolding(true) + .setMaxHingeAngle(165) + .setHingeAngleRotationBlockTimeMs(400) + .build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + thawRotation(); + enableOrientationSensor(); + + sendHingeAngleEvent(130); + + moveTimeForward( 300); + mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90)); + assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation( + SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); + } + + @Test + public void testSensorRotationAfterHingeEventBeforeTimeoutFlagDisabled_usesSensorData() + throws Exception { + mBuilder.setSupportHalfFoldAutoRotateOverride(true) + .setPauseRotationWhenUnfolding(false) + .setMaxHingeAngle(165) + .setHingeAngleRotationBlockTimeMs(400) + .build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + thawRotation(); + enableOrientationSensor(); + + sendHingeAngleEvent(130); + + moveTimeForward( 300); + mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90)); + assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation( + SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); + } + + @Test + public void testSensorRotationAfterHingeEventAfterTimeout_usesSensorData() throws Exception { + mBuilder.setSupportHalfFoldAutoRotateOverride(true) + .setPauseRotationWhenUnfolding(true) + .setMaxHingeAngle(165) + .setHingeAngleRotationBlockTimeMs(400) + .build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + thawRotation(); + enableOrientationSensor(); + + sendHingeAngleEvent(180); + + moveTimeForward(1010); + mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90)); + assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation( + SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); + } + + + @Test + public void testSensorRotationAfterLargeHingeEventBeforeTimeout_usesSensor() throws Exception { + mBuilder.setSupportHalfFoldAutoRotateOverride(true) + .setPauseRotationWhenUnfolding(true) + .setMaxHingeAngle(165) + .setHingeAngleRotationBlockTimeMs(400) + .build(); + configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); + thawRotation(); + enableOrientationSensor(); + + sendHingeAngleEvent(180); + + moveTimeForward(300); + mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90)); + assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation( + SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); + } + // ======================== // Non-rotation API Tests // ======================== @@ -963,6 +1093,12 @@ public class DisplayRotationTests { + " fixed to user rotation.", mTarget.isFixedToUserRotation()); } + private void moveTimeForward(long timeMillis) { + sCurrentUptimeMillis += timeMillis; + sClock.fastForward(timeMillis); + sHandler.timeAdvance(); + } + /** * Call {@link DisplayRotation#configure(int, int)} to configure {@link #mTarget} * according to given parameters. @@ -995,6 +1131,17 @@ public class DisplayRotationTests { mTarget.configure(width, height); } + private void sendHingeAngleEvent(int hingeAngle) { + mHingeAngleSensorListenerCaptor.getAllValues().forEach(sensorEventListener -> { + try { + sensorEventListener.onSensorChanged(createSensorEvent(mFakeHingeAngleSensor, + hingeAngle)); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } + private void freezeRotation(int rotation) { mTarget.freezeRotation(rotation); @@ -1016,7 +1163,11 @@ public class DisplayRotationTests { private class DisplayRotationBuilder { private boolean mIsDefaultDisplay = true; private boolean mSupportAutoRotation = true; + private boolean mPauseRotationWhenUnfolding = false; private boolean mSupportHalfFoldAutoRotateOverride = false; + private int mDisplaySwitchRotationBlockTimeMs; + private int mHingeAngleRotationBlockTimeMs; + private int mMaxHingeAngle; private int mLidOpenRotation = WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; private int mCarDockRotation; @@ -1028,6 +1179,29 @@ public class DisplayRotationTests { return this; } + public DisplayRotationBuilder setPauseRotationWhenUnfolding( + boolean pauseRotationWhenUnfolding) { + mPauseRotationWhenUnfolding = pauseRotationWhenUnfolding; + return this; + } + + public DisplayRotationBuilder setDisplaySwitchRotationBlockTimeMs( + int displaySwitchRotationBlockTimeMs) { + mDisplaySwitchRotationBlockTimeMs = displaySwitchRotationBlockTimeMs; + return this; + } + + public DisplayRotationBuilder setHingeAngleRotationBlockTimeMs( + int hingeAngleRotationBlockTimeMs) { + mHingeAngleRotationBlockTimeMs = hingeAngleRotationBlockTimeMs; + return this; + } + + public DisplayRotationBuilder setMaxHingeAngle(int maxHingeAngle) { + mMaxHingeAngle = maxHingeAngle; + return this; + } + private DisplayRotationBuilder setSupportAutoRotation(boolean supportAutoRotation) { mSupportAutoRotation = supportAutoRotation; return this; @@ -1153,10 +1327,27 @@ public class DisplayRotationTests { when(mMockDisplayContent.getWindowConfiguration()) .thenReturn(new WindowConfiguration()); + Field field = DisplayContent.class + .getDeclaredField("mFixedRotationTransitionListener"); + field.setAccessible(true); + field.set(mMockDisplayContent, mock(FixedRotationTransitionListener.class)); + mMockDisplayPolicy = mock(DisplayPolicy.class); mMockRes = mock(Resources.class); when(mMockContext.getResources()).thenReturn((mMockRes)); + when(mMockRes.getBoolean(com.android.internal.R.bool + .config_windowManagerPauseRotationWhenUnfolding)) + .thenReturn(mPauseRotationWhenUnfolding); + when(mMockRes.getInteger(com.android.internal.R.integer + .config_pauseRotationWhenUnfolding_displaySwitchTimeout)) + .thenReturn(mDisplaySwitchRotationBlockTimeMs); + when(mMockRes.getInteger(com.android.internal.R.integer + .config_pauseRotationWhenUnfolding_hingeEventTimeout)) + .thenReturn(mHingeAngleRotationBlockTimeMs); + when(mMockRes.getInteger(com.android.internal.R.integer + .config_pauseRotationWhenUnfolding_maxHingeAngle)) + .thenReturn(mMaxHingeAngle); when(mMockRes.getBoolean(com.android.internal.R.bool.config_supportAutoRotation)) .thenReturn(mSupportAutoRotation); when(mMockRes.getInteger(com.android.internal.R.integer.config_lidOpenRotation)) @@ -1169,11 +1360,16 @@ public class DisplayRotationTests { .thenReturn(convertRotationToDegrees(mUndockedHdmiRotation)); mMockSensorManager = mock(SensorManager.class); + when(mMockContext.getSystemService(SensorManager.class)) + .thenReturn(mMockSensorManager); when(mMockContext.getSystemService(Context.SENSOR_SERVICE)) .thenReturn(mMockSensorManager); mFakeOrientationSensor = createSensor(Sensor.TYPE_DEVICE_ORIENTATION); when(mMockSensorManager.getSensorList(Sensor.TYPE_DEVICE_ORIENTATION)).thenReturn( Collections.singletonList(mFakeOrientationSensor)); + mFakeHingeAngleSensor = mock(Sensor.class); + when(mMockSensorManager.getDefaultSensor(Sensor.TYPE_HINGE_ANGLE)).thenReturn( + mFakeHingeAngleSensor); when(mMockContext.getResources().getBoolean( com.android.internal.R.bool.config_windowManagerHalfFoldAutoRotateOverride)) @@ -1200,6 +1396,10 @@ public class DisplayRotationTests { reset(sMockWm); + verify(mMockSensorManager, atLeast(0)).registerListener( + mHingeAngleSensorListenerCaptor.capture(), eq(mFakeHingeAngleSensor), anyInt(), + any()); + captureObservers(); } } @@ -1226,5 +1426,15 @@ public class DisplayRotationTests { mProposedRotationCallback.accept(rotation); } } + + @Override + Handler getHandler() { + return sHandler; + } + + @Override + long uptimeMillis() { + return sCurrentUptimeMillis; + } } } |