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

Commit ddecd027 authored by Matt Pietal's avatar Matt Pietal
Browse files

Revert "Update user switching processes"

This reverts commit 124a5084.

Reason for revert: b/393881275 - HSUM user switching crash on boot

Change-Id: I6f531633ae27a457b3c5d1b48433ad817be471e3
parent 67e5e61c
Loading
Loading
Loading
Loading
+33 −201
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.systemui.keyguard;

import static android.app.KeyguardManager.LOCK_ON_USER_SWITCH_CALLBACK;
import static android.app.StatusBarManager.SESSION_KEYGUARD;
import static android.provider.Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT;
import static android.provider.Settings.System.LOCKSCREEN_SOUNDS_ENABLED;
@@ -76,7 +75,6 @@ import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
@@ -194,8 +192,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -286,9 +282,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
    private static final int SYSTEM_READY = 18;
    private static final int CANCEL_KEYGUARD_EXIT_ANIM = 19;
    private static final int BOOT_INTERACTOR = 20;
    private static final int BEFORE_USER_SWITCHING = 21;
    private static final int USER_SWITCHING = 22;
    private static final int USER_SWITCH_COMPLETE = 23;

    /** Enum for reasons behind updating wakeAndUnlock state. */
    @Retention(RetentionPolicy.SOURCE)
@@ -306,8 +299,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
        int WAKE_AND_UNLOCK = 3;
    }

    private final List<LockNowCallback> mLockNowCallbacks = new ArrayList<>();

    /**
     * The default amount of time we stay awake (used for all key input)
     */
@@ -366,18 +357,13 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
    private final Lazy<NotificationShadeDepthController> mNotificationShadeDepthController;
    private final Lazy<ShadeController> mShadeController;
    private final Lazy<CommunalSceneInteractor> mCommunalSceneInteractor;
    /*
     * Records the user id on request to go away, for validation when WM calls back to start the
     * exit animation.
     */
    private int mGoingAwayRequestedForUserId = -1;

    private boolean mSystemReady;
    private boolean mBootCompleted;
    private boolean mBootSendUserPresent;
    private boolean mShuttingDown;
    private boolean mDozing;
    private boolean mAnimatingScreenOff;
    private boolean mIgnoreDismiss;
    private final Context mContext;
    private final FalsingCollector mFalsingCollector;

@@ -640,92 +626,41 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
                }
            };

    @VisibleForTesting
    protected UserTracker.Callback mUserChangedCallback = new UserTracker.Callback() {

        @Override
        public void onBeforeUserSwitching(int newUser, @NonNull Runnable resultCallback) {
            mHandler.sendMessage(mHandler.obtainMessage(BEFORE_USER_SWITCHING,
                    newUser, 0, resultCallback));
        }

        @Override
        public void onUserChanging(int newUser, @NonNull Context userContext,
                @NonNull Runnable resultCallback) {
            mHandler.sendMessage(mHandler.obtainMessage(USER_SWITCHING,
                    newUser, 0, resultCallback));
        }
    KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {

        @Override
        public void onUserChanged(int newUser, Context userContext) {
            mHandler.sendMessage(mHandler.obtainMessage(USER_SWITCH_COMPLETE,
                    newUser, 0));
        }
    };

    /**
     * Handle {@link #BEFORE_USER_SWITCHING}
     */
    @VisibleForTesting
    void handleBeforeUserSwitching(int userId, Runnable resultCallback) {
        Log.d(TAG, String.format("onBeforeUserSwitching %d", userId));
        public void onKeyguardVisibilityChanged(boolean visible) {
            synchronized (KeyguardViewMediator.this) {
            mHandler.removeMessages(DISMISS);
            notifyTrustedChangedLocked(mUpdateMonitor.getUserHasTrust(userId));
            resetKeyguardDonePendingLocked();
            adjustStatusBarLocked();
            mKeyguardStateController.notifyKeyguardGoingAway(false);
            if (mLockPatternUtils.isSecure(userId) && !mShowing) {
                if (!visible && mPendingPinLock) {
                    Log.i(TAG, "PIN lock requested, starting keyguard");

                    // Bring the keyguard back in order to show the PIN lock
                    mPendingPinLock = false;
                    doKeyguardLocked(null);
            } else {
                resetStateLocked();
                }
            resultCallback.run();
            }
        }

    /**
     * Handle {@link #USER_SWITCHING}
     */
    @VisibleForTesting
    void handleUserSwitching(int userId, Runnable resultCallback) {
        @Override
        public void onUserSwitching(int userId) {
            Log.d(TAG, String.format("onUserSwitching %d", userId));
            synchronized (KeyguardViewMediator.this) {
            if (!mLockPatternUtils.isSecure(userId)) {
                dismiss(null, null);
            }
            resultCallback.run();
                mIgnoreDismiss = true;
                notifyTrustedChangedLocked(mUpdateMonitor.getUserHasTrust(userId));
                resetKeyguardDonePendingLocked();
                resetStateLocked();
                adjustStatusBarLocked();
            }
        }

    /**
     * Handle {@link #USER_SWITCH_COMPLETE}
     */
    @VisibleForTesting
    void handleUserSwitchComplete(int userId) {
        @Override
        public void onUserSwitchComplete(int userId) {
            mIgnoreDismiss = false;
            Log.d(TAG, String.format("onUserSwitchComplete %d", userId));
        // Calling dismiss on a secure user will show the bouncer
        if (mLockPatternUtils.isSecure(userId)) {
            // We are calling dismiss with a delay as there are race conditions in some scenarios
            // caused by async layout listeners
            mHandler.postDelayed(() -> dismiss(null /* callback */, null /* message */), 500);
        }
    }

    KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {

        @Override
        public void onKeyguardVisibilityChanged(boolean visible) {
            synchronized (KeyguardViewMediator.this) {
                if (!visible && mPendingPinLock) {
                    Log.i(TAG, "PIN lock requested, starting keyguard");

                    // Bring the keyguard back in order to show the PIN lock
                    mPendingPinLock = false;
                    doKeyguardLocked(null);
                }
            }
        }

        @Override
        public void onDeviceProvisioned() {
@@ -1736,13 +1671,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
                com.android.internal.R.anim.lock_screen_behind_enter);

        mWorkLockController = new WorkLockActivityController(mContext, mUserTracker);
        mUserTracker.addCallback(mUserChangedCallback, mContext.getMainExecutor());
        // start() can be invoked in the middle of user switching, so check for this state and issue
        // the call manually as that important event was missed.
        if (mUserTracker.isUserSwitching()) {
            handleBeforeUserSwitching(mUserTracker.getUserId(), () -> {});
            handleUserSwitching(mUserTracker.getUserId(), () -> {});
        }

        mJavaAdapter.alwaysCollectFlow(
                mWallpaperRepository.getWallpaperSupportsAmbientMode(),
                this::setWallpaperSupportsAmbientMode);
@@ -1791,7 +1720,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
            // System ready can be invoked in the middle of user switching, so check for this state
            // and issue the call manually as that important event was missed.
            if (mUserTracker.isUserSwitching()) {
                mUserChangedCallback.onUserChanging(mUserTracker.getUserId(), mContext, () -> {});
                mUpdateCallback.onUserSwitching(mUserTracker.getUserId());
            }
        }
        // Most services aren't available until the system reaches the ready state, so we
@@ -2432,23 +2361,12 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
            mCommunalSceneInteractor.get().showHubFromPowerButton();
        }

        int currentUserId = mSelectedUserInteractor.getSelectedUserId();
        if (options != null && options.getBinder(LOCK_ON_USER_SWITCH_CALLBACK) != null) {
            LockNowCallback callback = new LockNowCallback(currentUserId,
                    IRemoteCallback.Stub.asInterface(
                            options.getBinder(LOCK_ON_USER_SWITCH_CALLBACK)));
            synchronized (mLockNowCallbacks) {
                mLockNowCallbacks.add(callback);
            }
            Log.d(TAG, "LockNowCallback required for user: " + callback.mUserId);
        }

        // if another app is disabling us, don't show
        if (!mExternallyEnabled
                && !mLockPatternUtils.isUserInLockdown(
                        mSelectedUserInteractor.getSelectedUserId())) {
            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");
            notifyLockNowCallback();

            mNeedToReshowWhenReenabled = true;
            return;
        }
@@ -2466,7 +2384,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
                    // We're removing "reset" in the refactor - "resetting" the views will happen
                    // as a reaction to the root cause of the "reset" signal.
                    if (KeyguardWmStateRefactor.isEnabled()) {
                        notifyLockNowCallback();
                        return;
                    }

@@ -2479,7 +2396,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
                                    + "previously hiding. It should be safe to short-circuit "
                                    + "here.");
                    resetStateLocked(/* hideBouncer= */ false);
                    notifyLockNowCallback();
                    return;
                }
            } else {
@@ -2506,7 +2422,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
                Log.d(TAG, "doKeyguard: not showing because device isn't provisioned and the sim is"
                        + " not locked or missing");
            }
            notifyLockNowCallback();
            return;
        }

@@ -2514,7 +2429,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
        if (mLockPatternUtils.isLockScreenDisabled(mSelectedUserInteractor.getSelectedUserId())
                && !lockedOrMissing && !forceShow) {
            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
            notifyLockNowCallback();
            return;
        }

@@ -2562,6 +2476,11 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
    }

    public void dismiss(IKeyguardDismissCallback callback, CharSequence message) {
        if (mIgnoreDismiss) {
            android.util.Log.i(TAG, "Ignoring request to dismiss (user switch in progress?)");
            return;
        }

        if (mKeyguardStateController.isKeyguardGoingAway()) {
            Log.i(TAG, "Ignoring dismiss because we're already going away.");
            return;
@@ -2579,7 +2498,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
    }

    private void resetStateLocked(boolean hideBouncer) {
        if (DEBUG) Log.d(TAG, "resetStateLocked");
        if (DEBUG) Log.e(TAG, "resetStateLocked");
        Message msg = mHandler.obtainMessage(RESET, hideBouncer ? 1 : 0, 0);
        mHandler.sendMessage(msg);
    }
@@ -2827,18 +2746,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
                    message = "BOOT_INTERACTOR";
                    handleBootInteractor();
                    break;
                case BEFORE_USER_SWITCHING:
                    message = "BEFORE_USER_SWITCHING";
                    handleBeforeUserSwitching(msg.arg1, (Runnable) msg.obj);
                    break;
                case USER_SWITCHING:
                    message = "USER_SWITCHING";
                    handleUserSwitching(msg.arg1, (Runnable) msg.obj);
                    break;
                case USER_SWITCH_COMPLETE:
                    message = "USER_SWITCH_COMPLETE";
                    handleUserSwitchComplete(msg.arg1);
                    break;
            }
            Log.d(TAG, "KeyguardViewMediator queue processing message: " + message);
        }
@@ -2980,9 +2887,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
        mUiBgExecutor.execute(() -> {
            Log.d(TAG, "updateActivityLockScreenState(" + showing + ", " + aodShowing + ", "
                    + reason + ")");
            if (showing) {
                notifyLockNowCallback();
            }

            if (KeyguardWmStateRefactor.isEnabled()) {
                // Handled in WmLockscreenVisibilityManager if flag is enabled.
@@ -3027,7 +2931,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
        synchronized (KeyguardViewMediator.this) {
            if (!mSystemReady) {
                if (DEBUG) Log.d(TAG, "ignoring handleShow because system is not ready.");
                notifyLockNowCallback();
                return;
            }
            if (DEBUG) Log.d(TAG, "handleShow");
@@ -3086,11 +2989,12 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
        }
    }

    final Runnable mKeyguardGoingAwayRunnable = new Runnable() {
    private final Runnable mKeyguardGoingAwayRunnable = new Runnable() {
        @SuppressLint("MissingPermission")
        @Override
        public void run() {
            Trace.beginSection("KeyguardViewMediator.mKeyGuardGoingAwayRunnable");
            Log.d(TAG, "keyguardGoingAwayRunnable");
            mKeyguardViewControllerLazy.get().keyguardGoingAway();

            int flags = 0;
@@ -3127,10 +3031,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,

            // Handled in WmLockscreenVisibilityManager if flag is enabled.
            if (!KeyguardWmStateRefactor.isEnabled()) {
                mGoingAwayRequestedForUserId = mSelectedUserInteractor.getSelectedUserId();
                Log.d(TAG, "keyguardGoingAway requested for userId: "
                        + mGoingAwayRequestedForUserId);

                // Don't actually hide the Keyguard at the moment, wait for window manager
                // until it tells us it's safe to do so with startKeyguardExitAnimation.
                // Posting to mUiOffloadThread to ensure that calls to ActivityTaskManager
@@ -3269,30 +3169,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
            RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) {
        Log.d(TAG, "handleStartKeyguardExitAnimation startTime=" + startTime
                + " fadeoutDuration=" + fadeoutDuration);
        int currentUserId = mSelectedUserInteractor.getSelectedUserId();
        if (!KeyguardWmStateRefactor.isEnabled() && mGoingAwayRequestedForUserId != currentUserId) {
            Log.e(TAG, "Not executing handleStartKeyguardExitAnimationInner() due to userId "
                    + "mismatch. Requested: " + mGoingAwayRequestedForUserId + ", current: "
                    + currentUserId);
            if (finishedCallback != null) {
                // There will not execute animation, send a finish callback to ensure the remote
                // animation won't hang there.
                try {
                    finishedCallback.onAnimationFinished();
                } catch (RemoteException e) {
                    Slog.w(TAG, "Failed to call onAnimationFinished", e);
                }
            }
            mHiding = false;
            if (mLockPatternUtils.isSecure(currentUserId)) {
                doKeyguardLocked(null);
            } else {
                resetStateLocked();
                dismiss(null, null);
            }
            return;
        }

        synchronized (KeyguardViewMediator.this) {
            mIsKeyguardExitAnimationCanceled = false;
            // Tell ActivityManager that we canceled the keyguard animation if
@@ -3537,13 +3413,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
     * app transition before finishing the current RemoteAnimation, or the keyguard being re-shown).
     */
    private void handleCancelKeyguardExitAnimation() {
        if (!KeyguardWmStateRefactor.isEnabled()
                && mGoingAwayRequestedForUserId != mSelectedUserInteractor.getSelectedUserId()) {
            Log.e(TAG, "Setting pendingLock = true due to userId mismatch. Requested: "
                    + mGoingAwayRequestedForUserId + ", current: "
                    + mSelectedUserInteractor.getSelectedUserId());
            setPendingLock(true);
        }
        if (mPendingLock) {
            Log.d(TAG, "#handleCancelKeyguardExitAnimation: keyguard exit animation cancelled. "
                    + "There's a pending lock, so we were cancelled because the device was locked "
@@ -3644,7 +3513,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
        mSurfaceBehindRemoteAnimationRequested = true;

        if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS && !KeyguardWmStateRefactor.isEnabled()) {
            mGoingAwayRequestedForUserId = mSelectedUserInteractor.getSelectedUserId();
            startKeyguardTransition(false /* keyguardShowing */, false /* aodShowing */);
            return;
        }
@@ -3665,9 +3533,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,

            if (!KeyguardWmStateRefactor.isEnabled()) {
                // Handled in WmLockscreenVisibilityManager.
                mGoingAwayRequestedForUserId = mSelectedUserInteractor.getSelectedUserId();
                Log.d(TAG, "keyguardGoingAway requested for userId: "
                        + mGoingAwayRequestedForUserId);
                mActivityTaskManagerService.keyguardGoingAway(flags);
            }
        } catch (RemoteException e) {
@@ -4123,29 +3988,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
        mUiBgExecutor.execute(mTrustManager::reportKeyguardShowingChanged);
    }

    private void notifyLockNowCallback() {
        List<LockNowCallback> callbacks;
        synchronized (mLockNowCallbacks) {
            callbacks = new ArrayList<LockNowCallback>(mLockNowCallbacks);
            mLockNowCallbacks.clear();
        }
        Iterator<LockNowCallback> iter = callbacks.listIterator();
        while (iter.hasNext()) {
            LockNowCallback callback = iter.next();
            iter.remove();
            if (callback.mUserId != mSelectedUserInteractor.getSelectedUserId()) {
                Log.i(TAG, "Not notifying lockNowCallback due to user mismatch");
                continue;
            }
            Log.i(TAG, "Notifying lockNowCallback");
            try {
                callback.mRemoteCallback.sendResult(null);
            } catch (RemoteException e) {
                Log.e(TAG, "Could not issue LockNowCallback sendResult", e);
            }
        }
    }

    private void notifyTrustedChangedLocked(boolean trusted) {
        int size = mKeyguardStateCallbacks.size();
        for (int i = size - 1; i >= 0; i--) {
@@ -4310,14 +4152,4 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
            }
        };
    }

    private class LockNowCallback {
        final int mUserId;
        final IRemoteCallback mRemoteCallback;

        LockNowCallback(int userId, IRemoteCallback remoteCallback) {
            mUserId = userId;
            mRemoteCallback = remoteCallback;
        }
    }
}
+13 −153

File changed.

Preview size limit exceeded, changes collapsed.

+28 −10
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
import static android.app.ActivityManagerInternal.ALLOW_PROFILES_OR_NON_FULL;
import static android.app.KeyguardManager.LOCK_ON_USER_SWITCH_CALLBACK;
import static android.os.PowerWhitelistManager.REASON_BOOT_COMPLETED;
import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
@@ -3905,6 +3904,10 @@ class UserController implements Handler.Callback {
            return mService.mWindowManager;
        }

        ActivityTaskManagerInternal getActivityTaskManagerInternal() {
            return mService.mAtmInternal;
        }

        void activityManagerOnUserStopped(@UserIdInt int userId) {
            LocalServices.getService(ActivityTaskManagerInternal.class).onUserStopped(userId);
        }
@@ -4119,25 +4122,40 @@ class UserController implements Handler.Callback {
        }

        void lockDeviceNowAndWaitForKeyguardShown() {
            if (getWindowManager().isKeyguardLocked()) {
                Slogf.w(TAG, "Not locking the device since the keyguard is already locked");
                return;
            }

            final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
            t.traceBegin("lockDeviceNowAndWaitForKeyguardShown");

            final CountDownLatch latch = new CountDownLatch(1);
            Bundle bundle = new Bundle();
            bundle.putBinder(LOCK_ON_USER_SWITCH_CALLBACK, new IRemoteCallback.Stub() {
                public void sendResult(Bundle data) {
            ActivityTaskManagerInternal.ScreenObserver screenObserver =
                    new ActivityTaskManagerInternal.ScreenObserver() {
                        @Override
                        public void onAwakeStateChanged(boolean isAwake) {

                        }

                        @Override
                        public void onKeyguardStateChanged(boolean isShowing) {
                            if (isShowing) {
                                latch.countDown();
                            }
            });
            getWindowManager().lockNow(bundle);
                        }
                    };

            getActivityTaskManagerInternal().registerScreenObserver(screenObserver);
            getWindowManager().lockDeviceNow();
            try {
                if (!latch.await(20, TimeUnit.SECONDS)) {
                    throw new RuntimeException("User controller expected a callback while waiting "
                            + "to show the keyguard. Timed out after 20 seconds.");
                    throw new RuntimeException("Keyguard is not shown in 20 seconds");
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                getActivityTaskManagerInternal().unregisterScreenObserver(screenObserver);
                t.traceEnd();
            }
        }
+13 −6
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
import static android.app.ActivityManagerInternal.ALLOW_PROFILES_OR_NON_FULL;
import static android.app.KeyguardManager.LOCK_ON_USER_SWITCH_CALLBACK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;

@@ -116,6 +115,7 @@ import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerService;
import com.android.server.pm.UserTypeDetails;
import com.android.server.pm.UserTypeFactory;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerService;

import com.google.common.collect.Range;
@@ -1563,11 +1563,11 @@ public class UserControllerTest {
        // and the thread is still alive
        assertTrue(threadStartUser.isAlive());

        // mock the binder response for the user switch completion
        ArgumentCaptor<Bundle> captor = ArgumentCaptor.forClass(Bundle.class);
        verify(mInjector.mWindowManagerMock).lockNow(captor.capture());
        IRemoteCallback.Stub.asInterface(captor.getValue().getBinder(
                LOCK_ON_USER_SWITCH_CALLBACK)).sendResult(null);
        // mock send the keyguard shown event
        ArgumentCaptor<ActivityTaskManagerInternal.ScreenObserver> captor = ArgumentCaptor.forClass(
                ActivityTaskManagerInternal.ScreenObserver.class);
        verify(mInjector.mActivityTaskManagerInternal).registerScreenObserver(captor.capture());
        captor.getValue().onKeyguardStateChanged(true);

        // verify the switch now moves on...
        Thread.sleep(1000);
@@ -1757,6 +1757,7 @@ public class UserControllerTest {
        private final IStorageManager mStorageManagerMock;
        private final UserManagerInternal mUserManagerInternalMock;
        private final WindowManagerService mWindowManagerMock;
        private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
        private final PowerManagerInternal mPowerManagerInternal;
        private final AlarmManagerInternal mAlarmManagerInternal;
        private final KeyguardManager mKeyguardManagerMock;
@@ -1778,6 +1779,7 @@ public class UserControllerTest {
            mUserManagerMock = mock(UserManagerService.class);
            mUserManagerInternalMock = mock(UserManagerInternal.class);
            mWindowManagerMock = mock(WindowManagerService.class);
            mActivityTaskManagerInternal = mock(ActivityTaskManagerInternal.class);
            mStorageManagerMock = mock(IStorageManager.class);
            mPowerManagerInternal = mock(PowerManagerInternal.class);
            mAlarmManagerInternal = mock(AlarmManagerInternal.class);
@@ -1840,6 +1842,11 @@ public class UserControllerTest {
            return mWindowManagerMock;
        }

        @Override
        ActivityTaskManagerInternal getActivityTaskManagerInternal() {
            return mActivityTaskManagerInternal;
        }

        @Override
        PowerManagerInternal getPowerManagerInternal() {
            return mPowerManagerInternal;