summaryrefslogtreecommitdiffstats
path: root/src/com/android/settings/users
diff options
context:
space:
mode:
authorAndras Kloczl <andraskloczl@google.com>2020-04-21 11:32:12 +0100
committerAndras Kloczl <andraskloczl@google.com>2020-05-07 22:01:33 +0100
commit4d7d4effa5d98a0a84bf0c7539cd60bd05571c7b (patch)
tree6713d6bbba271db5e9db886399a7633857edb93d /src/com/android/settings/users
parent73d336790195315895554147f2cdb2efce7e6d46 (diff)
downloadpackages_apps_Settings-4d7d4effa5d98a0a84bf0c7539cd60bd05571c7b.tar.gz
packages_apps_Settings-4d7d4effa5d98a0a84bf0c7539cd60bd05571c7b.tar.bz2
packages_apps_Settings-4d7d4effa5d98a0a84bf0c7539cd60bd05571c7b.zip
Improve multi user settings screen
- Added switch and user delete functionality to details screen. - Added robo tests. Screenshots: http://shortn/_S6fbIMhAYO Bug: 142798722 Test: Run robo tests with this command: make -j64 RunSettingsRoboTests ROBOTEST_FILTER="com.android.settings.users.*SettingsTest" Change-Id: Ied67290e8fed87feb0a60a3f2c40eb91cc57988e
Diffstat (limited to 'src/com/android/settings/users')
-rw-r--r--src/com/android/settings/users/AppRestrictionsFragment.java8
-rw-r--r--src/com/android/settings/users/RestrictedProfileSettings.java33
-rw-r--r--src/com/android/settings/users/UserDetailsSettings.java252
-rw-r--r--src/com/android/settings/users/UserPreference.java79
-rw-r--r--src/com/android/settings/users/UserSettings.java256
5 files changed, 320 insertions, 308 deletions
diff --git a/src/com/android/settings/users/AppRestrictionsFragment.java b/src/com/android/settings/users/AppRestrictionsFragment.java
index 7b15e8a090..1caf49c449 100644
--- a/src/com/android/settings/users/AppRestrictionsFragment.java
+++ b/src/com/android/settings/users/AppRestrictionsFragment.java
@@ -97,8 +97,15 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
/** Key for extra passed in from calling fragment to indicate if this is a newly created user */
public static final String EXTRA_NEW_USER = "new_user";
+ /**
+ * Key for extra passed in from calling fragment to indicate if
+ * switch to user should be shown
+ */
+ public static final String EXTRA_SHOW_SWITCH_USER = "enable_switch";
+
private boolean mFirstTime = true;
private boolean mNewUser;
+ protected boolean mShowSwitchUser;
private boolean mAppListChanged;
protected boolean mRestrictedProfile;
@@ -219,6 +226,7 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
mUser = new UserHandle(args.getInt(EXTRA_USER_ID));
}
mNewUser = args.getBoolean(EXTRA_NEW_USER, false);
+ mShowSwitchUser = args.getBoolean(EXTRA_SHOW_SWITCH_USER, false);
}
}
diff --git a/src/com/android/settings/users/RestrictedProfileSettings.java b/src/com/android/settings/users/RestrictedProfileSettings.java
index 57c0d02886..44657cf959 100644
--- a/src/com/android/settings/users/RestrictedProfileSettings.java
+++ b/src/com/android/settings/users/RestrictedProfileSettings.java
@@ -16,6 +16,7 @@
package com.android.settings.users;
+import android.app.ActivityManager;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.DialogInterface;
@@ -23,7 +24,10 @@ import android.content.Intent;
import android.content.pm.UserInfo;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
@@ -36,6 +40,7 @@ import com.android.settingslib.utils.ThreadUtils;
public class RestrictedProfileSettings extends AppRestrictionsFragment
implements EditUserInfoController.OnContentChangedCallback {
+ private static final String TAG = RestrictedProfileSettings.class.getSimpleName();
public static final String FILE_PROVIDER_AUTHORITY = "com.android.settings.files";
static final int DIALOG_ID_EDIT_USER_INFO = 1;
private static final int DIALOG_CONFIRM_REMOVE = 2;
@@ -44,6 +49,8 @@ public class RestrictedProfileSettings extends AppRestrictionsFragment
private ImageView mUserIconView;
private TextView mUserNameView;
private ImageView mDeleteButton;
+ private View mSwitchUserView;
+ private TextView mSwitchTitle;
private EditUserInfoController mEditUserInfoController =
new EditUserInfoController();
@@ -67,6 +74,11 @@ public class RestrictedProfileSettings extends AppRestrictionsFragment
mUserNameView = (TextView) mHeaderView.findViewById(android.R.id.title);
mDeleteButton = (ImageView) mHeaderView.findViewById(R.id.delete);
mDeleteButton.setOnClickListener(this);
+
+ mSwitchTitle = mHeaderView.findViewById(R.id.switchTitle);
+ mSwitchUserView = mHeaderView.findViewById(R.id.switch_pref);
+ mSwitchUserView.setOnClickListener(v -> switchUser());
+
// This is going to bind the preferences.
super.onActivityCreated(savedInstanceState);
}
@@ -80,7 +92,6 @@ public class RestrictedProfileSettings extends AppRestrictionsFragment
@Override
public void onResume() {
super.onResume();
-
// Check if user still exists
UserInfo info = Utils.getExistingUser(mUserManager, mUser);
if (info == null) {
@@ -89,6 +100,16 @@ public class RestrictedProfileSettings extends AppRestrictionsFragment
((TextView) mHeaderView.findViewById(android.R.id.title)).setText(info.name);
((ImageView) mHeaderView.findViewById(android.R.id.icon)).setImageDrawable(
com.android.settingslib.Utils.getUserIcon(getActivity(), mUserManager, info));
+
+ boolean canSwitchUser =
+ mUserManager.getUserSwitchability() == UserManager.SWITCHABILITY_STATUS_OK;
+ if (mShowSwitchUser && canSwitchUser) {
+ mSwitchUserView.setVisibility(View.VISIBLE);
+ mSwitchTitle.setText(getString(com.android.settingslib.R.string.user_switch_to_user,
+ info.name));
+ } else {
+ mSwitchUserView.setVisibility(View.GONE);
+ }
}
}
@@ -158,6 +179,16 @@ public class RestrictedProfileSettings extends AppRestrictionsFragment
});
}
+ private void switchUser() {
+ try {
+ ActivityManager.getService().switchUser(mUser.getIdentifier());
+ } catch (RemoteException re) {
+ Log.e(TAG, "Error while switching to other user.");
+ } finally {
+ finishFragment();
+ }
+ }
+
@Override
public void onPhotoChanged(UserHandle user, Drawable photo) {
mUserIconView.setImageDrawable(photo);
diff --git a/src/com/android/settings/users/UserDetailsSettings.java b/src/com/android/settings/users/UserDetailsSettings.java
index 371c152e15..2696ddc131 100644
--- a/src/com/android/settings/users/UserDetailsSettings.java
+++ b/src/com/android/settings/users/UserDetailsSettings.java
@@ -16,55 +16,63 @@
package com.android.settings.users;
+import static android.os.UserHandle.USER_NULL;
+
+import android.app.ActivityManager;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.pm.UserInfo;
import android.os.Bundle;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.Log;
+import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.Utils;
+import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;
import java.util.List;
/**
- * Settings screen for configuring a specific user. It can contain user restrictions
- * and deletion controls. It is shown when you tap on the settings icon in the
- * user management (UserSettings) screen.
+ * Settings screen for configuring, deleting or switching to a specific user.
+ * It is shown when you tap on a user in the user management (UserSettings) screen.
*
* Arguments to this fragment must include the userId of the user (in EXTRA_USER_ID) for whom
- * to display controls, or should contain the EXTRA_USER_GUEST = true.
+ * to display controls.
*/
public class UserDetailsSettings extends SettingsPreferenceFragment
implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
private static final String TAG = UserDetailsSettings.class.getSimpleName();
+ private static final String KEY_SWITCH_USER = "switch_user";
private static final String KEY_ENABLE_TELEPHONY = "enable_calling";
private static final String KEY_REMOVE_USER = "remove_user";
/** Integer extra containing the userId to manage */
static final String EXTRA_USER_ID = "user_id";
- /** Boolean extra to indicate guest preferences */
- static final String EXTRA_USER_GUEST = "guest_user";
private static final int DIALOG_CONFIRM_REMOVE = 1;
private static final int DIALOG_CONFIRM_ENABLE_CALLING = 2;
private static final int DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS = 3;
private UserManager mUserManager;
+ @VisibleForTesting
+ Preference mSwitchUserPref;
private SwitchPreference mPhonePref;
- private Preference mRemoveUserPref;
+ @VisibleForTesting
+ Preference mRemoveUserPref;
- private UserInfo mUserInfo;
- private boolean mGuestUser;
+ @VisibleForTesting
+ UserInfo mUserInfo;
private Bundle mDefaultGuestRestrictions;
@Override
@@ -78,46 +86,28 @@ public class UserDetailsSettings extends SettingsPreferenceFragment
final Context context = getActivity();
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-
addPreferencesFromResource(R.xml.user_details_settings);
- mPhonePref = (SwitchPreference) findPreference(KEY_ENABLE_TELEPHONY);
- mRemoveUserPref = findPreference(KEY_REMOVE_USER);
- mGuestUser = getArguments().getBoolean(EXTRA_USER_GUEST, false);
+ initialize(context, getArguments());
+ }
- if (!mGuestUser) {
- // Regular user. Get the user id from the caller.
- final int userId = getArguments().getInt(EXTRA_USER_ID, -1);
- if (userId == -1) {
- throw new RuntimeException("Arguments to this fragment must contain the user id");
- }
- mUserInfo = mUserManager.getUserInfo(userId);
- mPhonePref.setChecked(!mUserManager.hasUserRestriction(
- UserManager.DISALLOW_OUTGOING_CALLS, new UserHandle(userId)));
- mRemoveUserPref.setOnPreferenceClickListener(this);
- } else {
- // These are not for an existing user, just general Guest settings.
- removePreference(KEY_REMOVE_USER);
- // Default title is for calling and SMS. Change to calling-only here
- mPhonePref.setTitle(R.string.user_enable_calling);
- mDefaultGuestRestrictions = mUserManager.getDefaultGuestRestrictions();
- mPhonePref.setChecked(
- !mDefaultGuestRestrictions.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
- }
- if (RestrictedLockUtilsInternal.hasBaseUserRestriction(context,
- UserManager.DISALLOW_REMOVE_USER, UserHandle.myUserId())) {
- removePreference(KEY_REMOVE_USER);
- }
- mPhonePref.setOnPreferenceChangeListener(this);
+ @Override
+ public void onResume() {
+ super.onResume();
+ mSwitchUserPref.setEnabled(canSwitchUserNow());
}
@Override
public boolean onPreferenceClick(Preference preference) {
if (preference == mRemoveUserPref) {
- if (!mUserManager.isAdminUser()) {
- throw new RuntimeException("Only admins can remove a user");
+ if (canDeleteUser()) {
+ showDialog(DIALOG_CONFIRM_REMOVE);
+ }
+ return true;
+ } else if (preference == mSwitchUserPref) {
+ if (canSwitchUserNow()) {
+ switchUser();
}
- showDialog(DIALOG_CONFIRM_REMOVE);
return true;
}
return false;
@@ -126,7 +116,7 @@ public class UserDetailsSettings extends SettingsPreferenceFragment
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (Boolean.TRUE.equals(newValue)) {
- showDialog(mGuestUser ? DIALOG_CONFIRM_ENABLE_CALLING
+ showDialog(mUserInfo.isGuest() ? DIALOG_CONFIRM_ENABLE_CALLING
: DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS);
return false;
}
@@ -134,9 +124,135 @@ public class UserDetailsSettings extends SettingsPreferenceFragment
return true;
}
- void enableCallsAndSms(boolean enabled) {
+ @Override
+ public int getDialogMetricsCategory(int dialogId) {
+ switch (dialogId) {
+ case DIALOG_CONFIRM_REMOVE:
+ return SettingsEnums.DIALOG_USER_REMOVE;
+ case DIALOG_CONFIRM_ENABLE_CALLING:
+ return SettingsEnums.DIALOG_USER_ENABLE_CALLING;
+ case DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS:
+ return SettingsEnums.DIALOG_USER_ENABLE_CALLING_AND_SMS;
+ default:
+ return 0;
+ }
+ }
+
+ @Override
+ public Dialog onCreateDialog(int dialogId) {
+ Context context = getActivity();
+ if (context == null) {
+ return null;
+ }
+ switch (dialogId) {
+ case DIALOG_CONFIRM_REMOVE:
+ return UserDialogs.createRemoveDialog(getActivity(), mUserInfo.id,
+ (dialog, which) -> removeUser());
+ case DIALOG_CONFIRM_ENABLE_CALLING:
+ return UserDialogs.createEnablePhoneCallsDialog(getActivity(),
+ (dialog, which) -> enableCallsAndSms(true));
+ case DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS:
+ return UserDialogs.createEnablePhoneCallsAndSmsDialog(getActivity(),
+ (dialog, which) -> enableCallsAndSms(true));
+ }
+ throw new IllegalArgumentException("Unsupported dialogId " + dialogId);
+ }
+
+ @VisibleForTesting
+ @Override
+ protected void showDialog(int dialogId) {
+ super.showDialog(dialogId);
+ }
+
+ @VisibleForTesting
+ void initialize(Context context, Bundle arguments) {
+ int userId = arguments != null ? arguments.getInt(EXTRA_USER_ID, USER_NULL) : USER_NULL;
+ if (userId == USER_NULL) {
+ throw new IllegalStateException("Arguments to this fragment must contain the user id");
+ }
+ mUserInfo = mUserManager.getUserInfo(userId);
+
+ mSwitchUserPref = findPreference(KEY_SWITCH_USER);
+ mPhonePref = findPreference(KEY_ENABLE_TELEPHONY);
+ mRemoveUserPref = findPreference(KEY_REMOVE_USER);
+
+ mSwitchUserPref.setTitle(
+ context.getString(com.android.settingslib.R.string.user_switch_to_user,
+ mUserInfo.name));
+ mSwitchUserPref.setOnPreferenceClickListener(this);
+
+ if (!mUserManager.isAdminUser()) { // non admin users can't remove users and allow calls
+ removePreference(KEY_ENABLE_TELEPHONY);
+ removePreference(KEY_REMOVE_USER);
+ } else {
+ if (!Utils.isVoiceCapable(context)) { // no telephony
+ removePreference(KEY_ENABLE_TELEPHONY);
+ }
+
+ if (!mUserInfo.isGuest()) {
+ mPhonePref.setChecked(!mUserManager.hasUserRestriction(
+ UserManager.DISALLOW_OUTGOING_CALLS, new UserHandle(userId)));
+ mRemoveUserPref.setTitle(R.string.user_remove_user);
+ } else {
+ // These are not for an existing user, just general Guest settings.
+ // Default title is for calling and SMS. Change to calling-only here
+ 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);
+ }
+ if (RestrictedLockUtilsInternal.hasBaseUserRestriction(context,
+ UserManager.DISALLOW_REMOVE_USER, UserHandle.myUserId())) {
+ removePreference(KEY_REMOVE_USER);
+ }
+
+ mRemoveUserPref.setOnPreferenceClickListener(this);
+ mPhonePref.setOnPreferenceChangeListener(this);
+ }
+ }
+
+ @VisibleForTesting
+ boolean canDeleteUser() {
+ if (!mUserManager.isAdminUser()) {
+ return false;
+ }
+
+ Context context = getActivity();
+ if (context == null) {
+ return false;
+ }
+
+ final RestrictedLockUtils.EnforcedAdmin removeDisallowedAdmin =
+ RestrictedLockUtilsInternal.checkIfRestrictionEnforced(context,
+ UserManager.DISALLOW_REMOVE_USER, UserHandle.myUserId());
+ if (removeDisallowedAdmin != null) {
+ RestrictedLockUtils.sendShowAdminSupportDetailsIntent(context,
+ removeDisallowedAdmin);
+ return false;
+ }
+ return true;
+ }
+
+ @VisibleForTesting
+ boolean canSwitchUserNow() {
+ return mUserManager.getUserSwitchability() == UserManager.SWITCHABILITY_STATUS_OK;
+ }
+
+ @VisibleForTesting
+ void switchUser() {
+ try {
+ ActivityManager.getService().switchUser(mUserInfo.id);
+ } catch (RemoteException re) {
+ Log.e(TAG, "Error while switching to other user.");
+ } finally {
+ finishFragment();
+ }
+ }
+
+ private void enableCallsAndSms(boolean enabled) {
mPhonePref.setChecked(enabled);
- if (mGuestUser) {
+ if (mUserInfo.isGuest()) {
mDefaultGuestRestrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, !enabled);
// SMS is always disabled for guest
mDefaultGuestRestrictions.putBoolean(UserManager.DISALLOW_SMS, true);
@@ -146,7 +262,7 @@ public class UserDetailsSettings extends SettingsPreferenceFragment
// TODO: Maybe setDefaultGuestRestrictions() can internally just set the restrictions
// on any existing guest rather than do it here with multiple Binder calls.
List<UserInfo> users = mUserManager.getUsers(true);
- for (UserInfo user: users) {
+ for (UserInfo user : users) {
if (user.isGuest()) {
UserHandle userHandle = UserHandle.of(user.id);
for (String key : mDefaultGuestRestrictions.keySet()) {
@@ -163,51 +279,7 @@ public class UserDetailsSettings extends SettingsPreferenceFragment
}
}
- @Override
- public Dialog onCreateDialog(int dialogId) {
- Context context = getActivity();
- if (context == null) return null;
- switch (dialogId) {
- case DIALOG_CONFIRM_REMOVE:
- return UserDialogs.createRemoveDialog(getActivity(), mUserInfo.id,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- removeUser();
- }
- });
- case DIALOG_CONFIRM_ENABLE_CALLING:
- return UserDialogs.createEnablePhoneCallsDialog(getActivity(),
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- enableCallsAndSms(true);
- }
- });
- case DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS:
- return UserDialogs.createEnablePhoneCallsAndSmsDialog(getActivity(),
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- enableCallsAndSms(true);
- }
- });
- }
- throw new IllegalArgumentException("Unsupported dialogId " + dialogId);
- }
-
- @Override
- public int getDialogMetricsCategory(int dialogId) {
- switch (dialogId) {
- case DIALOG_CONFIRM_REMOVE:
- return SettingsEnums.DIALOG_USER_REMOVE;
- case DIALOG_CONFIRM_ENABLE_CALLING:
- return SettingsEnums.DIALOG_USER_ENABLE_CALLING;
- case DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS:
- return SettingsEnums.DIALOG_USER_ENABLE_CALLING_AND_SMS;
- default:
- return 0;
- }
- }
-
- void removeUser() {
+ private void removeUser() {
mUserManager.removeUser(mUserInfo.id);
finishFragment();
}
diff --git a/src/com/android/settings/users/UserPreference.java b/src/com/android/settings/users/UserPreference.java
index 3603d44ea0..0b78d78760 100644
--- a/src/com/android/settings/users/UserPreference.java
+++ b/src/com/android/settings/users/UserPreference.java
@@ -21,18 +21,16 @@ import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.AttributeSet;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.ImageView;
import androidx.preference.PreferenceViewHolder;
-import com.android.settings.R;
-import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.RestrictedPreference;
import java.util.Comparator;
+/**
+ * Preference for a user that appear on {@link UserSettings} screen.
+ */
public class UserPreference extends RestrictedPreference {
private static final int ALPHA_ENABLED = 255;
private static final int ALPHA_DISABLED = 102;
@@ -44,8 +42,7 @@ public class UserPreference extends RestrictedPreference {
if (p1 == null) {
return -1;
- }
- else if (p2 == null) {
+ } else if (p2 == null) {
return 1;
}
int sn1 = p1.getSerialNumber();
@@ -58,26 +55,15 @@ public class UserPreference extends RestrictedPreference {
return 0;
};
- private OnClickListener mDeleteClickListener;
- private OnClickListener mSettingsClickListener;
private int mSerialNumber = -1;
private int mUserId = USERID_UNKNOWN;
- static final int SETTINGS_ID = R.id.manage_user;
- static final int DELETE_ID = R.id.trash_user;
public UserPreference(Context context, AttributeSet attrs) {
- this(context, attrs, USERID_UNKNOWN, null, null);
+ this(context, attrs, USERID_UNKNOWN);
}
- UserPreference(Context context, AttributeSet attrs, int userId,
- OnClickListener settingsListener,
- OnClickListener deleteListener) {
+ UserPreference(Context context, AttributeSet attrs, int userId) {
super(context, attrs);
- if (deleteListener != null || settingsListener != null) {
- setWidgetLayoutResource(R.layout.restricted_preference_user_delete_widget);
- }
- mDeleteClickListener = deleteListener;
- mSettingsClickListener = settingsListener;
mUserId = userId;
useAdminDisabledSummary(true);
}
@@ -92,62 +78,13 @@ public class UserPreference extends RestrictedPreference {
@Override
protected boolean shouldHideSecondTarget() {
- if (isDisabledByAdmin()) {
- // Disabled by admin, show no secondary target.
- return true;
- }
- if (canDeleteUser()) {
- // Need to show delete user target so don't hide.
- return false;
- }
- // Hide if don't have advanced setting listener.
- return mSettingsClickListener == null;
+ return true;
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
- final boolean disabledByAdmin = isDisabledByAdmin();
- dimIcon(disabledByAdmin);
- View userDeleteWidget = view.findViewById(R.id.user_delete_widget);
- if (userDeleteWidget != null) {
- userDeleteWidget.setVisibility(disabledByAdmin ? View.GONE : View.VISIBLE);
- }
- if (!disabledByAdmin) {
- View deleteDividerView = view.findViewById(R.id.divider_delete);
- View manageDividerView = view.findViewById(R.id.divider_manage);
- View deleteView = view.findViewById(R.id.trash_user);
- if (deleteView != null) {
- if (canDeleteUser()) {
- deleteView.setVisibility(View.VISIBLE);
- deleteDividerView.setVisibility(View.VISIBLE);
- deleteView.setOnClickListener(mDeleteClickListener);
- deleteView.setTag(this);
- } else {
- deleteView.setVisibility(View.GONE);
- deleteDividerView.setVisibility(View.GONE);
- }
- }
- ImageView manageView = (ImageView) view.findViewById(R.id.manage_user);
- if (manageView != null) {
- if (mSettingsClickListener != null) {
- manageView.setVisibility(View.VISIBLE);
- manageDividerView.setVisibility(mDeleteClickListener == null
- ? View.VISIBLE : View.GONE);
- manageView.setOnClickListener(mSettingsClickListener);
- manageView.setTag(this);
- } else {
- manageView.setVisibility(View.GONE);
- manageDividerView.setVisibility(View.GONE);
- }
- }
- }
- }
-
- private boolean canDeleteUser() {
- return mDeleteClickListener != null
- && !RestrictedLockUtilsInternal.hasBaseUserRestriction(getContext(),
- UserManager.DISALLOW_REMOVE_USER, UserHandle.myUserId());
+ dimIcon(isDisabledByAdmin());
}
private int getSerialNumber() {
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index 38ef199c5c..7d4ab5d531 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -48,7 +48,6 @@ import android.util.SparseArray;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
-import android.view.View;
import android.widget.SimpleAdapter;
import androidx.annotation.VisibleForTesting;
@@ -69,7 +68,6 @@ import com.android.settings.password.ChooseLockGeneric;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.widget.SwitchBar;
import com.android.settings.widget.SwitchBarController;
-import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.RestrictedPreference;
@@ -89,15 +87,14 @@ import java.util.Random;
/**
* Screen that manages the list of users on the device.
- * Guest user is an always visible entry, even if the guest is not currently
- * active/created. It is meant for controlling properties of a guest user.
+ * Secondary users and a guest user can be created if there is no restriction.
*
- * The first one is always the current user.
+ * The first user in the list is always the current user.
* Owner is the primary user.
*/
@SearchIndexable
public class UserSettings extends SettingsPreferenceFragment
- implements Preference.OnPreferenceClickListener, View.OnClickListener,
+ implements Preference.OnPreferenceClickListener,
MultiUserSwitchBarController.OnMultiUserSwitchChangedListener,
DialogInterface.OnDismissListener {
@@ -111,6 +108,7 @@ public class UserSettings extends SettingsPreferenceFragment
private static final String KEY_USER_LIST = "user_list";
private static final String KEY_USER_ME = "user_me";
private static final String KEY_USER_GUEST = "user_guest";
+ private static final String KEY_ADD_GUEST = "guest_add";
private static final String KEY_ADD_USER = "user_add";
private static final String KEY_ADD_USER_WHEN_LOCKED = "user_settings_add_users_when_locked";
private static final String KEY_MULTIUSER_FOOTER = "multiuser_footer";
@@ -156,7 +154,11 @@ public class UserSettings extends SettingsPreferenceFragment
@VisibleForTesting
UserPreference mMePreference;
@VisibleForTesting
+ RestrictedPreference mAddGuest;
+ @VisibleForTesting
RestrictedPreference mAddUser;
+ @VisibleForTesting
+ SparseArray<Bitmap> mUserIcons = new SparseArray<>();
private int mRemovingUserId = -1;
private int mAddedUserId = 0;
private boolean mAddingUser;
@@ -165,7 +167,6 @@ public class UserSettings extends SettingsPreferenceFragment
private boolean mShouldUpdateUserList = true;
private final Object mUserLock = new Object();
private UserManager mUserManager;
- private SparseArray<Bitmap> mUserIcons = new SparseArray<>();
private static SparseArray<Bitmap> sDarkDefaultUserBitmapCache = new SparseArray<>();
private MultiUserSwitchBarController mSwitchBarController;
@@ -271,15 +272,17 @@ public class UserSettings extends SettingsPreferenceFragment
final int myUserId = UserHandle.myUserId();
mUserListCategory = (PreferenceGroup) findPreference(KEY_USER_LIST);
- mMePreference = new UserPreference(getPrefContext(), null /* attrs */, myUserId,
- null /* settings icon handler */,
- null /* delete icon handler */);
+ mMePreference = new UserPreference(getPrefContext(), null /* attrs */, myUserId);
mMePreference.setKey(KEY_USER_ME);
mMePreference.setOnPreferenceClickListener(this);
if (mUserCaps.mIsAdmin) {
mMePreference.setSummary(R.string.user_admin);
}
- mAddUser = (RestrictedPreference) findPreference(KEY_ADD_USER);
+
+ mAddGuest = findPreference(KEY_ADD_GUEST);
+ mAddGuest.setOnPreferenceClickListener(this);
+
+ mAddUser = findPreference(KEY_ADD_USER);
if (!mUserCaps.mCanAddRestrictedProfile) {
// Label should only mention adding a "user", not a "profile"
mAddUser.setTitle(R.string.user_add_user_menu);
@@ -344,8 +347,7 @@ public class UserSettings extends SettingsPreferenceFragment
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
int pos = 0;
- final boolean canSwitchUsers = mUserManager.canSwitchUsers();
- if (!mUserCaps.mIsAdmin && canSwitchUsers) {
+ if (!mUserCaps.mIsAdmin && canSwitchUserNow()) {
String nickname = mUserManager.getUserName();
MenuItem removeThisUser = menu.add(0, MENU_REMOVE_USER, pos++,
getResources().getString(R.string.user_remove_user_menu, nickname));
@@ -386,10 +388,13 @@ public class UserSettings extends SettingsPreferenceFragment
* Loads profile information for the current user.
*/
private void loadProfile() {
- if (mUserCaps.mIsGuest) {
+ if (isCurrentUserGuest()) {
// No need to load profile information
mMePreference.setIcon(getEncircledDefaultIcon());
mMePreference.setTitle(R.string.user_exit_guest_title);
+ mMePreference.setSelectable(true);
+ // removing a guest will result in switching back to the admin user
+ mMePreference.setEnabled(canSwitchUserNow());
return;
}
@@ -412,7 +417,9 @@ public class UserSettings extends SettingsPreferenceFragment
}
private void finishLoadProfile(String profileName) {
- if (getActivity() == null) return;
+ if (getActivity() == null) {
+ return;
+ }
mMePreference.setTitle(getString(R.string.user_you, profileName));
int myUserId = UserHandle.myUserId();
Bitmap b = mUserManager.getUserIcon(myUserId);
@@ -477,38 +484,28 @@ public class UserSettings extends SettingsPreferenceFragment
private void onManageUserClicked(int userId, boolean newUser) {
mAddingUser = false;
- if (userId == UserPreference.USERID_GUEST_DEFAULTS) {
- Bundle extras = new Bundle();
- extras.putBoolean(UserDetailsSettings.EXTRA_USER_GUEST, true);
- new SubSettingLauncher(getContext())
- .setDestination(UserDetailsSettings.class.getName())
- .setArguments(extras)
- .setTitleRes(R.string.user_guest)
- .setSourceMetricsCategory(getMetricsCategory())
- .launch();
- return;
- }
- UserInfo info = mUserManager.getUserInfo(userId);
- if (info.isRestricted() && mUserCaps.mIsAdmin) {
+ UserInfo userInfo = mUserManager.getUserInfo(userId);
+ if (userInfo.isRestricted() && mUserCaps.mIsAdmin) {
Bundle extras = new Bundle();
extras.putInt(RestrictedProfileSettings.EXTRA_USER_ID, userId);
extras.putBoolean(RestrictedProfileSettings.EXTRA_NEW_USER, newUser);
+ extras.putBoolean(RestrictedProfileSettings.EXTRA_SHOW_SWITCH_USER, canSwitchUserNow());
new SubSettingLauncher(getContext())
.setDestination(RestrictedProfileSettings.class.getName())
.setArguments(extras)
.setTitleRes(R.string.user_restrictions_title)
.setSourceMetricsCategory(getMetricsCategory())
.launch();
- } else if (info.id == UserHandle.myUserId()) {
+ } else if (userId == UserHandle.myUserId()) {
// Jump to owner info panel
OwnerInfoSettings.show(this);
- } else if (mUserCaps.mIsAdmin) {
- final Bundle extras = new Bundle();
+ } else {
+ Bundle extras = new Bundle();
extras.putInt(UserDetailsSettings.EXTRA_USER_ID, userId);
new SubSettingLauncher(getContext())
.setDestination(UserDetailsSettings.class.getName())
.setArguments(extras)
- .setTitleText(info.name)
+ .setTitleText(userInfo.name)
.setSourceMetricsCategory(getMetricsCategory())
.launch();
}
@@ -538,7 +535,9 @@ public class UserSettings extends SettingsPreferenceFragment
@Override
public Dialog onCreateDialog(int dialogId) {
Context context = getActivity();
- if (context == null) return null;
+ if (context == null) {
+ return null;
+ }
switch (dialogId) {
case DIALOG_CONFIRM_REMOVE: {
Dialog dlg =
@@ -811,7 +810,7 @@ public class UserSettings extends SettingsPreferenceFragment
}
private void removeThisUser() {
- if (!mUserManager.canSwitchUsers()) {
+ if (!canSwitchUserNow()) {
Log.w(TAG, "Cannot remove current user when switching is disabled");
return;
}
@@ -882,10 +881,14 @@ public class UserSettings extends SettingsPreferenceFragment
}
private void switchUserNow(int userId) {
+ if (!canSwitchUserNow()) {
+ return;
+ }
+
try {
ActivityManager.getService().switchUser(userId);
} catch (RemoteException re) {
- // Nothing to do
+ Log.e(TAG, "Error while switching to other user.");
}
}
@@ -894,7 +897,7 @@ public class UserSettings extends SettingsPreferenceFragment
*/
private void exitGuest() {
// Just to be safe
- if (!mUserCaps.mIsGuest) {
+ if (!isCurrentUserGuest()) {
return;
}
removeThisUser();
@@ -908,12 +911,12 @@ public class UserSettings extends SettingsPreferenceFragment
}
final List<UserInfo> users = mUserManager.getUsers(true);
- final boolean voiceCapable = Utils.isVoiceCapable(context);
final ArrayList<Integer> missingIcons = new ArrayList<>();
final ArrayList<UserPreference> userPreferences = new ArrayList<>();
- int guestId = UserPreference.USERID_GUEST_DEFAULTS;
userPreferences.add(mMePreference);
+ boolean canOpenUserDetails =
+ mUserCaps.mIsAdmin || (canSwitchUserNow() && !mUserCaps.mDisallowSwitchUser);
for (UserInfo user : users) {
if (!user.supportsSwitchToByUser()) {
// Only users that can be switched to should show up here.
@@ -924,37 +927,38 @@ public class UserSettings extends SettingsPreferenceFragment
if (user.id == UserHandle.myUserId()) {
pref = mMePreference;
} else if (user.isGuest()) {
- // Skip over Guest. We add generic Guest settings after this loop
- guestId = user.id;
- continue;
+ pref = new UserPreference(getPrefContext(), null, user.id);
+ pref.setTitle(R.string.user_guest);
+ pref.setIcon(getEncircledDefaultIcon());
+ pref.setKey(KEY_USER_GUEST);
+ userPreferences.add(pref);
+ pref.setEnabled(canOpenUserDetails);
+ pref.setSelectable(true);
+
+ if (mUserCaps.mDisallowSwitchUser) {
+ pref.setDisabledByAdmin(RestrictedLockUtilsInternal.getDeviceOwner(context));
+ } else {
+ pref.setDisabledByAdmin(null);
+ }
+ pref.setOnPreferenceClickListener(this);
} else {
- // With Telephony:
- // Secondary user: Settings
- // Guest: Settings
- // Restricted Profile: There is no Restricted Profile
- // Without Telephony:
- // Secondary user: Delete
- // Guest: Nothing
- // Restricted Profile: Settings
- final boolean showSettings = mUserCaps.mIsAdmin
- && (voiceCapable || user.isRestricted());
- final boolean showDelete = mUserCaps.mIsAdmin
- && (!voiceCapable && !user.isRestricted() && !user.isGuest());
- pref = new UserPreference(getPrefContext(), null, user.id,
- showSettings ? this : null,
- showDelete ? this : null);
+ pref = new UserPreference(getPrefContext(), null, user.id);
pref.setKey("id=" + user.id);
userPreferences.add(pref);
if (user.isAdmin()) {
pref.setSummary(R.string.user_admin);
}
pref.setTitle(user.name);
- pref.setSelectable(false);
+ pref.setOnPreferenceClickListener(this);
+ pref.setEnabled(canOpenUserDetails);
+ pref.setSelectable(true);
}
if (pref == null) {
continue;
}
- if (!isInitialized(user)) {
+ if (user.id != UserHandle.myUserId() && !user.isGuest() && !user.isInitialized()) {
+ // sometimes after creating a guest the initialized flag isn't immediately set
+ // and we don't want to show "Not set up" summary for them
if (user.isRestricted()) {
pref.setSummary(R.string.user_summary_restricted_not_set_up);
} else {
@@ -962,10 +966,7 @@ public class UserSettings extends SettingsPreferenceFragment
}
// Disallow setting up user which results in user switching when the restriction is
// set.
- if (!mUserCaps.mDisallowSwitchUser) {
- pref.setOnPreferenceClickListener(this);
- pref.setSelectable(mUserManager.canSwitchUsers());
- }
+ pref.setEnabled(!mUserCaps.mDisallowSwitchUser && canSwitchUserNow());
} else if (user.isRestricted()) {
pref.setSummary(R.string.user_summary_restricted_profile);
}
@@ -986,53 +987,13 @@ public class UserSettings extends SettingsPreferenceFragment
// Add a temporary entry for the user being created
if (mAddingUser) {
UserPreference pref = new UserPreference(getPrefContext(), null,
- UserPreference.USERID_UNKNOWN, null, null);
+ UserPreference.USERID_UNKNOWN);
pref.setEnabled(false);
pref.setTitle(mAddingUserName);
pref.setIcon(getEncircledDefaultIcon());
userPreferences.add(pref);
}
- // Check if Guest tile should be added.
- if (!mUserCaps.mIsGuest && (mUserCaps.mCanAddGuest ||
- mUserCaps.mDisallowAddUserSetByAdmin)) {
- // Add a virtual Guest user for guest defaults
- UserPreference pref = new UserPreference(getPrefContext(), null,
- UserPreference.USERID_GUEST_DEFAULTS,
- mUserCaps.mIsAdmin && voiceCapable ? this : null /* settings icon handler */,
- null /* delete icon handler */);
- pref.setTitle(R.string.user_guest);
- pref.setIcon(getEncircledDefaultIcon());
- pref.setKey(KEY_USER_GUEST);
- userPreferences.add(pref);
- if (mUserCaps.mDisallowAddUser) {
- pref.setDisabledByAdmin(mUserCaps.mEnforcedAdmin);
- } else if (mUserCaps.mDisallowSwitchUser) {
- pref.setDisabledByAdmin(RestrictedLockUtilsInternal.getDeviceOwner(context));
- } else {
- pref.setDisabledByAdmin(null);
- }
- if (!mUserManager.canSwitchUsers()) {
- pref.setSelectable(false);
- }
- int finalGuestId = guestId;
- pref.setOnPreferenceClickListener(preference -> {
- int id = finalGuestId;
- if (id == UserPreference.USERID_GUEST_DEFAULTS) {
- UserInfo guest = mUserManager.createGuest(
- getContext(), preference.getTitle().toString());
- if (guest != null) {
- id = guest.id;
- }
- }
- try {
- ActivityManager.getService().switchUser(id);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- return true;
- });
- }
// Sort list of users by serialNum
Collections.sort(userPreferences, UserPreference.SERIAL_NUMBER_COMPARATOR);
@@ -1064,6 +1025,7 @@ public class UserSettings extends SettingsPreferenceFragment
mMultiUserFooterPreferenceController.updateState(multiUserFooterPrefence);
mUserListCategory.setVisible(mUserCaps.mUserSwitcherEnabled);
+ updateAddGuest(context, users.stream().anyMatch(UserInfo::isGuest));
updateAddUser(context);
if (!mUserCaps.mUserSwitcherEnabled) {
@@ -1077,15 +1039,38 @@ public class UserSettings extends SettingsPreferenceFragment
}
+ private boolean isCurrentUserGuest() {
+ return mUserCaps.mIsGuest;
+ }
+
+ private boolean canSwitchUserNow() {
+ return mUserManager.getUserSwitchability() == UserManager.SWITCHABILITY_STATUS_OK;
+ }
+
+ private void updateAddGuest(Context context, boolean isGuestAlreadyCreated) {
+ if (!isGuestAlreadyCreated && mUserCaps.mCanAddGuest
+ && WizardManagerHelper.isDeviceProvisioned(context)
+ && mUserCaps.mUserSwitcherEnabled) {
+ mAddGuest.setVisible(true);
+ mAddGuest.setIcon(getEncircledDefaultIcon());
+ mAddGuest.setEnabled(canSwitchUserNow());
+ mAddGuest.setSelectable(true);
+ } else {
+ mAddGuest.setVisible(false);
+ }
+ }
+
private void updateAddUser(Context context) {
if ((mUserCaps.mCanAddUser || mUserCaps.mDisallowAddUserSetByAdmin)
&& WizardManagerHelper.isDeviceProvisioned(context)
&& mUserCaps.mUserSwitcherEnabled) {
mAddUser.setVisible(true);
- final boolean moreUsers = mUserManager.canAddMoreUsers();
- mAddUser.setEnabled(moreUsers && !mAddingUser && mUserManager.canSwitchUsers());
- if (!moreUsers) {
- mAddUser.setSummary(getString(R.string.user_add_max_count, getMaxRealUsers()));
+ mAddUser.setSelectable(true);
+ final boolean canAddMoreUsers = mUserManager.canAddMoreUsers();
+ mAddUser.setEnabled(canAddMoreUsers && !mAddingUser && canSwitchUserNow());
+ if (!canAddMoreUsers) {
+ mAddUser.setSummary(
+ getString(R.string.user_add_max_count, getRealUsersCount()));
} else {
mAddUser.setSummary(null);
}
@@ -1098,18 +1083,15 @@ public class UserSettings extends SettingsPreferenceFragment
}
}
- private int getMaxRealUsers() {
- // guest is not counted against getMaxSupportedUsers() number
- final int maxUsersAndGuest = UserManager.getMaxSupportedUsers() + 1;
- final List<UserInfo> users = mUserManager.getUsers();
- // managed profiles are counted against getMaxSupportedUsers()
- int managedProfiles = 0;
- for (UserInfo user : users) {
- if (user.isManagedProfile()) {
- managedProfiles++;
- }
- }
- return maxUsersAndGuest - managedProfiles;
+ /**
+ * @return number of non-guest non-managed users
+ */
+ @VisibleForTesting
+ int getRealUsersCount() {
+ return (int) mUserManager.getUsers()
+ .stream()
+ .filter(user -> !user.isGuest() && !user.isProfile())
+ .count();
}
private void loadIconsAsync(List<Integer> missingIcons) {
@@ -1151,12 +1133,12 @@ public class UserSettings extends SettingsPreferenceFragment
@Override
public boolean onPreferenceClick(Preference pref) {
if (pref == mMePreference) {
- if (mUserCaps.mIsGuest) {
+ if (isCurrentUserGuest()) {
showDialog(DIALOG_CONFIRM_EXIT_GUEST);
return true;
}
// If this is a limited user, launch the user info settings instead of profile editor
- if (mUserManager.isLinkedUser()) {
+ if (mUserManager.isRestrictedProfile()) {
onManageUserClicked(UserHandle.myUserId(), false);
} else {
showDialog(DIALOG_USER_PROFILE_EDITOR);
@@ -1165,9 +1147,11 @@ public class UserSettings extends SettingsPreferenceFragment
int userId = ((UserPreference) pref).getUserId();
// Get the latest status of the user
UserInfo user = mUserManager.getUserInfo(userId);
- if (!isInitialized(user)) {
+ if (!user.isInitialized()) {
mHandler.sendMessage(mHandler.obtainMessage(
MESSAGE_SETUP_USER, user.id, user.serialNumber));
+ } else {
+ onManageUserClicked(userId, false);
}
} else if (pref == mAddUser) {
// If we allow both types, show a picker, otherwise directly go to
@@ -1177,40 +1161,20 @@ public class UserSettings extends SettingsPreferenceFragment
} else {
onAddUserClicked(USER_TYPE_USER);
}
+ } else if (pref == mAddGuest) {
+ UserInfo guest = mUserManager.createGuest(
+ getContext(), getString(com.android.settingslib.R.string.user_guest));
+ switchUserNow(guest.id);
}
return false;
}
- private boolean isInitialized(UserInfo user) {
- return (user.flags & UserInfo.FLAG_INITIALIZED) != 0;
- }
-
private Drawable encircle(Bitmap icon) {
Drawable circled = CircleFramedDrawable.getInstance(getActivity(), icon);
return circled;
}
@Override
- public void onClick(View v) {
- if (v.getTag() instanceof UserPreference) {
- int userId = ((UserPreference) v.getTag()).getUserId();
- if (v.getId() == UserPreference.DELETE_ID) {
- final EnforcedAdmin removeDisallowedAdmin =
- RestrictedLockUtilsInternal.checkIfRestrictionEnforced(getContext(),
- UserManager.DISALLOW_REMOVE_USER, UserHandle.myUserId());
- if (removeDisallowedAdmin != null) {
- RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(),
- removeDisallowedAdmin);
- } else {
- onRemoveUserClicked(userId);
- }
- } else if (v.getId() == UserPreference.SETTINGS_ID) {
- onManageUserClicked(userId, false);
- }
- }
- }
-
- @Override
public void onDismiss(DialogInterface dialog) {
synchronized (mUserLock) {
mRemovingUserId = -1;