diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 2c969aba8b3a2..c8f2777cc172a 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -1552,6 +1552,11 @@ public class DisplayRotation { } } + @Override + public boolean isKeyguardLocked() { + return mService.isKeyguardLocked(); + } + @Override public boolean isRotationResolverEnabled() { return mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE diff --git a/services/core/java/com/android/server/wm/WindowOrientationListener.java b/services/core/java/com/android/server/wm/WindowOrientationListener.java index 249880e7cf566..6a4767a21dc95 100644 --- a/services/core/java/com/android/server/wm/WindowOrientationListener.java +++ b/services/core/java/com/android/server/wm/WindowOrientationListener.java @@ -65,7 +65,10 @@ public abstract class WindowOrientationListener { private static final boolean USE_GRAVITY_SENSOR = false; private static final int DEFAULT_BATCH_LATENCY = 100000; private static final String KEY_ROTATION_RESOLVER_TIMEOUT = "rotation_resolver_timeout_millis"; + private static final String KEY_ROTATION_MEMORIZATION_TIMEOUT = + "rotation_memorization_timeout_millis"; private static final long DEFAULT_ROTATION_RESOLVER_TIMEOUT_MILLIS = 700L; + private static final long DEFAULT_ROTATION_MEMORIZATION_TIMEOUT_MILLIS = 300_000L; // 5 minutes private Handler mHandler; private SensorManager mSensorManager; @@ -291,6 +294,12 @@ public abstract class WindowOrientationListener { */ public abstract void onProposedRotationChanged(int rotation); + /** + * Whether the device is in the lock screen. + * @return returns true if the screen is locked. Otherwise, returns false. + */ + public abstract boolean isKeyguardLocked(); + public void dumpDebug(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); synchronized (mLock) { @@ -1062,13 +1071,17 @@ public abstract class WindowOrientationListener { } final class OrientationSensorJudge extends OrientationJudge { + private static final int ROTATION_UNSET = -1; private boolean mTouching; private long mTouchEndedTimestampNanos = Long.MIN_VALUE; private int mProposedRotation = -1; private int mDesiredRotation = -1; private boolean mRotationEvaluationScheduled; private long mRotationResolverTimeoutMillis; + private long mRotationMemorizationTimeoutMillis; private final ActivityTaskManagerInternal mActivityTaskManagerInternal; + private long mLastRotationResolutionTimeStamp; + private int mLastRotationResolution = ROTATION_UNSET; private int mCurrentCallbackId = 0; private Runnable mCancelRotationResolverRequest; @@ -1084,7 +1097,8 @@ public abstract class WindowOrientationListener { DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_WINDOW_MANAGER, ActivityThread.currentApplication().getMainExecutor(), (properties) -> { final Set keys = properties.getKeyset(); - if (keys.contains(KEY_ROTATION_RESOLVER_TIMEOUT)) { + if (keys.contains(KEY_ROTATION_RESOLVER_TIMEOUT) + || keys.contains(KEY_ROTATION_MEMORIZATION_TIMEOUT)) { readRotationResolverParameters(); } }); @@ -1093,9 +1107,13 @@ public abstract class WindowOrientationListener { private void readRotationResolverParameters() { mRotationResolverTimeoutMillis = DeviceConfig.getLong( - DeviceConfig.NAMESPACE_WINDOW_MANAGER, + NAMESPACE_WINDOW_MANAGER, KEY_ROTATION_RESOLVER_TIMEOUT, DEFAULT_ROTATION_RESOLVER_TIMEOUT_MILLIS); + mRotationMemorizationTimeoutMillis = DeviceConfig.getLong( + NAMESPACE_WINDOW_MANAGER, + KEY_ROTATION_MEMORIZATION_TIMEOUT, + DEFAULT_ROTATION_MEMORIZATION_TIMEOUT_MILLIS); } @Override @@ -1133,6 +1151,19 @@ public abstract class WindowOrientationListener { FrameworkStatsLog.DEVICE_ROTATED__ROTATION_EVENT_TYPE__ACTUAL_EVENT); if (isRotationResolverEnabled()) { + if (isKeyguardLocked()) { + if (mLastRotationResolution != ROTATION_UNSET + && SystemClock.uptimeMillis() - mLastRotationResolutionTimeStamp + < mRotationMemorizationTimeoutMillis) { + Slog.d(TAG, + "Reusing the last rotation resolution: " + mLastRotationResolution); + finalizeRotation(mLastRotationResolution); + } else { + finalizeRotation(Surface.ROTATION_0); + } + return; + } + if (mRotationResolverService == null) { mRotationResolverService = LocalServices.getService( RotationResolverInternal.class); @@ -1207,6 +1238,7 @@ public abstract class WindowOrientationListener { + Surface.rotationToString(mProposedRotation)); pw.println(prefix + "mTouching=" + mTouching); pw.println(prefix + "mTouchEndedTimestampNanos=" + mTouchEndedTimestampNanos); + pw.println(prefix + "mLastRotationResolution=" + mLastRotationResolution); } @Override @@ -1242,6 +1274,8 @@ public abstract class WindowOrientationListener { newRotation = evaluateRotationChangeLocked(); } if (newRotation >= 0) { + mLastRotationResolution = newRotation; + mLastRotationResolutionTimeStamp = SystemClock.uptimeMillis(); onProposedRotationChanged(newRotation); } } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java index 9ce3bf4c45b0d..2794d48371012 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java @@ -70,6 +70,7 @@ public class WindowOrientationListenerTest { mWindowOrientationListener = new TestableWindowOrientationListener(mMockContext, mHandler); mWindowOrientationListener.mRotationResolverService = mFakeRotationResolverInternal; + mWindowOrientationListener.mIsScreenLocked = false; mFakeSensor = new Sensor(mMockInputSensorInfo); mFakeSensorEvent = new SensorEvent(mFakeSensor, /* accuracy */ 1, /* timestamp */ 1L, @@ -156,14 +157,29 @@ public class WindowOrientationListenerTest { } } + @Test + public void testOnSensorChanged_inLockScreen_doNotCallRotationResolver() { + mWindowOrientationListener.mIsScreenLocked = true; + + mWindowOrientationListener.mOrientationJudge.onSensorChanged(mFakeSensorEvent); + + assertThat(mWindowOrientationListener.mIsOnProposedRotationChangedCalled).isFalse(); + } + final class TestableWindowOrientationListener extends WindowOrientationListener { - boolean mIsOnProposedRotationChangedCalled = false; + private boolean mIsOnProposedRotationChangedCalled = false; + private boolean mIsScreenLocked; TestableWindowOrientationListener(Context context, Handler handler) { super(context, handler); this.mOrientationJudge = new OrientationSensorJudge(); } + @Override + public boolean isKeyguardLocked() { + return mIsScreenLocked; + } + @Override public void onProposedRotationChanged(int rotation) { mFinalizedRotation = rotation;