Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c95d515c authored by Kweku Adams's avatar Kweku Adams Committed by Android (Google) Code Review
Browse files

Merge "Ensure AlarmManager knows of IDLE state." into udc-dev

parents de6e8248 26987e03
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -2402,7 +2402,6 @@ public class DeviceIdleController extends SystemService
            return mConstants;
        }


        /** Returns the current elapsed realtime in milliseconds. */
        long getElapsedRealtime() {
            return SystemClock.elapsedRealtime();
@@ -3819,6 +3818,7 @@ public class DeviceIdleController extends SystemService

                // Everything is in place to go into IDLE state.
            case STATE_IDLE_MAINTENANCE:
                moveToStateLocked(STATE_IDLE, reason);
                scheduleAlarmLocked(mNextIdleDelay, true);
                if (DEBUG) Slog.d(TAG, "Moved to STATE_IDLE. Next alarm in " + mNextIdleDelay +
                        " ms.");
@@ -3829,7 +3829,6 @@ public class DeviceIdleController extends SystemService
                if (mNextIdleDelay < mConstants.IDLE_TIMEOUT) {
                    mNextIdleDelay = mConstants.IDLE_TIMEOUT;
                }
                moveToStateLocked(STATE_IDLE, reason);
                if (mLightState != LIGHT_STATE_OVERRIDE) {
                    moveToLightStateLocked(LIGHT_STATE_OVERRIDE, "deep");
                    cancelLightAlarmLocked();
@@ -3842,6 +3841,7 @@ public class DeviceIdleController extends SystemService
                // We have been idling long enough, now it is time to do some work.
                mActiveIdleOpCount = 1;
                mActiveIdleWakeLock.acquire();
                moveToStateLocked(STATE_IDLE_MAINTENANCE, reason);
                scheduleAlarmLocked(mNextIdlePendingDelay, false);
                if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE to STATE_IDLE_MAINTENANCE. " +
                        "Next alarm in " + mNextIdlePendingDelay + " ms.");
@@ -3851,7 +3851,6 @@ public class DeviceIdleController extends SystemService
                if (mNextIdlePendingDelay < mConstants.IDLE_PENDING_TIMEOUT) {
                    mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
                }
                moveToStateLocked(STATE_IDLE_MAINTENANCE, reason);
                addEvent(EVENT_DEEP_MAINTENANCE, null);
                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
                break;
+154 −1
Original line number Diff line number Diff line
@@ -154,6 +154,7 @@ public class DeviceIdleControllerTest {
        ConstraintController constraintController;
        // Freeze time for testing.
        long nowElapsed;
        boolean useMotionSensor = true;

        InjectorForTest(Context ctx) {
            super(ctx);
@@ -245,7 +246,7 @@ public class DeviceIdleControllerTest {

        @Override
        boolean useMotionSensor() {
            return true;
            return useMotionSensor;
        }
    }

@@ -345,6 +346,12 @@ public class DeviceIdleControllerTest {
        mAnyMotionDetector = new AnyMotionDetectorForTest();
        mInjector = new InjectorForTest(getContext());

        setupDeviceIdleController();
    }

    private void setupDeviceIdleController() {
        reset(mTelephonyManager);

        mDeviceIdleController = new DeviceIdleController(getContext(), mInjector);
        spyOn(mDeviceIdleController);
        doNothing().when(mDeviceIdleController).publishBinderService(any(), any());
@@ -371,6 +378,10 @@ public class DeviceIdleControllerTest {
        if (mMockingSession != null) {
            mMockingSession.finishMocking();
        }
    }

    @After
    public void cleanupDeviceIdleController() {
        // DeviceIdleController adds these to LocalServices in the constructor, so we have to remove
        // them after each test, otherwise, subsequent tests will fail.
        LocalServices.removeServiceForTest(AppStateTracker.class);
@@ -617,6 +628,60 @@ public class DeviceIdleControllerTest {
                .scheduleAlarmLocked(eq(mConstants.INACTIVE_TIMEOUT), eq(false));
    }

    @Test
    public void testStateActiveToStateInactive_DoNotUseMotionSensor() {
        mInjector.useMotionSensor = false;
        cleanupDeviceIdleController();
        setupDeviceIdleController();
        mDeviceIdleController.becomeActiveLocked("testing", 0);
        verifyStateConditions(STATE_ACTIVE);

        setAlarmSoon(false);
        setChargingOn(false);
        setScreenOn(false);
        setEmergencyCallActive(false);

        mDeviceIdleController.becomeInactiveIfAppropriateLocked();
        verifyStateConditions(STATE_INACTIVE);
        verify(mDeviceIdleController)
                .scheduleAlarmLocked(eq(mConstants.INACTIVE_TIMEOUT), eq(false));
        // The device configuration doesn't require a motion sensor to proceed with idling.
        // This should be the case on TVs or other such devices. We should set an alarm to move
        // forward if the motion sensor is missing in this case.
        verify(mAlarmManager).setWindow(
                anyInt(), anyLong(), anyLong(),
                eq("DeviceIdleController.deep"), any(), any(Handler.class));
    }

    @Test
    public void testStateActiveToStateInactive_MissingMotionSensor() {
        mInjector.useMotionSensor = true;
        mMotionSensor = null;
        cleanupDeviceIdleController();
        setupDeviceIdleController();
        mDeviceIdleController.becomeActiveLocked("testing", 0);
        verifyStateConditions(STATE_ACTIVE);

        setAlarmSoon(false);
        setChargingOn(false);
        setScreenOn(false);
        setEmergencyCallActive(false);

        mDeviceIdleController.becomeInactiveIfAppropriateLocked();
        verifyStateConditions(STATE_INACTIVE);
        verify(mDeviceIdleController)
                .scheduleAlarmLocked(eq(mConstants.INACTIVE_TIMEOUT), eq(false));
        // The device configuration requires a motion sensor to proceed with idling,
        // so we should never set an alarm to move forward if the motion sensor is
        // missing in this case.
        verify(mAlarmManager, never()).setWindow(
                anyInt(), anyLong(), anyLong(),
                eq("DeviceIdleController.deep"), any(), any(Handler.class));
        verify(mAlarmManager, never()).set(
                anyInt(), anyLong(),
                eq("DeviceIdleController.deep"), any(), any(Handler.class));
    }

    @Test
    public void testStateActiveToStateInactive_UpcomingAlarm() {
        final long timeUntilAlarm = mConstants.MIN_TIME_TO_ALARM / 2;
@@ -756,6 +821,94 @@ public class DeviceIdleControllerTest {
        verifyStateConditions(STATE_IDLE_MAINTENANCE);
    }

    @Test
    public void testStepIdleStateLocked_ValidStates_MissingMotionSensor() {
        mInjector.useMotionSensor = true;
        mMotionSensor = null;
        cleanupDeviceIdleController();
        setupDeviceIdleController();
        mInjector.locationManager = mLocationManager;
        doReturn(mock(LocationProvider.class)).when(mLocationManager).getProvider(anyString());
        // Make sure the controller doesn't think there's a wake-from-idle alarm coming soon.
        setAlarmSoon(false);

        InOrder alarmManagerInOrder = inOrder(mAlarmManager);

        // Set state to INACTIVE.
        mDeviceIdleController.becomeActiveLocked("testing", 0);
        setChargingOn(false);
        setScreenOn(false);
        verifyStateConditions(STATE_INACTIVE);

        // The device configuration requires a motion sensor to proceed with idling,
        // so we should never set an alarm to move forward if the motion sensor is
        // missing in this case.
        alarmManagerInOrder.verify(mAlarmManager, never())
                .setWindow(anyInt(), anyLong(), anyLong(),
                        eq("DeviceIdleController.deep"), any(), any(Handler.class));

        // Pretend that someone is forcing state stepping via adb

        mDeviceIdleController.stepIdleStateLocked("testing");
        // verifyStateConditions knows this state typically shouldn't happen during normal
        // operation, so we can't use it directly here. For this test, all we care about
        // is that the state stepped forward.
        assertEquals(STATE_IDLE_PENDING, mDeviceIdleController.getState());
        // Still no alarm
        alarmManagerInOrder.verify(mAlarmManager, never())
                .setWindow(anyInt(), anyLong(), anyLong(),
                        eq("DeviceIdleController.deep"), any(), any(Handler.class));

        mDeviceIdleController.stepIdleStateLocked("testing");
        // verifyStateConditions knows this state typically shouldn't happen during normal
        // operation, so we can't use it directly here. For this test, all we care about
        // is that the state stepped forward.
        assertEquals(STATE_SENSING, mDeviceIdleController.getState());
        // Still no alarm
        alarmManagerInOrder.verify(mAlarmManager, never())
                .setWindow(anyInt(), anyLong(), anyLong(),
                        eq("DeviceIdleController.deep"), any(), any(Handler.class));

        mDeviceIdleController.stepIdleStateLocked("testing");
        // Location manager exists with a provider, so SENSING should go to LOCATING.
        // verifyStateConditions knows this state typically shouldn't happen during normal
        // operation, so we can't use it directly here. For this test, all we care about
        // is that the state stepped forward.
        assertEquals(STATE_LOCATING, mDeviceIdleController.getState());
        // Still no alarm
        alarmManagerInOrder.verify(mAlarmManager, never())
                .setWindow(anyInt(), anyLong(), anyLong(),
                        eq("DeviceIdleController.deep"), any(), any(Handler.class));

        mDeviceIdleController.stepIdleStateLocked("testing");
        verifyStateConditions(STATE_IDLE);
        // The device was forced into IDLE. AlarmManager should be notified.
        alarmManagerInOrder.verify(mAlarmManager)
                .setIdleUntil(anyInt(), anyLong(),
                        eq("DeviceIdleController.deep"), any(), any(Handler.class));

        // Should just alternate between IDLE and IDLE_MAINTENANCE now. Since we've gotten to this
        // point, alarms should be set on each transition.

        mDeviceIdleController.stepIdleStateLocked("testing");
        verifyStateConditions(STATE_IDLE_MAINTENANCE);
        alarmManagerInOrder.verify(mAlarmManager)
                .setWindow(anyInt(), anyLong(), anyLong(),
                        eq("DeviceIdleController.deep"), any(), any(Handler.class));

        mDeviceIdleController.stepIdleStateLocked("testing");
        verifyStateConditions(STATE_IDLE);
        alarmManagerInOrder.verify(mAlarmManager)
                .setIdleUntil(anyInt(), anyLong(),
                        eq("DeviceIdleController.deep"), any(), any(Handler.class));

        mDeviceIdleController.stepIdleStateLocked("testing");
        verifyStateConditions(STATE_IDLE_MAINTENANCE);
        alarmManagerInOrder.verify(mAlarmManager)
                .setWindow(anyInt(), anyLong(), anyLong(),
                        eq("DeviceIdleController.deep"), any(), any(Handler.class));
    }

    @Test
    public void testStepIdleStateLocked_ValidStates_WithWakeFromIdleAlarmSoon() {
        enterDeepState(STATE_ACTIVE);