From e08fd8c10d2731232d8935dd104d1a0f85ebb004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wilczy=C5=84ski?= Date: Tue, 7 Mar 2023 15:44:24 +0000 Subject: [PATCH] Report negative proximity if we lose the prox sensor Bug: 265612914 Test: Start a phone call, cover the prox sensor so the screen turns off, perform a state transition so that we no longer have a prox sensor, see that the screen turns back on. Test: atest DisplayPowerControllerTest Test: atest DisplayPowerController2Test Test: atest DisplayPowerProximityStateControllerTest Change-Id: I01e7c8ad2a5dc8fb9e01aa6e9622d2b4dbd812df --- .../display/DisplayPowerController.java | 9 ++ .../DisplayPowerProximityStateController.java | 9 ++ .../display/DisplayPowerController2Test.java | 95 ++++++++++++++++++- .../display/DisplayPowerControllerTest.java | 87 ++++++++++++++++- ...playPowerProximityStateControllerTest.java | 7 +- 5 files changed, 192 insertions(+), 15 deletions(-) diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 84fe8f21b7648..e1dcaae5db218 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -1441,8 +1441,17 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call sendOnProximityNegativeWithWakelock(); } } else { + setProximitySensorEnabled(false); mWaitingForNegativeProximity = false; mIgnoreProximityUntilChanged = false; + + if (mScreenOffBecauseOfProximity) { + // The screen *was* off due to prox being near, but now there's no prox sensor, so + // let's turn the screen back on. + mScreenOffBecauseOfProximity = false; + skipRampBecauseOfProximityChangeToNegative = true; + sendOnProximityNegativeWithWakelock(); + } } if (!mIsEnabled diff --git a/services/core/java/com/android/server/display/DisplayPowerProximityStateController.java b/services/core/java/com/android/server/display/DisplayPowerProximityStateController.java index 5bb3e6bf1c36f..c0747867b6203 100644 --- a/services/core/java/com/android/server/display/DisplayPowerProximityStateController.java +++ b/services/core/java/com/android/server/display/DisplayPowerProximityStateController.java @@ -262,8 +262,17 @@ public final class DisplayPowerProximityStateController { sendOnProximityNegativeWithWakelock(); } } else { + setProximitySensorEnabled(false); mWaitingForNegativeProximity = false; mIgnoreProximityUntilChanged = false; + + if (mScreenOffBecauseOfProximity) { + // The screen *was* off due to prox being near, but now there's no prox sensor, so + // let's turn the screen back on. + mScreenOffBecauseOfProximity = false; + mSkipRampBecauseOfProximityChangeToNegative = true; + sendOnProximityNegativeWithWakelock(); + } } } diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java index 7942e246c2a73..9b8c839959b74 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java @@ -30,6 +30,7 @@ import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.when; @@ -92,6 +93,7 @@ public final class DisplayPowerController2Test { private static final String FOLLOWER_UNIQUE_ID = "unique_id_456"; private static final int SECOND_FOLLOWER_DISPLAY_ID = FOLLOWER_DISPLAY_ID + 1; private static final String SECOND_FOLLOWER_UNIQUE_DISPLAY_ID = "unique_id_789"; + private static final float PROX_SENSOR_MAX_RANGE = 5; private MockitoSession mSession; private OffsettableClock mClock; @@ -160,7 +162,7 @@ public final class DisplayPowerController2Test { @Test public void testReleaseProxSuspendBlockersOnExit() throws Exception { when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - // send a display power request + // Send a display power request DisplayPowerRequest dpr = new DisplayPowerRequest(); dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; dpr.useProximitySensor = true; @@ -172,7 +174,7 @@ public final class DisplayPowerController2Test { SensorEventListener listener = getSensorEventListener(mProxSensor); assertNotNull(listener); - listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, 5 /* lux */)); + listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, /* value= */ 5)); advanceTime(1); // two times, one for unfinished business and one for proximity @@ -190,6 +192,83 @@ public final class DisplayPowerController2Test { WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); } + @Test + public void testScreenOffBecauseOfProximity() throws Exception { + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); + // Send a display power request + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; + dpr.useProximitySensor = true; + mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); + + // Run updatePowerState to start listener for the prox sensor + advanceTime(1); + + SensorEventListener listener = getSensorEventListener(mProxSensor); + assertNotNull(listener); + + // Send a positive proximity event + listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, /* value= */ 1)); + advanceTime(1); + + // The display should have been turned off + verify(mHolder.displayPowerState).setScreenState(Display.STATE_OFF); + + clearInvocations(mHolder.displayPowerState); + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_OFF); + // Send a negative proximity event + listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, + (int) PROX_SENSOR_MAX_RANGE + 1)); + // Advance time by less than PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY + advanceTime(1); + + // The prox sensor is debounced so the display should not have been turned back on yet + verify(mHolder.displayPowerState, never()).setScreenState(Display.STATE_ON); + + // Advance time by more than PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY + advanceTime(1000); + + // The display should have been turned back on + verify(mHolder.displayPowerState).setScreenState(Display.STATE_ON); + } + + @Test + public void testScreenOffBecauseOfProximity_ProxSensorGone() throws Exception { + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); + // Send a display power request + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; + dpr.useProximitySensor = true; + mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); + + // Run updatePowerState to start listener for the prox sensor + advanceTime(1); + + SensorEventListener listener = getSensorEventListener(mProxSensor); + assertNotNull(listener); + + // Send a positive proximity event + listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, /* value= */ 1)); + advanceTime(1); + + // The display should have been turned off + verify(mHolder.displayPowerState).setScreenState(Display.STATE_OFF); + + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_OFF); + // The display device changes and we no longer have a prox sensor + reset(mSensorManagerMock); + setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), + mock(DisplayDeviceConfig.class), /* isEnabled= */ true); + mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, Layout.NO_LEAD_DISPLAY); + + advanceTime(1); // Run updatePowerState + + // The display should have been turned back on and the listener should have been + // unregistered + verify(mHolder.displayPowerState).setScreenState(Display.STATE_ON); + verify(mSensorManagerMock).unregisterListener(listener); + } + @Test public void testProximitySensorListenerNotRegisteredForNonDefaultDisplay() { when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); @@ -222,8 +301,8 @@ public final class DisplayPowerController2Test { } private void setUpSensors() throws Exception { - mProxSensor = TestUtils.createSensor( - Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY); + mProxSensor = TestUtils.createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY, + PROX_SENSOR_MAX_RANGE); Sensor screenOffBrightnessSensor = TestUtils.createSensor( Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT); when(mSensorManagerMock.getSensorList(eq(Sensor.TYPE_ALL))) @@ -773,7 +852,13 @@ public final class DisplayPowerController2Test { SensorManager sensorManager) { return new DisplayPowerProximityStateController(wakelockController, displayDeviceConfig, looper, nudgeUpdatePowerState, displayId, - sensorManager, /* injector= */ null); + sensorManager, + new DisplayPowerProximityStateController.Injector() { + @Override + DisplayPowerProximityStateController.Clock createClock() { + return mClock::now; + } + }); } @Override diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java index 16bf2a227c8a1..eb1a3ffc6e4cd 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java @@ -30,6 +30,7 @@ import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.when; @@ -92,6 +93,7 @@ public final class DisplayPowerControllerTest { private static final String FOLLOWER_UNIQUE_DISPLAY_ID = "unique_id_456"; private static final int SECOND_FOLLOWER_DISPLAY_ID = FOLLOWER_DISPLAY_ID + 1; private static final String SECOND_FOLLOWER_UNIQUE_DISPLAY_ID = "unique_id_789"; + private static final float PROX_SENSOR_MAX_RANGE = 5; private MockitoSession mSession; private OffsettableClock mClock; @@ -161,7 +163,7 @@ public final class DisplayPowerControllerTest { @Test public void testReleaseProxSuspendBlockersOnExit() throws Exception { when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - // send a display power request + // Send a display power request DisplayPowerRequest dpr = new DisplayPowerRequest(); dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; dpr.useProximitySensor = true; @@ -173,7 +175,7 @@ public final class DisplayPowerControllerTest { SensorEventListener listener = getSensorEventListener(mProxSensor); assertNotNull(listener); - listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, 5 /* lux */)); + listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, /* value= */ 5)); advanceTime(1); // two times, one for unfinished business and one for proximity @@ -192,6 +194,83 @@ public final class DisplayPowerControllerTest { mHolder.dpc.getSuspendBlockerProxDebounceId(DISPLAY_ID)); } + @Test + public void testScreenOffBecauseOfProximity() throws Exception { + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); + // Send a display power request + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; + dpr.useProximitySensor = true; + mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); + + // Run updatePowerState to start listener for the prox sensor + advanceTime(1); + + SensorEventListener listener = getSensorEventListener(mProxSensor); + assertNotNull(listener); + + // Send a positive proximity event + listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, /* value= */ 1)); + advanceTime(1); + + // The display should have been turned off + verify(mHolder.displayPowerState).setScreenState(Display.STATE_OFF); + + clearInvocations(mHolder.displayPowerState); + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_OFF); + // Send a negative proximity event + listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, + (int) PROX_SENSOR_MAX_RANGE + 1)); + // Advance time by less than PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY + advanceTime(1); + + // The prox sensor is debounced so the display should not have been turned back on yet + verify(mHolder.displayPowerState, never()).setScreenState(Display.STATE_ON); + + // Advance time by more than PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY + advanceTime(1000); + + // The display should have been turned back on + verify(mHolder.displayPowerState).setScreenState(Display.STATE_ON); + } + + @Test + public void testScreenOffBecauseOfProximity_ProxSensorGone() throws Exception { + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); + // Send a display power request + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; + dpr.useProximitySensor = true; + mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); + + // Run updatePowerState to start listener for the prox sensor + advanceTime(1); + + SensorEventListener listener = getSensorEventListener(mProxSensor); + assertNotNull(listener); + + // Send a positive proximity event + listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, /* value= */ 1)); + advanceTime(1); + + // The display should have been turned off + verify(mHolder.displayPowerState).setScreenState(Display.STATE_OFF); + + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_OFF); + // The display device changes and we no longer have a prox sensor + reset(mSensorManagerMock); + setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), + mock(DisplayDeviceConfig.class), /* isEnabled= */ true); + mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, Layout.NO_LEAD_DISPLAY); + + advanceTime(1); // Run updatePowerState + + // The display should have been turned back on and the listener should have been + // unregistered + verify(mHolder.displayPowerState).setScreenState(Display.STATE_ON); + verify(mSensorManagerMock).unregisterListener(listener); + } + @Test public void testProximitySensorListenerNotRegisteredForNonDefaultDisplay() { DisplayPowerControllerHolder followerDpc = @@ -225,8 +304,8 @@ public final class DisplayPowerControllerTest { } private void setUpSensors() throws Exception { - mProxSensor = TestUtils.createSensor( - Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY); + mProxSensor = TestUtils.createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY, + PROX_SENSOR_MAX_RANGE); Sensor screenOffBrightnessSensor = TestUtils.createSensor( Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT); when(mSensorManagerMock.getSensorList(eq(Sensor.TYPE_ALL))) diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerProximityStateControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerProximityStateControllerTest.java index 6e91b249b4904..5b0b989d478ab 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerProximityStateControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerProximityStateControllerTest.java @@ -87,12 +87,7 @@ public final class DisplayPowerProximityStateControllerTest { new DisplayPowerProximityStateController.Injector() { @Override DisplayPowerProximityStateController.Clock createClock() { - return new DisplayPowerProximityStateController.Clock() { - @Override - public long uptimeMillis() { - return mClock.now(); - } - }; + return mClock::now; } }; mDisplayPowerProximityStateController = new DisplayPowerProximityStateController(