diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 66aa828ef8c3b..8b406c141fac9 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3529,6 +3529,12 @@ false + + false + Remove guest + + Reset guest Guest diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 7d5144f9cc570..24acba5a3adff 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1148,12 +1148,18 @@ Remove guest? + + Reset guest? + All apps and data in this session will be deleted. Remove + + Reset + Welcome back, guest! diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java index 95c68255db837..1d355f22edd5e 100644 --- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java +++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java @@ -16,7 +16,6 @@ package com.android.systemui; -import android.app.ActivityManager; import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.Context; @@ -24,11 +23,8 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.UserInfo; -import android.os.RemoteException; import android.os.UserHandle; -import android.os.UserManager; import android.util.Log; -import android.view.WindowManagerGlobal; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.UiEventLogger; @@ -36,6 +32,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.qs.QSUserSwitcherEvent; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.phone.SystemUIDialog; +import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.util.settings.SecureSettings; /** @@ -51,11 +48,14 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver { @VisibleForTesting public AlertDialog mNewSessionDialog; private final UserTracker mUserTracker; + private final UserSwitcherController mUserSwitcherController; private final UiEventLogger mUiEventLogger; private final SecureSettings mSecureSettings; - public GuestResumeSessionReceiver(UserTracker userTracker, UiEventLogger uiEventLogger, + public GuestResumeSessionReceiver(UserSwitcherController userSwitcherController, + UserTracker userTracker, UiEventLogger uiEventLogger, SecureSettings secureSettings) { + mUserSwitcherController = userSwitcherController; mUserTracker = userTracker; mUiEventLogger = uiEventLogger; mSecureSettings = secureSettings; @@ -92,8 +92,8 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver { int notFirstLogin = mSecureSettings.getIntForUser( SETTING_GUEST_HAS_LOGGED_IN, 0, userId); if (notFirstLogin != 0) { - mNewSessionDialog = new ResetSessionDialog(context, mUserTracker, mUiEventLogger, - userId); + mNewSessionDialog = new ResetSessionDialog(context, mUserSwitcherController, + mUserTracker, mUiEventLogger, userId); mNewSessionDialog.show(); } else { mSecureSettings.putIntForUser(SETTING_GUEST_HAS_LOGGED_IN, 1, userId); @@ -101,48 +101,6 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver { } } - /** - * Wipes the guest session. - * - * The guest must be the current user and its id must be {@param userId}. - */ - private static void wipeGuestSession(Context context, UserTracker userTracker, int userId) { - UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); - UserInfo currentUser = userTracker.getUserInfo(); - if (currentUser.id != userId) { - Log.w(TAG, "User requesting to start a new session (" + userId + ")" - + " is not current user (" + currentUser.id + ")"); - return; - } - if (!currentUser.isGuest()) { - Log.w(TAG, "User requesting to start a new session (" + userId + ")" - + " is not a guest"); - return; - } - - boolean marked = userManager.markGuestForDeletion(currentUser.id); - if (!marked) { - Log.w(TAG, "Couldn't mark the guest for deletion for user " + userId); - return; - } - UserInfo newGuest = userManager.createGuest(context, currentUser.name); - - try { - if (newGuest == null) { - Log.e(TAG, "Could not create new guest, switching back to system user"); - ActivityManager.getService().switchUser(UserHandle.USER_SYSTEM); - userManager.removeUser(currentUser.id); - WindowManagerGlobal.getWindowManagerService().lockNow(null /* options */); - return; - } - ActivityManager.getService().switchUser(newGuest.id); - userManager.removeUser(currentUser.id); - } catch (RemoteException e) { - Log.e(TAG, "Couldn't wipe session because ActivityManager or WindowManager is dead"); - return; - } - } - private void cancelDialog() { if (mNewSessionDialog != null && mNewSessionDialog.isShowing()) { mNewSessionDialog.cancel(); @@ -162,11 +120,14 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver { @VisibleForTesting public static final int BUTTON_DONTWIPE = BUTTON_POSITIVE; - private final UserTracker mUserTracker; + private final UserSwitcherController mUserSwitcherController; private final UiEventLogger mUiEventLogger; private final int mUserId; - ResetSessionDialog(Context context, UserTracker userTracker, UiEventLogger uiEventLogger, + ResetSessionDialog(Context context, + UserSwitcherController userSwitcherController, + UserTracker userTracker, + UiEventLogger uiEventLogger, int userId) { super(context); @@ -179,7 +140,7 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver { setButton(BUTTON_DONTWIPE, context.getString(R.string.guest_wipe_session_dontwipe), this); - mUserTracker = userTracker; + mUserSwitcherController = userSwitcherController; mUiEventLogger = uiEventLogger; mUserId = userId; } @@ -188,7 +149,7 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver { public void onClick(DialogInterface dialog, int which) { if (which == BUTTON_WIPE) { mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_WIPE); - wipeGuestSession(getContext(), mUserTracker, mUserId); + mUserSwitcherController.removeGuestUser(mUserId, UserHandle.USER_NULL); dismiss(); } else if (which == BUTTON_DONTWIPE) { mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_CONTINUE); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 327698392ac73..88e9f69620ed0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -119,6 +119,7 @@ import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.util.DeviceConfigProxy; import java.io.FileDescriptor; @@ -257,6 +258,9 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, /** TrustManager for letting it know when we change visibility */ private final TrustManager mTrustManager; + /** UserSwitcherController for creating guest user on boot complete */ + private final UserSwitcherController mUserSwitcherController; + /** * Used to keep the device awake while to ensure the keyguard finishes opening before * we sleep. @@ -805,6 +809,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, KeyguardUpdateMonitor keyguardUpdateMonitor, DumpManager dumpManager, @UiBackground Executor uiBgExecutor, PowerManager powerManager, TrustManager trustManager, + UserSwitcherController userSwitcherController, DeviceConfigProxy deviceConfig, NavigationModeController navigationModeController, KeyguardDisplayManager keyguardDisplayManager, @@ -825,6 +830,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, mUpdateMonitor = keyguardUpdateMonitor; mPM = powerManager; mTrustManager = trustManager; + mUserSwitcherController = userSwitcherController; mKeyguardDisplayManager = keyguardDisplayManager; dumpManager.registerDumpable(getClass().getName(), this); mDeviceConfig = deviceConfig; @@ -2558,6 +2564,11 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, @Override public void onBootCompleted() { synchronized (this) { + if (mContext.getResources().getBoolean( + com.android.internal.R.bool.config_guestUserAutoCreated)) { + // TODO(b/191067027): Move post-boot guest creation to system_server + mUserSwitcherController.guaranteeGuestPresent(); + } mBootCompleted = true; adjustStatusBarLocked(false, true); if (mBootSendUserPresent) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index 05d1361c3ab83..8a383b974d77b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -54,6 +54,7 @@ import com.android.systemui.statusbar.phone.KeyguardLiftController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.sensors.AsyncSensorManager; import com.android.systemui.util.settings.GlobalSettings; @@ -92,6 +93,7 @@ public class KeyguardModule { DumpManager dumpManager, PowerManager powerManager, TrustManager trustManager, + UserSwitcherController userSwitcherController, @UiBackground Executor uiBgExecutor, DeviceConfigProxy deviceConfig, NavigationModeController navigationModeController, @@ -114,6 +116,7 @@ public class KeyguardModule { uiBgExecutor, powerManager, trustManager, + userSwitcherController, deviceConfig, navigationModeController, keyguardDisplayManager, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index e2129bdc9a057..fae4423a4277b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -21,6 +21,7 @@ import static android.os.UserManager.SWITCHABILITY_STATUS_OK; import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import static com.android.systemui.DejankUtils.whitelistIpcs; +import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AlertDialog; import android.app.Dialog; @@ -49,6 +50,7 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManagerGlobal; import android.widget.BaseAdapter; import com.android.internal.annotations.VisibleForTesting; @@ -64,6 +66,7 @@ import com.android.systemui.SystemUISecondaryUserService; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.qs.QSUserSwitcherEvent; @@ -79,6 +82,8 @@ import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; import javax.inject.Inject; import javax.inject.Provider; @@ -125,21 +130,31 @@ public class UserSwitcherController implements Dumpable { // When false, there won't be any visual affordance to add a new user from the keyguard even if // the user is unlocked private boolean mAddUsersFromLockScreen; - private boolean mPauseRefreshUsers; + @VisibleForTesting + boolean mPauseRefreshUsers; private int mSecondaryUser = UserHandle.USER_NULL; private Intent mSecondaryUserServiceIntent; private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2); private final UiEventLogger mUiEventLogger; public final DetailAdapter mUserDetailAdapter; + private final Executor mUiBgExecutor; + private final boolean mGuestUserAutoCreated; + private final AtomicBoolean mGuestCreationScheduled; @Inject - public UserSwitcherController(Context context, UserManager userManager, UserTracker userTracker, + public UserSwitcherController(Context context, + UserManager userManager, + UserTracker userTracker, KeyguardStateController keyguardStateController, - @Main Handler handler, ActivityStarter activityStarter, - BroadcastDispatcher broadcastDispatcher, UiEventLogger uiEventLogger, + @Main Handler handler, + ActivityStarter activityStarter, + BroadcastDispatcher broadcastDispatcher, + UiEventLogger uiEventLogger, TelephonyListenerManager telephonyListenerManager, - IActivityTaskManager activityTaskManager, UserDetailAdapter userDetailAdapter, - SecureSettings secureSettings) { + IActivityTaskManager activityTaskManager, + UserDetailAdapter userDetailAdapter, + SecureSettings secureSettings, + @UiBackground Executor uiBgExecutor) { mContext = context; mUserTracker = userTracker; mBroadcastDispatcher = broadcastDispatcher; @@ -147,11 +162,15 @@ public class UserSwitcherController implements Dumpable { mActivityTaskManager = activityTaskManager; mUiEventLogger = uiEventLogger; mGuestResumeSessionReceiver = new GuestResumeSessionReceiver( - mUserTracker, mUiEventLogger, secureSettings); + this, mUserTracker, mUiEventLogger, secureSettings); mUserDetailAdapter = userDetailAdapter; + mUiBgExecutor = uiBgExecutor; if (!UserManager.isGuestUserEphemeral()) { mGuestResumeSessionReceiver.register(mBroadcastDispatcher); } + mGuestUserAutoCreated = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_guestUserAutoCreated); + mGuestCreationScheduled = new AtomicBoolean(); mKeyguardStateController = keyguardStateController; mHandler = handler; mActivityStarter = activityStarter; @@ -400,21 +419,13 @@ public class UserSwitcherController implements Dumpable { int id; if (record.isGuest && record.info == null) { // No guest user. Create one. - UserInfo guest; - try { - guest = mUserManager.createGuest(mContext, - mContext.getString(com.android.settingslib.R.string.guest_nickname)); - } catch (UserManager.UserOperationException e) { - Log.e(TAG, "Couldn't create guest user", e); - return; - } - if (guest == null) { - // Couldn't create guest, most likely because there already exists one, we just - // haven't reloaded the user list yet. + int guestId = createGuest(); + if (guestId == UserHandle.USER_NULL) { + // This may happen if we haven't reloaded the user list yet. return; } mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_ADD); - id = guest.id; + id = guestId; } else if (record.isAddUser) { showAddUserDialog(); return; @@ -478,11 +489,6 @@ public class UserSwitcherController implements Dumpable { mAddUserDialog.show(); } - protected void exitGuest(int id, int targetId) { - switchToUserId(targetId); - mUserManager.removeUser(id); - } - private void listenForCallState() { mTelephonyListenerManager.addCallStateListener(mPhoneStateListener); } @@ -588,6 +594,7 @@ public class UserSwitcherController implements Dumpable { pw.print(" "); pw.println(u.toString()); } pw.println("mSimpleUserSwitcher=" + mSimpleUserSwitcher); + pw.println("mGuestUserAutoCreated=" + mGuestUserAutoCreated); } /** Returns the name of the current user of the phone. */ @@ -614,6 +621,120 @@ public class UserSwitcherController implements Dumpable { return mUsers; } + /** + * Removes guest user and switches to target user. The guest must be the current user and its id + * must be {@code guestUserId}. + * + *

If {@code targetUserId} is {@link UserHandle.USER_NULL}, then create a new guest user in + * the foreground, and immediately switch to it. This is used for wiping the current guest and + * replacing it with a new one. + * + *

If {@code targetUserId} is specified, then remove the guest in the background while + * switching to {@code targetUserId}. + * + *

If device is configured with {@link + * com.android.internal.R.bool.config_guestUserAutoCreated}, then after guest user is removed, a + * new one is created in the background. This has no effect if {@code targetUserId} is {@link + * UserHandle.USER_NULL}. + * + * @param guestUserId id of the guest user to remove + * @param targetUserId id of the user to switch to after guest is removed. If {@link + * UserHandle.USER_NULL}, then switch immediately to the newly created guest user. + */ + public void removeGuestUser(@UserIdInt int guestUserId, @UserIdInt int targetUserId) { + UserInfo currentUser = mUserTracker.getUserInfo(); + if (currentUser.id != guestUserId) { + Log.w(TAG, "User requesting to start a new session (" + guestUserId + ")" + + " is not current user (" + currentUser.id + ")"); + return; + } + if (!currentUser.isGuest()) { + Log.w(TAG, "User requesting to start a new session (" + guestUserId + ")" + + " is not a guest"); + return; + } + + boolean marked = mUserManager.markGuestForDeletion(currentUser.id); + if (!marked) { + Log.w(TAG, "Couldn't mark the guest for deletion for user " + guestUserId); + return; + } + + try { + if (targetUserId == UserHandle.USER_NULL) { + // Create a new guest in the foreground, and then immediately switch to it + int newGuestId = createGuest(); + if (newGuestId == UserHandle.USER_NULL) { + Log.e(TAG, "Could not create new guest, switching back to system user"); + switchToUserId(UserHandle.USER_SYSTEM); + mUserManager.removeUser(currentUser.id); + WindowManagerGlobal.getWindowManagerService().lockNow(/* options= */ null); + return; + } + switchToUserId(newGuestId); + mUserManager.removeUser(currentUser.id); + } else { + if (mGuestUserAutoCreated) { + // TODO(b/191067027): Move guest recreation to system_server + scheduleGuestCreation(); + } + switchToUserId(targetUserId); + } + } catch (RemoteException e) { + Log.e(TAG, "Couldn't remove guest because ActivityManager or WindowManager is dead"); + return; + } + } + + private void scheduleGuestCreation() { + if (!mGuestCreationScheduled.compareAndSet(false, true)) { + return; + } + + mUiBgExecutor.execute(() -> { + int newGuestId = createGuest(); + if (newGuestId == UserHandle.USER_NULL) { + Log.w(TAG, "Could not create new guest while exiting existing guest"); + } + mGuestCreationScheduled.set(false); + }); + + } + + /** + * If there is no guest on the device, schedule creation of a new guest user in the background. + */ + public void guaranteeGuestPresent() { + if (mUserManager.findCurrentGuestUser() == null) { + scheduleGuestCreation(); + } + } + + /** + * Creates a guest user and return its multi-user user ID. + * + * This method does not check if a guest already exists before it makes a call to + * {@link UserManager} to create a new one. + * + * @return The multi-user user ID of the newly created guest user, or + * {@link UserHandle.USER_NULL} if the guest couldn't be created. + */ + public @UserIdInt int createGuest() { + UserInfo guest; + try { + guest = mUserManager.createGuest(mContext, + mContext.getString(com.android.settingslib.R.string.guest_nickname)); + } catch (UserManager.UserOperationException e) { + Log.e(TAG, "Couldn't create guest user", e); + return UserHandle.USER_NULL; + } + if (guest == null) { + Log.e(TAG, "Couldn't create guest, most likely because there already exists one"); + return UserHandle.USER_NULL; + } + return guest.id; + } + public static abstract class BaseUserAdapter extends BaseAdapter { final UserSwitcherController mController; @@ -674,10 +795,15 @@ public class UserSwitcherController implements Dumpable { public String getName(Context context, UserRecord item) { if (item.isGuest) { if (item.isCurrent) { - return context.getString(com.android.settingslib.R.string.guest_exit_guest); + return context.getString(mController.mGuestUserAutoCreated + ? com.android.settingslib.R.string.guest_reset_guest + : com.android.settingslib.R.string.guest_exit_guest); } else { + // If config_guestUserAutoCreated, always show guest nickname instead of "Add + // guest" to make it seem as though the device always has a guest ready for use return context.getString( - item.info == null ? com.android.settingslib.R.string.guest_new_guest + item.info == null && !mController.mGuestUserAutoCreated + ? com.android.settingslib.R.string.guest_new_guest : com.android.settingslib.R.string.guest_nickname); } } else if (item.isAddUser) { @@ -894,12 +1020,15 @@ public class UserSwitcherController implements Dumpable { public ExitGuestDialog(Context context, int guestId, int targetId) { super(context); - setTitle(R.string.guest_exit_guest_dialog_title); + setTitle(mGuestUserAutoCreated ? R.string.guest_reset_guest_dialog_title + : R.string.guest_exit_guest_dialog_title); setMessage(context.getString(R.string.guest_exit_guest_dialog_message)); setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(android.R.string.cancel), this); setButton(DialogInterface.BUTTON_POSITIVE, - context.getString(R.string.guest_exit_guest_dialog_remove), this); + context.getString( + mGuestUserAutoCreated ? R.string.guest_reset_guest_dialog_remove + : R.string.guest_exit_guest_dialog_remove), this); SystemUIDialog.setWindowOnTop(this); setCanceledOnTouchOutside(false); mGuestId = guestId; @@ -913,7 +1042,7 @@ public class UserSwitcherController implements Dumpable { } else { mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE); dismiss(); - exitGuest(mGuestId, mTargetId); + removeGuestUser(mGuestId, mTargetId); } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index d9b56a49f12a8..1dacc6245d841 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -52,6 +52,7 @@ import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.DeviceConfigProxyFake; import com.android.systemui.util.concurrency.FakeExecutor; @@ -78,6 +79,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock DumpManager mDumpManager; private @Mock PowerManager mPowerManager; private @Mock TrustManager mTrustManager; + private @Mock UserSwitcherController mUserSwitcherController; private @Mock NavigationModeController mNavigationModeController; private @Mock KeyguardDisplayManager mKeyguardDisplayManager; private @Mock DozeParameters mDozeParameters; @@ -100,13 +102,27 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { when(mPowerManager.newWakeLock(anyInt(), any())).thenReturn(mock(WakeLock.class)); mViewMediator = new KeyguardViewMediator( - mContext, mFalsingCollector, mLockPatternUtils, mBroadcastDispatcher, + mContext, + mFalsingCollector, + mLockPatternUtils, + mBroadcastDispatcher, () -> mStatusBarKeyguardViewManager, - mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor, - mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController, - mKeyguardDisplayManager, mDozeParameters, mStatusBarStateController, - mKeyguardStateController, () -> mKeyguardUnlockAnimationController, - mUnlockedScreenOffAnimationController, () -> mNotificationShadeDepthController); + mDismissCallbackRegistry, + mUpdateMonitor, + mDumpManager, + mUiBgExecutor, + mPowerManager, + mTrustManager, + mUserSwitcherController, + mDeviceConfig, + mNavigationModeController, + mKeyguardDisplayManager, + mDozeParameters, + mStatusBarStateController, + mKeyguardStateController, + () -> mKeyguardUnlockAnimationController, + mUnlockedScreenOffAnimationController, + () -> mNotificationShadeDepthController); mViewMediator.start(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt index e0f395d494463..019bd8d6320e0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt @@ -25,6 +25,7 @@ import android.graphics.Bitmap import android.hardware.face.FaceManager import android.hardware.fingerprint.FingerprintManager import android.os.Handler +import android.os.UserHandle import android.os.UserManager import android.testing.AndroidTestingRunner import android.testing.TestableLooper @@ -39,7 +40,9 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.qs.QSUserSwitcherEvent import com.android.systemui.settings.UserTracker import com.android.systemui.telephony.TelephonyListenerManager +import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.settings.SecureSettings +import com.android.systemui.util.time.FakeSystemClock import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Before @@ -67,24 +70,37 @@ class UserSwitcherControllerTest : SysuiTestCase() { @Mock private lateinit var activityTaskManager: IActivityTaskManager @Mock private lateinit var userDetailAdapter: UserSwitcherController.UserDetailAdapter @Mock private lateinit var telephonyListenerManager: TelephonyListenerManager - @Mock private lateinit var userInfo: UserInfo @Mock private lateinit var secureSettings: SecureSettings private lateinit var testableLooper: TestableLooper - private lateinit var userSwitcherController: UserSwitcherController + private lateinit var uiBgExecutor: FakeExecutor private lateinit var uiEventLogger: UiEventLoggerFake + private lateinit var userSwitcherController: UserSwitcherController private lateinit var picture: Bitmap + private val ownerId = UserHandle.USER_SYSTEM + private val ownerInfo = UserInfo(ownerId, "Owner", null, + UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL or UserInfo.FLAG_INITIALIZED or + UserInfo.FLAG_PRIMARY or UserInfo.FLAG_SYSTEM, + UserManager.USER_TYPE_FULL_SYSTEM) private val guestId = 1234 + private val guestInfo = UserInfo(guestId, "Guest", null, + UserInfo.FLAG_FULL or UserInfo.FLAG_GUEST, UserManager.USER_TYPE_FULL_GUEST) @Before fun setUp() { MockitoAnnotations.initMocks(this) testableLooper = TestableLooper.get(this) + uiBgExecutor = FakeExecutor(FakeSystemClock()) uiEventLogger = UiEventLoggerFake() + context.orCreateTestableResources.addOverride( + com.android.internal.R.bool.config_guestUserAutoCreated, false) + mContext.addMockSystemService(Context.FACE_SERVICE, mock(FaceManager::class.java)) mContext.addMockSystemService(Context.FINGERPRINT_SERVICE, mock(FingerprintManager::class.java)) + `when`(userManager.canAddMoreUsers()).thenReturn(true) + userSwitcherController = UserSwitcherController(context, userManager, userTracker, @@ -96,7 +112,10 @@ class UserSwitcherControllerTest : SysuiTestCase() { telephonyListenerManager, activityTaskManager, userDetailAdapter, - secureSettings) + secureSettings, + uiBgExecutor) + userSwitcherController.mPauseRefreshUsers = true + picture = UserIcons.convertToBitmap(context.getDrawable(R.drawable.ic_avatar_user)) } @@ -110,8 +129,10 @@ class UserSwitcherControllerTest : SysuiTestCase() { false /* isAddUser */, false /* isRestricted */, true /* isSwitchToEnabled */) + `when`(userTracker.userId).thenReturn(ownerId) + `when`(userTracker.userInfo).thenReturn(ownerInfo) - `when`(userManager.createGuest(any(), anyString())).thenReturn(userInfo) + `when`(userManager.createGuest(any(), anyString())).thenReturn(guestInfo) userSwitcherController.onUserListItemClicked(emptyGuestUserRecord) testableLooper.processAllMessages() @@ -122,13 +143,15 @@ class UserSwitcherControllerTest : SysuiTestCase() { @Test fun testRemoveGuest_removeButtonPressed_isLogged() { val currentGuestUserRecord = UserSwitcherController.UserRecord( - userInfo, + guestInfo, picture, true /* guest */, true /* current */, false /* isAddUser */, false /* isRestricted */, true /* isSwitchToEnabled */) + `when`(userTracker.userId).thenReturn(guestInfo.id) + `when`(userTracker.userInfo).thenReturn(guestInfo) userSwitcherController.onUserListItemClicked(currentGuestUserRecord) assertNotNull(userSwitcherController.mExitGuestDialog) @@ -142,13 +165,15 @@ class UserSwitcherControllerTest : SysuiTestCase() { @Test fun testRemoveGuest_cancelButtonPressed_isNotLogged() { val currentGuestUserRecord = UserSwitcherController.UserRecord( - userInfo, + guestInfo, picture, true /* guest */, true /* current */, false /* isAddUser */, false /* isRestricted */, true /* isSwitchToEnabled */) + `when`(userTracker.userId).thenReturn(guestId) + `when`(userTracker.userInfo).thenReturn(guestInfo) userSwitcherController.onUserListItemClicked(currentGuestUserRecord) assertNotNull(userSwitcherController.mExitGuestDialog) @@ -160,7 +185,6 @@ class UserSwitcherControllerTest : SysuiTestCase() { @Test fun testWipeGuest_startOverButtonPressed_isLogged() { - val guestInfo = UserInfo(guestId, null, null, 0, UserManager.USER_TYPE_FULL_GUEST) val currentGuestUserRecord = UserSwitcherController.UserRecord( guestInfo, picture, @@ -169,6 +193,8 @@ class UserSwitcherControllerTest : SysuiTestCase() { false /* isAddUser */, false /* isRestricted */, true /* isSwitchToEnabled */) + `when`(userTracker.userId).thenReturn(guestId) + `when`(userTracker.userInfo).thenReturn(guestInfo) // Simulate that guest user has already logged in `when`(secureSettings.getIntForUser( @@ -179,7 +205,6 @@ class UserSwitcherControllerTest : SysuiTestCase() { // Simulate a user switch event val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, guestId) - `when`(userTracker.userInfo).thenReturn(guestInfo) assertNotNull(userSwitcherController.mGuestResumeSessionReceiver) userSwitcherController.mGuestResumeSessionReceiver.onReceive(context, intent) @@ -194,7 +219,6 @@ class UserSwitcherControllerTest : SysuiTestCase() { @Test fun testWipeGuest_continueButtonPressed_isLogged() { - val guestInfo = UserInfo(guestId, null, null, 0, UserManager.USER_TYPE_FULL_GUEST) val currentGuestUserRecord = UserSwitcherController.UserRecord( guestInfo, picture, @@ -203,6 +227,8 @@ class UserSwitcherControllerTest : SysuiTestCase() { false /* isAddUser */, false /* isRestricted */, true /* isSwitchToEnabled */) + `when`(userTracker.userId).thenReturn(guestId) + `when`(userTracker.userInfo).thenReturn(guestInfo) // Simulate that guest user has already logged in `when`(secureSettings.getIntForUser( @@ -213,7 +239,6 @@ class UserSwitcherControllerTest : SysuiTestCase() { // Simulate a user switch event val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, guestId) - `when`(userTracker.userInfo).thenReturn(guestInfo) assertNotNull(userSwitcherController.mGuestResumeSessionReceiver) userSwitcherController.mGuestResumeSessionReceiver.onReceive(context, intent)