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

Commit 98b2f258 authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge "Re-register SMD after motion detected." into qt-qpr1-dev am: 23e867d5

Change-Id: I22d0ee2693590a13e99cff140b707c3af0a0aac7
parents 7c60c0f7 23e867d5
Loading
Loading
Loading
Loading
+57 −18
Original line number Diff line number Diff line
@@ -613,6 +613,15 @@ public class DeviceIdleController extends SystemService
        }
    };

    /** AlarmListener to start monitoring motion if there are registered stationary listeners. */
    private final AlarmManager.OnAlarmListener mMotionRegistrationAlarmListener = () -> {
        synchronized (DeviceIdleController.this) {
            if (mStationaryListeners.size() > 0) {
                startMonitoringMotionLocked();
            }
        }
    };

    private final AlarmManager.OnAlarmListener mMotionTimeoutAlarmListener = () -> {
        synchronized (DeviceIdleController.this) {
            if (!isStationaryLocked()) {
@@ -748,6 +757,7 @@ public class DeviceIdleController extends SystemService
        @Override
        public void onTrigger(TriggerEvent event) {
            synchronized (DeviceIdleController.this) {
                active = false;
                motionLocked();
            }
        }
@@ -755,6 +765,8 @@ public class DeviceIdleController extends SystemService
        @Override
        public void onSensorChanged(SensorEvent event) {
            synchronized (DeviceIdleController.this) {
                mSensorManager.unregisterListener(this, mMotionSensor);
                active = false;
                motionLocked();
            }
        }
@@ -1886,6 +1898,27 @@ public class DeviceIdleController extends SystemService
            return controller.new MyHandler(BackgroundThread.getHandler().getLooper());
        }

        Sensor getMotionSensor() {
            final SensorManager sensorManager = getSensorManager();
            Sensor motionSensor = null;
            int sigMotionSensorId = mContext.getResources().getInteger(
                    com.android.internal.R.integer.config_autoPowerModeAnyMotionSensor);
            if (sigMotionSensorId > 0) {
                motionSensor = sensorManager.getDefaultSensor(sigMotionSensorId, true);
            }
            if (motionSensor == null && mContext.getResources().getBoolean(
                    com.android.internal.R.bool.config_autoPowerModePreferWristTilt)) {
                motionSensor = sensorManager.getDefaultSensor(
                        Sensor.TYPE_WRIST_TILT_GESTURE, true);
            }
            if (motionSensor == null) {
                // As a last ditch, fall back to SMD.
                motionSensor = sensorManager.getDefaultSensor(
                        Sensor.TYPE_SIGNIFICANT_MOTION, true);
            }
            return motionSensor;
        }

        PowerManager getPowerManager() {
            return mContext.getSystemService(PowerManager.class);
        }
@@ -2037,21 +2070,7 @@ public class DeviceIdleController extends SystemService
                mSensorManager = mInjector.getSensorManager();

                if (mUseMotionSensor) {
                    int sigMotionSensorId = getContext().getResources().getInteger(
                            com.android.internal.R.integer.config_autoPowerModeAnyMotionSensor);
                    if (sigMotionSensorId > 0) {
                        mMotionSensor = mSensorManager.getDefaultSensor(sigMotionSensorId, true);
                    }
                    if (mMotionSensor == null && getContext().getResources().getBoolean(
                            com.android.internal.R.bool.config_autoPowerModePreferWristTilt)) {
                        mMotionSensor = mSensorManager.getDefaultSensor(
                                Sensor.TYPE_WRIST_TILT_GESTURE, true);
                    }
                    if (mMotionSensor == null) {
                        // As a last ditch, fall back to SMD.
                        mMotionSensor = mSensorManager.getDefaultSensor(
                                Sensor.TYPE_SIGNIFICANT_MOTION, true);
                    }
                    mMotionSensor = mInjector.getMotionSensor();
                }

                if (getContext().getResources().getBoolean(
@@ -3422,6 +3441,10 @@ public class DeviceIdleController extends SystemService
        if (mStationaryListeners.size() > 0) {
            postStationaryStatusUpdated();
            scheduleMotionTimeoutAlarmLocked();
            // 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.
            scheduleMotionRegistrationAlarmLocked();
        }
        if (mQuickDozeActivated && !mQuickDozeActivatedWhileIdling) {
            // Don't exit idle due to motion if quick doze is enabled.
@@ -3488,10 +3511,13 @@ public class DeviceIdleController extends SystemService
     */
    private void maybeStopMonitoringMotionLocked() {
        if (DEBUG) Slog.d(TAG, "maybeStopMonitoringMotionLocked()");
        if (mMotionSensor != null && mMotionListener.active && mStationaryListeners.size() == 0) {
        if (mMotionSensor != null && mStationaryListeners.size() == 0) {
            if (mMotionListener.active) {
                mMotionListener.unregisterLocked();
                cancelMotionTimeoutAlarmLocked();
            }
            cancelMotionRegistrationAlarmLocked();
        }
    }

    void cancelAlarmLocked() {
@@ -3521,6 +3547,10 @@ public class DeviceIdleController extends SystemService
        mAlarmManager.cancel(mMotionTimeoutAlarmListener);
    }

    private void cancelMotionRegistrationAlarmLocked() {
        mAlarmManager.cancel(mMotionRegistrationAlarmListener);
    }

    void cancelSensingTimeoutAlarmLocked() {
        if (mNextSensingTimeoutAlarmTime != 0) {
            mNextSensingTimeoutAlarmTime = 0;
@@ -3567,6 +3597,15 @@ public class DeviceIdleController extends SystemService
                mNextLightAlarmTime, "DeviceIdleController.light", mLightAlarmListener, mHandler);
    }

    private void scheduleMotionRegistrationAlarmLocked() {
        if (DEBUG) Slog.d(TAG, "scheduleMotionRegistrationAlarmLocked");
        long nextMotionRegistrationAlarmTime =
                mInjector.getElapsedRealtime() + mConstants.MOTION_INACTIVE_TIMEOUT / 2;
        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextMotionRegistrationAlarmTime,
                "DeviceIdleController.motion_registration", mMotionRegistrationAlarmListener,
                mHandler);
    }

    private void scheduleMotionTimeoutAlarmLocked() {
        if (DEBUG) Slog.d(TAG, "scheduleMotionAlarmLocked");
        long nextMotionTimeoutAlarmTime =
+137 −9
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;

import android.app.ActivityManagerInternal;
@@ -66,7 +67,11 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.net.ConnectivityManager;
@@ -127,6 +132,8 @@ public class DeviceIdleControllerTest {
    @Mock
    private PowerManagerInternal mPowerManagerInternal;
    @Mock
    private Sensor mMotionSensor;
    @Mock
    private SensorManager mSensorManager;

    class InjectorForTest extends DeviceIdleController.Injector {
@@ -193,6 +200,11 @@ public class DeviceIdleControllerTest {
            return mHandler;
        }

        @Override
        Sensor getMotionSensor() {
            return mMotionSensor;
        }

        @Override
        PowerManager getPowerManager() {
            return mPowerManager;
@@ -1673,22 +1685,36 @@ public class DeviceIdleControllerTest {
    }

    @Test
    public void testStationaryDetection_QuickDozeOn() {
    public void testStationaryDetection_QuickDozeOn_NoMotion() {
        // Short timeout for testing.
        mConstants.MOTION_INACTIVE_TIMEOUT = 6000L;
        doReturn(Sensor.REPORTING_MODE_ONE_SHOT).when(mMotionSensor).getReportingMode();
        doReturn(true).when(mSensorManager)
                .requestTriggerSensor(eq(mDeviceIdleController.mMotionListener), eq(mMotionSensor));
        setAlarmSoon(false);
        enterDeepState(STATE_QUICK_DOZE_DELAY);
        mDeviceIdleController.stepIdleStateLocked("testing");
        verifyStateConditions(STATE_IDLE);
        // Quick doze progression through states, so time should have increased appropriately.
        mInjector.nowElapsed += mConstants.QUICK_DOZE_DELAY_TIMEOUT;
        final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListener = ArgumentCaptor
        final ArgumentCaptor<AlarmManager.OnAlarmListener> motionAlarmListener = ArgumentCaptor
                .forClass(AlarmManager.OnAlarmListener.class);
        final ArgumentCaptor<AlarmManager.OnAlarmListener> motionRegistrationAlarmListener =
                ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
        doNothing().when(mAlarmManager).set(anyInt(), anyLong(), eq("DeviceIdleController.motion"),
                alarmListener.capture(), any());
                motionAlarmListener.capture(), any());
        doNothing().when(mAlarmManager).set(anyInt(), anyLong(),
                eq("DeviceIdleController.motion_registration"),
                motionRegistrationAlarmListener.capture(), any());

        StationaryListenerForTest stationaryListener = new StationaryListenerForTest();
        spyOn(stationaryListener);
        InOrder inOrder = inOrder(stationaryListener);

        stationaryListener.motionExpected = true;
        mDeviceIdleController.registerStationaryListener(stationaryListener);
        inOrder.verify(stationaryListener, timeout(1000L).times(1))
                .onDeviceStationaryChanged(eq(false));
        assertFalse(stationaryListener.isStationary);

        // Go to IDLE_MAINTENANCE
@@ -1700,13 +1726,17 @@ public class DeviceIdleControllerTest {
        mDeviceIdleController.stepIdleStateLocked("testing");

        // Now enough time has passed.
        mInjector.nowElapsed += mConstants.MOTION_INACTIVE_TIMEOUT / 2;
        mInjector.nowElapsed += mConstants.MOTION_INACTIVE_TIMEOUT;
        stationaryListener.motionExpected = false;
        alarmListener.getValue().onAlarm();
        motionAlarmListener.getValue().onAlarm();
        inOrder.verify(stationaryListener, timeout(1000L).times(1))
                .onDeviceStationaryChanged(eq(true));
        assertTrue(stationaryListener.isStationary);

        stationaryListener.motionExpected = true;
        mDeviceIdleController.mMotionListener.onSensorChanged(null);
        mDeviceIdleController.mMotionListener.onTrigger(null);
        inOrder.verify(stationaryListener, timeout(1000L).times(1))
                .onDeviceStationaryChanged(eq(false));
        assertFalse(stationaryListener.isStationary);

        // Since we're in quick doze, the device shouldn't stop idling.
@@ -1715,18 +1745,116 @@ public class DeviceIdleControllerTest {
        // Go to IDLE_MAINTENANCE
        mDeviceIdleController.stepIdleStateLocked("testing");

        motionRegistrationAlarmListener.getValue().onAlarm();
        mInjector.nowElapsed += mConstants.MOTION_INACTIVE_TIMEOUT / 2;

        // Back to IDLE
        stationaryListener.motionExpected = false;
        mDeviceIdleController.stepIdleStateLocked("testing");
        verify(mSensorManager,
                timeout(mConstants.MOTION_INACTIVE_TIMEOUT).times(2))
                .requestTriggerSensor(eq(mDeviceIdleController.mMotionListener), eq(mMotionSensor));

        // Now enough time has passed.
        mInjector.nowElapsed += mConstants.MOTION_INACTIVE_TIMEOUT / 2;
        stationaryListener.motionExpected = false;
        alarmListener.getValue().onAlarm();
        mInjector.nowElapsed += mConstants.MOTION_INACTIVE_TIMEOUT;
        motionAlarmListener.getValue().onAlarm();
        inOrder.verify(stationaryListener,
                timeout(mConstants.MOTION_INACTIVE_TIMEOUT).times(1))
                .onDeviceStationaryChanged(eq(true));
        assertTrue(stationaryListener.isStationary);
    }

    @Test
    public void testStationaryDetection_QuickDozeOn_OneShot() {
        // Short timeout for testing.
        mConstants.MOTION_INACTIVE_TIMEOUT = 6000L;
        doReturn(Sensor.REPORTING_MODE_ONE_SHOT).when(mMotionSensor).getReportingMode();
        setAlarmSoon(false);
        enterDeepState(STATE_QUICK_DOZE_DELAY);
        mDeviceIdleController.stepIdleStateLocked("testing");
        verifyStateConditions(STATE_IDLE);
        // Quick doze progression through states, so time should have increased appropriately.
        mInjector.nowElapsed += mConstants.QUICK_DOZE_DELAY_TIMEOUT;
        final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListener = ArgumentCaptor
                .forClass(AlarmManager.OnAlarmListener.class);
        doNothing().when(mAlarmManager)
                .set(anyInt(), anyLong(), eq("DeviceIdleController.motion"), any(), any());
        doNothing().when(mAlarmManager).set(anyInt(), anyLong(),
                eq("DeviceIdleController.motion_registration"),
                alarmListener.capture(), any());
        ArgumentCaptor<TriggerEventListener> listenerCaptor =
                ArgumentCaptor.forClass(TriggerEventListener.class);

        StationaryListenerForTest stationaryListener = new StationaryListenerForTest();
        spyOn(stationaryListener);
        InOrder inOrder = inOrder(stationaryListener, mSensorManager);

        stationaryListener.motionExpected = true;
        mDeviceIdleController.registerStationaryListener(stationaryListener);
        inOrder.verify(stationaryListener, timeout(1000L).times(1))
                .onDeviceStationaryChanged(eq(false));
        assertFalse(stationaryListener.isStationary);
        inOrder.verify(mSensorManager)
                .requestTriggerSensor(listenerCaptor.capture(), eq(mMotionSensor));
        final TriggerEventListener listener = listenerCaptor.getValue();

        // Trigger motion
        listener.onTrigger(mock(TriggerEvent.class));
        inOrder.verify(stationaryListener, timeout(1000L).times(1))
                .onDeviceStationaryChanged(eq(false));

        // Make sure the listener is re-registered.
        alarmListener.getValue().onAlarm();
        inOrder.verify(mSensorManager).requestTriggerSensor(eq(listener), eq(mMotionSensor));
    }

    @Test
    public void testStationaryDetection_QuickDozeOn_MultiShot() {
        // Short timeout for testing.
        mConstants.MOTION_INACTIVE_TIMEOUT = 6000L;
        doReturn(Sensor.REPORTING_MODE_CONTINUOUS).when(mMotionSensor).getReportingMode();
        setAlarmSoon(false);
        enterDeepState(STATE_QUICK_DOZE_DELAY);
        mDeviceIdleController.stepIdleStateLocked("testing");
        verifyStateConditions(STATE_IDLE);
        // Quick doze progression through states, so time should have increased appropriately.
        mInjector.nowElapsed += mConstants.QUICK_DOZE_DELAY_TIMEOUT;
        final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListener = ArgumentCaptor
                .forClass(AlarmManager.OnAlarmListener.class);
        doNothing().when(mAlarmManager)
                .set(anyInt(), anyLong(), eq("DeviceIdleController.motion"), any(), any());
        doNothing().when(mAlarmManager).set(anyInt(), anyLong(),
                eq("DeviceIdleController.motion_registration"),
                alarmListener.capture(), any());
        ArgumentCaptor<SensorEventListener> listenerCaptor =
                ArgumentCaptor.forClass(SensorEventListener.class);

        StationaryListenerForTest stationaryListener = new StationaryListenerForTest();
        spyOn(stationaryListener);
        InOrder inOrder = inOrder(stationaryListener, mSensorManager);

        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));
        final SensorEventListener listener = listenerCaptor.getValue();

        // Trigger motion
        listener.onSensorChanged(mock(SensorEvent.class));
        inOrder.verify(stationaryListener, timeout(1000L).times(1))
                .onDeviceStationaryChanged(eq(false));

        // Make sure the listener is re-registered.
        alarmListener.getValue().onAlarm();
        inOrder.verify(mSensorManager)
                .registerListener(eq(listener), eq(mMotionSensor),
                        eq(SensorManager.SENSOR_DELAY_NORMAL));
    }

    private void enterDeepState(int state) {
        switch (state) {
            case STATE_ACTIVE: