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