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

Commit 89b9417a authored by Prem Edhara's avatar Prem Edhara Committed by Android (Google) Code Review
Browse files

Merge "Add off-body listener to turn device active when on-body" into main

parents 451e2cf0 d1c02a58
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -48,6 +48,17 @@ public interface WearModeManagerInternal {
     */
    String QUICK_DOZE_REQUEST_IDENTIFIER = "quick_doze_request";

    /**
     * Mode manager off body state identifier.
     *
     * <p>Unique identifier that can be used as identifier parameter in
     * registerInternalStateObserver
     * to listen to changes in quick doze request state from mode manager.
     *
     * TODO(b/288276510): convert to int constant
     */
    String OFFBODY_STATE_ID = "off_body";

    /**
     * StringDef for Mode manager identifiers.
     *
@@ -55,7 +66,8 @@ public interface WearModeManagerInternal {
     */
    @Retention(RetentionPolicy.SOURCE)
    @StringDef({
            QUICK_DOZE_REQUEST_IDENTIFIER
            QUICK_DOZE_REQUEST_IDENTIFIER,
            OFFBODY_STATE_ID
    })
    @Target(ElementType.TYPE_USE)
    @interface Identifier {
+94 −6
Original line number Diff line number Diff line
@@ -377,7 +377,11 @@ public class DeviceIdleController extends SystemService
    @GuardedBy("this")
    private boolean mModeManagerRequestedQuickDoze;
    @GuardedBy("this")
    private boolean mIsOffBody;
    @GuardedBy("this")
    private boolean mForceModeManagerQuickDozeRequest;
    @GuardedBy("this")
    private boolean mForceModeManagerOffBodyState;

    /** Time in the elapsed realtime timebase when this listener last received a motion event. */
    @GuardedBy("this")
@@ -437,6 +441,7 @@ public class DeviceIdleController extends SystemService
    private static final int ACTIVE_REASON_ALARM = 7;
    private static final int ACTIVE_REASON_EMERGENCY_CALL = 8;
    private static final int ACTIVE_REASON_MODE_MANAGER = 9;
    private static final int ACTIVE_REASON_ONBODY = 10;

    @VisibleForTesting
    static String stateToString(int state) {
@@ -837,7 +842,7 @@ public class DeviceIdleController extends SystemService
    class ModeManagerQuickDozeRequestConsumer implements Consumer<Boolean> {
        @Override
        public void accept(Boolean enabled) {
            Slog.d(TAG, "Mode manager quick doze request: " + enabled);
            Slog.i(TAG, "Mode manager quick doze request: " + enabled);
            synchronized (DeviceIdleController.this) {
                if (!mForceModeManagerQuickDozeRequest
                        && mModeManagerRequestedQuickDoze != enabled) {
@@ -848,13 +853,46 @@ public class DeviceIdleController extends SystemService
        }

        @GuardedBy("DeviceIdleController.this")
        public void onModeManagerRequestChangedLocked() {
        private void onModeManagerRequestChangedLocked() {
            // Get into quick doze faster when mode manager requests instead of taking
            // traditional multi-stage approach.
            maybeBecomeActiveOnModeManagerEventsLocked();
            updateQuickDozeFlagLocked();
            if (!mModeManagerRequestedQuickDoze && !mBatterySaverEnabled) {
                mActiveReason = ACTIVE_REASON_MODE_MANAGER;
                becomeActiveLocked("mode_manager", Process.myUid());
        }
    }

    @VisibleForTesting
    class ModeManagerOffBodyStateConsumer implements Consumer<Boolean> {
        @Override
        public void accept(Boolean isOffBody) {
            Slog.i(TAG, "Offbody event from mode manager: " + isOffBody);
            synchronized (DeviceIdleController.this) {
                if (!mForceModeManagerOffBodyState && mIsOffBody != isOffBody) {
                    mIsOffBody = isOffBody;
                    onModeManagerOffBodyChangedLocked();
                }
            }
        }

        @GuardedBy("DeviceIdleController.this")
        private void onModeManagerOffBodyChangedLocked() {
            maybeBecomeActiveOnModeManagerEventsLocked();
        }
    }

    @GuardedBy("DeviceIdleController.this")
    private void maybeBecomeActiveOnModeManagerEventsLocked() {
        synchronized (DeviceIdleController.this) {
            if (mQuickDozeActivated) {
                // Quick doze is enabled so don't turn the device active.
                return;
            }
            // Fall through when quick doze is not requested.

            if (!mIsOffBody) {
                // Quick doze was not requested and device is on body so turn the device active.
                mActiveReason = ACTIVE_REASON_ONBODY;
                becomeActiveLocked("on_body", Process.myUid());
            }
        }
    }
@@ -863,6 +901,10 @@ public class DeviceIdleController extends SystemService
    final ModeManagerQuickDozeRequestConsumer mModeManagerQuickDozeRequestConsumer =
            new ModeManagerQuickDozeRequestConsumer();

    @VisibleForTesting
    final ModeManagerOffBodyStateConsumer mModeManagerOffBodyStateConsumer =
            new ModeManagerOffBodyStateConsumer();

    @VisibleForTesting
    final class MotionListener extends TriggerEventListener
            implements SensorEventListener {
@@ -2648,6 +2690,12 @@ public class DeviceIdleController extends SystemService
                                WearModeManagerInternal.QUICK_DOZE_REQUEST_IDENTIFIER,
                                AppSchedulingModuleThread.getExecutor(),
                                mModeManagerQuickDozeRequestConsumer);

                        modeManagerInternal.addActiveStateChangeListener(
                                WearModeManagerInternal.OFFBODY_STATE_ID,
                                AppSchedulingModuleThread.getExecutor(),
                                mModeManagerOffBodyStateConsumer
                        );
                    }
                }
                mLocalPowerManager.registerLowPowerModeObserver(ServiceType.QUICK_DOZE,
@@ -4463,7 +4511,7 @@ public class DeviceIdleController extends SystemService
        pw.println(
                "    Resume normal functioning after force-idle or force-inactive or "
                        + "force-modemanager-quickdoze.");
        pw.println("  get [light|deep|force|screen|charging|network|offbody|forcebodystate]");
        pw.println("  get [light|deep|force|screen|charging|network|offbody|forceoffbody]");
        pw.println("    Retrieve the current given state.");
        pw.println("  disable [light|deep|all]");
        pw.println("    Completely disable device idle mode.");
@@ -4500,6 +4548,10 @@ public class DeviceIdleController extends SystemService
        pw.println("  force-modemanager-quickdoze [true|false]");
        pw.println("    Simulate mode manager request to enable (true) or disable (false) "
                + "quick doze. Mode manager changes will be ignored until unforce is called.");
        pw.println("  force-modemanager-offbody [true|false]");
        pw.println("    Force mode manager offbody state, this can be used to simulate "
                + "device being off-body (true) or on-body (false). Mode manager changes "
                + "will be ignored until unforce is called.");
    }

    class Shell extends ShellCommand {
@@ -4634,6 +4686,9 @@ public class DeviceIdleController extends SystemService
                    mForceModeManagerQuickDozeRequest = false;
                    pw.println("mForceModeManagerQuickDozeRequest: "
                            + mForceModeManagerQuickDozeRequest);
                    mForceModeManagerOffBodyState = false;
                    pw.println("mForceModeManagerOffBodyState: "
                            + mForceModeManagerOffBodyState);
                } finally {
                    Binder.restoreCallingIdentity(token);
                }
@@ -4660,6 +4715,8 @@ public class DeviceIdleController extends SystemService
                            case "forcemodemanagerquick":
                                pw.println(mForceModeManagerQuickDozeRequest);
                                break;
                            case "offbody": pw.println(mIsOffBody); break;
                            case "forceoffbody": pw.println(mForceModeManagerOffBodyState); break;
                            default: pw.println("Unknown get option: " + arg); break;
                        }
                    } finally {
@@ -4982,6 +5039,31 @@ public class DeviceIdleController extends SystemService
                pw.println("Provide true or false argument after force-modemanager-quickdoze");
                return -1;
            }
        } else if ("force-modemanager-offbody".equals(cmd)) {
            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
                    null);
            String arg = shell.getNextArg();

            if ("true".equalsIgnoreCase(arg) || "false".equalsIgnoreCase(arg)) {
                boolean isOffBody = Boolean.parseBoolean(arg);

                synchronized (DeviceIdleController.this) {
                    final long token = Binder.clearCallingIdentity();
                    try {
                        mForceModeManagerOffBodyState = true;
                        pw.println("mForceModeManagerOffBodyState: "
                                + mForceModeManagerOffBodyState);
                        mIsOffBody = isOffBody;
                        pw.println("mIsOffBody: " + mIsOffBody);
                        mModeManagerOffBodyStateConsumer.onModeManagerOffBodyChangedLocked();
                    } finally {
                        Binder.restoreCallingIdentity(token);
                    }
                }
            } else {
                pw.println("Provide true or false argument after force-modemanager-offbody");
                return -1;
            }
        } else {
            return shell.handleDefaultCommands(cmd);
        }
@@ -5233,6 +5315,12 @@ public class DeviceIdleController extends SystemService
            if (mAlarmsActive) {
                pw.print("  mAlarmsActive="); pw.println(mAlarmsActive);
            }
            if (mConstants.USE_MODE_MANAGER) {
                pw.print("  mModeManagerRequestedQuickDoze=");
                pw.println(mModeManagerRequestedQuickDoze);
                pw.print("  mIsOffBody");
                pw.println(mIsOffBody);
            }
        }
    }

+124 −3
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@
package com.android.server;

import static androidx.test.InstrumentationRegistry.getContext;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -42,7 +41,6 @@ import static com.android.server.DeviceIdleController.STATE_QUICK_DOZE_DELAY;
import static com.android.server.DeviceIdleController.STATE_SENSING;
import static com.android.server.DeviceIdleController.lightStateToString;
import static com.android.server.DeviceIdleController.stateToString;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -2418,7 +2416,7 @@ public class DeviceIdleControllerTest {
    }

    @Test
    public void testModeManager_NoModeManagerLocalService_AddListenerNotCalled() {
    public void testModeManager_NoModeManagerLocalService_AddQuickDozeListenerNotCalled() {
        mConstants.USE_MODE_MANAGER = true;
        doReturn(null)
                .when(() -> LocalServices.getService(WearModeManagerInternal.class));
@@ -2429,6 +2427,33 @@ public class DeviceIdleControllerTest {
                eq(mDeviceIdleController.mModeManagerQuickDozeRequestConsumer));
    }

    @Test
    public void testModeManager_NoModeManagerLocalService_AddOffBodyListenerNotCalled() {
        mConstants.USE_MODE_MANAGER = true;
        doReturn(null)
                .when(() -> LocalServices.getService(WearModeManagerInternal.class));
        cleanupDeviceIdleController();
        setupDeviceIdleController();
        verify(mWearModeManagerInternal, never()).addActiveStateChangeListener(
                eq(WearModeManagerInternal.OFFBODY_STATE_ID), any(),
                eq(mDeviceIdleController.mModeManagerOffBodyStateConsumer));
    }

    @Test
    public void testModeManager_USEMODEMANAGERIsFalse_AddListenerNotCalled() {
        mConstants.USE_MODE_MANAGER = false;
        doReturn(new Object())
                .when(() -> LocalServices.getService(WearModeManagerInternal.class));
        cleanupDeviceIdleController();
        setupDeviceIdleController();
        verify(mWearModeManagerInternal, never()).addActiveStateChangeListener(
                eq(WearModeManagerInternal.OFFBODY_STATE_ID), any(),
                eq(mDeviceIdleController.mModeManagerOffBodyStateConsumer));
        verify(mWearModeManagerInternal, never()).addActiveStateChangeListener(
                eq(WearModeManagerInternal.QUICK_DOZE_REQUEST_IDENTIFIER), any(),
                eq(mDeviceIdleController.mModeManagerQuickDozeRequestConsumer));
    }

    @Test
    public void testModeManager_NoBatterySaver_QuickDoze() {
        mConstants.USE_MODE_MANAGER = true;
@@ -2469,6 +2494,102 @@ public class DeviceIdleControllerTest {
        assertTrue(mDeviceIdleController.isQuickDozeEnabled());
    }

    @Test
    public void testModeManager_QuickDozeRequestedBatterySaverEnabledOnBody_QuickDozeEnabled() {
        mConstants.USE_MODE_MANAGER = true;
        PowerSaveState powerSaveState = new PowerSaveState.Builder().setBatterySaverEnabled(
                true).build();
        when(mPowerManagerInternal.getLowPowerState(anyInt()))
                .thenReturn(powerSaveState);
        cleanupDeviceIdleController();
        setupDeviceIdleController();

        mDeviceIdleController.mModeManagerOffBodyStateConsumer.accept(false);
        mDeviceIdleController.mModeManagerQuickDozeRequestConsumer.accept(true);

        assertTrue(mDeviceIdleController.isQuickDozeEnabled());
    }

    @Test
    public void testModeManager_QuickDozeRequestedBatterySaverEnabledOffBody_QuickDozeEnabled() {
        mConstants.USE_MODE_MANAGER = true;
        PowerSaveState powerSaveState = new PowerSaveState.Builder().setBatterySaverEnabled(
                true).build();
        when(mPowerManagerInternal.getLowPowerState(anyInt()))
                .thenReturn(powerSaveState);
        cleanupDeviceIdleController();
        setupDeviceIdleController();

        mDeviceIdleController.mModeManagerOffBodyStateConsumer.accept(true);
        mDeviceIdleController.mModeManagerQuickDozeRequestConsumer.accept(true);

        assertTrue(mDeviceIdleController.isQuickDozeEnabled());
    }

    @Test
    public void testModeManager_QuickDozeRequestedBatterySaverDisabledOnBody_QuickDozeEnabled() {
        mConstants.USE_MODE_MANAGER = true;
        PowerSaveState powerSaveState = new PowerSaveState.Builder().setBatterySaverEnabled(
                false).build();
        when(mPowerManagerInternal.getLowPowerState(anyInt()))
                .thenReturn(powerSaveState);
        cleanupDeviceIdleController();
        setupDeviceIdleController();

        mDeviceIdleController.mModeManagerOffBodyStateConsumer.accept(false);
        mDeviceIdleController.mModeManagerQuickDozeRequestConsumer.accept(true);

        assertTrue(mDeviceIdleController.isQuickDozeEnabled());
    }

    @Test
    public void testModeManager_QuickDozeRequestedBatterySaverDisabledOffBody_QuickDozeEnabled() {
        mConstants.USE_MODE_MANAGER = true;
        PowerSaveState powerSaveState = new PowerSaveState.Builder().setBatterySaverEnabled(
                false).build();
        when(mPowerManagerInternal.getLowPowerState(anyInt()))
                .thenReturn(powerSaveState);
        cleanupDeviceIdleController();
        setupDeviceIdleController();

        mDeviceIdleController.mModeManagerOffBodyStateConsumer.accept(true);
        mDeviceIdleController.mModeManagerQuickDozeRequestConsumer.accept(true);

        assertTrue(mDeviceIdleController.isQuickDozeEnabled());
    }

    @Test
    public void testModeManager_QuickDozeNotRequestedBatterySaverEnabledOnBody_QuickDozeEnabled() {
        mConstants.USE_MODE_MANAGER = true;
        PowerSaveState powerSaveState = new PowerSaveState.Builder().setBatterySaverEnabled(
                true).build();
        when(mPowerManagerInternal.getLowPowerState(anyInt()))
                .thenReturn(powerSaveState);
        cleanupDeviceIdleController();
        setupDeviceIdleController();

        mDeviceIdleController.mModeManagerOffBodyStateConsumer.accept(false);
        mDeviceIdleController.mModeManagerQuickDozeRequestConsumer.accept(false);

        assertTrue(mDeviceIdleController.isQuickDozeEnabled());
    }

    @Test
    public void testModeManager_QuickDozeNotRequestedBatterySaverEnabledOffBody_QuickDozeEnabled() {
        mConstants.USE_MODE_MANAGER = true;
        PowerSaveState powerSaveState = new PowerSaveState.Builder().setBatterySaverEnabled(
                true).build();
        when(mPowerManagerInternal.getLowPowerState(anyInt()))
                .thenReturn(powerSaveState);
        cleanupDeviceIdleController();
        setupDeviceIdleController();

        mDeviceIdleController.mModeManagerOffBodyStateConsumer.accept(true);
        mDeviceIdleController.mModeManagerQuickDozeRequestConsumer.accept(false);

        assertTrue(mDeviceIdleController.isQuickDozeEnabled());
    }

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