From 24afd430ac3c8e76c0305a95e2888282c7c3b254 Mon Sep 17 00:00:00 2001 From: Kenneth Ford Date: Tue, 8 Feb 2022 22:42:27 +0000 Subject: [PATCH] Checks if there is a device state override active to determine if the device should be put to sleep or not This allows the device to stay awake regardless of the state it is transitioning to, provided it is an overridden state. An override request is triggered by user action or a cts test, so it provides a better user experience to stay awake during this transition. Bug: 216580217 Test: Manual & LogicalDisplayMapperTest Merged-In: I36959310d8e6c9b5e4e1e4093d17cad7d4f6238e Change-Id: I36959310d8e6c9b5e4e1e4093d17cad7d4f6238e (cherry picked from commit 7709d35564cc279f3c43d86063870dc847e7344d) --- .../server/display/DisplayManagerService.java | 12 +++- .../server/display/LogicalDisplayMapper.java | 59 ++++++++++++++++--- .../display/LogicalDisplayMapperTest.java | 54 +++++++++++++++++ 3 files changed, 117 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 66e9da0401027..b13b2d946c82a 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -3952,12 +3952,22 @@ public final class DisplayManagerService extends SystemService { * Listens to changes in device state and reports the state to LogicalDisplayMapper. */ class DeviceStateListener implements DeviceStateManager.DeviceStateCallback { + // Base state corresponds to the physical state of the device + private int mBaseState = DeviceStateManager.INVALID_DEVICE_STATE; + @Override public void onStateChanged(int deviceState) { + boolean isDeviceStateOverrideActive = deviceState != mBaseState; synchronized (mSyncRoot) { - mLogicalDisplayMapper.setDeviceStateLocked(deviceState); + mLogicalDisplayMapper + .setDeviceStateLocked(deviceState, isDeviceStateOverrideActive); } } + + @Override + public void onBaseStateChanged(int state) { + mBaseState = state; + } }; private class BrightnessPair { diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index 6f5729f89e0f8..add0a9f771089 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -359,7 +359,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { mDeviceStateToLayoutMap.dumpLocked(ipw); } - void setDeviceStateLocked(int state) { + void setDeviceStateLocked(int state, boolean isOverrideActive) { Slog.i(TAG, "Requesting Transition to state: " + state + ", from state=" + mDeviceState + ", interactive=" + mInteractive); // As part of a state transition, we may need to turn off some displays temporarily so that @@ -370,12 +370,10 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { resetLayoutLocked(mDeviceState, state, LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION); } mPendingDeviceState = state; - final boolean wakeDevice = mDeviceStatesOnWhichToWakeUp.get(mPendingDeviceState) - && !mDeviceStatesOnWhichToWakeUp.get(mDeviceState) - && !mInteractive && mBootCompleted; - final boolean sleepDevice = mDeviceStatesOnWhichToSleep.get(mPendingDeviceState) - && !mDeviceStatesOnWhichToSleep.get(mDeviceState) - && mInteractive && mBootCompleted; + final boolean wakeDevice = shouldDeviceBeWoken(mPendingDeviceState, mDeviceState, + mInteractive, mBootCompleted); + final boolean sleepDevice = shouldDeviceBePutToSleep(mPendingDeviceState, mDeviceState, + isOverrideActive, mInteractive, mBootCompleted); // If all displays are off already, we can just transition here, unless we are trying to // wake or sleep the device as part of this transition. In that case defer the final @@ -429,6 +427,53 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { } } + /** + * Returns if the device should be woken up or not. Called to check if the device state we are + * moving to is one that should awake the device, as well as if we are moving from a device + * state that shouldn't have been already woken from. + * + * @param pendingState device state we are moving to + * @param currentState device state we are currently in + * @param isInteractive if the device is in an interactive state + * @param isBootCompleted is the device fully booted + * + * @see #shouldDeviceBePutToSleep + * @see #setDeviceStateLocked + */ + @VisibleForTesting + boolean shouldDeviceBeWoken(int pendingState, int currentState, boolean isInteractive, + boolean isBootCompleted) { + return mDeviceStatesOnWhichToWakeUp.get(pendingState) + && !mDeviceStatesOnWhichToWakeUp.get(currentState) + && !isInteractive && isBootCompleted; + } + + /** + * Returns if the device should be put to sleep or not. + * + * Includes a check to verify that the device state that we are moving to, {@code pendingState}, + * is the same as the physical state of the device, {@code baseState}. Different values for + * these parameters indicate a device state override is active, and we shouldn't put the device + * to sleep to provide a better user experience. + * + * @param pendingState device state we are moving to + * @param currentState device state we are currently in + * @param isOverrideActive if a device state override is currently active or not + * @param isInteractive if the device is in an interactive state + * @param isBootCompleted is the device fully booted + * + * @see #shouldDeviceBeWoken + * @see #setDeviceStateLocked + */ + @VisibleForTesting + boolean shouldDeviceBePutToSleep(int pendingState, int currentState, boolean isOverrideActive, + boolean isInteractive, boolean isBootCompleted) { + return mDeviceStatesOnWhichToSleep.get(pendingState) + && !mDeviceStatesOnWhichToSleep.get(currentState) + && !isOverrideActive + && isInteractive && isBootCompleted; + } + private boolean areAllTransitioningDisplaysOffLocked() { final int count = mLogicalDisplays.size(); for (int i = 0; i < count; i++) { diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java index fefc425496884..86b6da0faad51 100644 --- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java +++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java @@ -28,7 +28,9 @@ import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EV import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.verify; @@ -70,6 +72,8 @@ import java.util.Set; @RunWith(AndroidJUnit4.class) public class LogicalDisplayMapperTest { private static int sUniqueTestDisplayId = 0; + private static final int DEVICE_STATE_CLOSED = 0; + private static final int DEVICE_STATE_OPEN = 2; private DisplayDeviceRepository mDisplayDeviceRepo; private LogicalDisplayMapper mLogicalDisplayMapper; @@ -113,6 +117,7 @@ public class LogicalDisplayMapperTest { mPowerManager = new PowerManager(mContextMock, mIPowerManagerMock, mIThermalServiceMock, null); + when(mContextMock.getSystemServiceName(PowerManager.class)) .thenReturn(Context.POWER_SERVICE); when(mContextMock.getSystemService(PowerManager.class)).thenReturn(mPowerManager); @@ -120,6 +125,12 @@ public class LogicalDisplayMapperTest { when(mResourcesMock.getBoolean( com.android.internal.R.bool.config_supportsConcurrentInternalDisplays)) .thenReturn(true); + when(mResourcesMock.getIntArray( + com.android.internal.R.array.config_deviceStatesOnWhichToWakeUp)) + .thenReturn(new int[]{1, 2}); + when(mResourcesMock.getIntArray( + com.android.internal.R.array.config_deviceStatesOnWhichToSleep)) + .thenReturn(new int[]{0}); mLooper = new TestLooper(); mHandler = new Handler(mLooper.getLooper()); @@ -312,6 +323,49 @@ public class LogicalDisplayMapperTest { mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display3))); } + @Test + public void testDeviceShouldBeWoken() { + assertTrue(mLogicalDisplayMapper.shouldDeviceBeWoken(DEVICE_STATE_OPEN, + DEVICE_STATE_CLOSED, + /* isInteractive= */false, + /* isBootCompleted= */true)); + } + + @Test + public void testDeviceShouldNotBeWoken() { + assertFalse(mLogicalDisplayMapper.shouldDeviceBeWoken(DEVICE_STATE_CLOSED, + DEVICE_STATE_OPEN, + /* isInteractive= */false, + /* isBootCompleted= */true)); + } + + @Test + public void testDeviceShouldBePutToSleep() { + assertTrue(mLogicalDisplayMapper.shouldDeviceBePutToSleep(DEVICE_STATE_CLOSED, + DEVICE_STATE_OPEN, + /* isOverrideActive= */false, + /* isInteractive= */true, + /* isBootCompleted= */true)); + } + + @Test + public void testDeviceShouldNotBePutToSleep() { + assertFalse(mLogicalDisplayMapper.shouldDeviceBePutToSleep(DEVICE_STATE_OPEN, + DEVICE_STATE_CLOSED, + /* isOverrideActive= */false, + /* isInteractive= */true, + /* isBootCompleted= */true)); + } + + @Test + public void testDeviceShouldNotBePutToSleepDifferentBaseState() { + assertFalse(mLogicalDisplayMapper.shouldDeviceBePutToSleep(DEVICE_STATE_CLOSED, + DEVICE_STATE_OPEN, + /* isOverrideActive= */true, + /* isInteractive= */true, + /* isBootCompleted= */true)); + } + ///////////////// // Helper Methods /////////////////