Merge "[Bouncer] Add manage users to bouncer." into tm-qpr-dev

This commit is contained in:
Aaron Liu
2022-10-15 17:45:10 +00:00
committed by Android (Google) Code Review
17 changed files with 285 additions and 116 deletions

View File

@@ -241,4 +241,6 @@
<string name="clock_title_bubble">Bubble</string> <string name="clock_title_bubble">Bubble</string>
<!-- Name of the "Analog" clock face [CHAR LIMIT=15]--> <!-- Name of the "Analog" clock face [CHAR LIMIT=15]-->
<string name="clock_title_analog">Analog</string> <string name="clock_title_analog">Analog</string>
<!-- Title of bouncer when we want to authenticate before continuing with action. [CHAR LIMIT=NONE] -->
<string name="keyguard_unlock_to_continue">Unlock your device to continue</string>
</resources> </resources>

View File

@@ -67,7 +67,6 @@ import android.view.ViewGroup;
import android.view.WindowInsets; import android.view.WindowInsets;
import android.view.WindowInsetsAnimation; import android.view.WindowInsetsAnimation;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
@@ -318,7 +317,8 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
} }
void initMode(@Mode int mode, GlobalSettings globalSettings, FalsingManager falsingManager, void initMode(@Mode int mode, GlobalSettings globalSettings, FalsingManager falsingManager,
UserSwitcherController userSwitcherController) { UserSwitcherController userSwitcherController,
UserSwitcherViewMode.UserSwitcherCallback userSwitcherCallback) {
if (mCurrentMode == mode) return; if (mCurrentMode == mode) return;
Log.i(TAG, "Switching mode from " + modeToString(mCurrentMode) + " to " Log.i(TAG, "Switching mode from " + modeToString(mCurrentMode) + " to "
+ modeToString(mode)); + modeToString(mode));
@@ -330,7 +330,7 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
mViewMode = new OneHandedViewMode(); mViewMode = new OneHandedViewMode();
break; break;
case MODE_USER_SWITCHER: case MODE_USER_SWITCHER:
mViewMode = new UserSwitcherViewMode(); mViewMode = new UserSwitcherViewMode(userSwitcherCallback);
break; break;
default: default:
mViewMode = new DefaultViewMode(); mViewMode = new DefaultViewMode();
@@ -864,6 +864,12 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
private UserSwitcherController.UserSwitchCallback mUserSwitchCallback = private UserSwitcherController.UserSwitchCallback mUserSwitchCallback =
this::setupUserSwitcher; this::setupUserSwitcher;
private UserSwitcherCallback mUserSwitcherCallback;
UserSwitcherViewMode(UserSwitcherCallback userSwitcherCallback) {
mUserSwitcherCallback = userSwitcherCallback;
}
@Override @Override
public void init(@NonNull ConstraintLayout v, @NonNull GlobalSettings globalSettings, public void init(@NonNull ConstraintLayout v, @NonNull GlobalSettings globalSettings,
@NonNull KeyguardSecurityViewFlipper viewFlipper, @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) -> { anchor.setOnClickListener((v) -> {
if (mFalsingManager.isFalseTap(LOW_PENALTY)) return; if (mFalsingManager.isFalseTap(LOW_PENALTY)) return;
mPopup = new KeyguardUserSwitcherPopupMenu(v.getContext(), mFalsingManager); mPopup = new KeyguardUserSwitcherPopupMenu(v.getContext(), mFalsingManager);
mPopup.setAnchorView(anchor); mPopup.setAnchorView(anchor);
mPopup.setAdapter(adapter); mPopup.setAdapter(adapter);
mPopup.setOnItemClickListener(new AdapterView.OnItemClickListener() { mPopup.setOnItemClickListener((parent, view, pos, id) -> {
public void onItemClick(AdapterView parent, View view, int pos, long id) { if (mFalsingManager.isFalseTap(LOW_PENALTY)) return;
if (mFalsingManager.isFalseTap(LOW_PENALTY)) return; if (!view.isEnabled()) return;
if (!view.isEnabled()) return; // Subtract one for the header
UserRecord user = adapter.getItem(pos - 1);
// Subtract one for the header if (user.isManageUsers || user.isAddSupervisedUser) {
UserRecord user = adapter.getItem(pos - 1); mUserSwitcherCallback.showUnlockToContinueMessage();
if (!user.isCurrent) { }
adapter.onUserListItemClicked(user); if (!user.isCurrent) {
} adapter.onUserListItemClicked(user);
mPopup.dismiss(); }
mPopup = null; mPopup.dismiss();
} mPopup = null;
}); });
mPopup.show(); mPopup.show();
}); });
} }
@@ -1122,6 +1119,10 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
constraintSet.applyTo(mView); constraintSet.applyTo(mView);
} }
} }
interface UserSwitcherCallback {
void showUnlockToContinueMessage();
}
} }
/** /**

View File

@@ -620,7 +620,9 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mode = KeyguardSecurityContainer.MODE_ONE_HANDED; mode = KeyguardSecurityContainer.MODE_ONE_HANDED;
} }
mView.initMode(mode, mGlobalSettings, mFalsingManager, mUserSwitcherController); mView.initMode(mode, mGlobalSettings, mFalsingManager, mUserSwitcherController,
() -> showMessage(getContext().getString(R.string.keyguard_unlock_to_continue),
null));
} }
public void reportFailedUnlockAttempt(int userId, int timeoutMs) { public void reportFailedUnlockAttempt(int userId, int timeoutMs) {

View File

@@ -35,8 +35,8 @@ protected constructor(
protected val controller: UserSwitcherController, protected val controller: UserSwitcherController,
) : BaseAdapter() { ) : BaseAdapter() {
protected open val users: ArrayList<UserRecord> protected open val users: List<UserRecord>
get() = controller.users get() = controller.users.filter { !controller.isKeyguardShowing || !it.isRestricted }
init { init {
controller.addAdapter(WeakReference(this)) controller.addAdapter(WeakReference(this))
@@ -112,6 +112,7 @@ protected constructor(
item.isGuest, item.isGuest,
item.isAddSupervisedUser, item.isAddSupervisedUser,
isTablet, isTablet,
item.isManageUsers,
) )
return checkNotNull(context.getDrawable(iconRes)) return checkNotNull(context.getDrawable(iconRes))
} }

View File

@@ -53,6 +53,7 @@ import com.android.systemui.user.data.source.UserRecord;
import com.android.systemui.util.ViewController; import com.android.systemui.util.ViewController;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
@@ -456,7 +457,7 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS
} }
void refreshUserOrder() { void refreshUserOrder() {
ArrayList<UserRecord> users = super.getUsers(); List<UserRecord> users = super.getUsers();
mUsersOrdered = new ArrayList<>(users.size()); mUsersOrdered = new ArrayList<>(users.size());
for (int i = 0; i < users.size(); i++) { for (int i = 0; i < users.size(); i++) {
UserRecord record = users.get(i); UserRecord record = users.get(i);

View File

@@ -249,7 +249,7 @@ constructor(
override fun startActivity(intent: Intent) { override fun startActivity(intent: Intent) {
if (useInteractor) { if (useInteractor) {
activityStarter.startActivity(intent, /* dismissShade= */ false) activityStarter.startActivity(intent, /* dismissShade= */ true)
} else { } else {
_oldImpl.startActivity(intent) _oldImpl.startActivity(intent)
} }

View File

@@ -49,6 +49,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.LatencyTracker; import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.users.UserCreatingDialog; import com.android.settingslib.users.UserCreatingDialog;
import com.android.systemui.GuestResetOrExitSessionReceiver; import com.android.systemui.GuestResetOrExitSessionReceiver;
import com.android.systemui.GuestResumeSessionReceiver; import com.android.systemui.GuestResumeSessionReceiver;
@@ -399,6 +400,16 @@ public class UserSwitcherControllerOldImpl implements UserSwitcherController {
records.add(userRecord); records.add(userRecord);
} }
if (canManageUsers()) {
records.add(LegacyUserDataHelper.createRecord(
mContext,
KeyguardUpdateMonitor.getCurrentUser(),
UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
/* isRestricted= */ false,
/* isSwitchToEnabled= */ true
));
}
mUiExecutor.execute(() -> { mUiExecutor.execute(() -> {
if (records != null) { if (records != null) {
mUsers = records; mUsers = records;
@@ -438,6 +449,14 @@ public class UserSwitcherControllerOldImpl implements UserSwitcherController {
&& mUserManager.canAddMoreUsers(UserManager.USER_TYPE_FULL_SECONDARY); && 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() { private boolean createIsRestricted() {
return !mAddUsersFromLockScreen.getValue(); return !mAddUsersFromLockScreen.getValue();
} }
@@ -525,6 +544,8 @@ public class UserSwitcherControllerOldImpl implements UserSwitcherController {
showAddUserDialog(dialogShower); showAddUserDialog(dialogShower);
} else if (record.isAddSupervisedUser) { } else if (record.isAddSupervisedUser) {
startSupervisedUserActivity(); startSupervisedUserActivity();
} else if (record.isManageUsers) {
startActivity(new Intent(Settings.ACTION_USER_SETTINGS));
} else { } else {
onUserListItemClicked(record.info.id, record, dialogShower); onUserListItemClicked(record.info.id, record, dialogShower);
} }
@@ -984,7 +1005,7 @@ public class UserSwitcherControllerOldImpl implements UserSwitcherController {
@Override @Override
public void startActivity(Intent intent) { public void startActivity(Intent intent) {
mActivityStarter.startActivity(intent, true); mActivityStarter.startActivity(intent, /* dismissShade= */ true);
} }
@Override @Override

View File

@@ -47,6 +47,9 @@ data class UserRecord(
* If not disabled, this is `null`. * If not disabled, this is `null`.
*/ */
@JvmField val enforcedAdmin: RestrictedLockUtils.EnforcedAdmin? = 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. */ /** Returns a new instance of [UserRecord] with its [isCurrent] set to the given value. */
fun copyWithIsCurrent(isCurrent: Boolean): UserRecord { fun copyWithIsCurrent(isCurrent: Boolean): UserRecord {

View File

@@ -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. * Returns `true` if the current user is allowed to add users to the device; `false` otherwise.
*/ */

View File

@@ -102,6 +102,7 @@ constructor(
interface UserCallback { interface UserCallback {
/** Returns `true` if this callback can be cleaned-up. */ /** Returns `true` if this callback can be cleaned-up. */
fun isEvictable(): Boolean = false fun isEvictable(): Boolean = false
/** Notifies that the state of users on the device has changed. */ /** Notifies that the state of users on the device has changed. */
fun onUserStateChanged() fun onUserStateChanged()
} }
@@ -164,10 +165,11 @@ constructor(
get() = get() =
if (isNewImpl) { if (isNewImpl) {
combine( combine(
repository.selectedUserInfo,
repository.userInfos, repository.userInfos,
repository.userSwitcherSettings, repository.userSwitcherSettings,
keyguardInteractor.isKeyguardShowing, keyguardInteractor.isKeyguardShowing,
) { userInfos, settings, isDeviceLocked -> ) { _, userInfos, settings, isDeviceLocked ->
buildList { buildList {
val hasGuestUser = userInfos.any { it.isGuest } val hasGuestUser = userInfos.any { it.isGuest }
if ( if (
@@ -183,35 +185,45 @@ constructor(
add(UserActionModel.ENTER_GUEST_MODE) 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 // 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 // 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 // always allowed, even when the device is locked, but the various "add
// user" actions below are not. We can finish building the list here. // 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 ( if (
UserActionsUtil.canCreateUser( UserActionsUtil.canManageUsers(
manager,
repository, repository,
settings.isUserSwitcherEnabled, settings.isUserSwitcherEnabled,
settings.isAddUsersFromLockscreen, settings.isAddUsersFromLockscreen,
) )
) { ) {
add(UserActionModel.ADD_USER) add(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)
}
if (
UserActionsUtil.canCreateSupervisedUser(
manager,
repository,
settings.isUserSwitcherEnabled,
settings.isAddUsersFromLockscreen,
supervisedUserPackageName,
)
) {
add(UserActionModel.ADD_SUPERVISED_USER)
} }
} }
} }
@@ -264,7 +276,10 @@ constructor(
toRecord( toRecord(
action = it, action = it,
selectedUserId = selectedUserInfo.id, 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) .setAction(UserManager.ACTION_CREATE_SUPERVISED_USER)
.setPackage(supervisedUserPackageName) .setPackage(supervisedUserPackageName)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
/* dismissShade= */ false, /* dismissShade= */ true,
) )
UserActionModel.NAVIGATE_TO_USER_MANAGEMENT -> UserActionModel.NAVIGATE_TO_USER_MANAGEMENT ->
activityStarter.startActivity( activityStarter.startActivity(
Intent(Settings.ACTION_USER_SETTINGS), Intent(Settings.ACTION_USER_SETTINGS),
/* dismissShade= */ false, /* dismissShade= */ true,
) )
} }
} else { } else {
@@ -575,20 +590,13 @@ constructor(
private suspend fun toRecord( private suspend fun toRecord(
action: UserActionModel, action: UserActionModel,
selectedUserId: Int, selectedUserId: Int,
isAddFromLockscreenEnabled: Boolean, isRestricted: Boolean,
): UserRecord { ): UserRecord {
return LegacyUserDataHelper.createRecord( return LegacyUserDataHelper.createRecord(
context = applicationContext, context = applicationContext,
selectedUserId = selectedUserId, selectedUserId = selectedUserId,
actionType = action, actionType = action,
isRestricted = isRestricted = 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
},
isSwitchToEnabled = isSwitchToEnabled =
canSwitchUsers(selectedUserId) && canSwitchUsers(selectedUserId) &&
// If the user is auto-created is must not be currently resetting. // If the user is auto-created is must not be currently resetting.

View File

@@ -80,6 +80,7 @@ object LegacyUserDataHelper {
context = context, context = context,
selectedUserId = selectedUserId, selectedUserId = selectedUserId,
), ),
isManageUsers = actionType == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
) )
} }
@@ -90,6 +91,7 @@ object LegacyUserDataHelper {
record.isAddUser -> UserActionModel.ADD_USER record.isAddUser -> UserActionModel.ADD_USER
record.isAddSupervisedUser -> UserActionModel.ADD_SUPERVISED_USER record.isAddSupervisedUser -> UserActionModel.ADD_SUPERVISED_USER
record.isGuest -> UserActionModel.ENTER_GUEST_MODE record.isGuest -> UserActionModel.ENTER_GUEST_MODE
record.isManageUsers -> UserActionModel.NAVIGATE_TO_USER_MANAGEMENT
else -> error("Not a known action: $record") else -> error("Not a known action: $record")
} }
} }

View File

@@ -39,6 +39,7 @@ object LegacyUserUiHelper {
isGuest: Boolean, isGuest: Boolean,
isAddSupervisedUser: Boolean, isAddSupervisedUser: Boolean,
isTablet: Boolean = false, isTablet: Boolean = false,
isManageUsers: Boolean,
): Int { ): Int {
return if (isAddUser && isTablet) { return if (isAddUser && isTablet) {
R.drawable.ic_account_circle_filled R.drawable.ic_account_circle_filled
@@ -48,6 +49,8 @@ object LegacyUserUiHelper {
R.drawable.ic_account_circle R.drawable.ic_account_circle
} else if (isAddSupervisedUser) { } else if (isAddSupervisedUser) {
R.drawable.ic_add_supervised_user R.drawable.ic_add_supervised_user
} else if (isManageUsers) {
R.drawable.ic_manage_users
} else { } else {
R.drawable.ic_avatar_user R.drawable.ic_avatar_user
} }
@@ -74,6 +77,7 @@ object LegacyUserUiHelper {
isAddUser = record.isAddUser, isAddUser = record.isAddUser,
isAddSupervisedUser = record.isAddSupervisedUser, isAddSupervisedUser = record.isAddSupervisedUser,
isTablet = isTablet, isTablet = isTablet,
isManageUsers = record.isManageUsers,
) )
) )
} }
@@ -103,8 +107,9 @@ object LegacyUserUiHelper {
isAddUser: Boolean, isAddUser: Boolean,
isAddSupervisedUser: Boolean, isAddSupervisedUser: Boolean,
isTablet: Boolean = false, isTablet: Boolean = false,
isManageUsers: Boolean,
): Int { ): Int {
check(isGuest || isAddUser || isAddSupervisedUser) check(isGuest || isAddUser || isAddSupervisedUser || isManageUsers)
return when { return when {
isGuest && isGuestUserAutoCreated && isGuestUserResetting -> isGuest && isGuestUserAutoCreated && isGuestUserResetting ->
@@ -114,6 +119,7 @@ object LegacyUserUiHelper {
isGuest -> com.android.internal.R.string.guest_name isGuest -> com.android.internal.R.string.guest_name
isAddUser -> com.android.settingslib.R.string.user_add_user isAddUser -> com.android.settingslib.R.string.user_add_user
isAddSupervisedUser -> R.string.add_user_supervised isAddSupervisedUser -> R.string.add_user_supervised
isManageUsers -> R.string.manage_users
else -> error("This should never happen!") else -> error("This should never happen!")
} }
} }

View File

@@ -19,8 +19,6 @@ package com.android.systemui.user.ui.viewmodel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider 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.common.ui.drawable.CircularDrawable
import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags import com.android.systemui.flags.Flags
@@ -162,12 +160,7 @@ private constructor(
): UserViewModel { ): UserViewModel {
return UserViewModel( return UserViewModel(
viewKey = model.id, viewKey = model.id,
name = name = model.name,
if (model.isGuest) {
Text.Resource(com.android.settingslib.R.string.guest_exit_quick_settings_button)
} else {
model.name
},
image = CircularDrawable(model.image), image = CircularDrawable(model.image),
isSelectionMarkerVisible = model.isSelected, isSelectionMarkerVisible = model.isSelected,
alpha = alpha =
@@ -186,29 +179,23 @@ private constructor(
return UserActionViewModel( return UserActionViewModel(
viewKey = model.ordinal.toLong(), viewKey = model.ordinal.toLong(),
iconResourceId = iconResourceId =
if (model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) { LegacyUserUiHelper.getUserSwitcherActionIconResourceId(
R.drawable.ic_manage_users isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER,
} else { isAddUser = model == UserActionModel.ADD_USER,
LegacyUserUiHelper.getUserSwitcherActionIconResourceId( isGuest = model == UserActionModel.ENTER_GUEST_MODE,
isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER, isManageUsers = model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
isAddUser = model == UserActionModel.ADD_USER, isTablet = true,
isGuest = model == UserActionModel.ENTER_GUEST_MODE, ),
isTablet = true,
)
},
textResourceId = textResourceId =
if (model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) { LegacyUserUiHelper.getUserSwitcherActionTextResourceId(
R.string.manage_users isGuest = model == UserActionModel.ENTER_GUEST_MODE,
} else { isGuestUserAutoCreated = guestUserInteractor.isGuestUserAutoCreated,
LegacyUserUiHelper.getUserSwitcherActionTextResourceId( isGuestUserResetting = guestUserInteractor.isGuestUserResetting,
isGuest = model == UserActionModel.ENTER_GUEST_MODE, isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER,
isGuestUserAutoCreated = guestUserInteractor.isGuestUserAutoCreated, isAddUser = model == UserActionModel.ADD_USER,
isGuestUserResetting = guestUserInteractor.isGuestUserResetting, isManageUsers = model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER, isTablet = true,
isAddUser = model == UserActionModel.ADD_USER, ),
isTablet = true,
)
},
onClicked = { onClicked = {
userInteractor.executeAction(action = model) userInteractor.executeAction(action = model)
// We don't finish because we want to show a dialog over the full-screen UI and // We don't finish because we want to show a dialog over the full-screen UI and

View File

@@ -221,15 +221,17 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
public void onResourcesUpdate_callsThroughOnRotationChange() { public void onResourcesUpdate_callsThroughOnRotationChange() {
// Rotation is the same, shouldn't cause an update // Rotation is the same, shouldn't cause an update
mKeyguardSecurityContainerController.updateResources(); mKeyguardSecurityContainerController.updateResources();
verify(mView, never()).initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager, verify(mView, never()).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
mUserSwitcherController); eq(mUserSwitcherController),
any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
// Update rotation. Should trigger update // Update rotation. Should trigger update
mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE; mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
mKeyguardSecurityContainerController.updateResources(); mKeyguardSecurityContainerController.updateResources();
verify(mView).initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager, verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
mUserSwitcherController); eq(mUserSwitcherController),
any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
} }
private void touchDown() { private void touchDown() {
@@ -263,8 +265,9 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
.thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController);
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern);
verify(mView).initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager, verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
mUserSwitcherController); eq(mUserSwitcherController),
any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
} }
@Test @Test
@@ -275,8 +278,9 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
.thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController);
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern);
verify(mView).initMode(MODE_ONE_HANDED, mGlobalSettings, mFalsingManager, verify(mView).initMode(eq(MODE_ONE_HANDED), eq(mGlobalSettings), eq(mFalsingManager),
mUserSwitcherController); eq(mUserSwitcherController),
any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
} }
@Test @Test
@@ -285,8 +289,26 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
setupGetSecurityView(); setupGetSecurityView();
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password);
verify(mView).initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager, verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
mUserSwitcherController); eq(mUserSwitcherController),
any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
}
@Test
public void addUserSwitcherCallback() {
ArgumentCaptor<KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback>
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 @Test

View File

@@ -119,7 +119,7 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
int systemBarInsetAmount = 0; int systemBarInsetAmount = 0;
mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager, mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
mUserSwitcherController); mUserSwitcherController, () -> {});
Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount); Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount); Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);
@@ -141,7 +141,7 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
int systemBarInsetAmount = paddingBottom + 1; int systemBarInsetAmount = paddingBottom + 1;
mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager, mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
mUserSwitcherController); mUserSwitcherController, () -> {});
Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount); Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount); Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);
@@ -158,9 +158,10 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
@Test @Test
public void testDefaultViewMode() { public void testDefaultViewMode() {
mKeyguardSecurityContainer.initMode(MODE_ONE_HANDED, mGlobalSettings, mFalsingManager, mKeyguardSecurityContainer.initMode(MODE_ONE_HANDED, mGlobalSettings, mFalsingManager,
mUserSwitcherController); mUserSwitcherController, () -> {
});
mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager, mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
mUserSwitcherController); mUserSwitcherController, () -> {});
ConstraintSet.Constraint viewFlipperConstraint = ConstraintSet.Constraint viewFlipperConstraint =
getViewConstraint(mSecurityViewFlipper.getId()); getViewConstraint(mSecurityViewFlipper.getId());
assertThat(viewFlipperConstraint.layout.topToTop).isEqualTo(PARENT_ID); assertThat(viewFlipperConstraint.layout.topToTop).isEqualTo(PARENT_ID);
@@ -377,7 +378,7 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
private void setupUserSwitcher() { private void setupUserSwitcher() {
when(mGlobalSettings.getInt(any(), anyInt())).thenReturn(ONE_HANDED_KEYGUARD_SIDE_RIGHT); when(mGlobalSettings.getInt(any(), anyInt())).thenReturn(ONE_HANDED_KEYGUARD_SIDE_RIGHT);
mKeyguardSecurityContainer.initMode(KeyguardSecurityContainer.MODE_USER_SWITCHER, mKeyguardSecurityContainer.initMode(KeyguardSecurityContainer.MODE_USER_SWITCHER,
mGlobalSettings, mFalsingManager, mUserSwitcherController); mGlobalSettings, mFalsingManager, mUserSwitcherController, () -> {});
} }
private ArrayList<UserRecord> buildUserRecords(int count) { private ArrayList<UserRecord> buildUserRecords(int count) {
@@ -387,7 +388,8 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
0 /* flags */); 0 /* flags */);
users.add(new UserRecord(info, null, false /* isGuest */, false /* isCurrent */, users.add(new UserRecord(info, null, false /* isGuest */, false /* isCurrent */,
false /* isAddUser */, false /* isRestricted */, true /* isSwitchToEnabled */, false /* isAddUser */, false /* isRestricted */, true /* isSwitchToEnabled */,
false /* isAddSupervisedUser */, null /* enforcedAdmin */)); false /* isAddSupervisedUser */, null /* enforcedAdmin */,
false /* isManageUsers */));
} }
return users; return users;
} }
@@ -395,7 +397,7 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
private void setupForUpdateKeyguardPosition(boolean oneHandedMode) { private void setupForUpdateKeyguardPosition(boolean oneHandedMode) {
int mode = oneHandedMode ? MODE_ONE_HANDED : MODE_DEFAULT; int mode = oneHandedMode ? MODE_ONE_HANDED : MODE_DEFAULT;
mKeyguardSecurityContainer.initMode(mode, mGlobalSettings, mFalsingManager, mKeyguardSecurityContainer.initMode(mode, mGlobalSettings, mFalsingManager,
mUserSwitcherController); mUserSwitcherController, () -> {});
} }
/** Get the ConstraintLayout constraint of the view. */ /** Get the ConstraintLayout constraint of the view. */

View File

@@ -57,14 +57,18 @@ import com.android.systemui.settings.UserTracker
import com.android.systemui.shade.NotificationShadeWindowView import com.android.systemui.shade.NotificationShadeWindowView
import com.android.systemui.telephony.TelephonyListenerManager import com.android.systemui.telephony.TelephonyListenerManager
import com.android.systemui.user.data.source.UserRecord 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.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture 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.mockito.nullable
import com.android.systemui.util.settings.GlobalSettings import com.android.systemui.util.settings.GlobalSettings
import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.time.FakeSystemClock import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull import org.junit.Assert.assertNotNull
@@ -123,7 +127,7 @@ class UserSwitcherControllerOldImplTest : SysuiTestCase() {
private val ownerId = UserHandle.USER_SYSTEM private val ownerId = UserHandle.USER_SYSTEM
private val ownerInfo = UserInfo(ownerId, "Owner", null, private val ownerInfo = UserInfo(ownerId, "Owner", null,
UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL or UserInfo.FLAG_INITIALIZED or 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) UserManager.USER_TYPE_FULL_SYSTEM)
private val guestId = 1234 private val guestId = 1234
private val guestInfo = UserInfo(guestId, "Guest", null, private val guestInfo = UserInfo(guestId, "Guest", null,
@@ -596,6 +600,76 @@ class UserSwitcherControllerOldImplTest : SysuiTestCase() {
assertFalse(userSwitcherController.canCreateSupervisedUser()) 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 @Test
fun addUserSwitchCallback() { fun addUserSwitchCallback() {
val broadcastReceiverCaptor = argumentCaptor<BroadcastReceiver>() val broadcastReceiverCaptor = argumentCaptor<BroadcastReceiver>()
@@ -632,4 +706,22 @@ class UserSwitcherControllerOldImplTest : SysuiTestCase() {
bgExecutor.runAllReady() bgExecutor.runAllReady()
verify(userManager).createGuest(context) 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<Intent>()
verify(activityStarter).startActivity(intentCaptor.capture(),
eq(true)
)
Truth.assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_USER_SETTINGS)
}
} }

View File

@@ -202,6 +202,7 @@ class UserInteractorRefactoredTest : UserInteractorTest() {
fun `actions - device unlocked`() = fun `actions - device unlocked`() =
runBlocking(IMMEDIATE) { runBlocking(IMMEDIATE) {
val userInfos = createUserInfos(count = 2, includeGuest = false) val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos) userRepository.setUserInfos(userInfos)
userRepository.setSelectedUserInfo(userInfos[0]) userRepository.setSelectedUserInfo(userInfos[0])
userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
@@ -215,6 +216,7 @@ class UserInteractorRefactoredTest : UserInteractorTest() {
UserActionModel.ENTER_GUEST_MODE, UserActionModel.ENTER_GUEST_MODE,
UserActionModel.ADD_USER, UserActionModel.ADD_USER,
UserActionModel.ADD_SUPERVISED_USER, UserActionModel.ADD_SUPERVISED_USER,
UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
) )
) )
@@ -276,6 +278,7 @@ class UserInteractorRefactoredTest : UserInteractorTest() {
UserActionModel.ENTER_GUEST_MODE, UserActionModel.ENTER_GUEST_MODE,
UserActionModel.ADD_USER, UserActionModel.ADD_USER,
UserActionModel.ADD_SUPERVISED_USER, UserActionModel.ADD_SUPERVISED_USER,
UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
) )
) )
@@ -283,7 +286,7 @@ class UserInteractorRefactoredTest : UserInteractorTest() {
} }
@Test @Test
fun `actions - device locked - only guest action is shown`() = fun `actions - device locked - only guest action and manage user is shown`() =
runBlocking(IMMEDIATE) { runBlocking(IMMEDIATE) {
val userInfos = createUserInfos(count = 2, includeGuest = false) val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos) userRepository.setUserInfos(userInfos)
@@ -293,7 +296,13 @@ class UserInteractorRefactoredTest : UserInteractorTest() {
var value: List<UserActionModel>? = null var value: List<UserActionModel>? = null
val job = underTest.actions.onEach { value = it }.launchIn(this) 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() job.cancel()
} }
@@ -330,7 +339,7 @@ class UserInteractorRefactoredTest : UserInteractorTest() {
underTest.executeAction(UserActionModel.ADD_SUPERVISED_USER) underTest.executeAction(UserActionModel.ADD_SUPERVISED_USER)
val intentCaptor = kotlinArgumentCaptor<Intent>() val intentCaptor = kotlinArgumentCaptor<Intent>()
verify(activityStarter).startActivity(intentCaptor.capture(), eq(false)) verify(activityStarter).startActivity(intentCaptor.capture(), eq(true))
assertThat(intentCaptor.value.action) assertThat(intentCaptor.value.action)
.isEqualTo(UserManager.ACTION_CREATE_SUPERVISED_USER) .isEqualTo(UserManager.ACTION_CREATE_SUPERVISED_USER)
assertThat(intentCaptor.value.`package`).isEqualTo(SUPERVISED_USER_CREATION_APP_PACKAGE) assertThat(intentCaptor.value.`package`).isEqualTo(SUPERVISED_USER_CREATION_APP_PACKAGE)
@@ -342,7 +351,7 @@ class UserInteractorRefactoredTest : UserInteractorTest() {
underTest.executeAction(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) underTest.executeAction(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)
val intentCaptor = kotlinArgumentCaptor<Intent>() val intentCaptor = kotlinArgumentCaptor<Intent>()
verify(activityStarter).startActivity(intentCaptor.capture(), eq(false)) verify(activityStarter).startActivity(intentCaptor.capture(), eq(true))
assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_USER_SETTINGS) assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_USER_SETTINGS)
} }
@@ -561,6 +570,7 @@ class UserInteractorRefactoredTest : UserInteractorTest() {
UserActionModel.ENTER_GUEST_MODE, UserActionModel.ENTER_GUEST_MODE,
UserActionModel.ADD_USER, UserActionModel.ADD_USER,
UserActionModel.ADD_SUPERVISED_USER, UserActionModel.ADD_SUPERVISED_USER,
UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
), ),
) )
} }
@@ -705,7 +715,7 @@ class UserInteractorRefactoredTest : UserInteractorTest() {
name, name,
/* iconPath= */ "", /* iconPath= */ "",
/* flags= */ if (isPrimary) { /* flags= */ if (isPrimary) {
UserInfo.FLAG_PRIMARY UserInfo.FLAG_PRIMARY or UserInfo.FLAG_ADMIN
} else { } else {
0 0
}, },