[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
This commit is contained in:
Aaron Liu
2022-10-11 12:11:32 -07:00
parent 1797647903
commit bb821889a8
17 changed files with 285 additions and 116 deletions

View File

@@ -241,4 +241,6 @@
<string name="clock_title_bubble">Bubble</string>
<!-- Name of the "Analog" clock face [CHAR LIMIT=15]-->
<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>

View File

@@ -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();
}
}
/**

View File

@@ -620,7 +620,9 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
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) {

View File

@@ -35,8 +35,8 @@ protected constructor(
protected val controller: UserSwitcherController,
) : BaseAdapter() {
protected open val users: ArrayList<UserRecord>
get() = controller.users
protected open val users: List<UserRecord>
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))
}

View File

@@ -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<KeyguardUserS
}
void refreshUserOrder() {
ArrayList<UserRecord> users = super.getUsers();
List<UserRecord> users = super.getUsers();
mUsersOrdered = new ArrayList<>(users.size());
for (int i = 0; i < users.size(); i++) {
UserRecord record = users.get(i);

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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 {

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.
*/

View File

@@ -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.

View File

@@ -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")
}
}

View File

@@ -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!")
}
}

View File

@@ -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

View File

@@ -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<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

View File

@@ -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<UserRecord> 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. */

View File

@@ -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<BroadcastReceiver>()
@@ -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<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`() =
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<UserActionModel>? = 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<Intent>()
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<Intent>()
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
},