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 },