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

Commit f9edc5c6 authored by Darrell Shi's avatar Darrell Shi
Browse files

Refactor idle/low-light state management.

- remove custom idle timeout, now dreams are triggered by system
inactivity
- remove mDozeToDreamLock, which wakes up the device briefly from
dozing, and puts it to dream. Sync with PowerManager on a better
approach.

Test: atest IdleHostViewControllerTest
Bug: 195606657
Fix: 195606657
Change-Id: Ife31527affa3943d5bce4c5ffad35ec33a397528
parent 8e9b12cd
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -638,9 +638,6 @@
         screen on inactivity. -->
    <bool name="config_enableIdleMode">false</bool>

    <!-- Timeout to idle mode duration in milliseconds. -->
    <integer name="config_idleModeTimeout">10000</integer>

    <!-- This value is used when calculating whether the device is in ambient light mode. It is
        light mode when the light sensor sample value exceeds above this value. -->
    <integer name="config_ambientLightModeThreshold">5</integer>
+0 −41
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.idle;

import android.content.Context;
import android.service.dreams.Sandman;

import javax.inject.Inject;

/**
 * A helper class to the idle mode for requests related to the
 * {@link DreamService}.
 */
public class DreamHelper {
    @Inject
    protected DreamHelper() {
    }

    /**
     * Requests the system to start dreaming.
     *
     * @param context The context within which the dream request is sent.
     */
    public void startDreaming(Context context) {
        Sandman.startDreamByUserRequest(context);
    }
}
+9 −204
Original line number Diff line number Diff line
@@ -24,22 +24,17 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.Log;
import android.view.Choreographer;
import android.view.View;

import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.concurrency.DelayableExecutor;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -52,13 +47,12 @@ import javax.inject.Provider;
 * {@link IdleHostViewController} processes signals to control the lifecycle of the idle screen.
 */
public class IdleHostViewController extends ViewController<IdleHostView> {
    private static final String INPUT_MONITOR_IDENTIFIER = "IdleHostViewController";
    private static final String TAG = "IdleHostViewController";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    @Retention(RetentionPolicy.RUNTIME)
    @IntDef({STATE_IDLE_MODE_ENABLED, STATE_KEYGUARD_SHOWING, STATE_DOZING, STATE_DREAMING,
            STATE_LOW_LIGHT, STATE_IDLING, STATE_SHOULD_START_IDLING})
            STATE_LOW_LIGHT})
    public @interface State {}

    // Set at construction to indicate idle mode is available.
@@ -76,76 +70,27 @@ public class IdleHostViewController extends ViewController<IdleHostView> {
    // Set when the device is in a low light environment.
    private static final int STATE_LOW_LIGHT = 1 << 4;

    // Set when the device is idling, which is either dozing or dreaming.
    private static final int STATE_IDLING = 1 << 5;

    // Set when the controller decides that the device should start idling (either dozing or
    // dreaming).
    private static final int STATE_SHOULD_START_IDLING = 1 << 6;

    // The aggregate current state.
    private int mState;
    private boolean mIdleModeActive;
    private boolean mLowLightModeActive;
    private boolean mIsMonitoringLowLight;
    private boolean mIsMonitoringDream;

    // Whether in a state waiting for dozing to complete before starting dreaming.
    private boolean mDozeToDreamLock = false;

    private final Context mContext;

    // Timeout to idle in milliseconds.
    private final int mIdleTimeout;

    // Factory for generating input listeners.
    private final InputMonitorFactory mInputMonitorFactory;

    // Delayable executor.
    private final DelayableExecutor mDelayableExecutor;

    private final BroadcastDispatcher mBroadcastDispatcher;

    private final PowerManager mPowerManager;

    // Runnable for canceling enabling idle.
    private Runnable mCancelEnableIdling;

    // Keyguard state controller for monitoring keyguard show state.
    private final KeyguardStateController mKeyguardStateController;

    // Status bar state controller for monitoring when the device is dozing.
    private final StatusBarStateController mStatusBarStateController;

    // Looper to use for monitoring input.
    private final Looper mLooper;

    // Choreographer to use for monitoring input.
    private final Choreographer mChoreographer;

    // Helper class for DreamService related requests.
    private final DreamHelper mDreamHelper;

    // Monitor for tracking touches for activity.
    private InputMonitorCompat mInputMonitor;

    // Input receiver of touch activities.
    private InputChannelCompat.InputEventReceiver mInputEventReceiver;

    // Intent filter for receiving dream broadcasts.
    private IntentFilter mDreamIntentFilter;

    // Monitor for the current ambient light mode. Used to trigger / exit low-light mode.
    private final AmbientLightModeMonitor mAmbientLightModeMonitor;

    // Delayed callback for starting idling.
    private final Runnable mEnableIdlingCallback = () -> {
        if (DEBUG) {
            Log.d(TAG, "time out, should start idling");
        }
        setState(STATE_SHOULD_START_IDLING, true);
    };

    private final KeyguardStateController.Callback mKeyguardCallback =
            new KeyguardStateController.Callback() {
                @Override
@@ -202,29 +147,20 @@ public class IdleHostViewController extends ViewController<IdleHostView> {

    @Inject
    protected IdleHostViewController(
            Context context,
            BroadcastDispatcher broadcastDispatcher,
            PowerManager powerManager,
            IdleHostView view, InputMonitorFactory factory,
            @Main DelayableExecutor delayableExecutor,
            IdleHostView view,
            @Main Resources resources,
            @Main Looper looper,
            @Named(IDLE_VIEW) Provider<View> idleViewProvider,
            Choreographer choreographer,
            KeyguardStateController keyguardStateController,
            StatusBarStateController statusBarStateController,
            DreamHelper dreamHelper,
            AmbientLightModeMonitor ambientLightModeMonitor) {
        super(view);
        mContext = context;
        mBroadcastDispatcher = broadcastDispatcher;
        mPowerManager = powerManager;
        mIdleViewProvider = idleViewProvider;
        mKeyguardStateController = keyguardStateController;
        mStatusBarStateController = statusBarStateController;
        mLooper = looper;
        mChoreographer = choreographer;
        mDreamHelper = dreamHelper;
        mAmbientLightModeMonitor = ambientLightModeMonitor;

        mState = STATE_KEYGUARD_SHOWING;
@@ -236,13 +172,8 @@ public class IdleHostViewController extends ViewController<IdleHostView> {

        setState(mState, true);

        mIdleTimeout = resources.getInteger(R.integer.config_idleModeTimeout);
        mInputMonitorFactory = factory;
        mDelayableExecutor = delayableExecutor;

        if (DEBUG) {
            Log.d(TAG, "initial state:" + mState + " enabled:" + enabled
                    + " timeout:" + mIdleTimeout);
            Log.d(TAG, "initial state:" + mState + " enabled:" + enabled);
        }
    }

@@ -255,20 +186,6 @@ public class IdleHostViewController extends ViewController<IdleHostView> {
    }

    private void setState(@State int state, boolean active) {
        // If waiting for dozing to stop, ignore any state update until dozing is stopped.
        if (mDozeToDreamLock) {
            if (state == STATE_DOZING && !active) {
                if (DEBUG) {
                    Log.d(TAG, "dozing stopped, now start dreaming");
                }

                mDozeToDreamLock = false;
                enableIdleMode(true);
            }

            return;
        }

        final int oldState = mState;

        if (active) {
@@ -281,53 +198,20 @@ public class IdleHostViewController extends ViewController<IdleHostView> {
            return;
        }

        // Updates STATE_IDLING.
        final boolean isIdling = getState(STATE_DOZING) || getState(STATE_DREAMING);
        if (isIdling) {
            mState |= STATE_IDLING;
        } else {
            mState &= ~STATE_IDLING;
        }

        // Updates STATE_SHOULD_START_IDLING.
        final boolean stoppedIdling = stoppedIdling(oldState);
        if (stoppedIdling) {
            mState &= ~STATE_SHOULD_START_IDLING;
        } else if (shouldStartIdling(oldState)) {
            mState |= STATE_SHOULD_START_IDLING;
        }

        if (DEBUG) {
            Log.d(TAG, "set " + getStateName(state) + " to " + active);
            logCurrentState();
        }

        final boolean wasLowLight = getState(STATE_LOW_LIGHT, oldState);
        final boolean isLowLight = getState(STATE_LOW_LIGHT);
        final boolean wasIdling = getState(STATE_IDLING, oldState);

        // When the device is idling and no longer in low light, wake up from dozing, wait till
        // done, and start dreaming.
        if (wasLowLight && !isLowLight && wasIdling && isIdling) {
            if (DEBUG) {
                Log.d(TAG, "idling and no longer in low light, stop dozing");
            }

            mDozeToDreamLock = true;

            enableLowLightMode(false);
            return;
        }

        final boolean inCommunalMode = getState(STATE_IDLE_MODE_ENABLED)
                && getState(STATE_KEYGUARD_SHOWING);

        enableDreamMonitoring(inCommunalMode);
        enableLowLightMonitoring(inCommunalMode);
        enableIdleMonitoring(inCommunalMode && !getState(STATE_IDLING));
        enableIdleMode(inCommunalMode && !getState(STATE_LOW_LIGHT)
                && getState(STATE_SHOULD_START_IDLING));
        enableLowLightMode(inCommunalMode && !stoppedIdling && getState(STATE_LOW_LIGHT));

        if (state == STATE_LOW_LIGHT) {
            enableLowLightMode(inCommunalMode && active);
        }
    }

    private void enableDreamMonitoring(boolean enable) {
@@ -354,64 +238,6 @@ public class IdleHostViewController extends ViewController<IdleHostView> {
        }
    }

    private void enableIdleMonitoring(boolean enable) {
        if (enable && mInputMonitor == null && mInputEventReceiver == null) {
            if (DEBUG) {
                Log.d(TAG, "enable idle monitoring");
            }
            // Set initial timeout to idle.
            mCancelEnableIdling = mDelayableExecutor.executeDelayed(mEnableIdlingCallback,
                    mIdleTimeout);

            // Monitor - any input should reset timer
            mInputMonitor = mInputMonitorFactory.getInputMonitor(INPUT_MONITOR_IDENTIFIER);
            mInputEventReceiver = mInputMonitor.getInputReceiver(mLooper, mChoreographer,
                    v -> {
                        if (DEBUG) {
                            Log.d(TAG, "touch detected, resetting timeout");
                        }
                        // When input is received, reset timeout.
                        if (mCancelEnableIdling != null) {
                            mCancelEnableIdling.run();
                            mCancelEnableIdling = null;
                        }
                        mCancelEnableIdling = mDelayableExecutor.executeDelayed(
                                mEnableIdlingCallback, mIdleTimeout);
                    });
        } else if (!enable && mInputMonitor != null && mInputEventReceiver != null) {
            if (DEBUG) {
                Log.d(TAG, "disable idle monitoring");
            }
            // Clean up idle callback and touch monitoring.
            if (mCancelEnableIdling != null) {
                mCancelEnableIdling.run();
                mCancelEnableIdling = null;
            }

            mInputEventReceiver.dispose();
            mInputMonitor.dispose();
            mInputEventReceiver = null;
            mInputMonitor = null;
        }
    }

    private void enableIdleMode(boolean enable) {
        if (mIdleModeActive == enable) {
            return;
        }

        if (DEBUG) {
            Log.d(TAG, (enable ? "enable" : "disable") + " idle mode");
        }

        mIdleModeActive = enable;

        if (mIdleModeActive) {
            // Start dream.
            mDreamHelper.startDreaming(mContext);
        }
    }

    private void enableLowLightMonitoring(boolean enable) {
        if (enable == mIsMonitoringLowLight) {
            return;
@@ -429,13 +255,11 @@ public class IdleHostViewController extends ViewController<IdleHostView> {
    }

    private void enableLowLightMode(boolean enable) {
        if (mLowLightModeActive == enable) {
        if (enable == getState(STATE_DOZING)) {
            return;
        }

        mLowLightModeActive = enable;

        if (mLowLightModeActive) {
        if (enable) {
            if (DEBUG) Log.d(TAG, "enter low light, start dozing");

            mPowerManager.goToSleep(
@@ -464,19 +288,6 @@ public class IdleHostViewController extends ViewController<IdleHostView> {
        mStatusBarStateController.removeCallback(mStatusBarCallback);
    }

    // Returns whether the device just stopped idling by comparing the previous state with the
    // current one.
    private boolean stoppedIdling(int oldState) {
        // The device stopped idling if it's no longer dreaming or dozing.
        return !getState(STATE_DOZING) && !getState(STATE_DREAMING)
                && (getState(STATE_DOZING, oldState) || getState(STATE_DREAMING, oldState));
    }

    private boolean shouldStartIdling(int oldState) {
        // Should start idling immediately if the device went in low light environment.
        return !getState(STATE_LOW_LIGHT, oldState) && getState(STATE_LOW_LIGHT);
    }

    private String getStateName(@State int state) {
        switch (state) {
            case STATE_IDLE_MODE_ENABLED:
@@ -489,10 +300,6 @@ public class IdleHostViewController extends ViewController<IdleHostView> {
                return "STATE_DREAMING";
            case STATE_LOW_LIGHT:
                return "STATE_LOW_LIGHT";
            case STATE_IDLING:
                return "STATE_IDLING";
            case STATE_SHOULD_START_IDLING:
                return "STATE_SHOULD_START_IDLING";
            default:
                return "STATE_UNKNOWN";
        }
@@ -517,8 +324,6 @@ public class IdleHostViewController extends ViewController<IdleHostView> {
                + "\t" + getStateLog(STATE_DOZING) + "\n"
                + "\t" + getStateLog(STATE_DREAMING) + "\n"
                + "\t" + getStateLog(STATE_LOW_LIGHT) + "\n"
                + "\t" + getStateLog(STATE_IDLING) + "\n"
                + "\t" + getStateLog(STATE_SHOULD_START_IDLING) + "\n"
                + "}");
    }
}
+17 −132
Original line number Diff line number Diff line
@@ -16,22 +16,16 @@

package com.android.systemui.idle;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Looper;
import android.os.PowerManager;
import android.testing.AndroidTestingRunner;
import android.view.Choreographer;
import android.view.View;

import androidx.test.filters.SmallTest;
@@ -40,10 +34,7 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;

import org.junit.Before;
import org.junit.Test;
@@ -60,22 +51,14 @@ public class IdleHostViewControllerTest extends SysuiTestCase {
    @Mock private BroadcastDispatcher mBroadcastDispatcher;
    @Mock private PowerManager mPowerManager;
    @Mock private IdleHostView mIdleHostView;
    @Mock private InputMonitorFactory mInputMonitorFactory;
    @Mock private DelayableExecutor mDelayableExecutor;
    @Mock private Resources mResources;
    @Mock private Looper mLooper;
    @Mock private Provider<View> mViewProvider;
    @Mock private Choreographer mChoreographer;
    @Mock private KeyguardStateController mKeyguardStateController;
    @Mock private StatusBarStateController mStatusBarStateController;
    @Mock private DreamHelper mDreamHelper;
    @Mock private InputMonitorCompat mInputMonitor;
    @Mock private InputChannelCompat.InputEventReceiver mInputEventReceiver;
    @Mock private AmbientLightModeMonitor mAmbientLightModeMonitor;

    private KeyguardStateController.Callback mKeyguardStateCallback;
    private StatusBarStateController.StateListener mStatusBarStateListener;
    private IdleHostViewController mController;

    @Before
    public void setup() {
@@ -83,17 +66,12 @@ public class IdleHostViewControllerTest extends SysuiTestCase {

        when(mResources.getBoolean(R.bool.config_enableIdleMode)).thenReturn(true);
        when(mStatusBarStateController.isDozing()).thenReturn(false);
        when(mInputMonitorFactory.getInputMonitor("IdleHostViewController"))
                .thenReturn(mInputMonitor);
        when(mInputMonitor.getInputReceiver(any(), any(), any())).thenReturn(mInputEventReceiver);

        mController = new IdleHostViewController(mContext,
                mBroadcastDispatcher, mPowerManager, mIdleHostView,
                mInputMonitorFactory, mDelayableExecutor, mResources, mLooper, mViewProvider,
                mChoreographer, mKeyguardStateController, mStatusBarStateController, mDreamHelper,
                mAmbientLightModeMonitor);
        mController.init();
        mController.onViewAttached();

        final IdleHostViewController controller = new IdleHostViewController(mBroadcastDispatcher,
                mPowerManager, mIdleHostView, mResources, mViewProvider, mKeyguardStateController,
                mStatusBarStateController, mAmbientLightModeMonitor);
        controller.init();
        controller.onViewAttached();

        // Captures keyguard state controller callback.
        ArgumentCaptor<KeyguardStateController.Callback> keyguardStateCallbackCaptor =
@@ -108,101 +86,6 @@ public class IdleHostViewControllerTest extends SysuiTestCase {
        mStatusBarStateListener = statusBarStateListenerCaptor.getValue();
    }

    @Test
    public void testTimeoutToIdleMode() {
        // Keyguard showing.
        when(mKeyguardStateController.isShowing()).thenReturn(true);
        mKeyguardStateCallback.onKeyguardShowingChanged();

        // Regular ambient lighting.
        final AmbientLightModeMonitor.Callback lightMonitorCallback =
                captureAmbientLightModeMonitorCallback();
        lightMonitorCallback.onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_LIGHT);

        // Times out.
        ArgumentCaptor<Runnable> callbackCapture = ArgumentCaptor.forClass(Runnable.class);
        verify(mDelayableExecutor).executeDelayed(callbackCapture.capture(), anyLong());
        callbackCapture.getValue().run();

        // Verifies start dreaming (idle mode).
        verify(mDreamHelper).startDreaming(any());
    }

    @Test
    public void testTimeoutToLowLightMode() {
        // Keyguard showing.
        when(mKeyguardStateController.isShowing()).thenReturn(true);
        mKeyguardStateCallback.onKeyguardShowingChanged();

        // Captures dream broadcast receiver;
        ArgumentCaptor<BroadcastReceiver> dreamBroadcastReceiverCaptor =
                ArgumentCaptor.forClass(BroadcastReceiver.class);
        verify(mBroadcastDispatcher)
                .registerReceiver(dreamBroadcastReceiverCaptor.capture(), any());
        final BroadcastReceiver dreamBroadcastReceiver = dreamBroadcastReceiverCaptor.getValue();

        // Low ambient lighting.
        final AmbientLightModeMonitor.Callback lightMonitorCallback =
                captureAmbientLightModeMonitorCallback();
        lightMonitorCallback.onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_DARK);

        // Verifies it goes to sleep because of low light.
        verify(mPowerManager).goToSleep(anyLong(), anyInt(), anyInt());

        mStatusBarStateListener.onDozingChanged(true /*isDozing*/);
        dreamBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_DREAMING_STARTED));

        // User wakes up the device.
        mStatusBarStateListener.onDozingChanged(false /*isDozing*/);
        dreamBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_DREAMING_STOPPED));

        // Clears power manager invocations to make sure the below dozing was triggered by the
        // timeout.
        clearInvocations(mPowerManager);

        // Times out.
        ArgumentCaptor<Runnable> callbackCapture = ArgumentCaptor.forClass(Runnable.class);
        verify(mDelayableExecutor, atLeastOnce()).executeDelayed(callbackCapture.capture(),
                anyLong());
        callbackCapture.getValue().run();

        // Verifies go to sleep (low light mode).
        verify(mPowerManager).goToSleep(anyLong(), anyInt(), anyInt());
    }

    @Test
    public void testTransitionBetweenIdleAndLowLightMode() {
        // Keyguard showing.
        when(mKeyguardStateController.isShowing()).thenReturn(true);
        mKeyguardStateCallback.onKeyguardShowingChanged();

        // Regular ambient lighting.
        final AmbientLightModeMonitor.Callback lightMonitorCallback =
                captureAmbientLightModeMonitorCallback();
        lightMonitorCallback.onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_LIGHT);

        // Times out.
        ArgumentCaptor<Runnable> callbackCapture = ArgumentCaptor.forClass(Runnable.class);
        verify(mDelayableExecutor).executeDelayed(callbackCapture.capture(), anyLong());
        callbackCapture.getValue().run();

        // Verifies in idle mode (dreaming).
        verify(mDreamHelper).startDreaming(any());
        clearInvocations(mDreamHelper);

        // Ambient lighting becomes dim.
        lightMonitorCallback.onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_DARK);

        // Verifies in low light mode (dozing).
        verify(mPowerManager).goToSleep(anyLong(), anyInt(), anyInt());

        // Ambient lighting becomes bright again.
        lightMonitorCallback.onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_LIGHT);

        // Verifies in idle mode (dreaming).
        verify(mDreamHelper).startDreaming(any());
    }

    @Test
    public void testStartDozingWhenLowLight() {
        // Keyguard showing.
@@ -225,20 +108,22 @@ public class IdleHostViewControllerTest extends SysuiTestCase {
    }

    @Test
    public void testInputEventReceiverLifecycle() {
    public void testWakeUpWhenRegularLight() {
        // Keyguard showing.
        when(mKeyguardStateController.isShowing()).thenReturn(true);
        mKeyguardStateCallback.onKeyguardShowingChanged();

        // Should register input event receiver.
        verify(mInputMonitor).getInputReceiver(any(), any(), any());
        // In low light / dozing.
        final AmbientLightModeMonitor.Callback lightMonitorCallback =
                captureAmbientLightModeMonitorCallback();
        lightMonitorCallback.onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_DARK);
        mStatusBarStateListener.onDozingChanged(true /*isDozing*/);

        // Keyguard dismissed.
        when(mKeyguardStateController.isShowing()).thenReturn(false);
        mKeyguardStateCallback.onKeyguardShowingChanged();
        // Regular ambient lighting.
        lightMonitorCallback.onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_LIGHT);

        // Should dispose input event receiver.
        verify(mInputEventReceiver).dispose();
        // Verifies it wakes up from sleep.
        verify(mPowerManager).wakeUp(anyLong(), anyInt(), anyString());
    }

    // Captures [AmbientLightModeMonitor.Callback] assuming that the ambient light mode monitor