2 * Copyright (C) 2012 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.settings.users;
19 import android.accounts.Account;
20 import android.accounts.AccountManager;
21 import android.app.Activity;
22 import android.app.ActivityManagerNative;
23 import android.app.AlertDialog;
24 import android.app.Dialog;
25 import android.app.admin.DevicePolicyManager;
26 import android.content.BroadcastReceiver;
27 import android.content.Context;
28 import android.content.DialogInterface;
29 import android.content.Intent;
30 import android.content.IntentFilter;
31 import android.content.SharedPreferences;
32 import android.content.pm.UserInfo;
33 import android.content.res.Resources;
34 import android.graphics.Bitmap;
35 import android.graphics.drawable.Drawable;
36 import android.os.AsyncTask;
37 import android.os.Bundle;
38 import android.os.Handler;
39 import android.os.Message;
40 import android.os.RemoteException;
41 import android.os.UserHandle;
42 import android.os.UserManager;
43 import android.preference.Preference;
44 import android.preference.Preference.OnPreferenceClickListener;
45 import android.preference.PreferenceGroup;
46 import android.preference.PreferenceScreen;
47 import android.provider.Settings;
48 import android.provider.Settings.Global;
49 import android.provider.Settings.Secure;
50 import android.util.Log;
51 import android.util.SparseArray;
52 import android.view.Menu;
53 import android.view.MenuInflater;
54 import android.view.MenuItem;
55 import android.view.View;
56 import android.view.View.OnClickListener;
57 import android.widget.SimpleAdapter;
59 import com.android.internal.logging.MetricsLogger;
60 import com.android.internal.widget.LockPatternUtils;
61 import com.android.settings.ChooseLockGeneric;
62 import com.android.settings.OwnerInfoSettings;
63 import com.android.settings.R;
64 import com.android.settings.SelectableEditTextPreference;
65 import com.android.settings.SettingsActivity;
66 import com.android.settings.SettingsPreferenceFragment;
67 import com.android.settings.Utils;
68 import com.android.settings.search.BaseSearchIndexProvider;
69 import com.android.settings.search.Indexable;
70 import com.android.settings.search.SearchIndexableRaw;
71 import com.android.settingslib.drawable.CircleFramedDrawable;
73 import java.util.ArrayList;
74 import java.util.Collections;
75 import java.util.HashMap;
76 import java.util.List;
79 * Screen that manages the list of users on the device.
80 * Guest user is an always visible entry, even if the guest is not currently
81 * active/created. It is meant for controlling properties of a guest user.
83 * The first one is always the current user.
84 * Owner is the primary user.
86 public class UserSettings extends SettingsPreferenceFragment
87 implements OnPreferenceClickListener, OnClickListener, DialogInterface.OnDismissListener,
88 Preference.OnPreferenceChangeListener,
89 EditUserInfoController.OnContentChangedCallback, Indexable {
91 private static final String TAG = "UserSettings";
93 /** UserId of the user being removed */
94 private static final String SAVE_REMOVING_USER = "removing_user";
95 /** UserId of the user that was just added */
96 private static final String SAVE_ADDING_USER = "adding_user";
98 private static final String KEY_USER_LIST = "user_list";
99 private static final String KEY_USER_ME = "user_me";
100 private static final String KEY_ADD_USER = "user_add";
102 private static final int MENU_REMOVE_USER = Menu.FIRST;
103 private static final int MENU_ADD_ON_LOCKSCREEN = Menu.FIRST + 1;
105 private static final int DIALOG_CONFIRM_REMOVE = 1;
106 private static final int DIALOG_ADD_USER = 2;
107 private static final int DIALOG_SETUP_USER = 3;
108 private static final int DIALOG_SETUP_PROFILE = 4;
109 private static final int DIALOG_USER_CANNOT_MANAGE = 5;
110 private static final int DIALOG_CHOOSE_USER_TYPE = 6;
111 private static final int DIALOG_NEED_LOCKSCREEN = 7;
112 private static final int DIALOG_CONFIRM_EXIT_GUEST = 8;
113 private static final int DIALOG_USER_PROFILE_EDITOR = 9;
115 private static final int MESSAGE_UPDATE_LIST = 1;
116 private static final int MESSAGE_SETUP_USER = 2;
117 private static final int MESSAGE_CONFIG_USER = 3;
119 private static final int USER_TYPE_USER = 1;
120 private static final int USER_TYPE_RESTRICTED_PROFILE = 2;
122 private static final int REQUEST_CHOOSE_LOCK = 10;
124 private static final String KEY_ADD_USER_LONG_MESSAGE_DISPLAYED =
125 "key_add_user_long_message_displayed";
127 private static final String KEY_TITLE = "title";
128 private static final String KEY_SUMMARY = "summary";
130 private PreferenceGroup mUserListCategory;
131 private UserPreference mMePreference;
132 private SelectableEditTextPreference mNicknamePreference;
133 private Preference mAddUser;
134 private int mRemovingUserId = -1;
135 private int mAddedUserId = 0;
136 private boolean mAddingUser;
137 private UserCapabilities mUserCaps;
139 private final Object mUserLock = new Object();
140 private UserManager mUserManager;
141 private SparseArray<Bitmap> mUserIcons = new SparseArray<Bitmap>();
143 private EditUserInfoController mEditUserInfoController =
144 new EditUserInfoController();
146 // A place to cache the generated default avatar
147 private Drawable mDefaultIconDrawable;
149 private Handler mHandler = new Handler() {
151 public void handleMessage(Message msg) {
153 case MESSAGE_UPDATE_LIST:
156 case MESSAGE_SETUP_USER:
157 onUserCreated(msg.arg1);
159 case MESSAGE_CONFIG_USER:
160 onManageUserClicked(msg.arg1, true);
166 private BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {
168 public void onReceive(Context context, Intent intent) {
169 if (intent.getAction().equals(Intent.ACTION_USER_REMOVED)) {
170 mRemovingUserId = -1;
171 } else if (intent.getAction().equals(Intent.ACTION_USER_INFO_CHANGED)) {
172 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
173 if (userHandle != -1) {
174 mUserIcons.remove(userHandle);
177 mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
182 protected int getMetricsCategory() {
183 return MetricsLogger.USER;
187 public void onCreate(Bundle icicle) {
188 super.onCreate(icicle);
190 if (icicle != null) {
191 if (icicle.containsKey(SAVE_ADDING_USER)) {
192 mAddedUserId = icicle.getInt(SAVE_ADDING_USER);
194 if (icicle.containsKey(SAVE_REMOVING_USER)) {
195 mRemovingUserId = icicle.getInt(SAVE_REMOVING_USER);
197 mEditUserInfoController.onRestoreInstanceState(icicle);
199 final Context context = getActivity();
200 mUserCaps = UserCapabilities.create(context);
201 mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
202 if (!mUserCaps.mEnabled) {
206 final int myUserId = UserHandle.myUserId();
208 addPreferencesFromResource(R.xml.user_settings);
209 mUserListCategory = (PreferenceGroup) findPreference(KEY_USER_LIST);
210 mMePreference = new UserPreference(context, null /* attrs */, myUserId,
211 null /* settings icon handler */,
212 null /* delete icon handler */);
213 mMePreference.setKey(KEY_USER_ME);
214 mMePreference.setOnPreferenceClickListener(this);
215 if (mUserCaps.mIsOwner) {
216 mMePreference.setSummary(R.string.user_owner);
218 mAddUser = findPreference(KEY_ADD_USER);
219 // Determine if add user/profile button should be visible
220 if (mUserCaps.mCanAddUser) {
221 mAddUser.setOnPreferenceClickListener(this);
222 // change label to only mention user, if restricted profiles are not supported
223 if (!mUserCaps.mCanAddRestrictedProfile) {
224 mAddUser.setTitle(R.string.user_add_user_menu);
228 setHasOptionsMenu(true);
229 IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
230 filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
231 context.registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null,
234 if (Global.getInt(getContext().getContentResolver(), Global.DEVICE_PROVISIONED, 0) == 0) {
235 getActivity().finish();
241 public void onResume() {
244 if (!mUserCaps.mEnabled) return;
251 public void onDestroy() {
254 if (!mUserCaps.mEnabled) return;
256 getActivity().unregisterReceiver(mUserChangeReceiver);
260 public void onSaveInstanceState(Bundle outState) {
261 super.onSaveInstanceState(outState);
262 mEditUserInfoController.onSaveInstanceState(outState);
263 outState.putInt(SAVE_ADDING_USER, mAddedUserId);
264 outState.putInt(SAVE_REMOVING_USER, mRemovingUserId);
268 public void startActivityForResult(Intent intent, int requestCode) {
269 mEditUserInfoController.startingActivityForResult();
270 super.startActivityForResult(intent, requestCode);
274 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
276 UserManager um = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
277 if (!mUserCaps.mIsOwner && !um.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER)) {
278 String nickname = mUserManager.getUserName();
279 MenuItem removeThisUser = menu.add(0, MENU_REMOVE_USER, pos++,
280 getResources().getString(R.string.user_remove_user_menu, nickname));
281 removeThisUser.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
283 if (mUserCaps.mIsOwner && !um.hasUserRestriction(UserManager.DISALLOW_ADD_USER)) {
284 MenuItem allowAddOnLockscreen = menu.add(0, MENU_ADD_ON_LOCKSCREEN, pos++,
285 R.string.user_add_on_lockscreen_menu);
286 allowAddOnLockscreen.setCheckable(true);
287 allowAddOnLockscreen.setChecked(Settings.Global.getInt(getContentResolver(),
288 Settings.Global.ADD_USERS_WHEN_LOCKED, 0) == 1);
290 super.onCreateOptionsMenu(menu, inflater);
294 public boolean onOptionsItemSelected(MenuItem item) {
295 final int itemId = item.getItemId();
296 if (itemId == MENU_REMOVE_USER) {
297 onRemoveUserClicked(UserHandle.myUserId());
299 } else if (itemId == MENU_ADD_ON_LOCKSCREEN) {
300 final boolean isChecked = item.isChecked();
301 Settings.Global.putInt(getContentResolver(), Settings.Global.ADD_USERS_WHEN_LOCKED,
303 item.setChecked(!isChecked);
306 return super.onOptionsItemSelected(item);
311 * Loads profile information for the current user.
313 private void loadProfile() {
314 if (mUserCaps.mIsGuest) {
315 // No need to load profile information
316 mMePreference.setIcon(getEncircledDefaultIcon());
317 mMePreference.setTitle(R.string.user_exit_guest_title);
321 new AsyncTask<Void, Void, String>() {
323 protected void onPostExecute(String result) {
324 finishLoadProfile(result);
328 protected String doInBackground(Void... values) {
329 UserInfo user = mUserManager.getUserInfo(UserHandle.myUserId());
330 if (user.iconPath == null || user.iconPath.equals("")) {
331 assignProfilePhoto(user);
338 private void finishLoadProfile(String profileName) {
339 if (getActivity() == null) return;
340 mMePreference.setTitle(getString(R.string.user_you, profileName));
341 int myUserId = UserHandle.myUserId();
342 Bitmap b = mUserManager.getUserIcon(myUserId);
344 mMePreference.setIcon(encircle(b));
345 mUserIcons.put(myUserId, b);
349 private boolean hasLockscreenSecurity() {
350 LockPatternUtils lpu = new LockPatternUtils(getActivity());
351 return lpu.isSecure(UserHandle.myUserId());
354 private void launchChooseLockscreen() {
355 Intent chooseLockIntent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
356 chooseLockIntent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
357 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
358 startActivityForResult(chooseLockIntent, REQUEST_CHOOSE_LOCK);
362 public void onActivityResult(int requestCode, int resultCode, Intent data) {
363 super.onActivityResult(requestCode, resultCode, data);
365 if (requestCode == REQUEST_CHOOSE_LOCK) {
366 if (resultCode != Activity.RESULT_CANCELED && hasLockscreenSecurity()) {
367 addUserNow(USER_TYPE_RESTRICTED_PROFILE);
370 mEditUserInfoController.onActivityResult(requestCode, resultCode, data);
374 private void onAddUserClicked(int userType) {
375 synchronized (mUserLock) {
376 if (mRemovingUserId == -1 && !mAddingUser) {
379 showDialog(DIALOG_ADD_USER);
381 case USER_TYPE_RESTRICTED_PROFILE:
382 if (hasLockscreenSecurity()) {
383 addUserNow(USER_TYPE_RESTRICTED_PROFILE);
385 showDialog(DIALOG_NEED_LOCKSCREEN);
393 private void onRemoveUserClicked(int userId) {
394 synchronized (mUserLock) {
395 if (mRemovingUserId == -1 && !mAddingUser) {
396 mRemovingUserId = userId;
397 showDialog(DIALOG_CONFIRM_REMOVE);
402 private UserInfo createLimitedUser() {
403 UserInfo newUserInfo = mUserManager.createSecondaryUser(
404 getResources().getString(R.string.user_new_profile_name),
405 UserInfo.FLAG_RESTRICTED);
406 int userId = newUserInfo.id;
407 UserHandle user = new UserHandle(userId);
408 mUserManager.setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user);
409 // Change the setting before applying the DISALLOW_SHARE_LOCATION restriction, otherwise
410 // the putIntForUser() will fail.
411 Secure.putIntForUser(getContentResolver(),
412 Secure.LOCATION_MODE, Secure.LOCATION_MODE_OFF, userId);
413 mUserManager.setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, true, user);
414 assignDefaultPhoto(newUserInfo);
415 // Add shared accounts
416 AccountManager am = AccountManager.get(getActivity());
417 Account [] accounts = am.getAccounts();
418 if (accounts != null) {
419 for (Account account : accounts) {
420 am.addSharedAccount(account, user);
426 private UserInfo createTrustedUser() {
427 UserInfo newUserInfo = mUserManager.createSecondaryUser(
428 getResources().getString(R.string.user_new_user_name), 0);
429 if (newUserInfo != null) {
430 assignDefaultPhoto(newUserInfo);
435 private void onManageUserClicked(int userId, boolean newUser) {
436 if (userId == UserPreference.USERID_GUEST_DEFAULTS) {
437 Bundle extras = new Bundle();
438 extras.putBoolean(UserDetailsSettings.EXTRA_USER_GUEST, true);
439 ((SettingsActivity) getActivity()).startPreferencePanel(
440 UserDetailsSettings.class.getName(),
441 extras, R.string.user_guest, null, null, 0);
444 UserInfo info = mUserManager.getUserInfo(userId);
445 if (info.isRestricted() && mUserCaps.mIsOwner) {
446 Bundle extras = new Bundle();
447 extras.putInt(RestrictedProfileSettings.EXTRA_USER_ID, userId);
448 extras.putBoolean(RestrictedProfileSettings.EXTRA_NEW_USER, newUser);
449 ((SettingsActivity) getActivity()).startPreferencePanel(
450 RestrictedProfileSettings.class.getName(),
451 extras, R.string.user_restrictions_title, null,
453 } else if (info.id == UserHandle.myUserId()) {
454 // Jump to owner info panel
455 OwnerInfoSettings.show(this);
456 } else if (mUserCaps.mIsOwner) {
457 Bundle extras = new Bundle();
458 extras.putInt(UserDetailsSettings.EXTRA_USER_ID, userId);
459 ((SettingsActivity) getActivity()).startPreferencePanel(
460 UserDetailsSettings.class.getName(),
462 -1, /* No title res id */
463 info.name, /* title */
465 0 /* resultRequestCode */);
469 private void onUserCreated(int userId) {
470 mAddedUserId = userId;
471 if (mUserManager.getUserInfo(userId).isRestricted()) {
472 showDialog(DIALOG_SETUP_PROFILE);
474 showDialog(DIALOG_SETUP_USER);
479 public void onDialogShowing() {
480 super.onDialogShowing();
482 setOnDismissListener(this);
486 public Dialog onCreateDialog(int dialogId) {
487 Context context = getActivity();
488 if (context == null) return null;
490 case DIALOG_CONFIRM_REMOVE: {
492 UserDialogs.createRemoveDialog(getActivity(), mRemovingUserId,
493 new DialogInterface.OnClickListener() {
494 public void onClick(DialogInterface dialog, int which) {
501 case DIALOG_USER_CANNOT_MANAGE:
502 return new AlertDialog.Builder(context)
503 .setMessage(R.string.user_cannot_manage_message)
504 .setPositiveButton(android.R.string.ok, null)
506 case DIALOG_ADD_USER: {
507 final SharedPreferences preferences = getActivity().getPreferences(
508 Context.MODE_PRIVATE);
509 final boolean longMessageDisplayed = preferences.getBoolean(
510 KEY_ADD_USER_LONG_MESSAGE_DISPLAYED, false);
511 final int messageResId = longMessageDisplayed
512 ? R.string.user_add_user_message_short
513 : R.string.user_add_user_message_long;
514 final int userType = dialogId == DIALOG_ADD_USER
515 ? USER_TYPE_USER : USER_TYPE_RESTRICTED_PROFILE;
516 Dialog dlg = new AlertDialog.Builder(context)
517 .setTitle(R.string.user_add_user_title)
518 .setMessage(messageResId)
519 .setPositiveButton(android.R.string.ok,
520 new DialogInterface.OnClickListener() {
521 public void onClick(DialogInterface dialog, int which) {
522 addUserNow(userType);
523 if (!longMessageDisplayed) {
524 preferences.edit().putBoolean(
525 KEY_ADD_USER_LONG_MESSAGE_DISPLAYED, true).apply();
529 .setNegativeButton(android.R.string.cancel, null)
533 case DIALOG_SETUP_USER: {
534 Dialog dlg = new AlertDialog.Builder(context)
535 .setTitle(R.string.user_setup_dialog_title)
536 .setMessage(R.string.user_setup_dialog_message)
537 .setPositiveButton(R.string.user_setup_button_setup_now,
538 new DialogInterface.OnClickListener() {
539 public void onClick(DialogInterface dialog, int which) {
540 switchUserNow(mAddedUserId);
543 .setNegativeButton(R.string.user_setup_button_setup_later, null)
547 case DIALOG_SETUP_PROFILE: {
548 Dialog dlg = new AlertDialog.Builder(context)
549 .setMessage(R.string.user_setup_profile_dialog_message)
550 .setPositiveButton(android.R.string.ok,
551 new DialogInterface.OnClickListener() {
552 public void onClick(DialogInterface dialog, int which) {
553 switchUserNow(mAddedUserId);
556 .setNegativeButton(android.R.string.cancel, null)
560 case DIALOG_CHOOSE_USER_TYPE: {
561 List<HashMap<String, String>> data = new ArrayList<HashMap<String,String>>();
562 HashMap<String,String> addUserItem = new HashMap<String,String>();
563 addUserItem.put(KEY_TITLE, getString(R.string.user_add_user_item_title));
564 addUserItem.put(KEY_SUMMARY, getString(R.string.user_add_user_item_summary));
565 HashMap<String,String> addProfileItem = new HashMap<String,String>();
566 addProfileItem.put(KEY_TITLE, getString(R.string.user_add_profile_item_title));
567 addProfileItem.put(KEY_SUMMARY, getString(R.string.user_add_profile_item_summary));
568 data.add(addUserItem);
569 data.add(addProfileItem);
570 AlertDialog.Builder builder = new AlertDialog.Builder(context);
571 SimpleAdapter adapter = new SimpleAdapter(builder.getContext(),
572 data, R.layout.two_line_list_item,
573 new String[] {KEY_TITLE, KEY_SUMMARY},
574 new int[] {R.id.title, R.id.summary});
575 builder.setTitle(R.string.user_add_user_type_title);
576 builder.setAdapter(adapter,
577 new DialogInterface.OnClickListener() {
579 public void onClick(DialogInterface dialog, int which) {
580 onAddUserClicked(which == 0
582 : USER_TYPE_RESTRICTED_PROFILE);
585 return builder.create();
587 case DIALOG_NEED_LOCKSCREEN: {
588 Dialog dlg = new AlertDialog.Builder(context)
589 .setMessage(R.string.user_need_lock_message)
590 .setPositiveButton(R.string.user_set_lock_button,
591 new DialogInterface.OnClickListener() {
593 public void onClick(DialogInterface dialog, int which) {
594 launchChooseLockscreen();
597 .setNegativeButton(android.R.string.cancel, null)
601 case DIALOG_CONFIRM_EXIT_GUEST: {
602 Dialog dlg = new AlertDialog.Builder(context)
603 .setTitle(R.string.user_exit_guest_confirm_title)
604 .setMessage(R.string.user_exit_guest_confirm_message)
605 .setPositiveButton(R.string.user_exit_guest_dialog_remove,
606 new DialogInterface.OnClickListener() {
608 public void onClick(DialogInterface dialog, int which) {
612 .setNegativeButton(android.R.string.cancel, null)
616 case DIALOG_USER_PROFILE_EDITOR: {
617 Dialog dlg = mEditUserInfoController.createDialog(
619 mMePreference.getIcon(),
620 mMePreference.getTitle(),
621 R.string.profile_info_settings_title,
623 android.os.Process.myUserHandle());
631 private void removeUserNow() {
632 if (mRemovingUserId == UserHandle.myUserId()) {
637 synchronized (mUserLock) {
638 mUserManager.removeUser(mRemovingUserId);
639 mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
646 private void removeThisUser() {
648 ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER);
649 ((UserManager) getActivity().getSystemService(Context.USER_SERVICE))
650 .removeUser(UserHandle.myUserId());
651 } catch (RemoteException re) {
652 Log.e(TAG, "Unable to remove self user");
656 private void addUserNow(final int userType) {
657 synchronized (mUserLock) {
663 // Could take a few seconds
664 if (userType == USER_TYPE_USER) {
665 user = createTrustedUser();
667 user = createLimitedUser();
669 synchronized (mUserLock) {
671 if (userType == USER_TYPE_USER) {
672 mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
673 mHandler.sendMessage(mHandler.obtainMessage(
674 MESSAGE_SETUP_USER, user.id, user.serialNumber));
676 mHandler.sendMessage(mHandler.obtainMessage(
677 MESSAGE_CONFIG_USER, user.id, user.serialNumber));
685 private void switchUserNow(int userId) {
687 ActivityManagerNative.getDefault().switchUser(userId);
688 } catch (RemoteException re) {
694 * Erase the current user (guest) and switch to another user.
696 private void exitGuest() {
698 if (!mUserCaps.mIsGuest) {
704 private void updateUserList() {
705 if (getActivity() == null) return;
706 List<UserInfo> users = mUserManager.getUsers(true);
707 final Context context = getActivity();
709 final boolean voiceCapable = Utils.isVoiceCapable(context);
710 final ArrayList<Integer> missingIcons = new ArrayList<>();
711 final ArrayList<UserPreference> userPreferences = new ArrayList<>();
712 userPreferences.add(mMePreference);
714 for (UserInfo user : users) {
715 if (user.isManagedProfile()) {
716 // Managed profiles appear under Accounts Settings instead
720 if (user.id == UserHandle.myUserId()) {
721 pref = mMePreference;
722 } else if (user.isGuest()) {
723 // Skip over Guest. We add generic Guest settings after this loop
727 // Secondary user: Settings
729 // Restricted Profile: There is no Restricted Profile
730 // Without Telephony:
731 // Secondary user: Delete
733 // Restricted Profile: Settings
734 final boolean showSettings = mUserCaps.mIsOwner
735 && (voiceCapable || user.isRestricted());
736 final boolean showDelete = mUserCaps.mIsOwner
737 && (!voiceCapable && !user.isRestricted() && !user.isGuest());
738 pref = new UserPreference(context, null, user.id,
739 showSettings ? this : null,
740 showDelete ? this : null);
741 pref.setOnPreferenceClickListener(this);
742 pref.setKey("id=" + user.id);
743 userPreferences.add(pref);
744 if (user.id == UserHandle.USER_OWNER) {
745 pref.setSummary(R.string.user_owner);
747 pref.setTitle(user.name);
749 if (!isInitialized(user)) {
750 if (user.isRestricted()) {
751 pref.setSummary(R.string.user_summary_restricted_not_set_up);
753 pref.setSummary(R.string.user_summary_not_set_up);
755 } else if (user.isRestricted()) {
756 pref.setSummary(R.string.user_summary_restricted_profile);
758 if (user.iconPath != null) {
759 if (mUserIcons.get(user.id) == null) {
760 // Icon not loaded yet, print a placeholder
761 missingIcons.add(user.id);
762 pref.setIcon(getEncircledDefaultIcon());
764 setPhotoId(pref, user);
767 // Icon not available yet, print a placeholder
768 pref.setIcon(getEncircledDefaultIcon());
772 // Add a temporary entry for the user being created
774 UserPreference pref = new UserPreference(getActivity(), null,
775 UserPreference.USERID_UNKNOWN, null, null);
776 pref.setEnabled(false);
777 pref.setTitle(R.string.user_new_user_name);
778 pref.setIcon(getEncircledDefaultIcon());
779 userPreferences.add(pref);
782 if (!mUserCaps.mIsGuest && (mUserCaps.mCanAddGuest || findGuest() != null)) {
783 // Add a virtual Guest user for guest defaults
784 UserPreference pref = new UserPreference(getActivity(), null,
785 UserPreference.USERID_GUEST_DEFAULTS,
786 mUserCaps.mIsOwner && voiceCapable? this : null /* settings icon handler */,
787 null /* delete icon handler */);
788 pref.setTitle(R.string.user_guest);
789 pref.setIcon(getEncircledDefaultIcon());
790 pref.setOnPreferenceClickListener(this);
791 userPreferences.add(pref);
794 // Sort list of users by serialNum
795 Collections.sort(userPreferences, UserPreference.SERIAL_NUMBER_COMPARATOR);
797 getActivity().invalidateOptionsMenu();
800 if (missingIcons.size() > 0) {
801 loadIconsAsync(missingIcons);
804 PreferenceScreen preferenceScreen = getPreferenceScreen();
805 preferenceScreen.removeAll();
807 // If profiles are supported, userPreferences will be added to the category labeled
808 // "User & Profiles", otherwise the category is skipped and elements are added directly
809 // to preferenceScreen
810 PreferenceGroup groupToAddUsers;
811 if (mUserCaps.mCanAddRestrictedProfile) {
812 mUserListCategory.removeAll();
813 mUserListCategory.setOrder(Preference.DEFAULT_ORDER);
814 preferenceScreen.addPreference(mUserListCategory);
815 groupToAddUsers = mUserListCategory;
817 groupToAddUsers = preferenceScreen;
819 for (UserPreference userPreference : userPreferences) {
820 userPreference.setOrder(Preference.DEFAULT_ORDER);
821 groupToAddUsers.addPreference(userPreference);
824 // Append Add user to the end of the list
825 if (mUserCaps.mCanAddUser) {
826 boolean moreUsers = mUserManager.canAddMoreUsers();
827 mAddUser.setOrder(Preference.DEFAULT_ORDER);
828 preferenceScreen.addPreference(mAddUser);
829 mAddUser.setEnabled(moreUsers);
831 mAddUser.setSummary(getString(R.string.user_add_max_count, getMaxRealUsers()));
833 mAddUser.setSummary(null);
838 private int getMaxRealUsers() {
839 // guest is not counted against getMaxSupportedUsers() number
840 final int maxUsersAndGuest = UserManager.getMaxSupportedUsers() + 1;
841 final List<UserInfo> users = mUserManager.getUsers();
842 // managed profiles are counted against getMaxSupportedUsers()
843 int managedProfiles = 0;
844 for (UserInfo user : users) {
845 if (user.isManagedProfile()) {
849 return maxUsersAndGuest - managedProfiles;
852 private void loadIconsAsync(List<Integer> missingIcons) {
853 new AsyncTask<List<Integer>, Void, Void>() {
855 protected void onPostExecute(Void result) {
860 protected Void doInBackground(List<Integer>... values) {
861 for (int userId : values[0]) {
862 Bitmap bitmap = mUserManager.getUserIcon(userId);
863 if (bitmap == null) {
864 bitmap = Utils.getDefaultUserIconAsBitmap(userId);
866 mUserIcons.append(userId, bitmap);
870 }.execute(missingIcons);
873 private void assignProfilePhoto(final UserInfo user) {
874 if (!Utils.copyMeProfilePhoto(getActivity(), user)) {
875 assignDefaultPhoto(user);
879 private void assignDefaultPhoto(UserInfo user) {
880 Bitmap bitmap = Utils.getDefaultUserIconAsBitmap(user.id);
881 mUserManager.setUserIcon(user.id, bitmap);
884 private Drawable getEncircledDefaultIcon() {
885 if (mDefaultIconDrawable == null) {
886 mDefaultIconDrawable = encircle(Utils.getDefaultUserIconAsBitmap(UserHandle.USER_NULL));
888 return mDefaultIconDrawable;
891 private void setPhotoId(Preference pref, UserInfo user) {
892 Bitmap bitmap = mUserIcons.get(user.id);
893 if (bitmap != null) {
894 pref.setIcon(encircle(bitmap));
898 private void setUserName(String name) {
899 mUserManager.setUserName(UserHandle.myUserId(), name);
900 mNicknamePreference.setSummary(name);
901 getActivity().invalidateOptionsMenu();
905 public boolean onPreferenceClick(Preference pref) {
906 if (pref == mMePreference) {
907 if (mUserCaps.mIsGuest) {
908 showDialog(DIALOG_CONFIRM_EXIT_GUEST);
911 // If this is a limited user, launch the user info settings instead of profile editor
912 if (mUserManager.isLinkedUser()) {
913 onManageUserClicked(UserHandle.myUserId(), false);
915 showDialog(DIALOG_USER_PROFILE_EDITOR);
917 } else if (pref instanceof UserPreference) {
918 int userId = ((UserPreference) pref).getUserId();
919 if (userId == UserPreference.USERID_GUEST_DEFAULTS) {
920 createAndSwitchToGuestUser();
922 // Get the latest status of the user
923 UserInfo user = mUserManager.getUserInfo(userId);
924 if (!isInitialized(user)) {
925 mHandler.sendMessage(mHandler.obtainMessage(
926 MESSAGE_SETUP_USER, user.id, user.serialNumber));
928 switchUserNow(userId);
931 } else if (pref == mAddUser) {
932 // If we allow both types, show a picker, otherwise directly go to
933 // flow for full user.
934 if (mUserCaps.mCanAddRestrictedProfile) {
935 showDialog(DIALOG_CHOOSE_USER_TYPE);
937 onAddUserClicked(USER_TYPE_USER);
943 private void createAndSwitchToGuestUser() {
944 final UserInfo guest = findGuest();
946 switchUserNow(guest.id);
949 UserInfo guestUser = mUserManager.createGuest(getActivity(),
950 getResources().getString(R.string.user_guest));
951 if (guestUser != null) {
952 switchUserNow(guestUser.id);
956 private UserInfo findGuest() {
957 List<UserInfo> users = mUserManager.getUsers();
958 for (UserInfo user : users) {
959 if (user.isGuest()) {
966 private boolean isInitialized(UserInfo user) {
967 return (user.flags & UserInfo.FLAG_INITIALIZED) != 0;
970 private Drawable encircle(Bitmap icon) {
971 Drawable circled = CircleFramedDrawable.getInstance(getActivity(), icon);
976 public void onClick(View v) {
977 if (v.getTag() instanceof UserPreference) {
978 int userId = ((UserPreference) v.getTag()).getUserId();
980 case UserPreference.DELETE_ID:
981 onRemoveUserClicked(userId);
983 case UserPreference.SETTINGS_ID:
984 onManageUserClicked(userId, false);
991 public void onDismiss(DialogInterface dialog) {
992 synchronized (mUserLock) {
994 mRemovingUserId = -1;
1000 public boolean onPreferenceChange(Preference preference, Object newValue) {
1001 if (preference == mNicknamePreference) {
1002 String value = (String) newValue;
1003 if (preference == mNicknamePreference && value != null
1004 && value.length() > 0) {
1013 public int getHelpResource() {
1014 return R.string.help_url_users;
1018 public void onPhotoChanged(Drawable photo) {
1019 mMePreference.setIcon(photo);
1023 public void onLabelChanged(CharSequence label) {
1024 mMePreference.setTitle(label);
1027 private static class UserCapabilities {
1028 boolean mEnabled = true;
1029 boolean mCanAddUser = true;
1030 boolean mCanAddRestrictedProfile = true;
1031 boolean mIsOwner = UserHandle.myUserId() == UserHandle.USER_OWNER;
1033 boolean mCanAddGuest;
1035 public static UserCapabilities create(Context context) {
1036 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
1037 UserCapabilities caps = new UserCapabilities();
1038 if (!UserManager.supportsMultipleUsers() || Utils.isMonkeyRunning()) {
1039 caps.mEnabled = false;
1043 final boolean disallowAddUser = userManager.hasUserRestriction(
1044 UserManager.DISALLOW_ADD_USER);
1045 if (!caps.mIsOwner || UserManager.getMaxSupportedUsers() < 2
1046 || !UserManager.supportsMultipleUsers()
1047 || disallowAddUser) {
1048 caps.mCanAddUser = false;
1050 DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
1051 Context.DEVICE_POLICY_SERVICE);
1052 // No restricted profiles for tablets with a device owner, or phones.
1053 if (dpm.getDeviceOwner() != null || Utils.isVoiceCapable(context)) {
1054 caps.mCanAddRestrictedProfile = false;
1056 final int myUserId = UserHandle.myUserId();
1057 caps.mIsGuest = userManager.getUserInfo(myUserId).isGuest();
1059 final boolean canAddUsersWhenLocked = caps.mIsOwner || Settings.Global.getInt(
1060 context.getContentResolver(), Settings.Global.ADD_USERS_WHEN_LOCKED, 0) == 1;
1061 caps.mCanAddGuest = !caps.mIsGuest && !disallowAddUser && canAddUsersWhenLocked;
1066 public String toString() {
1067 return "UserCapabilities{" +
1068 "mEnabled=" + mEnabled +
1069 ", mCanAddUser=" + mCanAddUser +
1070 ", mCanAddRestrictedProfile=" + mCanAddRestrictedProfile +
1071 ", mIsOwner=" + mIsOwner +
1072 ", mIsGuest=" + mIsGuest +
1077 public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
1078 new BaseSearchIndexProvider() {
1080 public List<SearchIndexableRaw> getRawDataToIndex(Context context,
1082 final List<SearchIndexableRaw> result = new ArrayList<>();
1083 final UserCapabilities userCaps = UserCapabilities.create(context);
1084 if (!userCaps.mEnabled) {
1087 final Resources res = context.getResources();
1088 SearchIndexableRaw data = new SearchIndexableRaw(context);
1089 data.title = res.getString(R.string.user_settings_title);
1090 data.screenTitle = res.getString(R.string.user_settings_title);
1093 if (userCaps.mCanAddUser) {
1094 data = new SearchIndexableRaw(context);
1095 data.title = res.getString(userCaps.mCanAddRestrictedProfile ?
1096 R.string.user_add_user_or_profile_menu
1097 : R.string.user_add_user_menu);
1098 data.screenTitle = res.getString(R.string.user_settings_title);