Fix StationaryListener updating.
Quick Doze bypasses motion detection, so if the device moves, the device will stay in Doze without resetting the motion sensor registration *for Doze*. If there's a StationaryListener registered, DeviceIdleController will set a new motion sensor registration ~5 minutes after motion is detected. However, DIC doesn't consider the device stationary unless there's been no motion for at least 10 minutes (and the motion sensor registration has been active for the past 10 minutes), so setting the motion timeout alarm to be 10 minutes after the motion recent motion event (which ends up being 5 minutes after DIC re-registers the motion sensor) will result in StationaryListeners being told the device is not stationary if the device is stationary long enough after a previous motion event. Bug: 231779749 Test: atest FrameworksMockingServicesTests:DeviceIdleControllerTest Change-Id: I452e76a4fd5513ff290f89e87182016fa93c1307
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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<AlarmManager.OnAlarmListener> regAlarmListener = ArgumentCaptor
|
||||
.forClass(AlarmManager.OnAlarmListener.class);
|
||||
final ArgumentCaptor<AlarmManager.OnAlarmListener> 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<SensorEventListener> 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<Long> 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<Long> 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:
|
||||
|
||||
Reference in New Issue
Block a user