Merge "Prevent autorotation during hinge movement" into tm-qpr-dev am: 74b7ca81aa
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22161746 Change-Id: Ie25727c1588156644081e661180c088ceec3ca19 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -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">
|
||||
|
||||
@@ -4032,6 +4032,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" />
|
||||
|
||||
@@ -2886,6 +2886,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.
|
||||
@@ -3263,6 +3264,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);
|
||||
|
||||
@@ -52,8 +52,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;
|
||||
@@ -1052,6 +1057,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
|
||||
@@ -1149,6 +1158,9 @@ public class DisplayRotation {
|
||||
int sensorRotation = mOrientationListener != null
|
||||
? mOrientationListener.getProposedRotation() // may be -1
|
||||
: -1;
|
||||
if (mFoldController != null && mFoldController.shouldIgnoreSensorRotation()) {
|
||||
sensorRotation = -1;
|
||||
}
|
||||
if (mDeviceStateController.shouldReverseRotationDirectionAroundZAxis()) {
|
||||
// Flipping 270 and 90 has the same effect as changing the direction which rotation is
|
||||
// applied.
|
||||
@@ -1396,6 +1408,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;
|
||||
|
||||
@@ -1489,6 +1506,12 @@ public class DisplayRotation {
|
||||
}
|
||||
}
|
||||
|
||||
void onDisplayRemoved() {
|
||||
if (mFoldController != null) {
|
||||
mFoldController.onDisplayRemoved();
|
||||
}
|
||||
}
|
||||
|
||||
/** Return whether the rotation settings has changed. */
|
||||
private boolean updateSettings() {
|
||||
final ContentResolver resolver = mContext.getContentResolver();
|
||||
@@ -1578,6 +1601,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");
|
||||
@@ -1619,13 +1658,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;
|
||||
|
||||
@@ -1682,6 +1745,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) {
|
||||
@@ -1711,6 +1816,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
|
||||
@@ -1757,6 +1863,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 {
|
||||
|
||||
@@ -61,6 +61,7 @@ import android.hardware.SensorManager;
|
||||
import android.hardware.devicestate.DeviceStateManager;
|
||||
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;
|
||||
@@ -74,6 +75,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;
|
||||
@@ -101,6 +105,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;
|
||||
@@ -110,6 +117,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;
|
||||
@@ -122,6 +130,9 @@ public class DisplayRotationTests {
|
||||
private ContentObserver mUserRotationObserver;
|
||||
private SensorEventListener mOrientationSensorListener;
|
||||
|
||||
ArgumentCaptor<SensorEventListener> mHingeAngleSensorListenerCaptor = ArgumentCaptor.forClass(
|
||||
SensorEventListener.class);
|
||||
|
||||
private DisplayRotationBuilder mBuilder;
|
||||
|
||||
private DeviceStateController mDeviceStateController;
|
||||
@@ -132,6 +143,7 @@ public class DisplayRotationTests {
|
||||
sMockWm = mock(WindowManagerService.class);
|
||||
sMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class);
|
||||
sMockWm.mPolicy = mock(WindowManagerPolicy.class);
|
||||
sHandler = new TestHandler(null, sClock);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
@@ -464,12 +476,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;
|
||||
}
|
||||
@@ -901,6 +917,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
|
||||
// ========================
|
||||
@@ -921,6 +1051,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.
|
||||
@@ -953,6 +1089,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);
|
||||
|
||||
@@ -974,7 +1121,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;
|
||||
@@ -986,6 +1137,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;
|
||||
@@ -1111,10 +1285,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))
|
||||
@@ -1127,11 +1318,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))
|
||||
@@ -1160,10 +1356,24 @@ public class DisplayRotationTests {
|
||||
WindowManagerService service, DisplayContent displayContent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
Handler getHandler() {
|
||||
return sHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
long uptimeMillis() {
|
||||
return sCurrentUptimeMillis;
|
||||
}
|
||||
};
|
||||
|
||||
reset(sMockWm);
|
||||
|
||||
verify(mMockSensorManager, atLeast(0)).registerListener(
|
||||
mHingeAngleSensorListenerCaptor.capture(), eq(mFakeHingeAngleSensor), anyInt(),
|
||||
any());
|
||||
|
||||
captureObservers();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user