• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 package com.android.settings.users;
18 
19 import android.app.Activity;
20 import android.app.ActivityManager;
21 import android.app.AlertDialog;
22 import android.app.Dialog;
23 import android.app.admin.DevicePolicyManager;
24 import android.content.BroadcastReceiver;
25 import android.content.Context;
26 import android.content.DialogInterface;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.content.SharedPreferences;
30 import android.content.pm.UserInfo;
31 import android.content.res.Resources;
32 import android.graphics.Bitmap;
33 import android.graphics.drawable.Drawable;
34 import android.os.AsyncTask;
35 import android.os.Bundle;
36 import android.os.Handler;
37 import android.os.Message;
38 import android.os.RemoteException;
39 import android.os.UserHandle;
40 import android.os.UserManager;
41 import android.provider.Settings.Global;
42 import android.support.v7.preference.Preference;
43 import android.support.v7.preference.Preference.OnPreferenceClickListener;
44 import android.support.v7.preference.PreferenceGroup;
45 import android.support.v7.preference.PreferenceScreen;
46 import android.util.Log;
47 import android.util.SparseArray;
48 import android.view.Menu;
49 import android.view.MenuInflater;
50 import android.view.MenuItem;
51 import android.view.View;
52 import android.view.View.OnClickListener;
53 import android.widget.SimpleAdapter;
54 
55 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
56 import com.android.internal.widget.LockPatternUtils;
57 import com.android.settings.DimmableIconPreference;
58 import com.android.settings.OwnerInfoSettings;
59 import com.android.settings.R;
60 import com.android.settings.SettingsActivity;
61 import com.android.settings.SettingsPreferenceFragment;
62 import com.android.settings.Utils;
63 import com.android.settings.dashboard.SummaryLoader;
64 import com.android.settings.password.ChooseLockGeneric;
65 import com.android.settings.search.BaseSearchIndexProvider;
66 import com.android.settings.search.Indexable;
67 import com.android.settings.search.SearchIndexableRaw;
68 import com.android.settingslib.RestrictedLockUtils;
69 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
70 import com.android.settingslib.drawable.CircleFramedDrawable;
71 
72 import java.util.ArrayList;
73 import java.util.Collections;
74 import java.util.HashMap;
75 import java.util.List;
76 
77 /**
78  * Screen that manages the list of users on the device.
79  * Guest user is an always visible entry, even if the guest is not currently
80  * active/created. It is meant for controlling properties of a guest user.
81  *
82  * The first one is always the current user.
83  * Owner is the primary user.
84  */
85 public class UserSettings extends SettingsPreferenceFragment
86         implements OnPreferenceClickListener, OnClickListener, DialogInterface.OnDismissListener,
87         EditUserInfoController.OnContentChangedCallback, Indexable {
88 
89     private static final String TAG = "UserSettings";
90 
91     /** UserId of the user being removed */
92     private static final String SAVE_REMOVING_USER = "removing_user";
93     /** UserId of the user that was just added */
94     private static final String SAVE_ADDING_USER = "adding_user";
95 
96     private static final String KEY_USER_LIST = "user_list";
97     private static final String KEY_USER_ME = "user_me";
98     private static final String KEY_ADD_USER = "user_add";
99 
100     private static final int MENU_REMOVE_USER = Menu.FIRST;
101 
102     private static final int DIALOG_CONFIRM_REMOVE = 1;
103     private static final int DIALOG_ADD_USER = 2;
104     private static final int DIALOG_SETUP_USER = 3;
105     private static final int DIALOG_SETUP_PROFILE = 4;
106     private static final int DIALOG_USER_CANNOT_MANAGE = 5;
107     private static final int DIALOG_CHOOSE_USER_TYPE = 6;
108     private static final int DIALOG_NEED_LOCKSCREEN = 7;
109     private static final int DIALOG_CONFIRM_EXIT_GUEST = 8;
110     private static final int DIALOG_USER_PROFILE_EDITOR = 9;
111 
112     private static final int MESSAGE_UPDATE_LIST = 1;
113     private static final int MESSAGE_SETUP_USER = 2;
114     private static final int MESSAGE_CONFIG_USER = 3;
115 
116     private static final int USER_TYPE_USER = 1;
117     private static final int USER_TYPE_RESTRICTED_PROFILE = 2;
118 
119     private static final int REQUEST_CHOOSE_LOCK = 10;
120 
121     private static final String KEY_ADD_USER_LONG_MESSAGE_DISPLAYED =
122             "key_add_user_long_message_displayed";
123 
124     private static final String KEY_TITLE = "title";
125     private static final String KEY_SUMMARY = "summary";
126 
127     private PreferenceGroup mUserListCategory;
128     private UserPreference mMePreference;
129     private DimmableIconPreference mAddUser;
130     private int mRemovingUserId = -1;
131     private int mAddedUserId = 0;
132     private boolean mAddingUser;
133     private String mAddingUserName;
134     private UserCapabilities mUserCaps;
135     private boolean mShouldUpdateUserList = true;
136     private final Object mUserLock = new Object();
137     private UserManager mUserManager;
138     private SparseArray<Bitmap> mUserIcons = new SparseArray<Bitmap>();
139 
140     private EditUserInfoController mEditUserInfoController =
141             new EditUserInfoController();
142 
143     // A place to cache the generated default avatar
144     private Drawable mDefaultIconDrawable;
145 
146     private Handler mHandler = new Handler() {
147         @Override
148         public void handleMessage(Message msg) {
149             switch (msg.what) {
150             case MESSAGE_UPDATE_LIST:
151                 updateUserList();
152                 break;
153             case MESSAGE_SETUP_USER:
154                 onUserCreated(msg.arg1);
155                 break;
156             case MESSAGE_CONFIG_USER:
157                 onManageUserClicked(msg.arg1, true);
158                 break;
159             }
160         }
161     };
162 
163     private BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {
164         @Override
165         public void onReceive(Context context, Intent intent) {
166             if (intent.getAction().equals(Intent.ACTION_USER_REMOVED)) {
167                 mRemovingUserId = -1;
168             } else if (intent.getAction().equals(Intent.ACTION_USER_INFO_CHANGED)) {
169                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
170                 if (userHandle != -1) {
171                     mUserIcons.remove(userHandle);
172                 }
173             }
174             mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
175         }
176     };
177 
178     @Override
getMetricsCategory()179     public int getMetricsCategory() {
180         return MetricsEvent.USER;
181     }
182 
183     @Override
onCreate(Bundle icicle)184     public void onCreate(Bundle icicle) {
185         super.onCreate(icicle);
186 
187         if (icicle != null) {
188             if (icicle.containsKey(SAVE_ADDING_USER)) {
189                 mAddedUserId = icicle.getInt(SAVE_ADDING_USER);
190             }
191             if (icicle.containsKey(SAVE_REMOVING_USER)) {
192                 mRemovingUserId = icicle.getInt(SAVE_REMOVING_USER);
193             }
194             mEditUserInfoController.onRestoreInstanceState(icicle);
195         }
196         final Context context = getActivity();
197         mUserCaps = UserCapabilities.create(context);
198         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
199         if (!mUserCaps.mEnabled) {
200             return;
201         }
202 
203         final int myUserId = UserHandle.myUserId();
204 
205         addPreferencesFromResource(R.xml.user_settings);
206         mUserListCategory = (PreferenceGroup) findPreference(KEY_USER_LIST);
207         mMePreference = new UserPreference(getPrefContext(), null /* attrs */, myUserId,
208                 null /* settings icon handler */,
209                 null /* delete icon handler */);
210         mMePreference.setKey(KEY_USER_ME);
211         mMePreference.setOnPreferenceClickListener(this);
212         if (mUserCaps.mIsAdmin) {
213             mMePreference.setSummary(R.string.user_admin);
214         }
215         mAddUser = (DimmableIconPreference) findPreference(KEY_ADD_USER);
216         mAddUser.useAdminDisabledSummary(false);
217         // Determine if add user/profile button should be visible
218         if (mUserCaps.mCanAddUser && Utils.isDeviceProvisioned(getActivity())) {
219             mAddUser.setOnPreferenceClickListener(this);
220             // change label to only mention user, if restricted profiles are not supported
221             if (!mUserCaps.mCanAddRestrictedProfile) {
222                 mAddUser.setTitle(R.string.user_add_user_menu);
223             }
224         }
225         setHasOptionsMenu(true);
226         IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
227         filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
228         context.registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null, mHandler);
229         loadProfile();
230         updateUserList();
231         mShouldUpdateUserList = false;
232 
233         if (Global.getInt(getContext().getContentResolver(), Global.DEVICE_PROVISIONED, 0) == 0) {
234             getActivity().finish();
235             return;
236         }
237     }
238 
239     @Override
onResume()240     public void onResume() {
241         super.onResume();
242 
243         if (!mUserCaps.mEnabled) return;
244         if (mShouldUpdateUserList) {
245             mUserCaps.updateAddUserCapabilities(getActivity());
246             loadProfile();
247             updateUserList();
248         }
249     }
250 
251     @Override
onPause()252     public void onPause() {
253         mShouldUpdateUserList = true;
254         super.onPause();
255     }
256 
257     @Override
onDestroy()258     public void onDestroy() {
259         super.onDestroy();
260 
261         if (!mUserCaps.mEnabled) return;
262 
263         getActivity().unregisterReceiver(mUserChangeReceiver);
264     }
265 
266     @Override
onSaveInstanceState(Bundle outState)267     public void onSaveInstanceState(Bundle outState) {
268         super.onSaveInstanceState(outState);
269         mEditUserInfoController.onSaveInstanceState(outState);
270         outState.putInt(SAVE_ADDING_USER, mAddedUserId);
271         outState.putInt(SAVE_REMOVING_USER, mRemovingUserId);
272     }
273 
274     @Override
startActivityForResult(Intent intent, int requestCode)275     public void startActivityForResult(Intent intent, int requestCode) {
276         mEditUserInfoController.startingActivityForResult();
277         super.startActivityForResult(intent, requestCode);
278     }
279 
280     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)281     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
282         int pos = 0;
283         UserManager um = getContext().getSystemService(UserManager.class);
284         boolean allowRemoveUser = !um.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER);
285         boolean canSwitchUsers = um.canSwitchUsers();
286         if (!mUserCaps.mIsAdmin && allowRemoveUser && canSwitchUsers) {
287             String nickname = mUserManager.getUserName();
288             MenuItem removeThisUser = menu.add(0, MENU_REMOVE_USER, pos++,
289                     getResources().getString(R.string.user_remove_user_menu, nickname));
290             removeThisUser.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
291         }
292         super.onCreateOptionsMenu(menu, inflater);
293     }
294 
295     @Override
onOptionsItemSelected(MenuItem item)296     public boolean onOptionsItemSelected(MenuItem item) {
297         final int itemId = item.getItemId();
298         if (itemId == MENU_REMOVE_USER) {
299             onRemoveUserClicked(UserHandle.myUserId());
300             return true;
301         } else {
302             return super.onOptionsItemSelected(item);
303         }
304     }
305 
306     /**
307      * Loads profile information for the current user.
308      */
loadProfile()309     private void loadProfile() {
310         if (mUserCaps.mIsGuest) {
311             // No need to load profile information
312             mMePreference.setIcon(getEncircledDefaultIcon());
313             mMePreference.setTitle(R.string.user_exit_guest_title);
314             return;
315         }
316 
317         new AsyncTask<Void, Void, String>() {
318             @Override
319             protected void onPostExecute(String result) {
320                 finishLoadProfile(result);
321             }
322 
323             @Override
324             protected String doInBackground(Void... values) {
325                 UserInfo user = mUserManager.getUserInfo(UserHandle.myUserId());
326                 if (user.iconPath == null || user.iconPath.equals("")) {
327                     // Assign profile photo.
328                     Utils.copyMeProfilePhoto(getActivity(), user);
329                 }
330                 return user.name;
331             }
332         }.execute();
333     }
334 
finishLoadProfile(String profileName)335     private void finishLoadProfile(String profileName) {
336         if (getActivity() == null) return;
337         mMePreference.setTitle(getString(R.string.user_you, profileName));
338         int myUserId = UserHandle.myUserId();
339         Bitmap b = mUserManager.getUserIcon(myUserId);
340         if (b != null) {
341             mMePreference.setIcon(encircle(b));
342             mUserIcons.put(myUserId, b);
343         }
344     }
345 
hasLockscreenSecurity()346     private boolean hasLockscreenSecurity() {
347         LockPatternUtils lpu = new LockPatternUtils(getActivity());
348         return lpu.isSecure(UserHandle.myUserId());
349     }
350 
launchChooseLockscreen()351     private void launchChooseLockscreen() {
352         Intent chooseLockIntent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
353         chooseLockIntent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
354                 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
355         startActivityForResult(chooseLockIntent, REQUEST_CHOOSE_LOCK);
356     }
357 
358     @Override
onActivityResult(int requestCode, int resultCode, Intent data)359     public void onActivityResult(int requestCode, int resultCode, Intent data) {
360         super.onActivityResult(requestCode, resultCode, data);
361 
362         if (requestCode == REQUEST_CHOOSE_LOCK) {
363             if (resultCode != Activity.RESULT_CANCELED && hasLockscreenSecurity()) {
364                 addUserNow(USER_TYPE_RESTRICTED_PROFILE);
365             }
366         } else {
367             mEditUserInfoController.onActivityResult(requestCode, resultCode, data);
368         }
369     }
370 
onAddUserClicked(int userType)371     private void onAddUserClicked(int userType) {
372         synchronized (mUserLock) {
373             if (mRemovingUserId == -1 && !mAddingUser) {
374                 switch (userType) {
375                 case USER_TYPE_USER:
376                     showDialog(DIALOG_ADD_USER);
377                     break;
378                 case USER_TYPE_RESTRICTED_PROFILE:
379                     if (hasLockscreenSecurity()) {
380                         addUserNow(USER_TYPE_RESTRICTED_PROFILE);
381                     } else {
382                         showDialog(DIALOG_NEED_LOCKSCREEN);
383                     }
384                     break;
385                 }
386             }
387         }
388     }
389 
onRemoveUserClicked(int userId)390     private void onRemoveUserClicked(int userId) {
391         synchronized (mUserLock) {
392             if (mRemovingUserId == -1 && !mAddingUser) {
393                 mRemovingUserId = userId;
394                 showDialog(DIALOG_CONFIRM_REMOVE);
395             }
396         }
397     }
398 
createRestrictedProfile()399     private UserInfo createRestrictedProfile() {
400         UserInfo newUserInfo = mUserManager.createRestrictedProfile(mAddingUserName);
401         if (newUserInfo != null && !Utils.assignDefaultPhoto(getActivity(), newUserInfo.id)) {
402             return null;
403         }
404         return newUserInfo;
405     }
406 
createTrustedUser()407     private UserInfo createTrustedUser() {
408         UserInfo newUserInfo = mUserManager.createUser(mAddingUserName, 0);
409         if (newUserInfo != null && !Utils.assignDefaultPhoto(getActivity(), newUserInfo.id)) {
410             return null;
411         }
412         return newUserInfo;
413     }
414 
onManageUserClicked(int userId, boolean newUser)415     private void onManageUserClicked(int userId, boolean newUser) {
416         mAddingUser = false;
417         if (userId == UserPreference.USERID_GUEST_DEFAULTS) {
418             Bundle extras = new Bundle();
419             extras.putBoolean(UserDetailsSettings.EXTRA_USER_GUEST, true);
420             ((SettingsActivity) getActivity()).startPreferencePanel(this,
421                     UserDetailsSettings.class.getName(),
422                     extras, R.string.user_guest, null, null, 0);
423             return;
424         }
425         UserInfo info = mUserManager.getUserInfo(userId);
426         if (info.isRestricted() && mUserCaps.mIsAdmin) {
427             Bundle extras = new Bundle();
428             extras.putInt(RestrictedProfileSettings.EXTRA_USER_ID, userId);
429             extras.putBoolean(RestrictedProfileSettings.EXTRA_NEW_USER, newUser);
430             ((SettingsActivity) getActivity()).startPreferencePanel(this,
431                     RestrictedProfileSettings.class.getName(),
432                     extras, R.string.user_restrictions_title, null,
433                     null, 0);
434         } else if (info.id == UserHandle.myUserId()) {
435             // Jump to owner info panel
436             OwnerInfoSettings.show(this);
437         } else if (mUserCaps.mIsAdmin) {
438             Bundle extras = new Bundle();
439             extras.putInt(UserDetailsSettings.EXTRA_USER_ID, userId);
440             ((SettingsActivity) getActivity()).startPreferencePanel(this,
441                     UserDetailsSettings.class.getName(),
442                     extras,
443                     -1, /* No title res id */
444                     info.name, /* title */
445                     null, /* resultTo */
446                     0 /* resultRequestCode */);
447         }
448     }
449 
onUserCreated(int userId)450     private void onUserCreated(int userId) {
451         mAddedUserId = userId;
452         mAddingUser = false;
453         if (mUserManager.getUserInfo(userId).isRestricted()) {
454             showDialog(DIALOG_SETUP_PROFILE);
455         } else {
456             showDialog(DIALOG_SETUP_USER);
457         }
458     }
459 
460     @Override
onDialogShowing()461     public void onDialogShowing() {
462         super.onDialogShowing();
463 
464         setOnDismissListener(this);
465     }
466 
467     @Override
onCreateDialog(int dialogId)468     public Dialog onCreateDialog(int dialogId) {
469         Context context = getActivity();
470         if (context == null) return null;
471         switch (dialogId) {
472             case DIALOG_CONFIRM_REMOVE: {
473                 Dialog dlg =
474                         UserDialogs.createRemoveDialog(getActivity(), mRemovingUserId,
475                                 new DialogInterface.OnClickListener() {
476                                     public void onClick(DialogInterface dialog, int which) {
477                                         removeUserNow();
478                                     }
479                                 }
480                         );
481                 return dlg;
482             }
483             case DIALOG_USER_CANNOT_MANAGE:
484                 return new AlertDialog.Builder(context)
485                     .setMessage(R.string.user_cannot_manage_message)
486                     .setPositiveButton(android.R.string.ok, null)
487                     .create();
488             case DIALOG_ADD_USER: {
489                 final SharedPreferences preferences = getActivity().getPreferences(
490                         Context.MODE_PRIVATE);
491                 final boolean longMessageDisplayed = preferences.getBoolean(
492                         KEY_ADD_USER_LONG_MESSAGE_DISPLAYED, false);
493                 final int messageResId = longMessageDisplayed
494                         ? R.string.user_add_user_message_short
495                         : R.string.user_add_user_message_long;
496                 final int userType = dialogId == DIALOG_ADD_USER
497                         ? USER_TYPE_USER : USER_TYPE_RESTRICTED_PROFILE;
498                 Dialog dlg = new AlertDialog.Builder(context)
499                     .setTitle(R.string.user_add_user_title)
500                     .setMessage(messageResId)
501                     .setPositiveButton(android.R.string.ok,
502                         new DialogInterface.OnClickListener() {
503                             public void onClick(DialogInterface dialog, int which) {
504                                 addUserNow(userType);
505                                 if (!longMessageDisplayed) {
506                                     preferences.edit().putBoolean(
507                                             KEY_ADD_USER_LONG_MESSAGE_DISPLAYED, true).apply();
508                                 }
509                             }
510                     })
511                     .setNegativeButton(android.R.string.cancel, null)
512                     .create();
513                 return dlg;
514             }
515             case DIALOG_SETUP_USER: {
516                 Dialog dlg = new AlertDialog.Builder(context)
517                     .setTitle(R.string.user_setup_dialog_title)
518                     .setMessage(R.string.user_setup_dialog_message)
519                     .setPositiveButton(R.string.user_setup_button_setup_now,
520                         new DialogInterface.OnClickListener() {
521                             public void onClick(DialogInterface dialog, int which) {
522                                 switchUserNow(mAddedUserId);
523                             }
524                     })
525                     .setNegativeButton(R.string.user_setup_button_setup_later, null)
526                     .create();
527                 return dlg;
528             }
529             case DIALOG_SETUP_PROFILE: {
530                 Dialog dlg = new AlertDialog.Builder(context)
531                     .setMessage(R.string.user_setup_profile_dialog_message)
532                     .setPositiveButton(android.R.string.ok,
533                         new DialogInterface.OnClickListener() {
534                             public void onClick(DialogInterface dialog, int which) {
535                                 switchUserNow(mAddedUserId);
536                             }
537                     })
538                     .setNegativeButton(android.R.string.cancel, null)
539                     .create();
540                 return dlg;
541             }
542             case DIALOG_CHOOSE_USER_TYPE: {
543                 List<HashMap<String, String>> data = new ArrayList<HashMap<String,String>>();
544                 HashMap<String,String> addUserItem = new HashMap<String,String>();
545                 addUserItem.put(KEY_TITLE, getString(R.string.user_add_user_item_title));
546                 addUserItem.put(KEY_SUMMARY, getString(R.string.user_add_user_item_summary));
547                 HashMap<String,String> addProfileItem = new HashMap<String,String>();
548                 addProfileItem.put(KEY_TITLE, getString(R.string.user_add_profile_item_title));
549                 addProfileItem.put(KEY_SUMMARY, getString(R.string.user_add_profile_item_summary));
550                 data.add(addUserItem);
551                 data.add(addProfileItem);
552                 AlertDialog.Builder builder = new AlertDialog.Builder(context);
553                 SimpleAdapter adapter = new SimpleAdapter(builder.getContext(),
554                         data, R.layout.two_line_list_item,
555                         new String[] {KEY_TITLE, KEY_SUMMARY},
556                         new int[] {R.id.title, R.id.summary});
557                 builder.setTitle(R.string.user_add_user_type_title);
558                 builder.setAdapter(adapter,
559                         new DialogInterface.OnClickListener() {
560                             @Override
561                             public void onClick(DialogInterface dialog, int which) {
562                                 onAddUserClicked(which == 0
563                                         ? USER_TYPE_USER
564                                         : USER_TYPE_RESTRICTED_PROFILE);
565                             }
566                         });
567                 return builder.create();
568             }
569             case DIALOG_NEED_LOCKSCREEN: {
570                 Dialog dlg = new AlertDialog.Builder(context)
571                         .setMessage(R.string.user_need_lock_message)
572                         .setPositiveButton(R.string.user_set_lock_button,
573                                 new DialogInterface.OnClickListener() {
574                                     @Override
575                                     public void onClick(DialogInterface dialog, int which) {
576                                         launchChooseLockscreen();
577                                     }
578                                 })
579                         .setNegativeButton(android.R.string.cancel, null)
580                         .create();
581                 return dlg;
582             }
583             case DIALOG_CONFIRM_EXIT_GUEST: {
584                 Dialog dlg = new AlertDialog.Builder(context)
585                         .setTitle(R.string.user_exit_guest_confirm_title)
586                         .setMessage(R.string.user_exit_guest_confirm_message)
587                         .setPositiveButton(R.string.user_exit_guest_dialog_remove,
588                                 new DialogInterface.OnClickListener() {
589                                     @Override
590                                     public void onClick(DialogInterface dialog, int which) {
591                                         exitGuest();
592                                     }
593                                 })
594                         .setNegativeButton(android.R.string.cancel, null)
595                         .create();
596                 return dlg;
597             }
598             case DIALOG_USER_PROFILE_EDITOR: {
599                 Dialog dlg = mEditUserInfoController.createDialog(
600                         this,
601                         null,
602                         mMePreference.getTitle(),
603                         R.string.profile_info_settings_title,
604                         this /* callback */,
605                         android.os.Process.myUserHandle());
606                 return dlg;
607             }
608             default:
609                 return null;
610         }
611     }
612 
613     @Override
getDialogMetricsCategory(int dialogId)614     public int getDialogMetricsCategory(int dialogId) {
615         switch (dialogId) {
616             case DIALOG_CONFIRM_REMOVE:
617                 return MetricsEvent.DIALOG_USER_REMOVE;
618             case DIALOG_USER_CANNOT_MANAGE:
619                 return MetricsEvent.DIALOG_USER_CANNOT_MANAGE;
620             case DIALOG_ADD_USER:
621                 return MetricsEvent.DIALOG_USER_ADD;
622             case DIALOG_SETUP_USER:
623                 return MetricsEvent.DIALOG_USER_SETUP;
624             case DIALOG_SETUP_PROFILE:
625                 return MetricsEvent.DIALOG_USER_SETUP_PROFILE;
626             case DIALOG_CHOOSE_USER_TYPE:
627                 return MetricsEvent.DIALOG_USER_CHOOSE_TYPE;
628             case DIALOG_NEED_LOCKSCREEN:
629                 return MetricsEvent.DIALOG_USER_NEED_LOCKSCREEN;
630             case DIALOG_CONFIRM_EXIT_GUEST:
631                 return MetricsEvent.DIALOG_USER_CONFIRM_EXIT_GUEST;
632             case DIALOG_USER_PROFILE_EDITOR:
633                 return MetricsEvent.DIALOG_USER_EDIT_PROFILE;
634             default:
635                 return 0;
636         }
637     }
638 
removeUserNow()639     private void removeUserNow() {
640         if (mRemovingUserId == UserHandle.myUserId()) {
641             removeThisUser();
642         } else {
643             new Thread() {
644                 public void run() {
645                     synchronized (mUserLock) {
646                         mUserManager.removeUser(mRemovingUserId);
647                         mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
648                     }
649                 }
650             }.start();
651         }
652     }
653 
removeThisUser()654     private void removeThisUser() {
655         if (!mUserManager.canSwitchUsers()) {
656             Log.w(TAG, "Cannot remove current user when switching is disabled");
657             return;
658         }
659         try {
660             ActivityManager.getService().switchUser(UserHandle.USER_SYSTEM);
661             getContext().getSystemService(UserManager.class).removeUser(UserHandle.myUserId());
662         } catch (RemoteException re) {
663             Log.e(TAG, "Unable to remove self user");
664         }
665     }
666 
addUserNow(final int userType)667     private void addUserNow(final int userType) {
668         synchronized (mUserLock) {
669             mAddingUser = true;
670             mAddingUserName = userType == USER_TYPE_USER ? getString(R.string.user_new_user_name)
671                     : getString(R.string.user_new_profile_name);
672             //updateUserList();
673             new Thread() {
674                 public void run() {
675                     UserInfo user;
676                     // Could take a few seconds
677                     if (userType == USER_TYPE_USER) {
678                         user = createTrustedUser();
679                     } else {
680                         user = createRestrictedProfile();
681                     }
682                     if (user == null) {
683                         mAddingUser = false;
684                         return;
685                     }
686                     synchronized (mUserLock) {
687                         if (userType == USER_TYPE_USER) {
688                             mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
689                             mHandler.sendMessage(mHandler.obtainMessage(
690                                     MESSAGE_SETUP_USER, user.id, user.serialNumber));
691                         } else {
692                             mHandler.sendMessage(mHandler.obtainMessage(
693                                     MESSAGE_CONFIG_USER, user.id, user.serialNumber));
694                         }
695                     }
696                 }
697             }.start();
698         }
699     }
700 
switchUserNow(int userId)701     private void switchUserNow(int userId) {
702         try {
703             ActivityManager.getService().switchUser(userId);
704         } catch (RemoteException re) {
705             // Nothing to do
706         }
707     }
708 
709     /**
710      * Erase the current user (guest) and switch to another user.
711      */
exitGuest()712     private void exitGuest() {
713         // Just to be safe
714         if (!mUserCaps.mIsGuest) {
715             return;
716         }
717         removeThisUser();
718     }
719 
updateUserList()720     private void updateUserList() {
721         if (getActivity() == null) return;
722         List<UserInfo> users = mUserManager.getUsers(true);
723         final Context context = getActivity();
724 
725         final boolean voiceCapable = Utils.isVoiceCapable(context);
726         final ArrayList<Integer> missingIcons = new ArrayList<>();
727         final ArrayList<UserPreference> userPreferences = new ArrayList<>();
728         int guestId = UserPreference.USERID_GUEST_DEFAULTS;
729         userPreferences.add(mMePreference);
730 
731         for (UserInfo user : users) {
732             if (!user.supportsSwitchToByUser()) {
733                 // Only users that can be switched to should show up here.
734                 // e.g. Managed profiles appear under Accounts Settings instead
735                 continue;
736             }
737             UserPreference pref;
738             if (user.id == UserHandle.myUserId()) {
739                 pref = mMePreference;
740             } else if (user.isGuest()) {
741                 // Skip over Guest. We add generic Guest settings after this loop
742                 guestId = user.id;
743                 continue;
744             } else {
745                 // With Telephony:
746                 //   Secondary user: Settings
747                 //   Guest: Settings
748                 //   Restricted Profile: There is no Restricted Profile
749                 // Without Telephony:
750                 //   Secondary user: Delete
751                 //   Guest: Nothing
752                 //   Restricted Profile: Settings
753                 final boolean showSettings = mUserCaps.mIsAdmin
754                         && (voiceCapable || user.isRestricted());
755                 final boolean showDelete = mUserCaps.mIsAdmin
756                         && (!voiceCapable && !user.isRestricted() && !user.isGuest());
757                 pref = new UserPreference(getPrefContext(), null, user.id,
758                         showSettings ? this : null,
759                         showDelete ? this : null);
760                 pref.setKey("id=" + user.id);
761                 userPreferences.add(pref);
762                 if (user.isAdmin()) {
763                     pref.setSummary(R.string.user_admin);
764                 }
765                 pref.setTitle(user.name);
766                 pref.setSelectable(false);
767             }
768             if (pref == null) {
769                 continue;
770             }
771             if (!isInitialized(user)) {
772                 if (user.isRestricted()) {
773                     pref.setSummary(R.string.user_summary_restricted_not_set_up);
774                 } else {
775                     pref.setSummary(R.string.user_summary_not_set_up);
776                 }
777                 pref.setOnPreferenceClickListener(this);
778                 pref.setSelectable(true);
779             } else if (user.isRestricted()) {
780                 pref.setSummary(R.string.user_summary_restricted_profile);
781             }
782             if (user.iconPath != null) {
783                 if (mUserIcons.get(user.id) == null) {
784                     // Icon not loaded yet, print a placeholder
785                     missingIcons.add(user.id);
786                     pref.setIcon(getEncircledDefaultIcon());
787                 } else {
788                     setPhotoId(pref, user);
789                 }
790             } else {
791                 // Icon not available yet, print a placeholder
792                 pref.setIcon(getEncircledDefaultIcon());
793             }
794         }
795 
796         // Add a temporary entry for the user being created
797         if (mAddingUser) {
798             UserPreference pref = new UserPreference(getPrefContext(), null,
799                     UserPreference.USERID_UNKNOWN, null, null);
800             pref.setEnabled(false);
801             pref.setTitle(mAddingUserName);
802             pref.setIcon(getEncircledDefaultIcon());
803             userPreferences.add(pref);
804         }
805 
806         // Check if Guest tile should be added.
807         if (!mUserCaps.mIsGuest && (mUserCaps.mCanAddGuest ||
808                 mUserCaps.mDisallowAddUserSetByAdmin)) {
809             // Add a virtual Guest user for guest defaults
810             UserPreference pref = new UserPreference(getPrefContext(), null,
811                     UserPreference.USERID_GUEST_DEFAULTS,
812                     mUserCaps.mIsAdmin && voiceCapable? this : null /* settings icon handler */,
813                     null /* delete icon handler */);
814             pref.setTitle(R.string.user_guest);
815             pref.setIcon(getEncircledDefaultIcon());
816             userPreferences.add(pref);
817             pref.setDisabledByAdmin(
818                     mUserCaps.mDisallowAddUser ? mUserCaps.mEnforcedAdmin : null);
819             int finalGuestId = guestId;
820             pref.setOnPreferenceClickListener(preference -> {
821                 int id = finalGuestId;
822                 if (id == UserPreference.USERID_GUEST_DEFAULTS) {
823                     UserInfo guest = mUserManager.createGuest(
824                             getContext(), preference.getTitle().toString());
825                     if (guest != null) {
826                         id = guest.id;
827                     }
828                 }
829                 try {
830                     ActivityManager.getService().switchUser(id);
831                 } catch (RemoteException e) {
832                     e.rethrowFromSystemServer();
833                 }
834                 return true;
835             });
836         }
837 
838         // Sort list of users by serialNum
839         Collections.sort(userPreferences, UserPreference.SERIAL_NUMBER_COMPARATOR);
840 
841         getActivity().invalidateOptionsMenu();
842 
843         // Load the icons
844         if (missingIcons.size() > 0) {
845             loadIconsAsync(missingIcons);
846         }
847 
848         PreferenceScreen preferenceScreen = getPreferenceScreen();
849         preferenceScreen.removeAll();
850 
851         // If profiles are supported, userPreferences will be added to the category labeled
852         // "User & Profiles", otherwise the category is skipped and elements are added directly
853         // to preferenceScreen
854         PreferenceGroup groupToAddUsers;
855         if (mUserCaps.mCanAddRestrictedProfile) {
856             mUserListCategory.removeAll();
857             mUserListCategory.setOrder(Preference.DEFAULT_ORDER);
858             preferenceScreen.addPreference(mUserListCategory);
859             groupToAddUsers = mUserListCategory;
860         } else {
861             groupToAddUsers = preferenceScreen;
862         }
863         for (UserPreference userPreference : userPreferences) {
864             userPreference.setOrder(Preference.DEFAULT_ORDER);
865             groupToAddUsers.addPreference(userPreference);
866         }
867 
868         // Append Add user to the end of the list
869         if ((mUserCaps.mCanAddUser || mUserCaps.mDisallowAddUserSetByAdmin) &&
870                 Utils.isDeviceProvisioned(getActivity())) {
871             boolean moreUsers = mUserManager.canAddMoreUsers();
872             mAddUser.setOrder(Preference.DEFAULT_ORDER);
873             preferenceScreen.addPreference(mAddUser);
874             mAddUser.setEnabled(moreUsers && !mAddingUser);
875             if (!moreUsers) {
876                 mAddUser.setSummary(getString(R.string.user_add_max_count, getMaxRealUsers()));
877             } else {
878                 mAddUser.setSummary(null);
879             }
880             if (mAddUser.isEnabled()) {
881                 mAddUser.setDisabledByAdmin(
882                         mUserCaps.mDisallowAddUser ? mUserCaps.mEnforcedAdmin : null);
883             }
884         }
885 
886     }
887 
getMaxRealUsers()888     private int getMaxRealUsers() {
889         // guest is not counted against getMaxSupportedUsers() number
890         final int maxUsersAndGuest = UserManager.getMaxSupportedUsers() + 1;
891         final List<UserInfo> users = mUserManager.getUsers();
892         // managed profiles are counted against getMaxSupportedUsers()
893         int managedProfiles = 0;
894         for (UserInfo user : users) {
895             if (user.isManagedProfile()) {
896                 managedProfiles++;
897             }
898         }
899         return maxUsersAndGuest - managedProfiles;
900     }
901 
loadIconsAsync(List<Integer> missingIcons)902     private void loadIconsAsync(List<Integer> missingIcons) {
903         new AsyncTask<List<Integer>, Void, Void>() {
904             @Override
905             protected void onPostExecute(Void result) {
906                 updateUserList();
907             }
908 
909             @Override
910             protected Void doInBackground(List<Integer>... values) {
911                 for (int userId : values[0]) {
912                     Bitmap bitmap = mUserManager.getUserIcon(userId);
913                     if (bitmap == null) {
914                         bitmap = Utils.getDefaultUserIconAsBitmap(userId);
915                     }
916                     mUserIcons.append(userId, bitmap);
917                 }
918                 return null;
919             }
920         }.execute(missingIcons);
921     }
922 
getEncircledDefaultIcon()923     private Drawable getEncircledDefaultIcon() {
924         if (mDefaultIconDrawable == null) {
925             mDefaultIconDrawable = encircle(Utils.getDefaultUserIconAsBitmap(UserHandle.USER_NULL));
926         }
927         return mDefaultIconDrawable;
928     }
929 
setPhotoId(Preference pref, UserInfo user)930     private void setPhotoId(Preference pref, UserInfo user) {
931         Bitmap bitmap = mUserIcons.get(user.id);
932         if (bitmap != null) {
933             pref.setIcon(encircle(bitmap));
934         }
935     }
936 
937     @Override
onPreferenceClick(Preference pref)938     public boolean onPreferenceClick(Preference pref) {
939         if (pref == mMePreference) {
940             if (mUserCaps.mIsGuest) {
941                 showDialog(DIALOG_CONFIRM_EXIT_GUEST);
942                 return true;
943             }
944             // If this is a limited user, launch the user info settings instead of profile editor
945             if (mUserManager.isLinkedUser()) {
946                 onManageUserClicked(UserHandle.myUserId(), false);
947             } else {
948                 showDialog(DIALOG_USER_PROFILE_EDITOR);
949             }
950         } else if (pref instanceof UserPreference) {
951             int userId = ((UserPreference) pref).getUserId();
952             // Get the latest status of the user
953             UserInfo user = mUserManager.getUserInfo(userId);
954             if (!isInitialized(user)) {
955                 mHandler.sendMessage(mHandler.obtainMessage(
956                         MESSAGE_SETUP_USER, user.id, user.serialNumber));
957             }
958         } else if (pref == mAddUser) {
959             // If we allow both types, show a picker, otherwise directly go to
960             // flow for full user.
961             if (mUserCaps.mCanAddRestrictedProfile) {
962                 showDialog(DIALOG_CHOOSE_USER_TYPE);
963             } else {
964                 onAddUserClicked(USER_TYPE_USER);
965             }
966         }
967         return false;
968     }
969 
isInitialized(UserInfo user)970     private boolean isInitialized(UserInfo user) {
971         return (user.flags & UserInfo.FLAG_INITIALIZED) != 0;
972     }
973 
encircle(Bitmap icon)974     private Drawable encircle(Bitmap icon) {
975         Drawable circled = CircleFramedDrawable.getInstance(getActivity(), icon);
976         return circled;
977     }
978 
979     @Override
onClick(View v)980     public void onClick(View v) {
981         if (v.getTag() instanceof UserPreference) {
982             int userId = ((UserPreference) v.getTag()).getUserId();
983             switch (v.getId()) {
984             case UserPreference.DELETE_ID:
985                 final EnforcedAdmin removeDisallowedAdmin =
986                         RestrictedLockUtils.checkIfRestrictionEnforced(getContext(),
987                                 UserManager.DISALLOW_REMOVE_USER, UserHandle.myUserId());
988                 if (removeDisallowedAdmin != null) {
989                     RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(),
990                             removeDisallowedAdmin);
991                 } else {
992                     onRemoveUserClicked(userId);
993                 }
994                 break;
995             case UserPreference.SETTINGS_ID:
996                 onManageUserClicked(userId, false);
997                 break;
998             }
999         }
1000     }
1001 
1002     @Override
onDismiss(DialogInterface dialog)1003     public void onDismiss(DialogInterface dialog) {
1004         synchronized (mUserLock) {
1005             mRemovingUserId = -1;
1006             updateUserList();
1007         }
1008     }
1009 
1010     @Override
getHelpResource()1011     public int getHelpResource() {
1012         return R.string.help_url_users;
1013     }
1014 
1015     @Override
onPhotoChanged(Drawable photo)1016     public void onPhotoChanged(Drawable photo) {
1017         mMePreference.setIcon(photo);
1018     }
1019 
1020     @Override
onLabelChanged(CharSequence label)1021     public void onLabelChanged(CharSequence label) {
1022         mMePreference.setTitle(label);
1023     }
1024 
1025     private static class SummaryProvider implements SummaryLoader.SummaryProvider {
1026 
1027         private final Context mContext;
1028         private final SummaryLoader mSummaryLoader;
1029 
SummaryProvider(Context context, SummaryLoader summaryLoader)1030         public SummaryProvider(Context context, SummaryLoader summaryLoader) {
1031             mContext = context;
1032             mSummaryLoader = summaryLoader;
1033         }
1034 
1035         @Override
setListening(boolean listening)1036         public void setListening(boolean listening) {
1037             if (listening) {
1038                 UserInfo info = mContext.getSystemService(UserManager.class).getUserInfo(
1039                     UserHandle.myUserId());
1040                 mSummaryLoader.setSummary(this, mContext.getString(R.string.users_summary,
1041                     info.name));
1042             }
1043         }
1044     }
1045 
1046     public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY =
1047         new SummaryLoader.SummaryProviderFactory() {
1048             @Override
1049             public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity,
1050                     SummaryLoader summaryLoader) {
1051                 return new SummaryProvider(activity, summaryLoader);
1052             }
1053         };
1054 
1055     public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
1056             new BaseSearchIndexProvider() {
1057                 @Override
1058                 public List<SearchIndexableRaw> getRawDataToIndex(Context context,
1059                         boolean enabled) {
1060                     final List<SearchIndexableRaw> result = new ArrayList<>();
1061                     final UserCapabilities userCaps = UserCapabilities.create(context);
1062                     if (!userCaps.mEnabled) {
1063                         return result;
1064                     }
1065                     final Resources res = context.getResources();
1066                     SearchIndexableRaw data = new SearchIndexableRaw(context);
1067                     data.title = res.getString(R.string.user_settings_title);
1068                     data.screenTitle = res.getString(R.string.user_settings_title);
1069                     result.add(data);
1070 
1071                     if (userCaps.mCanAddUser || userCaps.mDisallowAddUserSetByAdmin) {
1072                         data = new SearchIndexableRaw(context);
1073                         data.title = res.getString(userCaps.mCanAddRestrictedProfile ?
1074                                 R.string.user_add_user_or_profile_menu
1075                                 : R.string.user_add_user_menu);
1076                         data.screenTitle = res.getString(R.string.user_settings_title);
1077                         result.add(data);
1078                     }
1079                     return result;
1080                 }
1081             };
1082 
1083 }
1084