Add tests for guest user metrics
Test: statsd_testdrive -terse 90 Test: atest SystemUITests:com.android.systemui.qs.tiles.UserDetailViewAdapterTest Test: atest SystemUITests:com.android.systemui.statusbar.policy.UserSwitcherControllerTest Bug: 169783558 Bug: 194441567 Change-Id: I009fc0eba32e34cb62f2cc15f9337bce9b81c89d Merged-In: I009fc0eba32e34cb62f2cc15f9337bce9b81c89d
This commit is contained in:
@@ -16,25 +16,24 @@
|
|||||||
|
|
||||||
package com.android.systemui;
|
package com.android.systemui;
|
||||||
|
|
||||||
import android.app.ActivityManager;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.provider.Settings;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.logging.UiEventLogger;
|
import com.android.internal.logging.UiEventLogger;
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||||
import com.android.systemui.qs.QSUserSwitcherEvent;
|
import com.android.systemui.qs.QSUserSwitcherEvent;
|
||||||
|
import com.android.systemui.settings.UserTracker;
|
||||||
import com.android.systemui.statusbar.phone.SystemUIDialog;
|
import com.android.systemui.statusbar.phone.SystemUIDialog;
|
||||||
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
||||||
|
import com.android.systemui.util.settings.SecureSettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages notification when a guest session is resumed.
|
* Manages notification when a guest session is resumed.
|
||||||
@@ -43,16 +42,23 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver {
|
|||||||
|
|
||||||
private static final String TAG = "GuestResumeSessionReceiver";
|
private static final String TAG = "GuestResumeSessionReceiver";
|
||||||
|
|
||||||
private static final String SETTING_GUEST_HAS_LOGGED_IN = "systemui.guest_has_logged_in";
|
@VisibleForTesting
|
||||||
|
public static final String SETTING_GUEST_HAS_LOGGED_IN = "systemui.guest_has_logged_in";
|
||||||
|
|
||||||
private Dialog mNewSessionDialog;
|
@VisibleForTesting
|
||||||
|
public AlertDialog mNewSessionDialog;
|
||||||
|
private final UserTracker mUserTracker;
|
||||||
private final UserSwitcherController mUserSwitcherController;
|
private final UserSwitcherController mUserSwitcherController;
|
||||||
private final UiEventLogger mUiEventLogger;
|
private final UiEventLogger mUiEventLogger;
|
||||||
|
private final SecureSettings mSecureSettings;
|
||||||
|
|
||||||
public GuestResumeSessionReceiver(UserSwitcherController userSwitcherController,
|
public GuestResumeSessionReceiver(UserSwitcherController userSwitcherController,
|
||||||
UiEventLogger uiEventLogger) {
|
UserTracker userTracker, UiEventLogger uiEventLogger,
|
||||||
|
SecureSettings secureSettings) {
|
||||||
mUserSwitcherController = userSwitcherController;
|
mUserSwitcherController = userSwitcherController;
|
||||||
|
mUserTracker = userTracker;
|
||||||
mUiEventLogger = uiEventLogger;
|
mUiEventLogger = uiEventLogger;
|
||||||
|
mSecureSettings = secureSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -78,26 +84,19 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UserInfo currentUser;
|
UserInfo currentUser = mUserTracker.getUserInfo();
|
||||||
try {
|
|
||||||
currentUser = ActivityManager.getService().getCurrentUser();
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!currentUser.isGuest()) {
|
if (!currentUser.isGuest()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentResolver cr = context.getContentResolver();
|
int notFirstLogin = mSecureSettings.getIntForUser(
|
||||||
int notFirstLogin = Settings.System.getIntForUser(
|
SETTING_GUEST_HAS_LOGGED_IN, 0, userId);
|
||||||
cr, SETTING_GUEST_HAS_LOGGED_IN, 0, userId);
|
|
||||||
if (notFirstLogin != 0) {
|
if (notFirstLogin != 0) {
|
||||||
mNewSessionDialog = new ResetSessionDialog(context, mUserSwitcherController,
|
mNewSessionDialog = new ResetSessionDialog(context, mUserSwitcherController,
|
||||||
mUiEventLogger, userId);
|
mUiEventLogger, userId);
|
||||||
mNewSessionDialog.show();
|
mNewSessionDialog.show();
|
||||||
} else {
|
} else {
|
||||||
Settings.System.putIntForUser(
|
mSecureSettings.putIntForUser(SETTING_GUEST_HAS_LOGGED_IN, 1, userId);
|
||||||
cr, SETTING_GUEST_HAS_LOGGED_IN, 1, userId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,18 +108,26 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ResetSessionDialog extends SystemUIDialog implements
|
/**
|
||||||
|
* Dialog shown when user when asking for confirmation before deleting guest user.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
public static class ResetSessionDialog extends SystemUIDialog implements
|
||||||
DialogInterface.OnClickListener {
|
DialogInterface.OnClickListener {
|
||||||
|
|
||||||
private static final int BUTTON_WIPE = BUTTON_NEGATIVE;
|
@VisibleForTesting
|
||||||
private static final int BUTTON_DONTWIPE = BUTTON_POSITIVE;
|
public static final int BUTTON_WIPE = BUTTON_NEGATIVE;
|
||||||
|
@VisibleForTesting
|
||||||
|
public static final int BUTTON_DONTWIPE = BUTTON_POSITIVE;
|
||||||
|
|
||||||
private final UserSwitcherController mUserSwitcherController;
|
private final UserSwitcherController mUserSwitcherController;
|
||||||
private final UiEventLogger mUiEventLogger;
|
private final UiEventLogger mUiEventLogger;
|
||||||
private final int mUserId;
|
private final int mUserId;
|
||||||
|
|
||||||
ResetSessionDialog(Context context, UserSwitcherController userSwitcherController,
|
ResetSessionDialog(Context context,
|
||||||
UiEventLogger uiEventLogger, int userId) {
|
UserSwitcherController userSwitcherController,
|
||||||
|
UiEventLogger uiEventLogger,
|
||||||
|
int userId) {
|
||||||
super(context);
|
super(context);
|
||||||
|
|
||||||
setTitle(context.getString(R.string.guest_wipe_session_title));
|
setTitle(context.getString(R.string.guest_wipe_session_title));
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import static com.android.systemui.DejankUtils.whitelistIpcs;
|
|||||||
|
|
||||||
import android.annotation.UserIdInt;
|
import android.annotation.UserIdInt;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.IActivityTaskManager;
|
import android.app.IActivityTaskManager;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
@@ -71,9 +72,11 @@ import com.android.systemui.plugins.FalsingManager;
|
|||||||
import com.android.systemui.plugins.qs.DetailAdapter;
|
import com.android.systemui.plugins.qs.DetailAdapter;
|
||||||
import com.android.systemui.qs.QSUserSwitcherEvent;
|
import com.android.systemui.qs.QSUserSwitcherEvent;
|
||||||
import com.android.systemui.qs.tiles.UserDetailView;
|
import com.android.systemui.qs.tiles.UserDetailView;
|
||||||
|
import com.android.systemui.settings.UserTracker;
|
||||||
import com.android.systemui.statusbar.phone.SystemUIDialog;
|
import com.android.systemui.statusbar.phone.SystemUIDialog;
|
||||||
import com.android.systemui.telephony.TelephonyListenerManager;
|
import com.android.systemui.telephony.TelephonyListenerManager;
|
||||||
import com.android.systemui.user.CreateUserActivity;
|
import com.android.systemui.user.CreateUserActivity;
|
||||||
|
import com.android.systemui.util.settings.SecureSettings;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
@@ -104,9 +107,12 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
|
private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
|
||||||
|
|
||||||
protected final Context mContext;
|
protected final Context mContext;
|
||||||
|
protected final UserTracker mUserTracker;
|
||||||
protected final UserManager mUserManager;
|
protected final UserManager mUserManager;
|
||||||
|
private final ContentObserver mSettingsObserver;
|
||||||
private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>();
|
private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>();
|
||||||
private final GuestResumeSessionReceiver mGuestResumeSessionReceiver;
|
@VisibleForTesting
|
||||||
|
final GuestResumeSessionReceiver mGuestResumeSessionReceiver;
|
||||||
private final KeyguardStateController mKeyguardStateController;
|
private final KeyguardStateController mKeyguardStateController;
|
||||||
protected final Handler mHandler;
|
protected final Handler mHandler;
|
||||||
private final ActivityStarter mActivityStarter;
|
private final ActivityStarter mActivityStarter;
|
||||||
@@ -115,15 +121,18 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
private final IActivityTaskManager mActivityTaskManager;
|
private final IActivityTaskManager mActivityTaskManager;
|
||||||
|
|
||||||
private ArrayList<UserRecord> mUsers = new ArrayList<>();
|
private ArrayList<UserRecord> mUsers = new ArrayList<>();
|
||||||
private Dialog mExitGuestDialog;
|
@VisibleForTesting
|
||||||
private Dialog mAddUserDialog;
|
AlertDialog mExitGuestDialog;
|
||||||
|
@VisibleForTesting
|
||||||
|
Dialog mAddUserDialog;
|
||||||
private int mLastNonGuestUser = UserHandle.USER_SYSTEM;
|
private int mLastNonGuestUser = UserHandle.USER_SYSTEM;
|
||||||
private boolean mResumeUserOnGuestLogout = true;
|
private boolean mResumeUserOnGuestLogout = true;
|
||||||
private boolean mSimpleUserSwitcher;
|
private boolean mSimpleUserSwitcher;
|
||||||
// When false, there won't be any visual affordance to add a new user from the keyguard even if
|
// When false, there won't be any visual affordance to add a new user from the keyguard even if
|
||||||
// the user is unlocked
|
// the user is unlocked
|
||||||
private boolean mAddUsersFromLockScreen;
|
private boolean mAddUsersFromLockScreen;
|
||||||
private boolean mPauseRefreshUsers;
|
@VisibleForTesting
|
||||||
|
boolean mPauseRefreshUsers;
|
||||||
private int mSecondaryUser = UserHandle.USER_NULL;
|
private int mSecondaryUser = UserHandle.USER_NULL;
|
||||||
private Intent mSecondaryUserServiceIntent;
|
private Intent mSecondaryUserServiceIntent;
|
||||||
private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
|
private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
|
||||||
@@ -137,6 +146,8 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public UserSwitcherController(Context context,
|
public UserSwitcherController(Context context,
|
||||||
|
UserManager userManager,
|
||||||
|
UserTracker userTracker,
|
||||||
KeyguardStateController keyguardStateController,
|
KeyguardStateController keyguardStateController,
|
||||||
@Main Handler handler,
|
@Main Handler handler,
|
||||||
ActivityStarter activityStarter,
|
ActivityStarter activityStarter,
|
||||||
@@ -146,14 +157,17 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
TelephonyListenerManager telephonyListenerManager,
|
TelephonyListenerManager telephonyListenerManager,
|
||||||
IActivityTaskManager activityTaskManager,
|
IActivityTaskManager activityTaskManager,
|
||||||
UserDetailAdapter userDetailAdapter,
|
UserDetailAdapter userDetailAdapter,
|
||||||
|
SecureSettings secureSettings,
|
||||||
@UiBackground Executor uiBgExecutor) {
|
@UiBackground Executor uiBgExecutor) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
|
mUserTracker = userTracker;
|
||||||
mBroadcastDispatcher = broadcastDispatcher;
|
mBroadcastDispatcher = broadcastDispatcher;
|
||||||
mTelephonyListenerManager = telephonyListenerManager;
|
mTelephonyListenerManager = telephonyListenerManager;
|
||||||
mActivityTaskManager = activityTaskManager;
|
mActivityTaskManager = activityTaskManager;
|
||||||
mUiEventLogger = uiEventLogger;
|
mUiEventLogger = uiEventLogger;
|
||||||
mFalsingManager = falsingManager;
|
mFalsingManager = falsingManager;
|
||||||
mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(this, mUiEventLogger);
|
mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(
|
||||||
|
this, mUserTracker, mUiEventLogger, secureSettings);
|
||||||
mUserDetailAdapter = userDetailAdapter;
|
mUserDetailAdapter = userDetailAdapter;
|
||||||
mUiBgExecutor = uiBgExecutor;
|
mUiBgExecutor = uiBgExecutor;
|
||||||
if (!UserManager.isGuestUserEphemeral()) {
|
if (!UserManager.isGuestUserEphemeral()) {
|
||||||
@@ -166,7 +180,7 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
mKeyguardStateController = keyguardStateController;
|
mKeyguardStateController = keyguardStateController;
|
||||||
mHandler = handler;
|
mHandler = handler;
|
||||||
mActivityStarter = activityStarter;
|
mActivityStarter = activityStarter;
|
||||||
mUserManager = UserManager.get(context);
|
mUserManager = userManager;
|
||||||
IntentFilter filter = new IntentFilter();
|
IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(Intent.ACTION_USER_ADDED);
|
filter.addAction(Intent.ACTION_USER_ADDED);
|
||||||
filter.addAction(Intent.ACTION_USER_REMOVED);
|
filter.addAction(Intent.ACTION_USER_REMOVED);
|
||||||
@@ -185,6 +199,15 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter,
|
mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter,
|
||||||
PERMISSION_SELF, null /* scheduler */);
|
PERMISSION_SELF, null /* scheduler */);
|
||||||
|
|
||||||
|
mSettingsObserver = new ContentObserver(mHandler) {
|
||||||
|
@Override
|
||||||
|
public void onChange(boolean selfChange) {
|
||||||
|
mSimpleUserSwitcher = shouldUseSimpleUserSwitcher();
|
||||||
|
mAddUsersFromLockScreen = Settings.Global.getInt(mContext.getContentResolver(),
|
||||||
|
Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0;
|
||||||
|
refreshUsers(UserHandle.USER_NULL);
|
||||||
|
};
|
||||||
|
};
|
||||||
mContext.getContentResolver().registerContentObserver(
|
mContext.getContentResolver().registerContentObserver(
|
||||||
Settings.Global.getUriFor(SIMPLE_USER_SWITCHER_GLOBAL_SETTING), true,
|
Settings.Global.getUriFor(SIMPLE_USER_SWITCHER_GLOBAL_SETTING), true,
|
||||||
mSettingsObserver);
|
mSettingsObserver);
|
||||||
@@ -246,11 +269,11 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
ArrayList<UserRecord> records = new ArrayList<>(infos.size());
|
ArrayList<UserRecord> records = new ArrayList<>(infos.size());
|
||||||
int currentId = ActivityManager.getCurrentUser();
|
int currentId = mUserTracker.getUserId();
|
||||||
// Check user switchability of the foreground user since SystemUI is running in
|
// Check user switchability of the foreground user since SystemUI is running in
|
||||||
// User 0
|
// User 0
|
||||||
boolean canSwitchUsers = mUserManager.getUserSwitchability(
|
boolean canSwitchUsers = mUserManager.getUserSwitchability(
|
||||||
UserHandle.of(ActivityManager.getCurrentUser())) == SWITCHABILITY_STATUS_OK;
|
UserHandle.of(mUserTracker.getUserId())) == SWITCHABILITY_STATUS_OK;
|
||||||
UserInfo currentUserInfo = null;
|
UserInfo currentUserInfo = null;
|
||||||
UserRecord guestRecord = null;
|
UserRecord guestRecord = null;
|
||||||
|
|
||||||
@@ -391,7 +414,7 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void logoutCurrentUser() {
|
public void logoutCurrentUser() {
|
||||||
int currentUser = ActivityManager.getCurrentUser();
|
int currentUser = mUserTracker.getUserId();
|
||||||
if (currentUser != UserHandle.USER_SYSTEM) {
|
if (currentUser != UserHandle.USER_SYSTEM) {
|
||||||
pauseRefreshUsers();
|
pauseRefreshUsers();
|
||||||
ActivityManager.logoutCurrentUser();
|
ActivityManager.logoutCurrentUser();
|
||||||
@@ -403,7 +426,7 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
Log.w(TAG, "User " + userId + " could not removed.");
|
Log.w(TAG, "User " + userId + " could not removed.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ActivityManager.getCurrentUser() == userId) {
|
if (mUserTracker.getUserId() == userId) {
|
||||||
switchToUserId(UserHandle.USER_SYSTEM);
|
switchToUserId(UserHandle.USER_SYSTEM);
|
||||||
}
|
}
|
||||||
if (mUserManager.removeUser(userId)) {
|
if (mUserManager.removeUser(userId)) {
|
||||||
@@ -411,7 +434,8 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onUserListItemClicked(UserRecord record) {
|
@VisibleForTesting
|
||||||
|
void onUserListItemClicked(UserRecord record) {
|
||||||
int id;
|
int id;
|
||||||
if (record.isGuest && record.info == null) {
|
if (record.isGuest && record.info == null) {
|
||||||
// No guest user. Create one.
|
// No guest user. Create one.
|
||||||
@@ -429,7 +453,7 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
id = record.info.id;
|
id = record.info.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
int currUserId = ActivityManager.getCurrentUser();
|
int currUserId = mUserTracker.getUserId();
|
||||||
if (currUserId == id) {
|
if (currUserId == id) {
|
||||||
if (record.isGuest) {
|
if (record.isGuest) {
|
||||||
showExitGuestDialog(id);
|
showExitGuestDialog(id);
|
||||||
@@ -587,15 +611,6 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
|
|
||||||
public void onChange(boolean selfChange) {
|
|
||||||
mSimpleUserSwitcher = shouldUseSimpleUserSwitcher();
|
|
||||||
mAddUsersFromLockScreen = Settings.Global.getInt(mContext.getContentResolver(),
|
|
||||||
Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0;
|
|
||||||
refreshUsers(UserHandle.USER_NULL);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||||
pw.println("UserSwitcherController state:");
|
pw.println("UserSwitcherController state:");
|
||||||
@@ -654,13 +669,7 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
* UserHandle.USER_NULL}, then switch immediately to the newly created guest user.
|
* UserHandle.USER_NULL}, then switch immediately to the newly created guest user.
|
||||||
*/
|
*/
|
||||||
public void removeGuestUser(@UserIdInt int guestUserId, @UserIdInt int targetUserId) {
|
public void removeGuestUser(@UserIdInt int guestUserId, @UserIdInt int targetUserId) {
|
||||||
UserInfo currentUser;
|
UserInfo currentUser = mUserTracker.getUserInfo();
|
||||||
try {
|
|
||||||
currentUser = ActivityManager.getService().getCurrentUser();
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Couldn't remove guest because ActivityManager is dead");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (currentUser.id != guestUserId) {
|
if (currentUser.id != guestUserId) {
|
||||||
Log.w(TAG, "User requesting to start a new session (" + guestUserId + ")"
|
Log.w(TAG, "User requesting to start a new session (" + guestUserId + ")"
|
||||||
+ " is not current user (" + currentUser.id + ")");
|
+ " is not current user (" + currentUser.id + ")");
|
||||||
@@ -874,9 +883,9 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
|
|
||||||
private void checkIfAddUserDisallowedByAdminOnly(UserRecord record) {
|
private void checkIfAddUserDisallowedByAdminOnly(UserRecord record) {
|
||||||
EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(mContext,
|
EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(mContext,
|
||||||
UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser());
|
UserManager.DISALLOW_ADD_USER, mUserTracker.getUserId());
|
||||||
if (admin != null && !RestrictedLockUtilsInternal.hasBaseUserRestriction(mContext,
|
if (admin != null && !RestrictedLockUtilsInternal.hasBaseUserRestriction(mContext,
|
||||||
UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser())) {
|
UserManager.DISALLOW_ADD_USER, mUserTracker.getUserId())) {
|
||||||
record.isDisabledByAdmin = true;
|
record.isDisabledByAdmin = true;
|
||||||
record.enforcedAdmin = admin;
|
record.enforcedAdmin = admin;
|
||||||
} else {
|
} else {
|
||||||
@@ -1088,7 +1097,8 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class AddUserDialog extends SystemUIDialog implements
|
@VisibleForTesting
|
||||||
|
final class AddUserDialog extends SystemUIDialog implements
|
||||||
DialogInterface.OnClickListener {
|
DialogInterface.OnClickListener {
|
||||||
|
|
||||||
public AddUserDialog(Context context) {
|
public AddUserDialog(Context context) {
|
||||||
|
|||||||
@@ -0,0 +1,248 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.systemui.statusbar.policy
|
||||||
|
|
||||||
|
import android.app.IActivityTaskManager
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.UserInfo
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.UserHandle
|
||||||
|
import android.os.UserManager
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import android.testing.TestableLooper
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.internal.logging.testing.UiEventLoggerFake
|
||||||
|
import com.android.internal.util.UserIcons
|
||||||
|
import com.android.systemui.GuestResumeSessionReceiver
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||||
|
import com.android.systemui.plugins.ActivityStarter
|
||||||
|
import com.android.systemui.plugins.FalsingManager
|
||||||
|
import com.android.systemui.qs.QSUserSwitcherEvent
|
||||||
|
import com.android.systemui.settings.UserTracker
|
||||||
|
import com.android.systemui.telephony.TelephonyListenerManager
|
||||||
|
import com.android.systemui.util.concurrency.FakeExecutor
|
||||||
|
import com.android.systemui.util.settings.SecureSettings
|
||||||
|
import com.android.systemui.util.time.FakeSystemClock
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertNotNull
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentMatchers.anyInt
|
||||||
|
import org.mockito.ArgumentMatchers.eq
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.any
|
||||||
|
import org.mockito.Mockito.anyString
|
||||||
|
import org.mockito.Mockito.`when`
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
@TestableLooper.RunWithLooper(setAsMainLooper = true)
|
||||||
|
@SmallTest
|
||||||
|
class UserSwitcherControllerTest : SysuiTestCase() {
|
||||||
|
@Mock private lateinit var keyguardStateController: KeyguardStateController
|
||||||
|
@Mock private lateinit var handler: Handler
|
||||||
|
@Mock private lateinit var userTracker: UserTracker
|
||||||
|
@Mock private lateinit var userManager: UserManager
|
||||||
|
@Mock private lateinit var activityStarter: ActivityStarter
|
||||||
|
@Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
|
||||||
|
@Mock private lateinit var activityTaskManager: IActivityTaskManager
|
||||||
|
@Mock private lateinit var userDetailAdapter: UserSwitcherController.UserDetailAdapter
|
||||||
|
@Mock private lateinit var telephonyListenerManager: TelephonyListenerManager
|
||||||
|
@Mock private lateinit var secureSettings: SecureSettings
|
||||||
|
@Mock private lateinit var falsingManager: FalsingManager
|
||||||
|
private lateinit var testableLooper: TestableLooper
|
||||||
|
private lateinit var uiBgExecutor: FakeExecutor
|
||||||
|
private lateinit var uiEventLogger: UiEventLoggerFake
|
||||||
|
private lateinit var userSwitcherController: UserSwitcherController
|
||||||
|
private lateinit var picture: Bitmap
|
||||||
|
private val ownerId = UserHandle.USER_SYSTEM
|
||||||
|
private val ownerInfo = UserInfo(ownerId, "Owner", null,
|
||||||
|
UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL or UserInfo.FLAG_INITIALIZED or
|
||||||
|
UserInfo.FLAG_PRIMARY or UserInfo.FLAG_SYSTEM,
|
||||||
|
UserManager.USER_TYPE_FULL_SYSTEM)
|
||||||
|
private val guestId = 1234
|
||||||
|
private val guestInfo = UserInfo(guestId, "Guest", null,
|
||||||
|
UserInfo.FLAG_FULL or UserInfo.FLAG_GUEST, UserManager.USER_TYPE_FULL_GUEST)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
testableLooper = TestableLooper.get(this)
|
||||||
|
uiBgExecutor = FakeExecutor(FakeSystemClock())
|
||||||
|
uiEventLogger = UiEventLoggerFake()
|
||||||
|
|
||||||
|
context.orCreateTestableResources.addOverride(
|
||||||
|
com.android.internal.R.bool.config_guestUserAutoCreated, false)
|
||||||
|
|
||||||
|
`when`(userManager.canAddMoreUsers()).thenReturn(true)
|
||||||
|
|
||||||
|
userSwitcherController = UserSwitcherController(context,
|
||||||
|
userManager,
|
||||||
|
userTracker,
|
||||||
|
keyguardStateController,
|
||||||
|
handler,
|
||||||
|
activityStarter,
|
||||||
|
broadcastDispatcher,
|
||||||
|
uiEventLogger,
|
||||||
|
falsingManager,
|
||||||
|
telephonyListenerManager,
|
||||||
|
activityTaskManager,
|
||||||
|
userDetailAdapter,
|
||||||
|
secureSettings,
|
||||||
|
uiBgExecutor)
|
||||||
|
userSwitcherController.mPauseRefreshUsers = true
|
||||||
|
|
||||||
|
picture = UserIcons.convertToBitmap(context.getDrawable(R.drawable.ic_avatar_user))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAddGuest_okButtonPressed_isLogged() {
|
||||||
|
val emptyGuestUserRecord = UserSwitcherController.UserRecord(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
true /* guest */,
|
||||||
|
false /* current */,
|
||||||
|
false /* isAddUser */,
|
||||||
|
false /* isRestricted */,
|
||||||
|
true /* isSwitchToEnabled */)
|
||||||
|
`when`(userTracker.userId).thenReturn(ownerId)
|
||||||
|
`when`(userTracker.userInfo).thenReturn(ownerInfo)
|
||||||
|
|
||||||
|
`when`(userManager.createGuest(any(), anyString())).thenReturn(guestInfo)
|
||||||
|
|
||||||
|
userSwitcherController.onUserListItemClicked(emptyGuestUserRecord)
|
||||||
|
assertEquals(1, uiEventLogger.numLogs())
|
||||||
|
assertEquals(QSUserSwitcherEvent.QS_USER_GUEST_ADD.id, uiEventLogger.eventId(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRemoveGuest_removeButtonPressed_isLogged() {
|
||||||
|
val currentGuestUserRecord = UserSwitcherController.UserRecord(
|
||||||
|
guestInfo,
|
||||||
|
picture,
|
||||||
|
true /* guest */,
|
||||||
|
true /* current */,
|
||||||
|
false /* isAddUser */,
|
||||||
|
false /* isRestricted */,
|
||||||
|
true /* isSwitchToEnabled */)
|
||||||
|
`when`(userTracker.userId).thenReturn(guestInfo.id)
|
||||||
|
`when`(userTracker.userInfo).thenReturn(guestInfo)
|
||||||
|
|
||||||
|
userSwitcherController.onUserListItemClicked(currentGuestUserRecord)
|
||||||
|
assertNotNull(userSwitcherController.mExitGuestDialog)
|
||||||
|
userSwitcherController.mExitGuestDialog
|
||||||
|
.getButton(DialogInterface.BUTTON_POSITIVE).performClick()
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
assertEquals(1, uiEventLogger.numLogs())
|
||||||
|
assertEquals(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE.id, uiEventLogger.eventId(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRemoveGuest_cancelButtonPressed_isNotLogged() {
|
||||||
|
val currentGuestUserRecord = UserSwitcherController.UserRecord(
|
||||||
|
guestInfo,
|
||||||
|
picture,
|
||||||
|
true /* guest */,
|
||||||
|
true /* current */,
|
||||||
|
false /* isAddUser */,
|
||||||
|
false /* isRestricted */,
|
||||||
|
true /* isSwitchToEnabled */)
|
||||||
|
`when`(userTracker.userId).thenReturn(guestId)
|
||||||
|
`when`(userTracker.userInfo).thenReturn(guestInfo)
|
||||||
|
|
||||||
|
userSwitcherController.onUserListItemClicked(currentGuestUserRecord)
|
||||||
|
assertNotNull(userSwitcherController.mExitGuestDialog)
|
||||||
|
userSwitcherController.mExitGuestDialog
|
||||||
|
.getButton(DialogInterface.BUTTON_NEGATIVE).performClick()
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
assertEquals(0, uiEventLogger.numLogs())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testWipeGuest_startOverButtonPressed_isLogged() {
|
||||||
|
val currentGuestUserRecord = UserSwitcherController.UserRecord(
|
||||||
|
guestInfo,
|
||||||
|
picture,
|
||||||
|
true /* guest */,
|
||||||
|
false /* current */,
|
||||||
|
false /* isAddUser */,
|
||||||
|
false /* isRestricted */,
|
||||||
|
true /* isSwitchToEnabled */)
|
||||||
|
`when`(userTracker.userId).thenReturn(guestId)
|
||||||
|
`when`(userTracker.userInfo).thenReturn(guestInfo)
|
||||||
|
|
||||||
|
// Simulate that guest user has already logged in
|
||||||
|
`when`(secureSettings.getIntForUser(
|
||||||
|
eq(GuestResumeSessionReceiver.SETTING_GUEST_HAS_LOGGED_IN), anyInt(), anyInt()))
|
||||||
|
.thenReturn(1)
|
||||||
|
|
||||||
|
userSwitcherController.onUserListItemClicked(currentGuestUserRecord)
|
||||||
|
|
||||||
|
// Simulate a user switch event
|
||||||
|
val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, guestId)
|
||||||
|
|
||||||
|
assertNotNull(userSwitcherController.mGuestResumeSessionReceiver)
|
||||||
|
userSwitcherController.mGuestResumeSessionReceiver.onReceive(context, intent)
|
||||||
|
|
||||||
|
assertNotNull(userSwitcherController.mGuestResumeSessionReceiver.mNewSessionDialog)
|
||||||
|
userSwitcherController.mGuestResumeSessionReceiver.mNewSessionDialog
|
||||||
|
.getButton(GuestResumeSessionReceiver.ResetSessionDialog.BUTTON_WIPE).performClick()
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
assertEquals(1, uiEventLogger.numLogs())
|
||||||
|
assertEquals(QSUserSwitcherEvent.QS_USER_GUEST_WIPE.id, uiEventLogger.eventId(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testWipeGuest_continueButtonPressed_isLogged() {
|
||||||
|
val currentGuestUserRecord = UserSwitcherController.UserRecord(
|
||||||
|
guestInfo,
|
||||||
|
picture,
|
||||||
|
true /* guest */,
|
||||||
|
false /* current */,
|
||||||
|
false /* isAddUser */,
|
||||||
|
false /* isRestricted */,
|
||||||
|
true /* isSwitchToEnabled */)
|
||||||
|
`when`(userTracker.userId).thenReturn(guestId)
|
||||||
|
`when`(userTracker.userInfo).thenReturn(guestInfo)
|
||||||
|
|
||||||
|
// Simulate that guest user has already logged in
|
||||||
|
`when`(secureSettings.getIntForUser(
|
||||||
|
eq(GuestResumeSessionReceiver.SETTING_GUEST_HAS_LOGGED_IN), anyInt(), anyInt()))
|
||||||
|
.thenReturn(1)
|
||||||
|
|
||||||
|
userSwitcherController.onUserListItemClicked(currentGuestUserRecord)
|
||||||
|
|
||||||
|
// Simulate a user switch event
|
||||||
|
val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, guestId)
|
||||||
|
|
||||||
|
assertNotNull(userSwitcherController.mGuestResumeSessionReceiver)
|
||||||
|
userSwitcherController.mGuestResumeSessionReceiver.onReceive(context, intent)
|
||||||
|
|
||||||
|
assertNotNull(userSwitcherController.mGuestResumeSessionReceiver.mNewSessionDialog)
|
||||||
|
userSwitcherController.mGuestResumeSessionReceiver.mNewSessionDialog
|
||||||
|
.getButton(GuestResumeSessionReceiver.ResetSessionDialog.BUTTON_DONTWIPE)
|
||||||
|
.performClick()
|
||||||
|
testableLooper.processAllMessages()
|
||||||
|
assertEquals(1, uiEventLogger.numLogs())
|
||||||
|
assertEquals(QSUserSwitcherEvent.QS_USER_GUEST_CONTINUE.id, uiEventLogger.eventId(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user