diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index e9ce87f554d86..2eb86c1b720fb 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -693,6 +693,7 @@ public class DeviceIdleController extends SystemService synchronized (DeviceIdleController.this) { if (mStationaryListeners.size() > 0) { startMonitoringMotionLocked(); + scheduleMotionTimeoutAlarmLocked(); } } }; @@ -3859,7 +3860,7 @@ public class DeviceIdleController extends SystemService void handleMotionDetectedLocked(long timeout, String type) { if (mStationaryListeners.size() > 0) { postStationaryStatusUpdated(); - scheduleMotionTimeoutAlarmLocked(); + cancelMotionTimeoutAlarmLocked(); // We need to re-register the motion listener, but we don't want the sensors to be // constantly active or to churn the CPU by registering too early, register after some // delay. diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java index ac115a26f9e47..cb14864876ab8 100644 --- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java @@ -284,7 +284,7 @@ public class DeviceIdleControllerTest { @Override public void onDeviceStationaryChanged(boolean isStationary) { if (isStationary == motionExpected) { - fail("Unexpected device stationary status: " + isStationary); + fail("Got unexpected device stationary status: " + isStationary); } this.isStationary = isStationary; } @@ -2096,6 +2096,70 @@ public class DeviceIdleControllerTest { eq(SensorManager.SENSOR_DELAY_NORMAL)); } + @Test + public void testStationaryDetection_NoDoze_AfterMotion() { + // Short timeout for testing. + mConstants.MOTION_INACTIVE_TIMEOUT = 6000L; + doReturn(Sensor.REPORTING_MODE_CONTINUOUS).when(mMotionSensor).getReportingMode(); + setAlarmSoon(true); + + final ArgumentCaptor regAlarmListener = ArgumentCaptor + .forClass(AlarmManager.OnAlarmListener.class); + final ArgumentCaptor motionAlarmListener = ArgumentCaptor + .forClass(AlarmManager.OnAlarmListener.class); + doNothing().when(mAlarmManager).setWindow( + anyInt(), anyLong(), anyLong(), eq("DeviceIdleController.motion"), + motionAlarmListener.capture(), any()); + doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(), + eq("DeviceIdleController.motion_registration"), + regAlarmListener.capture(), any()); + ArgumentCaptor listenerCaptor = + ArgumentCaptor.forClass(SensorEventListener.class); + + StationaryListenerForTest stationaryListener = new StationaryListenerForTest(); + spyOn(stationaryListener); + InOrder inOrder = inOrder(stationaryListener, mSensorManager, mAlarmManager); + + stationaryListener.motionExpected = true; + mDeviceIdleController.registerStationaryListener(stationaryListener); + inOrder.verify(stationaryListener, timeout(1000L).times(1)) + .onDeviceStationaryChanged(eq(false)); + assertFalse(stationaryListener.isStationary); + inOrder.verify(mSensorManager) + .registerListener(listenerCaptor.capture(), eq(mMotionSensor), + eq(SensorManager.SENSOR_DELAY_NORMAL)); + inOrder.verify(mAlarmManager).setWindow( + anyInt(), eq(mInjector.nowElapsed + mConstants.MOTION_INACTIVE_TIMEOUT), anyLong(), + eq("DeviceIdleController.motion"), any(), any()); + final SensorEventListener listener = listenerCaptor.getValue(); + + // Trigger motion + listener.onSensorChanged(mock(SensorEvent.class)); + inOrder.verify(stationaryListener, timeout(1000L).times(1)) + .onDeviceStationaryChanged(eq(false)); + final ArgumentCaptor registrationTimeCaptor = ArgumentCaptor.forClass(Long.class); + inOrder.verify(mAlarmManager).setWindow( + anyInt(), registrationTimeCaptor.capture(), anyLong(), + eq("DeviceIdleController.motion_registration"), any(), any()); + + // Make sure the listener is re-registered. + mInjector.nowElapsed = registrationTimeCaptor.getValue(); + regAlarmListener.getValue().onAlarm(); + inOrder.verify(mSensorManager) + .registerListener(eq(listener), eq(mMotionSensor), + eq(SensorManager.SENSOR_DELAY_NORMAL)); + final ArgumentCaptor timeoutCaptor = ArgumentCaptor.forClass(Long.class); + inOrder.verify(mAlarmManager).setWindow(anyInt(), timeoutCaptor.capture(), anyLong(), + eq("DeviceIdleController.motion"), any(), any()); + + // No motion before timeout + stationaryListener.motionExpected = false; + mInjector.nowElapsed = timeoutCaptor.getValue(); + motionAlarmListener.getValue().onAlarm(); + inOrder.verify(stationaryListener, timeout(1000L).times(1)) + .onDeviceStationaryChanged(eq(true)); + } + private void enterDeepState(int state) { switch (state) { case STATE_ACTIVE: