Merge "Ensure AlarmManager is brought out of device idle."

This commit is contained in:
TreeHugger Robot
2019-02-12 02:22:40 +00:00
committed by Android (Google) Code Review
4 changed files with 340 additions and 88 deletions

View File

@@ -26,6 +26,8 @@ public interface AlarmManagerInternal {
void broadcastAlarmComplete(int recipientUid);
}
/** Returns true if AlarmManager is delaying alarms due to device idle. */
boolean isIdling();
public void removeAlarmsForUid(int uid);
public void registerInFlightListener(InFlightListener callback);
}

View File

@@ -1990,6 +1990,11 @@ class AlarmManagerService extends SystemService {
* System-process internal API
*/
private final class LocalService implements AlarmManagerInternal {
@Override
public boolean isIdling() {
return isIdlingImpl();
}
@Override
public void removeAlarmsForUid(int uid) {
synchronized (mLock) {
@@ -2823,6 +2828,12 @@ class AlarmManagerService extends SystemService {
}
}
private boolean isIdlingImpl() {
synchronized (mLock) {
return mPendingIdleUntil != null;
}
}
AlarmManager.AlarmClockInfo getNextAlarmClockImpl(int userId) {
synchronized (mLock) {
return mNextAlarmClockForUser.get(userId);

View File

@@ -271,6 +271,7 @@ public class DeviceIdleController extends SystemService
private static final int EVENT_BUFFER_SIZE = 100;
private AlarmManager mAlarmManager;
private AlarmManagerInternal mLocalAlarmManager;
private IBatteryStats mBatteryStats;
private ActivityManagerInternal mLocalActivityManager;
private ActivityTaskManagerInternal mLocalActivityTaskManager;
@@ -616,7 +617,8 @@ public class DeviceIdleController extends SystemService
}
};
private final AlarmManager.OnAlarmListener mDeepAlarmListener
@VisibleForTesting
final AlarmManager.OnAlarmListener mDeepAlarmListener
= new AlarmManager.OnAlarmListener() {
@Override
public void onAlarm() {
@@ -1874,6 +1876,7 @@ public class DeviceIdleController extends SystemService
if (phase == PHASE_SYSTEM_SERVICES_READY) {
synchronized (this) {
mAlarmManager = mInjector.getAlarmManager();
mLocalAlarmManager = getLocalService(AlarmManagerInternal.class);
mBatteryStats = BatteryStatsService.getService();
mLocalActivityManager = getLocalService(ActivityManagerInternal.class);
mLocalActivityTaskManager = getLocalService(ActivityTaskManagerInternal.class);
@@ -2605,6 +2608,16 @@ public class DeviceIdleController extends SystemService
// next natural time to come out of it.
}
/** Returns true if the screen is locked. */
@VisibleForTesting
boolean isKeyguardShowing() {
synchronized (this) {
return mScreenLocked;
}
}
@VisibleForTesting
void keyguardShowingLocked(boolean showing) {
if (DEBUG) Slog.i(TAG, "keyguardShowing=" + showing);
if (mScreenLocked != showing) {
@@ -2616,25 +2629,38 @@ public class DeviceIdleController extends SystemService
}
}
@VisibleForTesting
void scheduleReportActiveLocked(String activeReason, int activeUid) {
Message msg = mHandler.obtainMessage(MSG_REPORT_ACTIVE, activeUid, 0, activeReason);
mHandler.sendMessage(msg);
}
void becomeActiveLocked(String activeReason, int activeUid) {
if (DEBUG) Slog.i(TAG, "becomeActiveLocked, reason = " + activeReason);
becomeActiveLocked(activeReason, activeUid, mConstants.INACTIVE_TIMEOUT, true);
}
private void becomeActiveLocked(String activeReason, int activeUid,
long newInactiveTimeout, boolean changeLightIdle) {
if (DEBUG) {
Slog.i(TAG, "becomeActiveLocked, reason=" + activeReason
+ ", changeLightIdle=" + changeLightIdle);
}
if (mState != STATE_ACTIVE || mLightState != STATE_ACTIVE) {
EventLogTags.writeDeviceIdle(STATE_ACTIVE, activeReason);
EventLogTags.writeDeviceIdleLight(LIGHT_STATE_ACTIVE, activeReason);
scheduleReportActiveLocked(activeReason, activeUid);
mState = STATE_ACTIVE;
mLightState = LIGHT_STATE_ACTIVE;
mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
mInactiveTimeout = newInactiveTimeout;
mCurIdleBudget = 0;
mMaintenanceStartTime = 0;
resetIdleManagementLocked();
resetLightIdleManagementLocked();
addEvent(EVENT_NORMAL, activeReason);
if (changeLightIdle) {
EventLogTags.writeDeviceIdleLight(LIGHT_STATE_ACTIVE, activeReason);
mLightState = LIGHT_STATE_ACTIVE;
resetLightIdleManagementLocked();
// Only report active if light is also ACTIVE.
scheduleReportActiveLocked(activeReason, activeUid);
addEvent(EVENT_NORMAL, activeReason);
}
}
}
@@ -2654,49 +2680,81 @@ public class DeviceIdleController extends SystemService
}
}
/** Sanity check to make sure DeviceIdleController and AlarmManager are on the same page. */
private void verifyAlarmStateLocked() {
if (mState == STATE_ACTIVE && mNextAlarmTime != 0) {
Slog.wtf(TAG, "mState=ACTIVE but mNextAlarmTime=" + mNextAlarmTime);
}
if (mState != STATE_IDLE && mLocalAlarmManager.isIdling()) {
Slog.wtf(TAG, "mState=" + stateToString(mState) + " but AlarmManager is idling");
}
if (mState == STATE_IDLE && !mLocalAlarmManager.isIdling()) {
Slog.wtf(TAG, "mState=IDLE but AlarmManager is not idling");
}
if (mLightState == LIGHT_STATE_ACTIVE && mNextLightAlarmTime != 0) {
Slog.wtf(TAG, "mLightState=ACTIVE but mNextLightAlarmTime is "
+ TimeUtils.formatDuration(mNextLightAlarmTime - SystemClock.elapsedRealtime())
+ " from now");
}
}
void becomeInactiveIfAppropriateLocked() {
if (DEBUG) Slog.d(TAG, "becomeInactiveIfAppropriateLocked()");
if ((!mScreenOn && !mCharging) || mForceIdle) {
// Become inactive and determine if we will ultimately go idle.
if (mDeepEnabled) {
if (mQuickDozeActivated) {
if (mState == STATE_QUICK_DOZE_DELAY || mState == STATE_IDLE
|| mState == STATE_IDLE_MAINTENANCE) {
// Already "idling". Don't want to restart the process.
// mLightState can't be LIGHT_STATE_ACTIVE if mState is any of these 3
// values, so returning here is safe.
return;
}
if (DEBUG) {
Slog.d(TAG, "Moved from "
+ stateToString(mState) + " to STATE_QUICK_DOZE_DELAY");
}
mState = STATE_QUICK_DOZE_DELAY;
// Make sure any motion sensing or locating is stopped.
resetIdleManagementLocked();
// Wait a small amount of time in case something (eg: background service from
// recently closed app) needs to finish running.
scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false);
EventLogTags.writeDeviceIdle(mState, "no activity");
} else if (mState == STATE_ACTIVE) {
mState = STATE_INACTIVE;
if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE");
resetIdleManagementLocked();
long delay = mInactiveTimeout;
if (shouldUseIdleTimeoutFactorLocked()) {
delay = (long) (mPreIdleFactor * delay);
}
scheduleAlarmLocked(delay, false);
EventLogTags.writeDeviceIdle(mState, "no activity");
verifyAlarmStateLocked();
final boolean isScreenBlockingInactive =
mScreenOn && (!mConstants.WAIT_FOR_UNLOCK || !mScreenLocked);
if (DEBUG) {
Slog.d(TAG, "becomeInactiveIfAppropriateLocked():"
+ " isScreenBlockingInactive=" + isScreenBlockingInactive
+ " (mScreenOn=" + mScreenOn
+ ", WAIT_FOR_UNLOCK=" + mConstants.WAIT_FOR_UNLOCK
+ ", mScreenLocked=" + mScreenLocked + ")"
+ " mCharging=" + mCharging
+ " mForceIdle=" + mForceIdle
);
}
if (!mForceIdle && (mCharging || isScreenBlockingInactive)) {
return;
}
// Become inactive and determine if we will ultimately go idle.
if (mDeepEnabled) {
if (mQuickDozeActivated) {
if (mState == STATE_QUICK_DOZE_DELAY || mState == STATE_IDLE
|| mState == STATE_IDLE_MAINTENANCE) {
// Already "idling". Don't want to restart the process.
// mLightState can't be LIGHT_STATE_ACTIVE if mState is any of these 3
// values, so returning here is safe.
return;
}
if (DEBUG) {
Slog.d(TAG, "Moved from "
+ stateToString(mState) + " to STATE_QUICK_DOZE_DELAY");
}
mState = STATE_QUICK_DOZE_DELAY;
// Make sure any motion sensing or locating is stopped.
resetIdleManagementLocked();
// Wait a small amount of time in case something (eg: background service from
// recently closed app) needs to finish running.
scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false);
EventLogTags.writeDeviceIdle(mState, "no activity");
} else if (mState == STATE_ACTIVE) {
mState = STATE_INACTIVE;
if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE");
resetIdleManagementLocked();
long delay = mInactiveTimeout;
if (shouldUseIdleTimeoutFactorLocked()) {
delay = (long) (mPreIdleFactor * delay);
}
scheduleAlarmLocked(delay, false);
EventLogTags.writeDeviceIdle(mState, "no activity");
}
if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) {
mLightState = LIGHT_STATE_INACTIVE;
if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE");
resetLightIdleManagementLocked();
scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
EventLogTags.writeDeviceIdleLight(mLightState, "no activity");
}
}
if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) {
mLightState = LIGHT_STATE_INACTIVE;
if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE");
resetLightIdleManagementLocked();
scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
EventLogTags.writeDeviceIdleLight(mLightState, "no activity");
}
}
@@ -3216,33 +3274,10 @@ public class DeviceIdleController extends SystemService
// The device is not yet active, so we want to go back to the pending idle
// state to wait again for no motion. Note that we only monitor for motion
// after moving out of the inactive state, so no need to worry about that.
boolean becomeInactive = false;
if (mState != STATE_ACTIVE) {
// Motion shouldn't affect light state, if it's already in doze-light or maintenance
boolean lightIdle = mLightState == LIGHT_STATE_IDLE
|| mLightState == LIGHT_STATE_WAITING_FOR_NETWORK
|| mLightState == LIGHT_STATE_IDLE_MAINTENANCE;
if (!lightIdle) {
// Only switch to active state if we're not in either idle state
scheduleReportActiveLocked(type, Process.myUid());
addEvent(EVENT_NORMAL, type);
}
mActiveReason = ACTIVE_REASON_MOTION;
mState = STATE_ACTIVE;
mInactiveTimeout = timeout;
mCurIdleBudget = 0;
mMaintenanceStartTime = 0;
EventLogTags.writeDeviceIdle(mState, type);
becomeInactive = true;
updateActiveConstraintsLocked();
}
if (mLightState == LIGHT_STATE_OVERRIDE) {
// We went out of light idle mode because we had started deep idle mode... let's
// now go back and reset things so we resume light idling if appropriate.
mLightState = LIGHT_STATE_ACTIVE;
EventLogTags.writeDeviceIdleLight(mLightState, type);
becomeInactive = true;
}
final boolean becomeInactive = mState != STATE_ACTIVE
|| mLightState == LIGHT_STATE_OVERRIDE;
// We only want to change the IDLE state if it's OVERRIDE.
becomeActiveLocked(type, Process.myUid(), timeout, mLightState == LIGHT_STATE_OVERRIDE);
if (becomeInactive) {
becomeInactiveIfAppropriateLocked();
}

View File

@@ -19,6 +19,7 @@ import static androidx.test.InstrumentationRegistry.getContext;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -51,6 +52,9 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
@@ -82,6 +86,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
@@ -105,6 +110,8 @@ public class DeviceIdleControllerTest {
@Mock
private ContentResolver mContentResolver;
@Mock
private DeviceIdleController.MyHandler mHandler;
@Mock
private IActivityManager mIActivityManager;
@Mock
private LocationManager mLocationManager;
@@ -154,7 +161,7 @@ public class DeviceIdleControllerTest {
@Override
DeviceIdleController.MyHandler getHandler(DeviceIdleController controller) {
return mock(DeviceIdleController.MyHandler.class, Answers.RETURNS_DEEP_STUBS);
return mHandler;
}
@Override
@@ -232,10 +239,12 @@ public class DeviceIdleControllerTest {
.when(() -> LocalServices.getService(ActivityManagerInternal.class));
doReturn(mock(ActivityTaskManagerInternal.class))
.when(() -> LocalServices.getService(ActivityTaskManagerInternal.class));
doReturn(mock(AlarmManagerInternal.class))
.when(() -> LocalServices.getService(AlarmManagerInternal.class));
doReturn(mPowerManagerInternal)
.when(() -> LocalServices.getService(PowerManagerInternal.class));
when(mPowerManagerInternal.getLowPowerState(anyInt())).thenReturn(
mock(PowerSaveState.class));
when(mPowerManagerInternal.getLowPowerState(anyInt()))
.thenReturn(mock(PowerSaveState.class));
doReturn(mock(NetworkPolicyManagerInternal.class))
.when(() -> LocalServices.getService(NetworkPolicyManagerInternal.class));
when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mWakeLock);
@@ -246,8 +255,11 @@ public class DeviceIdleControllerTest {
doReturn(true).when(mSensorManager).registerListener(any(), any(), anyInt());
mAppStateTracker = new AppStateTrackerForTest(getContext(), Looper.getMainLooper());
mAnyMotionDetector = new AnyMotionDetectorForTest();
mHandler = mock(DeviceIdleController.MyHandler.class, Answers.RETURNS_DEEP_STUBS);
doNothing().when(mHandler).handleMessage(any());
mInjector = new InjectorForTest(getContext());
doNothing().when(mContentResolver).registerContentObserver(any(), anyBoolean(), any());
mDeviceIdleController = new DeviceIdleController(getContext(), mInjector);
spyOn(mDeviceIdleController);
doNothing().when(mDeviceIdleController).publishBinderService(any(), any());
@@ -423,6 +435,29 @@ public class DeviceIdleControllerTest {
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
verifyStateConditions(STATE_ACTIVE);
mConstants.WAIT_FOR_UNLOCK = false;
setScreenLocked(true);
setScreenOn(true);
setChargingOn(false);
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
verifyStateConditions(STATE_ACTIVE);
setScreenLocked(false);
setScreenOn(true);
setChargingOn(false);
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
verifyStateConditions(STATE_ACTIVE);
mConstants.WAIT_FOR_UNLOCK = true;
setScreenLocked(false);
setScreenOn(true);
setChargingOn(false);
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
verifyStateConditions(STATE_ACTIVE);
}
@Test
@@ -1307,7 +1342,7 @@ public class DeviceIdleControllerTest {
}
@Test
public void testbecomeActiveLocked_deep() {
public void testBecomeActiveLocked_deep() {
// becomeActiveLocked should put everything into ACTIVE.
enterDeepState(STATE_ACTIVE);
@@ -1344,7 +1379,7 @@ public class DeviceIdleControllerTest {
}
@Test
public void testbecomeActiveLocked_light() {
public void testBecomeActiveLocked_light() {
// becomeActiveLocked should put everything into ACTIVE.
enterLightState(LIGHT_STATE_ACTIVE);
@@ -1376,6 +1411,163 @@ public class DeviceIdleControllerTest {
verifyLightStateConditions(LIGHT_STATE_ACTIVE);
}
/** Test based on b/119058625. */
@Test
public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOn_ScreenThenMotion() {
mConstants.WAIT_FOR_UNLOCK = true;
enterDeepState(STATE_IDLE);
reset(mAlarmManager);
spyOn(mDeviceIdleController);
mDeviceIdleController.keyguardShowingLocked(true);
setScreenOn(true);
// With WAIT_FOR_UNLOCK = true and the screen locked, turning the screen on by itself
// shouldn't bring the device out of deep IDLE.
verifyStateConditions(STATE_IDLE);
mDeviceIdleController.handleMotionDetectedLocked(1000, "test");
// Motion should bring the device out of Doze. Since the screen is still locked (albeit
// on), the states should go back into INACTIVE.
verifyStateConditions(STATE_INACTIVE);
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener));
verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt());
}
/** Test based on b/119058625. */
@Test
public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOff_ScreenThenMotion() {
mConstants.WAIT_FOR_UNLOCK = true;
enterDeepState(STATE_IDLE);
reset(mAlarmManager);
spyOn(mDeviceIdleController);
mDeviceIdleController.keyguardShowingLocked(false);
setScreenOn(true);
// With WAIT_FOR_UNLOCK = true and the screen unlocked, turning the screen on by itself
// should bring the device out of deep IDLE.
verifyStateConditions(STATE_ACTIVE);
verifyLightStateConditions(LIGHT_STATE_ACTIVE);
verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener));
verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt());
}
/** Test based on b/119058625. */
@Test
public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOn_MotionThenScreen() {
mConstants.WAIT_FOR_UNLOCK = true;
enterDeepState(STATE_IDLE);
reset(mAlarmManager);
spyOn(mDeviceIdleController);
InOrder alarmManagerInOrder = inOrder(mAlarmManager);
InOrder controllerInOrder = inOrder(mDeviceIdleController);
mDeviceIdleController.keyguardShowingLocked(true);
mDeviceIdleController.handleMotionDetectedLocked(1000, "test");
// The screen is still off, so motion should result in the INACTIVE state.
verifyStateConditions(STATE_INACTIVE);
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
alarmManagerInOrder.verify(mAlarmManager)
.cancel(eq(mDeviceIdleController.mDeepAlarmListener));
controllerInOrder.verify(mDeviceIdleController)
.scheduleReportActiveLocked(anyString(), anyInt());
setScreenOn(true);
// With WAIT_FOR_UNLOCK = true and the screen locked, turning the screen on by itself
// shouldn't bring the device all the way to ACTIVE.
verifyStateConditions(STATE_INACTIVE);
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
alarmManagerInOrder.verify(mAlarmManager, never()).cancel(
eq(mDeviceIdleController.mDeepAlarmListener));
// User finally unlocks the device. Device should be fully active.
mDeviceIdleController.keyguardShowingLocked(false);
verifyStateConditions(STATE_ACTIVE);
verifyLightStateConditions(LIGHT_STATE_ACTIVE);
alarmManagerInOrder.verify(mAlarmManager)
.cancel(eq(mDeviceIdleController.mDeepAlarmListener));
controllerInOrder.verify(mDeviceIdleController)
.scheduleReportActiveLocked(anyString(), anyInt());
}
/** Test based on b/119058625. */
@Test
public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOff_MotionThenScreen() {
mConstants.WAIT_FOR_UNLOCK = true;
enterDeepState(STATE_IDLE);
reset(mAlarmManager);
spyOn(mDeviceIdleController);
InOrder alarmManagerInOrder = inOrder(mAlarmManager);
InOrder controllerInOrder = inOrder(mDeviceIdleController);
mDeviceIdleController.keyguardShowingLocked(false);
mDeviceIdleController.handleMotionDetectedLocked(1000, "test");
// The screen is still off, so motion should result in the INACTIVE state.
verifyStateConditions(STATE_INACTIVE);
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
alarmManagerInOrder.verify(mAlarmManager)
.cancel(eq(mDeviceIdleController.mDeepAlarmListener));
controllerInOrder.verify(mDeviceIdleController)
.scheduleReportActiveLocked(anyString(), anyInt());
setScreenOn(true);
// With WAIT_FOR_UNLOCK = true and the screen unlocked, turning the screen on by itself
// should bring the device out of deep IDLE.
verifyStateConditions(STATE_ACTIVE);
verifyLightStateConditions(LIGHT_STATE_ACTIVE);
alarmManagerInOrder.verify(mAlarmManager)
.cancel(eq(mDeviceIdleController.mDeepAlarmListener));
controllerInOrder.verify(mDeviceIdleController)
.scheduleReportActiveLocked(anyString(), anyInt());
}
@Test
public void testExitNotifiesDependencies_WaitForUnlockOff_Screen() {
mConstants.WAIT_FOR_UNLOCK = false;
enterDeepState(STATE_IDLE);
reset(mAlarmManager);
spyOn(mDeviceIdleController);
setScreenOn(true);
// With WAIT_FOR_UNLOCK = false and the screen locked, turning the screen on by itself
// should bring the device out of deep IDLE.
verifyStateConditions(STATE_ACTIVE);
verifyLightStateConditions(LIGHT_STATE_ACTIVE);
verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener));
verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt());
}
@Test
public void testExitNotifiesDependencies_WaitForUnlockOff_MotionThenScreen() {
mConstants.WAIT_FOR_UNLOCK = false;
enterDeepState(STATE_IDLE);
reset(mAlarmManager);
spyOn(mDeviceIdleController);
InOrder alarmManagerInOrder = inOrder(mAlarmManager);
InOrder controllerInOrder = inOrder(mDeviceIdleController);
mDeviceIdleController.handleMotionDetectedLocked(1000, "test");
// The screen is still off, so motion should result in the INACTIVE state.
verifyStateConditions(STATE_INACTIVE);
verifyLightStateConditions(LIGHT_STATE_INACTIVE);
alarmManagerInOrder.verify(mAlarmManager)
.cancel(eq(mDeviceIdleController.mDeepAlarmListener));
controllerInOrder.verify(mDeviceIdleController)
.scheduleReportActiveLocked(anyString(), anyInt());
setScreenOn(true);
// With WAIT_FOR_UNLOCK = false and the screen locked, turning the screen on by itself
// should bring the device out of deep IDLE.
verifyStateConditions(STATE_ACTIVE);
verifyLightStateConditions(LIGHT_STATE_ACTIVE);
alarmManagerInOrder.verify(mAlarmManager)
.cancel(eq(mDeviceIdleController.mDeepAlarmListener));
controllerInOrder.verify(mDeviceIdleController)
.scheduleReportActiveLocked(anyString(), anyInt());
}
@Test
public void testStepToIdleMode() {
float delta = mDeviceIdleController.MIN_PRE_IDLE_FACTOR_CHANGE;
@@ -1508,6 +1700,10 @@ public class DeviceIdleControllerTest {
mDeviceIdleController.updateChargingLocked(on);
}
private void setScreenLocked(boolean locked) {
mDeviceIdleController.keyguardShowingLocked(locked);
}
private void setScreenOn(boolean on) {
doReturn(on).when(mPowerManager).isInteractive();
mDeviceIdleController.updateInteractivityLocked();
@@ -1549,7 +1745,8 @@ public class DeviceIdleControllerTest {
assertFalse(mDeviceIdleController.mMotionListener.isActive());
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
assertFalse(mDeviceIdleController.isScreenOn());
assertFalse(mDeviceIdleController.isScreenOn()
&& !mDeviceIdleController.isKeyguardShowing());
break;
case STATE_IDLE_PENDING:
assertEquals(
@@ -1557,7 +1754,8 @@ public class DeviceIdleControllerTest {
mDeviceIdleController.mMotionListener.isActive());
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
assertFalse(mDeviceIdleController.isScreenOn());
assertFalse(mDeviceIdleController.isScreenOn()
&& !mDeviceIdleController.isKeyguardShowing());
break;
case STATE_SENSING:
assertEquals(
@@ -1567,14 +1765,16 @@ public class DeviceIdleControllerTest {
mDeviceIdleController.hasMotionSensor(),
mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
assertFalse(mDeviceIdleController.isScreenOn());
assertFalse(mDeviceIdleController.isScreenOn()
&& !mDeviceIdleController.isKeyguardShowing());
break;
case STATE_LOCATING:
assertEquals(
mDeviceIdleController.hasMotionSensor(),
mDeviceIdleController.mMotionListener.isActive());
assertFalse(mDeviceIdleController.isCharging());
assertFalse(mDeviceIdleController.isScreenOn());
assertFalse(mDeviceIdleController.isScreenOn()
&& !mDeviceIdleController.isKeyguardShowing());
break;
case STATE_IDLE:
if (mDeviceIdleController.hasMotionSensor()) {
@@ -1584,7 +1784,8 @@ public class DeviceIdleControllerTest {
}
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
assertFalse(mDeviceIdleController.isScreenOn());
assertFalse(mDeviceIdleController.isScreenOn()
&& !mDeviceIdleController.isKeyguardShowing());
// Light state should be OVERRIDE at this point.
verifyLightStateConditions(LIGHT_STATE_OVERRIDE);
break;
@@ -1596,14 +1797,16 @@ public class DeviceIdleControllerTest {
}
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
assertFalse(mDeviceIdleController.isScreenOn());
assertFalse(mDeviceIdleController.isScreenOn()
&& !mDeviceIdleController.isKeyguardShowing());
break;
case STATE_QUICK_DOZE_DELAY:
// If quick doze is enabled, the motion listener should NOT be active.
assertFalse(mDeviceIdleController.mMotionListener.isActive());
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
assertFalse(mDeviceIdleController.isScreenOn());
assertFalse(mDeviceIdleController.isScreenOn()
&& !mDeviceIdleController.isKeyguardShowing());
break;
default:
fail("Conditions for " + stateToString(expectedState) + " unknown.");
@@ -1632,7 +1835,8 @@ public class DeviceIdleControllerTest {
case LIGHT_STATE_IDLE_MAINTENANCE:
case LIGHT_STATE_OVERRIDE:
assertFalse(mDeviceIdleController.isCharging());
assertFalse(mDeviceIdleController.isScreenOn());
assertFalse(mDeviceIdleController.isScreenOn()
&& !mDeviceIdleController.isKeyguardShowing());
break;
default:
fail("Conditions for " + lightStateToString(expectedLightState) + " unknown.");