Make use of config for auto-created guest users
If frameworks config config_guestUserAutoCreated=true, then Settings will: - Create a new guest user any time the current guest user is removed - Show "Guest" instead of "Add guest" - Show "Reset guest" instead of "Remove guest" Bug: 188542158 Test: With config_guestUserAutoCreated=true, delete current guest user using adb (`adb shell cmd user list -v --all` to find the user ids, then remove each guest user with `adb shell pm remove-user <id>`), then as owner, open multi-users settings page. Check that there is a item for "Guest" instead of "Add guest". Select "Guest", then confirm there is an item for "Reset guest" (it should be disabled). Select "Switch to guest", then switch back to owner. Open the multi-users settings page again. Check that "Reset guest" is now enabled. Tap "Reset guest", and press confirmation button, named "Reset". You should be take back to the main multi-user settings page and still see "Guest". Wait a few seconds, then use adb to confirm there is a guest user present. Test: With config_guestUserAutoCreated=true, switch to guest user, open multi-users settings page, check that there is an option to "Reset guest". Select "Reset guest", and press confirmation button, named "Reset". Phone should switch back to last active user, and QS tile should now show "Guest" instead of "Add guest". Run `adb shell cmd user list -v --all` to confirm guest has a new user id. Test: With config_guestUserAutoCreated=false, confirm that "Add guest" and "Remove guest" features remain unchanged Change-Id: I7d5b81bd2e5c6b999ae18cd6b1280ae0496db94b
This commit is contained in:
@@ -42,6 +42,9 @@ import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
import com.android.settingslib.RestrictedPreference;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Settings screen for configuring, deleting or switching to a specific user.
|
||||
@@ -67,9 +70,13 @@ public class UserDetailsSettings extends SettingsPreferenceFragment
|
||||
private static final int DIALOG_CONFIRM_ENABLE_CALLING = 2;
|
||||
private static final int DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS = 3;
|
||||
private static final int DIALOG_SETUP_USER = 4;
|
||||
private static final int DIALOG_CONFIRM_RESET_GUEST = 5;
|
||||
|
||||
private UserManager mUserManager;
|
||||
private UserCapabilities mUserCaps;
|
||||
private boolean mGuestUserAutoCreated;
|
||||
private final AtomicBoolean mGuestCreationScheduled = new AtomicBoolean();
|
||||
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
|
||||
|
||||
@VisibleForTesting
|
||||
RestrictedPreference mSwitchUserPref;
|
||||
@@ -97,6 +104,9 @@ public class UserDetailsSettings extends SettingsPreferenceFragment
|
||||
mUserCaps = UserCapabilities.create(context);
|
||||
addPreferencesFromResource(R.xml.user_details_settings);
|
||||
|
||||
mGuestUserAutoCreated = getPrefContext().getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_guestUserAutoCreated);
|
||||
|
||||
initialize(context, getArguments());
|
||||
}
|
||||
|
||||
@@ -104,13 +114,20 @@ public class UserDetailsSettings extends SettingsPreferenceFragment
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
mSwitchUserPref.setEnabled(canSwitchUserNow());
|
||||
if (mGuestUserAutoCreated) {
|
||||
mRemoveUserPref.setEnabled((mUserInfo.flags & UserInfo.FLAG_INITIALIZED) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
if (preference == mRemoveUserPref) {
|
||||
if (canDeleteUser()) {
|
||||
if (mUserInfo.isGuest()) {
|
||||
showDialog(DIALOG_CONFIRM_RESET_GUEST);
|
||||
} else {
|
||||
showDialog(DIALOG_CONFIRM_REMOVE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else if (preference == mSwitchUserPref) {
|
||||
@@ -144,6 +161,7 @@ public class UserDetailsSettings extends SettingsPreferenceFragment
|
||||
public int getDialogMetricsCategory(int dialogId) {
|
||||
switch (dialogId) {
|
||||
case DIALOG_CONFIRM_REMOVE:
|
||||
case DIALOG_CONFIRM_RESET_GUEST:
|
||||
return SettingsEnums.DIALOG_USER_REMOVE;
|
||||
case DIALOG_CONFIRM_ENABLE_CALLING:
|
||||
return SettingsEnums.DIALOG_USER_ENABLE_CALLING;
|
||||
@@ -179,10 +197,30 @@ public class UserDetailsSettings extends SettingsPreferenceFragment
|
||||
switchUser();
|
||||
}
|
||||
});
|
||||
case DIALOG_CONFIRM_RESET_GUEST:
|
||||
return UserDialogs.createResetGuestDialog(getActivity(),
|
||||
(dialog, which) -> resetGuest());
|
||||
}
|
||||
throw new IllegalArgumentException("Unsupported dialogId " + dialogId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase the current guest user and create a new one in the background. UserSettings will
|
||||
* handle guest creation after receiving the {@link UserSettings.RESULT_GUEST_REMOVED} result.
|
||||
*/
|
||||
private void resetGuest() {
|
||||
// Just to be safe, check that the selected user is a guest
|
||||
if (!mUserInfo.isGuest()) {
|
||||
return;
|
||||
}
|
||||
mMetricsFeatureProvider.action(getActivity(),
|
||||
SettingsEnums.ACTION_USER_GUEST_EXIT_CONFIRMED);
|
||||
|
||||
mUserManager.removeUser(mUserInfo.id);
|
||||
setResult(UserSettings.RESULT_GUEST_REMOVED);
|
||||
finishFragment();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Override
|
||||
protected void showDialog(int dialogId) {
|
||||
@@ -239,11 +277,17 @@ public class UserDetailsSettings extends SettingsPreferenceFragment
|
||||
if (mUserInfo.isGuest()) {
|
||||
// These are not for an existing user, just general Guest settings.
|
||||
// Default title is for calling and SMS. Change to calling-only here
|
||||
// TODO(b/191483069): These settings can't be changed unless guest user exists
|
||||
mPhonePref.setTitle(R.string.user_enable_calling);
|
||||
mDefaultGuestRestrictions = mUserManager.getDefaultGuestRestrictions();
|
||||
mPhonePref.setChecked(
|
||||
!mDefaultGuestRestrictions.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
|
||||
mRemoveUserPref.setTitle(R.string.user_exit_guest_title);
|
||||
mRemoveUserPref.setTitle(mGuestUserAutoCreated
|
||||
? com.android.settingslib.R.string.guest_reset_guest
|
||||
: R.string.user_exit_guest_title);
|
||||
if (mGuestUserAutoCreated) {
|
||||
mRemoveUserPref.setEnabled((mUserInfo.flags & UserInfo.FLAG_INITIALIZED) != 0);
|
||||
}
|
||||
} else {
|
||||
mPhonePref.setChecked(!mUserManager.hasUserRestriction(
|
||||
UserManager.DISALLOW_OUTGOING_CALLS, new UserHandle(userId)));
|
||||
|
@@ -154,4 +154,24 @@ public final class UserDialogs {
|
||||
null)
|
||||
.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a dialog to confirm with the user if it's ok to reset the guest user, which will
|
||||
* delete all the guest user's data.
|
||||
*
|
||||
* @param context a Context object
|
||||
* @param onConfirmListener Callback object for positive action
|
||||
* @return the created Dialog
|
||||
*/
|
||||
public static Dialog createResetGuestDialog(Context context,
|
||||
DialogInterface.OnClickListener onConfirmListener) {
|
||||
return new AlertDialog.Builder(context)
|
||||
.setTitle(com.android.settingslib.R.string.guest_reset_guest_dialog_title)
|
||||
.setMessage(R.string.user_exit_guest_confirm_message)
|
||||
.setPositiveButton(
|
||||
com.android.settingslib.R.string.guest_reset_guest_confirm_button,
|
||||
onConfirmListener)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
}
|
||||
}
|
||||
|
@@ -87,6 +87,9 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Screen that manages the list of users on the device.
|
||||
@@ -128,6 +131,7 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
private static final int DIALOG_USER_PROFILE_EDITOR = 9;
|
||||
private static final int DIALOG_USER_PROFILE_EDITOR_ADD_USER = 10;
|
||||
private static final int DIALOG_USER_PROFILE_EDITOR_ADD_RESTRICTED_PROFILE = 11;
|
||||
private static final int DIALOG_CONFIRM_RESET_GUEST = 12;
|
||||
|
||||
private static final int MESSAGE_UPDATE_LIST = 1;
|
||||
private static final int MESSAGE_USER_CREATED = 2;
|
||||
@@ -136,6 +140,9 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
private static final int USER_TYPE_RESTRICTED_PROFILE = 2;
|
||||
|
||||
private static final int REQUEST_CHOOSE_LOCK = 10;
|
||||
private static final int REQUEST_EDIT_GUEST = 11;
|
||||
|
||||
static final int RESULT_GUEST_REMOVED = 100;
|
||||
|
||||
private static final String KEY_ADD_USER_LONG_MESSAGE_DISPLAYED =
|
||||
"key_add_user_long_message_displayed";
|
||||
@@ -160,6 +167,7 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
SparseArray<Bitmap> mUserIcons = new SparseArray<>();
|
||||
private int mRemovingUserId = -1;
|
||||
private boolean mAddingUser;
|
||||
private boolean mGuestUserAutoCreated;
|
||||
private String mAddingUserName;
|
||||
private UserCapabilities mUserCaps;
|
||||
private boolean mShouldUpdateUserList = true;
|
||||
@@ -173,6 +181,8 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
private AddUserWhenLockedPreferenceController mAddUserWhenLockedPreferenceController;
|
||||
private MultiUserTopIntroPreferenceController mMultiUserTopIntroPreferenceController;
|
||||
private UserCreatingDialog mUserCreatingDialog;
|
||||
private final AtomicBoolean mGuestCreationScheduled = new AtomicBoolean();
|
||||
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
|
||||
|
||||
private CharSequence mPendingUserName;
|
||||
private Drawable mPendingUserIcon;
|
||||
@@ -240,6 +250,9 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
return;
|
||||
}
|
||||
|
||||
mGuestUserAutoCreated = getPrefContext().getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_guestUserAutoCreated);
|
||||
|
||||
mAddUserWhenLockedPreferenceController = new AddUserWhenLockedPreferenceController(
|
||||
activity, KEY_ADD_USER_WHEN_LOCKED);
|
||||
|
||||
@@ -343,7 +356,10 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
int pos = 0;
|
||||
if (!mUserCaps.mIsAdmin && canSwitchUserNow()) {
|
||||
// TODO(b/191509236): The menu item does not need to be accessible for guest users,
|
||||
// regardless of mGuestUserAutoCreated
|
||||
if (!mUserCaps.mIsAdmin && canSwitchUserNow() && !(isCurrentUserGuest()
|
||||
&& mGuestUserAutoCreated)) {
|
||||
String nickname = mUserManager.getUserName();
|
||||
MenuItem removeThisUser = menu.add(0, MENU_REMOVE_USER, pos++,
|
||||
getResources().getString(R.string.user_remove_user_menu, nickname));
|
||||
@@ -387,7 +403,9 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
if (isCurrentUserGuest()) {
|
||||
// No need to load profile information
|
||||
mMePreference.setIcon(getEncircledDefaultIcon());
|
||||
mMePreference.setTitle(R.string.user_exit_guest_title);
|
||||
mMePreference.setTitle(
|
||||
mGuestUserAutoCreated ? com.android.settingslib.R.string.guest_reset_guest
|
||||
: R.string.user_exit_guest_title);
|
||||
mMePreference.setSelectable(true);
|
||||
// removing a guest will result in switching back to the admin user
|
||||
mMePreference.setEnabled(canSwitchUserNow());
|
||||
@@ -445,6 +463,9 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
if (resultCode != Activity.RESULT_CANCELED && hasLockscreenSecurity()) {
|
||||
addUserNow(USER_TYPE_RESTRICTED_PROFILE);
|
||||
}
|
||||
} else if (mGuestUserAutoCreated && requestCode == REQUEST_EDIT_GUEST
|
||||
&& resultCode == RESULT_GUEST_REMOVED) {
|
||||
scheduleGuestCreation();
|
||||
} else {
|
||||
mEditUserInfoController.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
@@ -508,12 +529,15 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
extras.putBoolean(AppRestrictionsFragment.EXTRA_NEW_USER, newUser);
|
||||
|
||||
final Context context = getContext();
|
||||
new SubSettingLauncher(context)
|
||||
SubSettingLauncher launcher = new SubSettingLauncher(context)
|
||||
.setDestination(UserDetailsSettings.class.getName())
|
||||
.setArguments(extras)
|
||||
.setTitleText(getUserName(context, userInfo))
|
||||
.setSourceMetricsCategory(getMetricsCategory())
|
||||
.launch();
|
||||
.setSourceMetricsCategory(getMetricsCategory());
|
||||
if (mGuestUserAutoCreated && userInfo.isGuest()) {
|
||||
launcher.setResultListener(this, REQUEST_EDIT_GUEST);
|
||||
}
|
||||
launcher.launch();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -651,6 +675,10 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
}
|
||||
return buildAddUserDialog(USER_TYPE_RESTRICTED_PROFILE);
|
||||
}
|
||||
case DIALOG_CONFIRM_RESET_GUEST: {
|
||||
return UserDialogs.createResetGuestDialog(getActivity(),
|
||||
(dialog, which) -> resetGuest());
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -727,6 +755,7 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
case DIALOG_NEED_LOCKSCREEN:
|
||||
return SettingsEnums.DIALOG_USER_NEED_LOCKSCREEN;
|
||||
case DIALOG_CONFIRM_EXIT_GUEST:
|
||||
case DIALOG_CONFIRM_RESET_GUEST:
|
||||
return SettingsEnums.DIALOG_USER_CONFIRM_EXIT_GUEST;
|
||||
case DIALOG_USER_PROFILE_EDITOR:
|
||||
case DIALOG_USER_PROFILE_EDITOR_ADD_USER:
|
||||
@@ -840,6 +869,55 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
removeThisUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase the current user (assuming it is a guest user), and create a new one in the background
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void resetGuest() {
|
||||
// Just to be safe
|
||||
if (!isCurrentUserGuest()) {
|
||||
return;
|
||||
}
|
||||
int guestUserId = UserHandle.myUserId();
|
||||
// Using markGuestForDeletion allows us to create a new guest before this one is
|
||||
// fully removed. This could happen if someone calls scheduleGuestCreation()
|
||||
// immediately after calling this method.
|
||||
boolean marked = mUserManager.markGuestForDeletion(guestUserId);
|
||||
if (!marked) {
|
||||
Log.w(TAG, "Couldn't mark the guest for deletion for user " + guestUserId);
|
||||
return;
|
||||
}
|
||||
exitGuest();
|
||||
scheduleGuestCreation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a guest user in the background
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void scheduleGuestCreation() {
|
||||
// TODO(b/191067027): Move guest recreation to system_server
|
||||
if (mGuestCreationScheduled.compareAndSet(/* expect= */ false, /* update= */ true)) {
|
||||
// Once mGuestCreationScheduled=true, mAddGuest needs to be updated so that it shows
|
||||
// "Resetting guest..."
|
||||
mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
|
||||
mExecutor.execute(() -> {
|
||||
UserInfo guest = mUserManager.createGuest(
|
||||
getContext(), getString(com.android.settingslib.R.string.user_guest));
|
||||
mGuestCreationScheduled.set(false);
|
||||
if (guest == null) {
|
||||
Log.e(TAG, "Unable to automatically recreate guest user");
|
||||
}
|
||||
// The list needs to be updated whether or not guest creation worked. If guest
|
||||
// creation failed, the list needs to update so that "Add guest" is displayed.
|
||||
// Otherwise, the UX could be stuck in a state where there is no way to switch to
|
||||
// the guest user (e.g. Guest would not be selectable, and it would be stuck
|
||||
// saying "Resetting guest...")
|
||||
mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void updateUserList() {
|
||||
final Context context = getActivity();
|
||||
@@ -988,8 +1066,15 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
&& mUserCaps.mUserSwitcherEnabled) {
|
||||
mAddGuest.setVisible(true);
|
||||
mAddGuest.setIcon(getEncircledDefaultIcon());
|
||||
mAddGuest.setEnabled(canSwitchUserNow());
|
||||
mAddGuest.setSelectable(true);
|
||||
if (mGuestUserAutoCreated && mGuestCreationScheduled.get()) {
|
||||
mAddGuest.setTitle(com.android.settingslib.R.string.user_guest);
|
||||
mAddGuest.setSummary(R.string.guest_resetting);
|
||||
mAddGuest.setEnabled(false);
|
||||
} else {
|
||||
mAddGuest.setTitle(com.android.settingslib.R.string.guest_new_guest);
|
||||
mAddGuest.setEnabled(canSwitchUserNow());
|
||||
}
|
||||
} else {
|
||||
mAddGuest.setVisible(false);
|
||||
}
|
||||
@@ -1077,7 +1162,11 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
public boolean onPreferenceClick(Preference pref) {
|
||||
if (pref == mMePreference) {
|
||||
if (isCurrentUserGuest()) {
|
||||
if (mGuestUserAutoCreated) {
|
||||
showDialog(DIALOG_CONFIRM_RESET_GUEST);
|
||||
} else {
|
||||
showDialog(DIALOG_CONFIRM_EXIT_GUEST);
|
||||
}
|
||||
} else {
|
||||
showDialog(DIALOG_USER_PROFILE_EDITOR);
|
||||
}
|
||||
|
Reference in New Issue
Block a user