Merge "Introduce config for auto-created guest users" into sc-dev
This commit is contained in:
@@ -3529,6 +3529,12 @@
|
|||||||
<!-- If true, all guest users created on the device will be ephemeral. -->
|
<!-- If true, all guest users created on the device will be ephemeral. -->
|
||||||
<bool name="config_guestUserEphemeral">false</bool>
|
<bool name="config_guestUserEphemeral">false</bool>
|
||||||
|
|
||||||
|
<!-- Whether device should always have a guest user available. If true, guest user will be
|
||||||
|
created on boot, and a new guest user will be created in the background anytime the current
|
||||||
|
guest user is removed. Instead of showing "Add guest" and "Remove guest", the UI will show
|
||||||
|
"Guest" and "Reset guest". -->
|
||||||
|
<bool name="config_guestUserAutoCreated">false</bool>
|
||||||
|
|
||||||
<!-- Enforce strong auth on boot. Setting this to false represents a security risk and should
|
<!-- Enforce strong auth on boot. Setting this to false represents a security risk and should
|
||||||
not be ordinarily done. The only case in which this might be permissible is in a car head
|
not be ordinarily done. The only case in which this might be permissible is in a car head
|
||||||
unit where there are hardware mechanisms to protect the device (physical keys) and not
|
unit where there are hardware mechanisms to protect the device (physical keys) and not
|
||||||
|
|||||||
@@ -402,6 +402,7 @@
|
|||||||
<java-symbol type="bool" name="config_supportsSystemDecorsOnSecondaryDisplays" />
|
<java-symbol type="bool" name="config_supportsSystemDecorsOnSecondaryDisplays" />
|
||||||
<java-symbol type="bool" name="config_supportsInsecureLockScreen" />
|
<java-symbol type="bool" name="config_supportsInsecureLockScreen" />
|
||||||
<java-symbol type="bool" name="config_guestUserEphemeral" />
|
<java-symbol type="bool" name="config_guestUserEphemeral" />
|
||||||
|
<java-symbol type="bool" name="config_guestUserAutoCreated" />
|
||||||
<java-symbol type="bool" name="config_localDisplaysMirrorContent" />
|
<java-symbol type="bool" name="config_localDisplaysMirrorContent" />
|
||||||
<java-symbol type="array" name="config_localPrivateDisplayPorts" />
|
<java-symbol type="array" name="config_localPrivateDisplayPorts" />
|
||||||
<java-symbol type="integer" name="config_defaultDisplayDefaultColorMode" />
|
<java-symbol type="integer" name="config_defaultDisplayDefaultColorMode" />
|
||||||
|
|||||||
@@ -1422,6 +1422,8 @@
|
|||||||
<string name="guest_new_guest">Add guest</string>
|
<string name="guest_new_guest">Add guest</string>
|
||||||
<!-- Label for exiting and removing the guest session in the user switcher [CHAR LIMIT=35] -->
|
<!-- Label for exiting and removing the guest session in the user switcher [CHAR LIMIT=35] -->
|
||||||
<string name="guest_exit_guest">Remove guest</string>
|
<string name="guest_exit_guest">Remove guest</string>
|
||||||
|
<!-- Label for resetting guest session in the user switcher, which will remove all data from the current guest session [CHAR LIMIT=35] -->
|
||||||
|
<string name="guest_reset_guest">Reset guest</string>
|
||||||
<!-- Name for the guest user [CHAR LIMIT=35] -->
|
<!-- Name for the guest user [CHAR LIMIT=35] -->
|
||||||
<string name="guest_nickname">Guest</string>
|
<string name="guest_nickname">Guest</string>
|
||||||
|
|
||||||
|
|||||||
@@ -1148,12 +1148,18 @@
|
|||||||
<!-- Title of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] -->
|
<!-- Title of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] -->
|
||||||
<string name="guest_exit_guest_dialog_title">Remove guest?</string>
|
<string name="guest_exit_guest_dialog_title">Remove guest?</string>
|
||||||
|
|
||||||
|
<!-- Title of the confirmation dialog when resetting guest session [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="guest_reset_guest_dialog_title">Reset guest?</string>
|
||||||
|
|
||||||
<!-- Message of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] -->
|
<!-- Message of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] -->
|
||||||
<string name="guest_exit_guest_dialog_message">All apps and data in this session will be deleted.</string>
|
<string name="guest_exit_guest_dialog_message">All apps and data in this session will be deleted.</string>
|
||||||
|
|
||||||
<!-- Label for button in confirmation dialog when exiting guest session [CHAR LIMIT=35] -->
|
<!-- Label for button in confirmation dialog when exiting guest session [CHAR LIMIT=35] -->
|
||||||
<string name="guest_exit_guest_dialog_remove">Remove</string>
|
<string name="guest_exit_guest_dialog_remove">Remove</string>
|
||||||
|
|
||||||
|
<!-- Label for button in confirmation dialog when resetting guest session [CHAR LIMIT=35] -->
|
||||||
|
<string name="guest_reset_guest_dialog_remove">Reset</string>
|
||||||
|
|
||||||
<!-- Title of the notification when resuming an existing guest session [CHAR LIMIT=NONE] -->
|
<!-- Title of the notification when resuming an existing guest session [CHAR LIMIT=NONE] -->
|
||||||
<string name="guest_wipe_session_title">Welcome back, guest!</string>
|
<string name="guest_wipe_session_title">Welcome back, guest!</string>
|
||||||
|
|
||||||
|
|||||||
@@ -27,15 +27,14 @@ import android.content.IntentFilter;
|
|||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.WindowManagerGlobal;
|
|
||||||
|
|
||||||
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.statusbar.phone.SystemUIDialog;
|
import com.android.systemui.statusbar.phone.SystemUIDialog;
|
||||||
|
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages notification when a guest session is resumed.
|
* Manages notification when a guest session is resumed.
|
||||||
@@ -47,9 +46,12 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver {
|
|||||||
private static final String SETTING_GUEST_HAS_LOGGED_IN = "systemui.guest_has_logged_in";
|
private static final String SETTING_GUEST_HAS_LOGGED_IN = "systemui.guest_has_logged_in";
|
||||||
|
|
||||||
private Dialog mNewSessionDialog;
|
private Dialog mNewSessionDialog;
|
||||||
|
private final UserSwitcherController mUserSwitcherController;
|
||||||
private final UiEventLogger mUiEventLogger;
|
private final UiEventLogger mUiEventLogger;
|
||||||
|
|
||||||
public GuestResumeSessionReceiver(UiEventLogger uiEventLogger) {
|
public GuestResumeSessionReceiver(UserSwitcherController userSwitcherController,
|
||||||
|
UiEventLogger uiEventLogger) {
|
||||||
|
mUserSwitcherController = userSwitcherController;
|
||||||
mUiEventLogger = uiEventLogger;
|
mUiEventLogger = uiEventLogger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +92,8 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver {
|
|||||||
int notFirstLogin = Settings.System.getIntForUser(
|
int notFirstLogin = Settings.System.getIntForUser(
|
||||||
cr, 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, mUiEventLogger, userId);
|
mNewSessionDialog = new ResetSessionDialog(context, mUserSwitcherController,
|
||||||
|
mUiEventLogger, userId);
|
||||||
mNewSessionDialog.show();
|
mNewSessionDialog.show();
|
||||||
} else {
|
} else {
|
||||||
Settings.System.putIntForUser(
|
Settings.System.putIntForUser(
|
||||||
@@ -99,54 +102,6 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Wipes the guest session.
|
|
||||||
*
|
|
||||||
* The guest must be the current user and its id must be {@param userId}.
|
|
||||||
*/
|
|
||||||
private static void wipeGuestSession(Context context, int userId) {
|
|
||||||
UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
|
||||||
UserInfo currentUser;
|
|
||||||
try {
|
|
||||||
currentUser = ActivityManager.getService().getCurrentUser();
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Couldn't wipe session because ActivityManager is dead");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (currentUser.id != userId) {
|
|
||||||
Log.w(TAG, "User requesting to start a new session (" + userId + ")"
|
|
||||||
+ " is not current user (" + currentUser.id + ")");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!currentUser.isGuest()) {
|
|
||||||
Log.w(TAG, "User requesting to start a new session (" + userId + ")"
|
|
||||||
+ " is not a guest");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean marked = userManager.markGuestForDeletion(currentUser.id);
|
|
||||||
if (!marked) {
|
|
||||||
Log.w(TAG, "Couldn't mark the guest for deletion for user " + userId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
UserInfo newGuest = userManager.createGuest(context, currentUser.name);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (newGuest == null) {
|
|
||||||
Log.e(TAG, "Could not create new guest, switching back to system user");
|
|
||||||
ActivityManager.getService().switchUser(UserHandle.USER_SYSTEM);
|
|
||||||
userManager.removeUser(currentUser.id);
|
|
||||||
WindowManagerGlobal.getWindowManagerService().lockNow(null /* options */);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ActivityManager.getService().switchUser(newGuest.id);
|
|
||||||
userManager.removeUser(currentUser.id);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Couldn't wipe session because ActivityManager or WindowManager is dead");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cancelDialog() {
|
private void cancelDialog() {
|
||||||
if (mNewSessionDialog != null && mNewSessionDialog.isShowing()) {
|
if (mNewSessionDialog != null && mNewSessionDialog.isShowing()) {
|
||||||
mNewSessionDialog.cancel();
|
mNewSessionDialog.cancel();
|
||||||
@@ -160,10 +115,12 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver {
|
|||||||
private static final int BUTTON_WIPE = BUTTON_NEGATIVE;
|
private static final int BUTTON_WIPE = BUTTON_NEGATIVE;
|
||||||
private static final int BUTTON_DONTWIPE = BUTTON_POSITIVE;
|
private static final int BUTTON_DONTWIPE = BUTTON_POSITIVE;
|
||||||
|
|
||||||
|
private final UserSwitcherController mUserSwitcherController;
|
||||||
private final UiEventLogger mUiEventLogger;
|
private final UiEventLogger mUiEventLogger;
|
||||||
private final int mUserId;
|
private final int mUserId;
|
||||||
|
|
||||||
ResetSessionDialog(Context context, UiEventLogger uiEventLogger, int userId) {
|
ResetSessionDialog(Context context, 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));
|
||||||
@@ -175,6 +132,7 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver {
|
|||||||
setButton(BUTTON_DONTWIPE,
|
setButton(BUTTON_DONTWIPE,
|
||||||
context.getString(R.string.guest_wipe_session_dontwipe), this);
|
context.getString(R.string.guest_wipe_session_dontwipe), this);
|
||||||
|
|
||||||
|
mUserSwitcherController = userSwitcherController;
|
||||||
mUiEventLogger = uiEventLogger;
|
mUiEventLogger = uiEventLogger;
|
||||||
mUserId = userId;
|
mUserId = userId;
|
||||||
}
|
}
|
||||||
@@ -183,7 +141,7 @@ public class GuestResumeSessionReceiver extends BroadcastReceiver {
|
|||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
if (which == BUTTON_WIPE) {
|
if (which == BUTTON_WIPE) {
|
||||||
mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_WIPE);
|
mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_WIPE);
|
||||||
wipeGuestSession(getContext(), mUserId);
|
mUserSwitcherController.removeGuestUser(mUserId, UserHandle.USER_NULL);
|
||||||
dismiss();
|
dismiss();
|
||||||
} else if (which == BUTTON_DONTWIPE) {
|
} else if (which == BUTTON_DONTWIPE) {
|
||||||
mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_CONTINUE);
|
mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_CONTINUE);
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ import com.android.systemui.statusbar.phone.NotificationPanelViewController;
|
|||||||
import com.android.systemui.statusbar.phone.StatusBar;
|
import com.android.systemui.statusbar.phone.StatusBar;
|
||||||
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
|
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||||
|
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
||||||
import com.android.systemui.util.DeviceConfigProxy;
|
import com.android.systemui.util.DeviceConfigProxy;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
@@ -257,6 +258,9 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
|
|||||||
/** TrustManager for letting it know when we change visibility */
|
/** TrustManager for letting it know when we change visibility */
|
||||||
private final TrustManager mTrustManager;
|
private final TrustManager mTrustManager;
|
||||||
|
|
||||||
|
/** UserSwitcherController for creating guest user on boot complete */
|
||||||
|
private final UserSwitcherController mUserSwitcherController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to keep the device awake while to ensure the keyguard finishes opening before
|
* Used to keep the device awake while to ensure the keyguard finishes opening before
|
||||||
* we sleep.
|
* we sleep.
|
||||||
@@ -805,6 +809,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
|
|||||||
KeyguardUpdateMonitor keyguardUpdateMonitor, DumpManager dumpManager,
|
KeyguardUpdateMonitor keyguardUpdateMonitor, DumpManager dumpManager,
|
||||||
@UiBackground Executor uiBgExecutor, PowerManager powerManager,
|
@UiBackground Executor uiBgExecutor, PowerManager powerManager,
|
||||||
TrustManager trustManager,
|
TrustManager trustManager,
|
||||||
|
UserSwitcherController userSwitcherController,
|
||||||
DeviceConfigProxy deviceConfig,
|
DeviceConfigProxy deviceConfig,
|
||||||
NavigationModeController navigationModeController,
|
NavigationModeController navigationModeController,
|
||||||
KeyguardDisplayManager keyguardDisplayManager,
|
KeyguardDisplayManager keyguardDisplayManager,
|
||||||
@@ -825,6 +830,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
|
|||||||
mUpdateMonitor = keyguardUpdateMonitor;
|
mUpdateMonitor = keyguardUpdateMonitor;
|
||||||
mPM = powerManager;
|
mPM = powerManager;
|
||||||
mTrustManager = trustManager;
|
mTrustManager = trustManager;
|
||||||
|
mUserSwitcherController = userSwitcherController;
|
||||||
mKeyguardDisplayManager = keyguardDisplayManager;
|
mKeyguardDisplayManager = keyguardDisplayManager;
|
||||||
dumpManager.registerDumpable(getClass().getName(), this);
|
dumpManager.registerDumpable(getClass().getName(), this);
|
||||||
mDeviceConfig = deviceConfig;
|
mDeviceConfig = deviceConfig;
|
||||||
@@ -2558,6 +2564,11 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
|
|||||||
@Override
|
@Override
|
||||||
public void onBootCompleted() {
|
public void onBootCompleted() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
if (mContext.getResources().getBoolean(
|
||||||
|
com.android.internal.R.bool.config_guestUserAutoCreated)) {
|
||||||
|
// TODO(b/191067027): Move post-boot guest creation to system_server
|
||||||
|
mUserSwitcherController.guaranteeGuestPresent();
|
||||||
|
}
|
||||||
mBootCompleted = true;
|
mBootCompleted = true;
|
||||||
adjustStatusBarLocked(false, true);
|
adjustStatusBarLocked(false, true);
|
||||||
if (mBootSendUserPresent) {
|
if (mBootSendUserPresent) {
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import com.android.systemui.statusbar.phone.KeyguardLiftController;
|
|||||||
import com.android.systemui.statusbar.phone.StatusBar;
|
import com.android.systemui.statusbar.phone.StatusBar;
|
||||||
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
|
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||||
|
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
||||||
import com.android.systemui.util.DeviceConfigProxy;
|
import com.android.systemui.util.DeviceConfigProxy;
|
||||||
import com.android.systemui.util.sensors.AsyncSensorManager;
|
import com.android.systemui.util.sensors.AsyncSensorManager;
|
||||||
import com.android.systemui.util.settings.GlobalSettings;
|
import com.android.systemui.util.settings.GlobalSettings;
|
||||||
@@ -92,6 +93,7 @@ public class KeyguardModule {
|
|||||||
DumpManager dumpManager,
|
DumpManager dumpManager,
|
||||||
PowerManager powerManager,
|
PowerManager powerManager,
|
||||||
TrustManager trustManager,
|
TrustManager trustManager,
|
||||||
|
UserSwitcherController userSwitcherController,
|
||||||
@UiBackground Executor uiBgExecutor,
|
@UiBackground Executor uiBgExecutor,
|
||||||
DeviceConfigProxy deviceConfig,
|
DeviceConfigProxy deviceConfig,
|
||||||
NavigationModeController navigationModeController,
|
NavigationModeController navigationModeController,
|
||||||
@@ -114,6 +116,7 @@ public class KeyguardModule {
|
|||||||
uiBgExecutor,
|
uiBgExecutor,
|
||||||
powerManager,
|
powerManager,
|
||||||
trustManager,
|
trustManager,
|
||||||
|
userSwitcherController,
|
||||||
deviceConfig,
|
deviceConfig,
|
||||||
navigationModeController,
|
navigationModeController,
|
||||||
keyguardDisplayManager,
|
keyguardDisplayManager,
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import static android.os.UserManager.SWITCHABILITY_STATUS_OK;
|
|||||||
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||||
import static com.android.systemui.DejankUtils.whitelistIpcs;
|
import static com.android.systemui.DejankUtils.whitelistIpcs;
|
||||||
|
|
||||||
|
import android.annotation.UserIdInt;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.IActivityTaskManager;
|
import android.app.IActivityTaskManager;
|
||||||
@@ -48,6 +49,7 @@ import android.util.SparseArray;
|
|||||||
import android.util.SparseBooleanArray;
|
import android.util.SparseBooleanArray;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.WindowManagerGlobal;
|
||||||
import android.widget.BaseAdapter;
|
import android.widget.BaseAdapter;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
@@ -63,6 +65,7 @@ import com.android.systemui.SystemUISecondaryUserService;
|
|||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||||
import com.android.systemui.dagger.SysUISingleton;
|
import com.android.systemui.dagger.SysUISingleton;
|
||||||
import com.android.systemui.dagger.qualifiers.Main;
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
|
import com.android.systemui.dagger.qualifiers.UiBackground;
|
||||||
import com.android.systemui.plugins.ActivityStarter;
|
import com.android.systemui.plugins.ActivityStarter;
|
||||||
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;
|
||||||
@@ -76,6 +79,8 @@ import java.io.PrintWriter;
|
|||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Provider;
|
import javax.inject.Provider;
|
||||||
@@ -123,23 +128,35 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
|
private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
|
||||||
private final UiEventLogger mUiEventLogger;
|
private final UiEventLogger mUiEventLogger;
|
||||||
public final DetailAdapter mUserDetailAdapter;
|
public final DetailAdapter mUserDetailAdapter;
|
||||||
|
private final Executor mUiBgExecutor;
|
||||||
|
private final boolean mGuestUserAutoCreated;
|
||||||
|
private final AtomicBoolean mGuestCreationScheduled;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public UserSwitcherController(Context context, KeyguardStateController keyguardStateController,
|
public UserSwitcherController(Context context,
|
||||||
@Main Handler handler, ActivityStarter activityStarter,
|
KeyguardStateController keyguardStateController,
|
||||||
BroadcastDispatcher broadcastDispatcher, UiEventLogger uiEventLogger,
|
@Main Handler handler,
|
||||||
|
ActivityStarter activityStarter,
|
||||||
|
BroadcastDispatcher broadcastDispatcher,
|
||||||
|
UiEventLogger uiEventLogger,
|
||||||
TelephonyListenerManager telephonyListenerManager,
|
TelephonyListenerManager telephonyListenerManager,
|
||||||
IActivityTaskManager activityTaskManager, UserDetailAdapter userDetailAdapter) {
|
IActivityTaskManager activityTaskManager,
|
||||||
|
UserDetailAdapter userDetailAdapter,
|
||||||
|
@UiBackground Executor uiBgExecutor) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mBroadcastDispatcher = broadcastDispatcher;
|
mBroadcastDispatcher = broadcastDispatcher;
|
||||||
mTelephonyListenerManager = telephonyListenerManager;
|
mTelephonyListenerManager = telephonyListenerManager;
|
||||||
mActivityTaskManager = activityTaskManager;
|
mActivityTaskManager = activityTaskManager;
|
||||||
mUiEventLogger = uiEventLogger;
|
mUiEventLogger = uiEventLogger;
|
||||||
mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(mUiEventLogger);
|
mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(this, mUiEventLogger);
|
||||||
mUserDetailAdapter = userDetailAdapter;
|
mUserDetailAdapter = userDetailAdapter;
|
||||||
|
mUiBgExecutor = uiBgExecutor;
|
||||||
if (!UserManager.isGuestUserEphemeral()) {
|
if (!UserManager.isGuestUserEphemeral()) {
|
||||||
mGuestResumeSessionReceiver.register(mBroadcastDispatcher);
|
mGuestResumeSessionReceiver.register(mBroadcastDispatcher);
|
||||||
}
|
}
|
||||||
|
mGuestUserAutoCreated = mContext.getResources().getBoolean(
|
||||||
|
com.android.internal.R.bool.config_guestUserAutoCreated);
|
||||||
|
mGuestCreationScheduled = new AtomicBoolean();
|
||||||
mKeyguardStateController = keyguardStateController;
|
mKeyguardStateController = keyguardStateController;
|
||||||
mHandler = handler;
|
mHandler = handler;
|
||||||
mActivityStarter = activityStarter;
|
mActivityStarter = activityStarter;
|
||||||
@@ -379,21 +396,13 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
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.
|
||||||
UserInfo guest;
|
int guestId = createGuest();
|
||||||
try {
|
if (guestId == UserHandle.USER_NULL) {
|
||||||
guest = mUserManager.createGuest(mContext,
|
// This may happen if we haven't reloaded the user list yet.
|
||||||
mContext.getString(com.android.settingslib.R.string.guest_nickname));
|
|
||||||
} catch (UserManager.UserOperationException e) {
|
|
||||||
Log.e(TAG, "Couldn't create guest user", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (guest == null) {
|
|
||||||
// Couldn't create guest, most likely because there already exists one, we just
|
|
||||||
// haven't reloaded the user list yet.
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_ADD);
|
mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_ADD);
|
||||||
id = guest.id;
|
id = guestId;
|
||||||
} else if (record.isAddUser) {
|
} else if (record.isAddUser) {
|
||||||
showAddUserDialog();
|
showAddUserDialog();
|
||||||
return;
|
return;
|
||||||
@@ -457,11 +466,6 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
mAddUserDialog.show();
|
mAddUserDialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void exitGuest(int id, int targetId) {
|
|
||||||
switchToUserId(targetId);
|
|
||||||
mUserManager.removeUser(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void listenForCallState() {
|
private void listenForCallState() {
|
||||||
mTelephonyListenerManager.addCallStateListener(mPhoneStateListener);
|
mTelephonyListenerManager.addCallStateListener(mPhoneStateListener);
|
||||||
}
|
}
|
||||||
@@ -576,6 +580,7 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
pw.print(" "); pw.println(u.toString());
|
pw.print(" "); pw.println(u.toString());
|
||||||
}
|
}
|
||||||
pw.println("mSimpleUserSwitcher=" + mSimpleUserSwitcher);
|
pw.println("mSimpleUserSwitcher=" + mSimpleUserSwitcher);
|
||||||
|
pw.println("mGuestUserAutoCreated=" + mGuestUserAutoCreated);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the name of the current user of the phone. */
|
/** Returns the name of the current user of the phone. */
|
||||||
@@ -602,6 +607,126 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
return mUsers;
|
return mUsers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes guest user and switches to target user. The guest must be the current user and its id
|
||||||
|
* must be {@code guestUserId}.
|
||||||
|
*
|
||||||
|
* <p>If {@code targetUserId} is {@link UserHandle.USER_NULL}, then create a new guest user in
|
||||||
|
* the foreground, and immediately switch to it. This is used for wiping the current guest and
|
||||||
|
* replacing it with a new one.
|
||||||
|
*
|
||||||
|
* <p>If {@code targetUserId} is specified, then remove the guest in the background while
|
||||||
|
* switching to {@code targetUserId}.
|
||||||
|
*
|
||||||
|
* <p>If device is configured with {@link
|
||||||
|
* com.android.internal.R.bool.config_guestUserAutoCreated}, then after guest user is removed, a
|
||||||
|
* new one is created in the background. This has no effect if {@code targetUserId} is {@link
|
||||||
|
* UserHandle.USER_NULL}.
|
||||||
|
*
|
||||||
|
* @param guestUserId id of the guest user to remove
|
||||||
|
* @param targetUserId id of the user to switch to after guest is removed. If {@link
|
||||||
|
* UserHandle.USER_NULL}, then switch immediately to the newly created guest user.
|
||||||
|
*/
|
||||||
|
public void removeGuestUser(@UserIdInt int guestUserId, @UserIdInt int targetUserId) {
|
||||||
|
UserInfo currentUser;
|
||||||
|
try {
|
||||||
|
currentUser = ActivityManager.getService().getCurrentUser();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "Couldn't remove guest because ActivityManager is dead");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (currentUser.id != guestUserId) {
|
||||||
|
Log.w(TAG, "User requesting to start a new session (" + guestUserId + ")"
|
||||||
|
+ " is not current user (" + currentUser.id + ")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!currentUser.isGuest()) {
|
||||||
|
Log.w(TAG, "User requesting to start a new session (" + guestUserId + ")"
|
||||||
|
+ " is not a guest");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean marked = mUserManager.markGuestForDeletion(currentUser.id);
|
||||||
|
if (!marked) {
|
||||||
|
Log.w(TAG, "Couldn't mark the guest for deletion for user " + guestUserId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (targetUserId == UserHandle.USER_NULL) {
|
||||||
|
// Create a new guest in the foreground, and then immediately switch to it
|
||||||
|
int newGuestId = createGuest();
|
||||||
|
if (newGuestId == UserHandle.USER_NULL) {
|
||||||
|
Log.e(TAG, "Could not create new guest, switching back to system user");
|
||||||
|
switchToUserId(UserHandle.USER_SYSTEM);
|
||||||
|
mUserManager.removeUser(currentUser.id);
|
||||||
|
WindowManagerGlobal.getWindowManagerService().lockNow(/* options= */ null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switchToUserId(newGuestId);
|
||||||
|
mUserManager.removeUser(currentUser.id);
|
||||||
|
} else {
|
||||||
|
if (mGuestUserAutoCreated) {
|
||||||
|
// TODO(b/191067027): Move guest recreation to system_server
|
||||||
|
scheduleGuestCreation();
|
||||||
|
}
|
||||||
|
switchToUserId(targetUserId);
|
||||||
|
}
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "Couldn't remove guest because ActivityManager or WindowManager is dead");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleGuestCreation() {
|
||||||
|
if (!mGuestCreationScheduled.compareAndSet(false, true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mUiBgExecutor.execute(() -> {
|
||||||
|
int newGuestId = createGuest();
|
||||||
|
if (newGuestId == UserHandle.USER_NULL) {
|
||||||
|
Log.w(TAG, "Could not create new guest while exiting existing guest");
|
||||||
|
}
|
||||||
|
mGuestCreationScheduled.set(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If there is no guest on the device, schedule creation of a new guest user in the background.
|
||||||
|
*/
|
||||||
|
public void guaranteeGuestPresent() {
|
||||||
|
if (mUserManager.findCurrentGuestUser() == null) {
|
||||||
|
scheduleGuestCreation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a guest user and return its multi-user user ID.
|
||||||
|
*
|
||||||
|
* This method does not check if a guest already exists before it makes a call to
|
||||||
|
* {@link UserManager} to create a new one.
|
||||||
|
*
|
||||||
|
* @return The multi-user user ID of the newly created guest user, or
|
||||||
|
* {@link UserHandle.USER_NULL} if the guest couldn't be created.
|
||||||
|
*/
|
||||||
|
public @UserIdInt int createGuest() {
|
||||||
|
UserInfo guest;
|
||||||
|
try {
|
||||||
|
guest = mUserManager.createGuest(mContext,
|
||||||
|
mContext.getString(com.android.settingslib.R.string.guest_nickname));
|
||||||
|
} catch (UserManager.UserOperationException e) {
|
||||||
|
Log.e(TAG, "Couldn't create guest user", e);
|
||||||
|
return UserHandle.USER_NULL;
|
||||||
|
}
|
||||||
|
if (guest == null) {
|
||||||
|
Log.e(TAG, "Couldn't create guest, most likely because there already exists one");
|
||||||
|
return UserHandle.USER_NULL;
|
||||||
|
}
|
||||||
|
return guest.id;
|
||||||
|
}
|
||||||
|
|
||||||
public static abstract class BaseUserAdapter extends BaseAdapter {
|
public static abstract class BaseUserAdapter extends BaseAdapter {
|
||||||
|
|
||||||
final UserSwitcherController mController;
|
final UserSwitcherController mController;
|
||||||
@@ -662,10 +787,15 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
public String getName(Context context, UserRecord item) {
|
public String getName(Context context, UserRecord item) {
|
||||||
if (item.isGuest) {
|
if (item.isGuest) {
|
||||||
if (item.isCurrent) {
|
if (item.isCurrent) {
|
||||||
return context.getString(com.android.settingslib.R.string.guest_exit_guest);
|
return context.getString(mController.mGuestUserAutoCreated
|
||||||
|
? com.android.settingslib.R.string.guest_reset_guest
|
||||||
|
: com.android.settingslib.R.string.guest_exit_guest);
|
||||||
} else {
|
} else {
|
||||||
|
// If config_guestUserAutoCreated, always show guest nickname instead of "Add
|
||||||
|
// guest" to make it seem as though the device always has a guest ready for use
|
||||||
return context.getString(
|
return context.getString(
|
||||||
item.info == null ? com.android.settingslib.R.string.guest_new_guest
|
item.info == null && !mController.mGuestUserAutoCreated
|
||||||
|
? com.android.settingslib.R.string.guest_new_guest
|
||||||
: com.android.settingslib.R.string.guest_nickname);
|
: com.android.settingslib.R.string.guest_nickname);
|
||||||
}
|
}
|
||||||
} else if (item.isAddUser) {
|
} else if (item.isAddUser) {
|
||||||
@@ -882,12 +1012,15 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
|
|
||||||
public ExitGuestDialog(Context context, int guestId, int targetId) {
|
public ExitGuestDialog(Context context, int guestId, int targetId) {
|
||||||
super(context);
|
super(context);
|
||||||
setTitle(R.string.guest_exit_guest_dialog_title);
|
setTitle(mGuestUserAutoCreated ? R.string.guest_reset_guest_dialog_title
|
||||||
|
: R.string.guest_exit_guest_dialog_title);
|
||||||
setMessage(context.getString(R.string.guest_exit_guest_dialog_message));
|
setMessage(context.getString(R.string.guest_exit_guest_dialog_message));
|
||||||
setButton(DialogInterface.BUTTON_NEGATIVE,
|
setButton(DialogInterface.BUTTON_NEGATIVE,
|
||||||
context.getString(android.R.string.cancel), this);
|
context.getString(android.R.string.cancel), this);
|
||||||
setButton(DialogInterface.BUTTON_POSITIVE,
|
setButton(DialogInterface.BUTTON_POSITIVE,
|
||||||
context.getString(R.string.guest_exit_guest_dialog_remove), this);
|
context.getString(
|
||||||
|
mGuestUserAutoCreated ? R.string.guest_reset_guest_dialog_remove
|
||||||
|
: R.string.guest_exit_guest_dialog_remove), this);
|
||||||
SystemUIDialog.setWindowOnTop(this);
|
SystemUIDialog.setWindowOnTop(this);
|
||||||
setCanceledOnTouchOutside(false);
|
setCanceledOnTouchOutside(false);
|
||||||
mGuestId = guestId;
|
mGuestId = guestId;
|
||||||
@@ -901,7 +1034,7 @@ public class UserSwitcherController implements Dumpable {
|
|||||||
} else {
|
} else {
|
||||||
mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE);
|
mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE);
|
||||||
dismiss();
|
dismiss();
|
||||||
exitGuest(mGuestId, mTargetId);
|
removeGuestUser(mGuestId, mTargetId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import com.android.systemui.statusbar.phone.DozeParameters;
|
|||||||
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
|
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
|
||||||
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
|
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||||
|
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
||||||
import com.android.systemui.util.DeviceConfigProxy;
|
import com.android.systemui.util.DeviceConfigProxy;
|
||||||
import com.android.systemui.util.DeviceConfigProxyFake;
|
import com.android.systemui.util.DeviceConfigProxyFake;
|
||||||
import com.android.systemui.util.concurrency.FakeExecutor;
|
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||||
@@ -78,6 +79,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
|
|||||||
private @Mock DumpManager mDumpManager;
|
private @Mock DumpManager mDumpManager;
|
||||||
private @Mock PowerManager mPowerManager;
|
private @Mock PowerManager mPowerManager;
|
||||||
private @Mock TrustManager mTrustManager;
|
private @Mock TrustManager mTrustManager;
|
||||||
|
private @Mock UserSwitcherController mUserSwitcherController;
|
||||||
private @Mock NavigationModeController mNavigationModeController;
|
private @Mock NavigationModeController mNavigationModeController;
|
||||||
private @Mock KeyguardDisplayManager mKeyguardDisplayManager;
|
private @Mock KeyguardDisplayManager mKeyguardDisplayManager;
|
||||||
private @Mock DozeParameters mDozeParameters;
|
private @Mock DozeParameters mDozeParameters;
|
||||||
@@ -100,13 +102,27 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
|
|||||||
when(mPowerManager.newWakeLock(anyInt(), any())).thenReturn(mock(WakeLock.class));
|
when(mPowerManager.newWakeLock(anyInt(), any())).thenReturn(mock(WakeLock.class));
|
||||||
|
|
||||||
mViewMediator = new KeyguardViewMediator(
|
mViewMediator = new KeyguardViewMediator(
|
||||||
mContext, mFalsingCollector, mLockPatternUtils, mBroadcastDispatcher,
|
mContext,
|
||||||
|
mFalsingCollector,
|
||||||
|
mLockPatternUtils,
|
||||||
|
mBroadcastDispatcher,
|
||||||
() -> mStatusBarKeyguardViewManager,
|
() -> mStatusBarKeyguardViewManager,
|
||||||
mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor,
|
mDismissCallbackRegistry,
|
||||||
mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController,
|
mUpdateMonitor,
|
||||||
mKeyguardDisplayManager, mDozeParameters, mStatusBarStateController,
|
mDumpManager,
|
||||||
mKeyguardStateController, () -> mKeyguardUnlockAnimationController,
|
mUiBgExecutor,
|
||||||
mUnlockedScreenOffAnimationController, () -> mNotificationShadeDepthController);
|
mPowerManager,
|
||||||
|
mTrustManager,
|
||||||
|
mUserSwitcherController,
|
||||||
|
mDeviceConfig,
|
||||||
|
mNavigationModeController,
|
||||||
|
mKeyguardDisplayManager,
|
||||||
|
mDozeParameters,
|
||||||
|
mStatusBarStateController,
|
||||||
|
mKeyguardStateController,
|
||||||
|
() -> mKeyguardUnlockAnimationController,
|
||||||
|
mUnlockedScreenOffAnimationController,
|
||||||
|
() -> mNotificationShadeDepthController);
|
||||||
mViewMediator.start();
|
mViewMediator.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user