From bb821889a84299c79878a54505283ef70bb8cf03 Mon Sep 17 00:00:00 2001 From: Aaron Liu Date: Tue, 11 Oct 2022 12:11:32 -0700 Subject: [PATCH] [Bouncer] Add manage users to bouncer. Add a manage users option to the user switcher for the Bouncer. This adds a isMangeUsers property to the UserRecord and makes some changes around that. If user is on bouncer while trying to go to manage users or add a child user, bouncer will show a message to indicate that user needs to unlock the device in order to proceed. Bug: 241811308 Test: Added a unit test and manual test. Manual test consists of testing with new userswitcher code flag on and off, testing non fullscreen user switcher, user switcher activity, and user switcher in the bouncer. In addition to testing the manage users. I've added the max number of users and tested add user and add child user. I also tested scenarios where we click on manage users and then exit bouncer. Change-Id: Ib20c32914fd95eb891676028b5b588009b9e50a6 --- .../SystemUI/res-keyguard/values/strings.xml | 2 + .../keyguard/KeyguardSecurityContainer.java | 53 ++++++----- .../KeyguardSecurityContainerController.java | 4 +- .../policy/BaseUserSwitcherAdapter.kt | 5 +- .../KeyguardUserSwitcherController.java | 3 +- .../policy/UserSwitcherControllerImpl.kt | 2 +- .../policy/UserSwitcherControllerOldImpl.java | 23 ++++- .../systemui/user/data/source/UserRecord.kt | 3 + .../user/domain/interactor/UserActionsUtil.kt | 9 ++ .../user/domain/interactor/UserInteractor.kt | 68 ++++++++------ .../legacyhelper/data/LegacyUserDataHelper.kt | 2 + .../legacyhelper/ui/LegacyUserUiHelper.kt | 8 +- .../ui/viewmodel/UserSwitcherViewModel.kt | 47 ++++------ ...yguardSecurityContainerControllerTest.java | 42 +++++++-- .../KeyguardSecurityContainerTest.java | 16 ++-- .../UserSwitcherControllerOldImplTest.kt | 94 ++++++++++++++++++- .../UserInteractorRefactoredTest.kt | 20 +++- 17 files changed, 285 insertions(+), 116 deletions(-) diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml index d90156d451c78..8135aaa6faeab 100644 --- a/packages/SystemUI/res-keyguard/values/strings.xml +++ b/packages/SystemUI/res-keyguard/values/strings.xml @@ -241,4 +241,6 @@ Bubble Analog + + Unlock your device to continue diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index c34db1532d6c9..93ee151f26c58 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -67,7 +67,6 @@ import android.view.ViewGroup; import android.view.WindowInsets; import android.view.WindowInsetsAnimation; import android.view.WindowManager; -import android.widget.AdapterView; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @@ -318,7 +317,8 @@ public class KeyguardSecurityContainer extends ConstraintLayout { } void initMode(@Mode int mode, GlobalSettings globalSettings, FalsingManager falsingManager, - UserSwitcherController userSwitcherController) { + UserSwitcherController userSwitcherController, + UserSwitcherViewMode.UserSwitcherCallback userSwitcherCallback) { if (mCurrentMode == mode) return; Log.i(TAG, "Switching mode from " + modeToString(mCurrentMode) + " to " + modeToString(mode)); @@ -330,7 +330,7 @@ public class KeyguardSecurityContainer extends ConstraintLayout { mViewMode = new OneHandedViewMode(); break; case MODE_USER_SWITCHER: - mViewMode = new UserSwitcherViewMode(); + mViewMode = new UserSwitcherViewMode(userSwitcherCallback); break; default: mViewMode = new DefaultViewMode(); @@ -864,6 +864,12 @@ public class KeyguardSecurityContainer extends ConstraintLayout { private UserSwitcherController.UserSwitchCallback mUserSwitchCallback = this::setupUserSwitcher; + private UserSwitcherCallback mUserSwitcherCallback; + + UserSwitcherViewMode(UserSwitcherCallback userSwitcherCallback) { + mUserSwitcherCallback = userSwitcherCallback; + } + @Override public void init(@NonNull ConstraintLayout v, @NonNull GlobalSettings globalSettings, @NonNull KeyguardSecurityViewFlipper viewFlipper, @@ -1040,34 +1046,25 @@ public class KeyguardSecurityContainer extends ConstraintLayout { } }; - if (adapter.getCount() < 2) { - // The drop down arrow is at index 1 - ((LayerDrawable) mUserSwitcher.getBackground()).getDrawable(1).setAlpha(0); - anchor.setClickable(false); - return; - } else { - ((LayerDrawable) mUserSwitcher.getBackground()).getDrawable(1).setAlpha(255); - } - anchor.setOnClickListener((v) -> { if (mFalsingManager.isFalseTap(LOW_PENALTY)) return; mPopup = new KeyguardUserSwitcherPopupMenu(v.getContext(), mFalsingManager); mPopup.setAnchorView(anchor); mPopup.setAdapter(adapter); - mPopup.setOnItemClickListener(new AdapterView.OnItemClickListener() { - public void onItemClick(AdapterView parent, View view, int pos, long id) { - if (mFalsingManager.isFalseTap(LOW_PENALTY)) return; - if (!view.isEnabled()) return; - - // Subtract one for the header - UserRecord user = adapter.getItem(pos - 1); - if (!user.isCurrent) { - adapter.onUserListItemClicked(user); - } - mPopup.dismiss(); - mPopup = null; - } - }); + mPopup.setOnItemClickListener((parent, view, pos, id) -> { + if (mFalsingManager.isFalseTap(LOW_PENALTY)) return; + if (!view.isEnabled()) return; + // Subtract one for the header + UserRecord user = adapter.getItem(pos - 1); + if (user.isManageUsers || user.isAddSupervisedUser) { + mUserSwitcherCallback.showUnlockToContinueMessage(); + } + if (!user.isCurrent) { + adapter.onUserListItemClicked(user); + } + mPopup.dismiss(); + mPopup = null; + }); mPopup.show(); }); } @@ -1122,6 +1119,10 @@ public class KeyguardSecurityContainer extends ConstraintLayout { constraintSet.applyTo(mView); } } + + interface UserSwitcherCallback { + void showUnlockToContinueMessage(); + } } /** diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index d448f40ed5290..bcd1a1ee26960 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -620,7 +620,9 @@ public class KeyguardSecurityContainerController extends ViewController showMessage(getContext().getString(R.string.keyguard_unlock_to_continue), + null)); } public void reportFailedUnlockAttempt(int userId, int timeoutMs) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt index 5b2d69564585b..2f0ebf752a232 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt @@ -35,8 +35,8 @@ protected constructor( protected val controller: UserSwitcherController, ) : BaseAdapter() { - protected open val users: ArrayList - get() = controller.users + protected open val users: List + get() = controller.users.filter { !controller.isKeyguardShowing || !it.isRestricted } init { controller.addAdapter(WeakReference(this)) @@ -112,6 +112,7 @@ protected constructor( item.isGuest, item.isAddSupervisedUser, isTablet, + item.isManageUsers, ) return checkNotNull(context.getDrawable(iconRes)) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java index 494a4bbbdf9fb..c1506541229d1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java @@ -53,6 +53,7 @@ import com.android.systemui.user.data.source.UserRecord; import com.android.systemui.util.ViewController; import java.util.ArrayList; +import java.util.List; import javax.inject.Inject; @@ -456,7 +457,7 @@ public class KeyguardUserSwitcherController extends ViewController users = super.getUsers(); + List users = super.getUsers(); mUsersOrdered = new ArrayList<>(users.size()); for (int i = 0; i < users.size(); i++) { UserRecord record = users.get(i); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerImpl.kt index af39eeed26b06..935fc7f10198d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerImpl.kt @@ -249,7 +249,7 @@ constructor( override fun startActivity(intent: Intent) { if (useInteractor) { - activityStarter.startActivity(intent, /* dismissShade= */ false) + activityStarter.startActivity(intent, /* dismissShade= */ true) } else { _oldImpl.startActivity(intent) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImpl.java index 46d2f3ac9ce4f..c294c370a6011 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImpl.java @@ -49,6 +49,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.UiEventLogger; import com.android.internal.util.LatencyTracker; +import com.android.keyguard.KeyguardUpdateMonitor; import com.android.settingslib.users.UserCreatingDialog; import com.android.systemui.GuestResetOrExitSessionReceiver; import com.android.systemui.GuestResumeSessionReceiver; @@ -399,6 +400,16 @@ public class UserSwitcherControllerOldImpl implements UserSwitcherController { records.add(userRecord); } + if (canManageUsers()) { + records.add(LegacyUserDataHelper.createRecord( + mContext, + KeyguardUpdateMonitor.getCurrentUser(), + UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, + /* isRestricted= */ false, + /* isSwitchToEnabled= */ true + )); + } + mUiExecutor.execute(() -> { if (records != null) { mUsers = records; @@ -438,6 +449,14 @@ public class UserSwitcherControllerOldImpl implements UserSwitcherController { && mUserManager.canAddMoreUsers(UserManager.USER_TYPE_FULL_SECONDARY); } + @VisibleForTesting + boolean canManageUsers() { + UserInfo currentUser = mUserTracker.getUserInfo(); + return mUserSwitcherEnabled + && ((currentUser != null && currentUser.isAdmin()) + || mAddUsersFromLockScreen.getValue()); + } + private boolean createIsRestricted() { return !mAddUsersFromLockScreen.getValue(); } @@ -525,6 +544,8 @@ public class UserSwitcherControllerOldImpl implements UserSwitcherController { showAddUserDialog(dialogShower); } else if (record.isAddSupervisedUser) { startSupervisedUserActivity(); + } else if (record.isManageUsers) { + startActivity(new Intent(Settings.ACTION_USER_SETTINGS)); } else { onUserListItemClicked(record.info.id, record, dialogShower); } @@ -984,7 +1005,7 @@ public class UserSwitcherControllerOldImpl implements UserSwitcherController { @Override public void startActivity(Intent intent) { - mActivityStarter.startActivity(intent, true); + mActivityStarter.startActivity(intent, /* dismissShade= */ true); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt b/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt index 9370286d7ee7b..d4fb5634bd1d8 100644 --- a/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt +++ b/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt @@ -47,6 +47,9 @@ data class UserRecord( * If not disabled, this is `null`. */ @JvmField val enforcedAdmin: RestrictedLockUtils.EnforcedAdmin? = null, + + /** Whether this record is to go to the Settings page to manage users. */ + @JvmField val isManageUsers: Boolean = false ) { /** Returns a new instance of [UserRecord] with its [isCurrent] set to the given value. */ fun copyWithIsCurrent(isCurrent: Boolean): UserRecord { diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt index 1b4746a99f8fe..dc004f3603a0b 100644 --- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt +++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt @@ -82,6 +82,15 @@ object UserActionsUtil { ) } + fun canManageUsers( + repository: UserRepository, + isUserSwitcherEnabled: Boolean, + isAddUsersFromLockScreenEnabled: Boolean, + ): Boolean { + return isUserSwitcherEnabled && + (repository.getSelectedUserInfo().isAdmin || isAddUsersFromLockScreenEnabled) + } + /** * Returns `true` if the current user is allowed to add users to the device; `false` otherwise. */ diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt index 142a328b2bc4c..ba5a82a42d943 100644 --- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt @@ -102,6 +102,7 @@ constructor( interface UserCallback { /** Returns `true` if this callback can be cleaned-up. */ fun isEvictable(): Boolean = false + /** Notifies that the state of users on the device has changed. */ fun onUserStateChanged() } @@ -164,10 +165,11 @@ constructor( get() = if (isNewImpl) { combine( + repository.selectedUserInfo, repository.userInfos, repository.userSwitcherSettings, keyguardInteractor.isKeyguardShowing, - ) { userInfos, settings, isDeviceLocked -> + ) { _, userInfos, settings, isDeviceLocked -> buildList { val hasGuestUser = userInfos.any { it.isGuest } if ( @@ -183,35 +185,45 @@ constructor( add(UserActionModel.ENTER_GUEST_MODE) } - if (isDeviceLocked && !settings.isAddUsersFromLockscreen) { + if (!isDeviceLocked || settings.isAddUsersFromLockscreen) { // The device is locked and our setting to allow actions that add users // from the lock-screen is not enabled. The guest action from above is // always allowed, even when the device is locked, but the various "add // user" actions below are not. We can finish building the list here. - return@buildList + + val canCreateUsers = + UserActionsUtil.canCreateUser( + manager, + repository, + settings.isUserSwitcherEnabled, + settings.isAddUsersFromLockscreen, + ) + + if (canCreateUsers) { + add(UserActionModel.ADD_USER) + } + + if ( + UserActionsUtil.canCreateSupervisedUser( + manager, + repository, + settings.isUserSwitcherEnabled, + settings.isAddUsersFromLockscreen, + supervisedUserPackageName, + ) + ) { + add(UserActionModel.ADD_SUPERVISED_USER) + } } if ( - UserActionsUtil.canCreateUser( - manager, + UserActionsUtil.canManageUsers( repository, settings.isUserSwitcherEnabled, settings.isAddUsersFromLockscreen, ) ) { - add(UserActionModel.ADD_USER) - } - - if ( - UserActionsUtil.canCreateSupervisedUser( - manager, - repository, - settings.isUserSwitcherEnabled, - settings.isAddUsersFromLockscreen, - supervisedUserPackageName, - ) - ) { - add(UserActionModel.ADD_SUPERVISED_USER) + add(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) } } } @@ -264,7 +276,10 @@ constructor( toRecord( action = it, selectedUserId = selectedUserInfo.id, - isAddFromLockscreenEnabled = settings.isAddUsersFromLockscreen, + isRestricted = + it != UserActionModel.ENTER_GUEST_MODE && + it != UserActionModel.NAVIGATE_TO_USER_MANAGEMENT && + !settings.isAddUsersFromLockscreen, ) } ) @@ -482,12 +497,12 @@ constructor( .setAction(UserManager.ACTION_CREATE_SUPERVISED_USER) .setPackage(supervisedUserPackageName) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), - /* dismissShade= */ false, + /* dismissShade= */ true, ) UserActionModel.NAVIGATE_TO_USER_MANAGEMENT -> activityStarter.startActivity( Intent(Settings.ACTION_USER_SETTINGS), - /* dismissShade= */ false, + /* dismissShade= */ true, ) } } else { @@ -575,20 +590,13 @@ constructor( private suspend fun toRecord( action: UserActionModel, selectedUserId: Int, - isAddFromLockscreenEnabled: Boolean, + isRestricted: Boolean, ): UserRecord { return LegacyUserDataHelper.createRecord( context = applicationContext, selectedUserId = selectedUserId, actionType = action, - isRestricted = - if (action == UserActionModel.ENTER_GUEST_MODE) { - // Entering guest mode is never restricted, so it's allowed to happen from the - // lockscreen even if the "add from lockscreen" system setting is off. - false - } else { - !isAddFromLockscreenEnabled - }, + isRestricted = isRestricted, isSwitchToEnabled = canSwitchUsers(selectedUserId) && // If the user is auto-created is must not be currently resetting. diff --git a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/data/LegacyUserDataHelper.kt b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/data/LegacyUserDataHelper.kt index 137de1544b2d4..03a7470a3fe60 100644 --- a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/data/LegacyUserDataHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/data/LegacyUserDataHelper.kt @@ -80,6 +80,7 @@ object LegacyUserDataHelper { context = context, selectedUserId = selectedUserId, ), + isManageUsers = actionType == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, ) } @@ -90,6 +91,7 @@ object LegacyUserDataHelper { record.isAddUser -> UserActionModel.ADD_USER record.isAddSupervisedUser -> UserActionModel.ADD_SUPERVISED_USER record.isGuest -> UserActionModel.ENTER_GUEST_MODE + record.isManageUsers -> UserActionModel.NAVIGATE_TO_USER_MANAGEMENT else -> error("Not a known action: $record") } } diff --git a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt index 12641a8f584dc..e74232df3ac36 100644 --- a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt @@ -39,6 +39,7 @@ object LegacyUserUiHelper { isGuest: Boolean, isAddSupervisedUser: Boolean, isTablet: Boolean = false, + isManageUsers: Boolean, ): Int { return if (isAddUser && isTablet) { R.drawable.ic_account_circle_filled @@ -48,6 +49,8 @@ object LegacyUserUiHelper { R.drawable.ic_account_circle } else if (isAddSupervisedUser) { R.drawable.ic_add_supervised_user + } else if (isManageUsers) { + R.drawable.ic_manage_users } else { R.drawable.ic_avatar_user } @@ -74,6 +77,7 @@ object LegacyUserUiHelper { isAddUser = record.isAddUser, isAddSupervisedUser = record.isAddSupervisedUser, isTablet = isTablet, + isManageUsers = record.isManageUsers, ) ) } @@ -103,8 +107,9 @@ object LegacyUserUiHelper { isAddUser: Boolean, isAddSupervisedUser: Boolean, isTablet: Boolean = false, + isManageUsers: Boolean, ): Int { - check(isGuest || isAddUser || isAddSupervisedUser) + check(isGuest || isAddUser || isAddSupervisedUser || isManageUsers) return when { isGuest && isGuestUserAutoCreated && isGuestUserResetting -> @@ -114,6 +119,7 @@ object LegacyUserUiHelper { isGuest -> com.android.internal.R.string.guest_name isAddUser -> com.android.settingslib.R.string.user_add_user isAddSupervisedUser -> R.string.add_user_supervised + isManageUsers -> R.string.manage_users else -> error("This should never happen!") } } diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt index 9c588532f34a0..219dae29117fe 100644 --- a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt @@ -19,8 +19,6 @@ package com.android.systemui.user.ui.viewmodel import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.android.systemui.R -import com.android.systemui.common.shared.model.Text import com.android.systemui.common.ui.drawable.CircularDrawable import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags @@ -162,12 +160,7 @@ private constructor( ): UserViewModel { return UserViewModel( viewKey = model.id, - name = - if (model.isGuest) { - Text.Resource(com.android.settingslib.R.string.guest_exit_quick_settings_button) - } else { - model.name - }, + name = model.name, image = CircularDrawable(model.image), isSelectionMarkerVisible = model.isSelected, alpha = @@ -186,29 +179,23 @@ private constructor( return UserActionViewModel( viewKey = model.ordinal.toLong(), iconResourceId = - if (model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) { - R.drawable.ic_manage_users - } else { - LegacyUserUiHelper.getUserSwitcherActionIconResourceId( - isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER, - isAddUser = model == UserActionModel.ADD_USER, - isGuest = model == UserActionModel.ENTER_GUEST_MODE, - isTablet = true, - ) - }, + LegacyUserUiHelper.getUserSwitcherActionIconResourceId( + isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER, + isAddUser = model == UserActionModel.ADD_USER, + isGuest = model == UserActionModel.ENTER_GUEST_MODE, + isManageUsers = model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, + isTablet = true, + ), textResourceId = - if (model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) { - R.string.manage_users - } else { - LegacyUserUiHelper.getUserSwitcherActionTextResourceId( - isGuest = model == UserActionModel.ENTER_GUEST_MODE, - isGuestUserAutoCreated = guestUserInteractor.isGuestUserAutoCreated, - isGuestUserResetting = guestUserInteractor.isGuestUserResetting, - isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER, - isAddUser = model == UserActionModel.ADD_USER, - isTablet = true, - ) - }, + LegacyUserUiHelper.getUserSwitcherActionTextResourceId( + isGuest = model == UserActionModel.ENTER_GUEST_MODE, + isGuestUserAutoCreated = guestUserInteractor.isGuestUserAutoCreated, + isGuestUserResetting = guestUserInteractor.isGuestUserResetting, + isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER, + isAddUser = model == UserActionModel.ADD_USER, + isManageUsers = model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, + isTablet = true, + ), onClicked = { userInteractor.executeAction(action = model) // We don't finish because we want to show a dialog over the full-screen UI and diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java index c6ebaa8bb46c8..48e82397e826a 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java @@ -221,15 +221,17 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { public void onResourcesUpdate_callsThroughOnRotationChange() { // Rotation is the same, shouldn't cause an update mKeyguardSecurityContainerController.updateResources(); - verify(mView, never()).initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager, - mUserSwitcherController); + verify(mView, never()).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager), + eq(mUserSwitcherController), + any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class)); // Update rotation. Should trigger update mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE; mKeyguardSecurityContainerController.updateResources(); - verify(mView).initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager, - mUserSwitcherController); + verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager), + eq(mUserSwitcherController), + any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class)); } private void touchDown() { @@ -263,8 +265,9 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern); - verify(mView).initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager, - mUserSwitcherController); + verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager), + eq(mUserSwitcherController), + any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class)); } @Test @@ -275,8 +278,9 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern); - verify(mView).initMode(MODE_ONE_HANDED, mGlobalSettings, mFalsingManager, - mUserSwitcherController); + verify(mView).initMode(eq(MODE_ONE_HANDED), eq(mGlobalSettings), eq(mFalsingManager), + eq(mUserSwitcherController), + any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class)); } @Test @@ -285,8 +289,26 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { setupGetSecurityView(); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password); - verify(mView).initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager, - mUserSwitcherController); + verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager), + eq(mUserSwitcherController), + any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class)); + } + + @Test + public void addUserSwitcherCallback() { + ArgumentCaptor + captor = ArgumentCaptor.forClass( + KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class); + + setupGetSecurityView(); + + mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password); + verify(mView).initMode(anyInt(), any(GlobalSettings.class), any(FalsingManager.class), + any(UserSwitcherController.class), + captor.capture()); + captor.getValue().showUnlockToContinueMessage(); + verify(mKeyguardPasswordViewControllerMock).showMessage( + getContext().getString(R.string.keyguard_unlock_to_continue), null); } @Test diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java index 52f8825c724bc..82d3ca7851616 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java @@ -119,7 +119,7 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { int systemBarInsetAmount = 0; mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager, - mUserSwitcherController); + mUserSwitcherController, () -> {}); Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount); Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount); @@ -141,7 +141,7 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { int systemBarInsetAmount = paddingBottom + 1; mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager, - mUserSwitcherController); + mUserSwitcherController, () -> {}); Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount); Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount); @@ -158,9 +158,10 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { @Test public void testDefaultViewMode() { mKeyguardSecurityContainer.initMode(MODE_ONE_HANDED, mGlobalSettings, mFalsingManager, - mUserSwitcherController); + mUserSwitcherController, () -> { + }); mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager, - mUserSwitcherController); + mUserSwitcherController, () -> {}); ConstraintSet.Constraint viewFlipperConstraint = getViewConstraint(mSecurityViewFlipper.getId()); assertThat(viewFlipperConstraint.layout.topToTop).isEqualTo(PARENT_ID); @@ -377,7 +378,7 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { private void setupUserSwitcher() { when(mGlobalSettings.getInt(any(), anyInt())).thenReturn(ONE_HANDED_KEYGUARD_SIDE_RIGHT); mKeyguardSecurityContainer.initMode(KeyguardSecurityContainer.MODE_USER_SWITCHER, - mGlobalSettings, mFalsingManager, mUserSwitcherController); + mGlobalSettings, mFalsingManager, mUserSwitcherController, () -> {}); } private ArrayList buildUserRecords(int count) { @@ -387,7 +388,8 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { 0 /* flags */); users.add(new UserRecord(info, null, false /* isGuest */, false /* isCurrent */, false /* isAddUser */, false /* isRestricted */, true /* isSwitchToEnabled */, - false /* isAddSupervisedUser */, null /* enforcedAdmin */)); + false /* isAddSupervisedUser */, null /* enforcedAdmin */, + false /* isManageUsers */)); } return users; } @@ -395,7 +397,7 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { private void setupForUpdateKeyguardPosition(boolean oneHandedMode) { int mode = oneHandedMode ? MODE_ONE_HANDED : MODE_DEFAULT; mKeyguardSecurityContainer.initMode(mode, mGlobalSettings, mFalsingManager, - mUserSwitcherController); + mUserSwitcherController, () -> {}); } /** Get the ConstraintLayout constraint of the view. */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImplTest.kt index 76ecc1c7f36da..169f4fb2715be 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImplTest.kt @@ -57,14 +57,18 @@ import com.android.systemui.settings.UserTracker import com.android.systemui.shade.NotificationShadeWindowView import com.android.systemui.telephony.TelephonyListenerManager import com.android.systemui.user.data.source.UserRecord +import com.android.systemui.user.legacyhelper.data.LegacyUserDataHelper +import com.android.systemui.user.shared.model.UserActionModel import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture +import com.android.systemui.util.mockito.kotlinArgumentCaptor import com.android.systemui.util.mockito.nullable import com.android.systemui.util.settings.GlobalSettings import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.time.FakeSystemClock +import com.google.common.truth.Truth import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertNotNull @@ -123,7 +127,7 @@ class UserSwitcherControllerOldImplTest : SysuiTestCase() { 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, + UserInfo.FLAG_PRIMARY or UserInfo.FLAG_SYSTEM or UserInfo.FLAG_ADMIN, UserManager.USER_TYPE_FULL_SYSTEM) private val guestId = 1234 private val guestInfo = UserInfo(guestId, "Guest", null, @@ -596,6 +600,76 @@ class UserSwitcherControllerOldImplTest : SysuiTestCase() { assertFalse(userSwitcherController.canCreateSupervisedUser()) } + @Test + fun testCanManageUser_userSwitcherEnabled_addUserWhenLocked() { + `when`( + globalSettings.getIntForUser( + eq(Settings.Global.USER_SWITCHER_ENABLED), + anyInt(), + eq(UserHandle.USER_SYSTEM) + ) + ).thenReturn(1) + + `when`( + globalSettings.getIntForUser( + eq(Settings.Global.ADD_USERS_WHEN_LOCKED), + anyInt(), + eq(UserHandle.USER_SYSTEM) + ) + ).thenReturn(1) + setupController() + assertTrue(userSwitcherController.canManageUsers()) + } + + @Test + fun testCanManageUser_userSwitcherDisabled_addUserWhenLocked() { + `when`( + globalSettings.getIntForUser( + eq(Settings.Global.USER_SWITCHER_ENABLED), + anyInt(), + eq(UserHandle.USER_SYSTEM) + ) + ).thenReturn(0) + + `when`( + globalSettings.getIntForUser( + eq(Settings.Global.ADD_USERS_WHEN_LOCKED), + anyInt(), + eq(UserHandle.USER_SYSTEM) + ) + ).thenReturn(1) + setupController() + assertFalse(userSwitcherController.canManageUsers()) + } + + @Test + fun testCanManageUser_userSwitcherEnabled_isAdmin() { + `when`( + globalSettings.getIntForUser( + eq(Settings.Global.USER_SWITCHER_ENABLED), + anyInt(), + eq(UserHandle.USER_SYSTEM) + ) + ).thenReturn(1) + + setupController() + assertTrue(userSwitcherController.canManageUsers()) + } + + @Test + fun testCanManageUser_userSwitcherDisabled_isAdmin() { + `when`( + globalSettings.getIntForUser( + eq(Settings.Global.USER_SWITCHER_ENABLED), + anyInt(), + eq(UserHandle.USER_SYSTEM) + ) + ).thenReturn(0) + + setupController() + assertFalse(userSwitcherController.canManageUsers()) + } + @Test fun addUserSwitchCallback() { val broadcastReceiverCaptor = argumentCaptor() @@ -632,4 +706,22 @@ class UserSwitcherControllerOldImplTest : SysuiTestCase() { bgExecutor.runAllReady() verify(userManager).createGuest(context) } + + @Test + fun onUserItemClicked_manageUsers() { + val manageUserRecord = LegacyUserDataHelper.createRecord( + mContext, + ownerId, + UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, + isRestricted = false, + isSwitchToEnabled = true + ) + + userSwitcherController.onUserListItemClicked(manageUserRecord, null) + val intentCaptor = kotlinArgumentCaptor() + verify(activityStarter).startActivity(intentCaptor.capture(), + eq(true) + ) + Truth.assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_USER_SETTINGS) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorRefactoredTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorRefactoredTest.kt index 37c378c9a530e..1540f85520021 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorRefactoredTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorRefactoredTest.kt @@ -202,6 +202,7 @@ class UserInteractorRefactoredTest : UserInteractorTest() { fun `actions - device unlocked`() = runBlocking(IMMEDIATE) { val userInfos = createUserInfos(count = 2, includeGuest = false) + userRepository.setUserInfos(userInfos) userRepository.setSelectedUserInfo(userInfos[0]) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) @@ -215,6 +216,7 @@ class UserInteractorRefactoredTest : UserInteractorTest() { UserActionModel.ENTER_GUEST_MODE, UserActionModel.ADD_USER, UserActionModel.ADD_SUPERVISED_USER, + UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, ) ) @@ -276,6 +278,7 @@ class UserInteractorRefactoredTest : UserInteractorTest() { UserActionModel.ENTER_GUEST_MODE, UserActionModel.ADD_USER, UserActionModel.ADD_SUPERVISED_USER, + UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, ) ) @@ -283,7 +286,7 @@ class UserInteractorRefactoredTest : UserInteractorTest() { } @Test - fun `actions - device locked - only guest action is shown`() = + fun `actions - device locked - only guest action and manage user is shown`() = runBlocking(IMMEDIATE) { val userInfos = createUserInfos(count = 2, includeGuest = false) userRepository.setUserInfos(userInfos) @@ -293,7 +296,13 @@ class UserInteractorRefactoredTest : UserInteractorTest() { var value: List? = null val job = underTest.actions.onEach { value = it }.launchIn(this) - assertThat(value).isEqualTo(listOf(UserActionModel.ENTER_GUEST_MODE)) + assertThat(value) + .isEqualTo( + listOf( + UserActionModel.ENTER_GUEST_MODE, + UserActionModel.NAVIGATE_TO_USER_MANAGEMENT + ) + ) job.cancel() } @@ -330,7 +339,7 @@ class UserInteractorRefactoredTest : UserInteractorTest() { underTest.executeAction(UserActionModel.ADD_SUPERVISED_USER) val intentCaptor = kotlinArgumentCaptor() - verify(activityStarter).startActivity(intentCaptor.capture(), eq(false)) + verify(activityStarter).startActivity(intentCaptor.capture(), eq(true)) assertThat(intentCaptor.value.action) .isEqualTo(UserManager.ACTION_CREATE_SUPERVISED_USER) assertThat(intentCaptor.value.`package`).isEqualTo(SUPERVISED_USER_CREATION_APP_PACKAGE) @@ -342,7 +351,7 @@ class UserInteractorRefactoredTest : UserInteractorTest() { underTest.executeAction(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) val intentCaptor = kotlinArgumentCaptor() - verify(activityStarter).startActivity(intentCaptor.capture(), eq(false)) + verify(activityStarter).startActivity(intentCaptor.capture(), eq(true)) assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_USER_SETTINGS) } @@ -561,6 +570,7 @@ class UserInteractorRefactoredTest : UserInteractorTest() { UserActionModel.ENTER_GUEST_MODE, UserActionModel.ADD_USER, UserActionModel.ADD_SUPERVISED_USER, + UserActionModel.NAVIGATE_TO_USER_MANAGEMENT, ), ) } @@ -705,7 +715,7 @@ class UserInteractorRefactoredTest : UserInteractorTest() { name, /* iconPath= */ "", /* flags= */ if (isPrimary) { - UserInfo.FLAG_PRIMARY + UserInfo.FLAG_PRIMARY or UserInfo.FLAG_ADMIN } else { 0 },