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.accounts.Account;
20 import android.accounts.AccountManager;
21 import android.app.Activity;
22 import android.app.ActivityManagerNative;
23 import android.app.AlertDialog;
24 import android.app.Dialog;
25 import android.app.Fragment;
26 import android.app.admin.DevicePolicyManager;
27 import android.content.BroadcastReceiver;
28 import android.content.Context;
29 import android.content.DialogInterface;
30 import android.content.Intent;
31 import android.content.IntentFilter;
32 import android.content.SharedPreferences;
33 import android.content.pm.UserInfo;
34 import android.content.res.Resources;
35 import android.graphics.Bitmap;
36 import android.graphics.drawable.Drawable;
37 import android.os.AsyncTask;
38 import android.os.Bundle;
39 import android.os.Handler;
40 import android.os.Message;
41 import android.os.RemoteException;
42 import android.os.UserHandle;
43 import android.os.UserManager;
44 import android.preference.Preference;
45 import android.preference.Preference.OnPreferenceClickListener;
46 import android.preference.PreferenceGroup;
47 import android.provider.Settings;
48 import android.provider.Settings.Secure;
49 import android.util.Log;
50 import android.util.SparseArray;
51 import android.view.Menu;
52 import android.view.MenuInflater;
53 import android.view.MenuItem;
54 import android.view.View;
55 import android.view.View.OnClickListener;
56 import android.widget.SimpleAdapter;
57 
58 import com.android.internal.util.UserIcons;
59 import com.android.internal.widget.LockPatternUtils;
60 import com.android.settings.ChooseLockGeneric;
61 import com.android.settings.OwnerInfoSettings;
62 import com.android.settings.R;
63 import com.android.settings.SelectableEditTextPreference;
64 import com.android.settings.SettingsActivity;
65 import com.android.settings.SettingsPreferenceFragment;
66 import com.android.settings.Utils;
67 import com.android.settings.drawable.CircleFramedDrawable;
68 
69 import java.util.ArrayList;
70 import java.util.HashMap;
71 import java.util.List;
72 
73 /**
74  * Screen that manages the list of users on the device.
75  * Guest user is an always visible entry, even if the guest is not currently
76  * active/created. It is meant for controlling properties of a guest user.
77  *
78  * The first one is always the current user.
79  * Owner is the primary user.
80  */
81 public class UserSettings extends SettingsPreferenceFragment
82         implements OnPreferenceClickListener, OnClickListener, DialogInterface.OnDismissListener,
83         Preference.OnPreferenceChangeListener,
84         EditUserInfoController.OnContentChangedCallback {
85 
86     private static final String TAG = "UserSettings";
87 
88     /** UserId of the user being removed */
89     private static final String SAVE_REMOVING_USER = "removing_user";
90     /** UserId of the user that was just added */
91     private static final String SAVE_ADDING_USER = "adding_user";
92 
93     private static final String KEY_USER_LIST = "user_list";
94     private static final String KEY_USER_ME = "user_me";
95     private static final String KEY_ADD_USER = "user_add";
96 
97     private static final int MENU_REMOVE_USER = Menu.FIRST;
98     private static final int MENU_ADD_ON_LOCKSCREEN = Menu.FIRST + 1;
99 
100     private static final int DIALOG_CONFIRM_REMOVE = 1;
101     private static final int DIALOG_ADD_USER = 2;
102     private static final int DIALOG_SETUP_USER = 3;
103     private static final int DIALOG_SETUP_PROFILE = 4;
104     private static final int DIALOG_USER_CANNOT_MANAGE = 5;
105     private static final int DIALOG_CHOOSE_USER_TYPE = 6;
106     private static final int DIALOG_NEED_LOCKSCREEN = 7;
107     private static final int DIALOG_CONFIRM_EXIT_GUEST = 8;
108     private static final int DIALOG_USER_PROFILE_EDITOR = 9;
109 
110     private static final int MESSAGE_UPDATE_LIST = 1;
111     private static final int MESSAGE_SETUP_USER = 2;
112     private static final int MESSAGE_CONFIG_USER = 3;
113 
114     private static final int USER_TYPE_USER = 1;
115     private static final int USER_TYPE_RESTRICTED_PROFILE = 2;
116 
117     private static final int REQUEST_CHOOSE_LOCK = 10;
118 
119     private static final String KEY_ADD_USER_LONG_MESSAGE_DISPLAYED =
120             "key_add_user_long_message_displayed";
121 
122     private static final String KEY_TITLE = "title";
123     private static final String KEY_SUMMARY = "summary";
124 
125     private PreferenceGroup mUserListCategory;
126     private Preference mMePreference;
127     private SelectableEditTextPreference mNicknamePreference;
128     private Preference mAddUser;
129     private int mRemovingUserId = -1;
130     private int mAddedUserId = 0;
131     private boolean mAddingUser;
132     private boolean mEnabled = true;
133     private boolean mCanAddRestrictedProfile = true;
134 
135     private final Object mUserLock = new Object();
136     private UserManager mUserManager;
137     private SparseArray<Bitmap> mUserIcons = new SparseArray<Bitmap>();
138     private boolean mIsOwner = UserHandle.myUserId() == UserHandle.USER_OWNER;
139     private boolean mIsGuest;
140 
141     private EditUserInfoController mEditUserInfoController =
142             new EditUserInfoController();
143 
144     // A place to cache the generated default avatar
145     private Drawable mDefaultIconDrawable;
146 
147     private Handler mHandler = new Handler() {
148         @Override
149         public void handleMessage(Message msg) {
150             switch (msg.what) {
151             case MESSAGE_UPDATE_LIST:
152                 updateUserList();
153                 break;
154             case MESSAGE_SETUP_USER:
155                 onUserCreated(msg.arg1);
156                 break;
157             case MESSAGE_CONFIG_USER:
158                 onManageUserClicked(msg.arg1, true);
159                 break;
160             }
161         }
162     };
163 
164     private BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {
165         @Override
166         public void onReceive(Context context, Intent intent) {
167             if (intent.getAction().equals(Intent.ACTION_USER_REMOVED)) {
168                 mRemovingUserId = -1;
169             } else if (intent.getAction().equals(Intent.ACTION_USER_INFO_CHANGED)) {
170                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
171                 if (userHandle != -1) {
172                     mUserIcons.remove(userHandle);
173                 }
174             }
175             mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
176         }
177     };
178 
179     @Override
onCreate(Bundle icicle)180     public void onCreate(Bundle icicle) {
181         super.onCreate(icicle);
182 
183         if (icicle != null) {
184             if (icicle.containsKey(SAVE_ADDING_USER)) {
185                 mAddedUserId = icicle.getInt(SAVE_ADDING_USER);
186             }
187             if (icicle.containsKey(SAVE_REMOVING_USER)) {
188                 mRemovingUserId = icicle.getInt(SAVE_REMOVING_USER);
189             }
190             mEditUserInfoController.onRestoreInstanceState(icicle);
191         }
192         final Context context = getActivity();
193         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
194         boolean hasMultipleUsers = mUserManager.getUserCount() > 1;
195         if ((!UserManager.supportsMultipleUsers() && !hasMultipleUsers)
196                 || Utils.isMonkeyRunning()) {
197             mEnabled = false;
198             return;
199         }
200 
201         final int myUserId = UserHandle.myUserId();
202         mIsGuest = mUserManager.getUserInfo(myUserId).isGuest();
203 
204         addPreferencesFromResource(R.xml.user_settings);
205         mUserListCategory = (PreferenceGroup) findPreference(KEY_USER_LIST);
206         mMePreference = new UserPreference(context, null /* attrs */, myUserId,
207                 null /* settings icon handler */,
208                 null /* delete icon handler */);
209         mMePreference.setKey(KEY_USER_ME);
210         mMePreference.setOnPreferenceClickListener(this);
211         if (mIsOwner) {
212             mMePreference.setSummary(R.string.user_owner);
213         }
214         mAddUser = findPreference(KEY_ADD_USER);
215         if (!mIsOwner || UserManager.getMaxSupportedUsers() < 2
216                 || !UserManager.supportsMultipleUsers()
217                 || mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)) {
218             removePreference(KEY_ADD_USER);
219         } else {
220             mAddUser.setOnPreferenceClickListener(this);
221             DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
222                     Context.DEVICE_POLICY_SERVICE);
223             // No restricted profiles for tablets with a device owner, or phones.
224             if (dpm.getDeviceOwner() != null || Utils.isVoiceCapable(context)) {
225                 mCanAddRestrictedProfile = false;
226                 mAddUser.setTitle(R.string.user_add_user_menu);
227             }
228         }
229         loadProfile();
230         setHasOptionsMenu(true);
231         IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
232         filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
233         context.registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null,
234                 mHandler);
235     }
236 
237     @Override
onResume()238     public void onResume() {
239         super.onResume();
240 
241         if (!mEnabled) return;
242 
243         loadProfile();
244         updateUserList();
245     }
246 
247     @Override
onDestroy()248     public void onDestroy() {
249         super.onDestroy();
250 
251         if (!mEnabled) return;
252 
253         getActivity().unregisterReceiver(mUserChangeReceiver);
254     }
255 
256     @Override
onSaveInstanceState(Bundle outState)257     public void onSaveInstanceState(Bundle outState) {
258         super.onSaveInstanceState(outState);
259         mEditUserInfoController.onSaveInstanceState(outState);
260         outState.putInt(SAVE_ADDING_USER, mAddedUserId);
261         outState.putInt(SAVE_REMOVING_USER, mRemovingUserId);
262     }
263 
264     @Override
startActivityForResult(Intent intent, int requestCode)265     public void startActivityForResult(Intent intent, int requestCode) {
266         mEditUserInfoController.startingActivityForResult();
267         super.startActivityForResult(intent, requestCode);
268     }
269 
270     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)271     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
272         int pos = 0;
273         UserManager um = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
274         if (!mIsOwner && !um.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER)) {
275             String nickname = mUserManager.getUserName();
276             MenuItem removeThisUser = menu.add(0, MENU_REMOVE_USER, pos++,
277                     getResources().getString(R.string.user_remove_user_menu, nickname));
278             removeThisUser.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
279         }
280         if (mIsOwner && !um.hasUserRestriction(UserManager.DISALLOW_ADD_USER)) {
281             MenuItem allowAddOnLockscreen = menu.add(0, MENU_ADD_ON_LOCKSCREEN, pos++,
282                     R.string.user_add_on_lockscreen_menu);
283             allowAddOnLockscreen.setCheckable(true);
284             allowAddOnLockscreen.setChecked(Settings.Global.getInt(getContentResolver(),
285                     Settings.Global.ADD_USERS_WHEN_LOCKED, 0) == 1);
286         }
287         super.onCreateOptionsMenu(menu, inflater);
288     }
289 
290     @Override
onOptionsItemSelected(MenuItem item)291     public boolean onOptionsItemSelected(MenuItem item) {
292         final int itemId = item.getItemId();
293         if (itemId == MENU_REMOVE_USER) {
294             onRemoveUserClicked(UserHandle.myUserId());
295             return true;
296         } else if (itemId == MENU_ADD_ON_LOCKSCREEN) {
297             final boolean isChecked = item.isChecked();
298             Settings.Global.putInt(getContentResolver(), Settings.Global.ADD_USERS_WHEN_LOCKED,
299                     isChecked ? 0 : 1);
300             item.setChecked(!isChecked);
301             return true;
302         } else {
303             return super.onOptionsItemSelected(item);
304         }
305     }
306 
307     /**
308      * Loads profile information for the current user.
309      */
loadProfile()310     private void loadProfile() {
311         if (mIsGuest) {
312             // No need to load profile information
313             mMePreference.setIcon(getEncircledDefaultIcon());
314             mMePreference.setTitle(R.string.user_exit_guest_title);
315             return;
316         }
317 
318         new AsyncTask<Void, Void, String>() {
319             @Override
320             protected void onPostExecute(String result) {
321                 finishLoadProfile(result);
322             }
323 
324             @Override
325             protected String doInBackground(Void... values) {
326                 UserInfo user = mUserManager.getUserInfo(UserHandle.myUserId());
327                 if (user.iconPath == null || user.iconPath.equals("")) {
328                     assignProfilePhoto(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.isLockPasswordEnabled() || lpu.isLockPatternEnabled();
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 
createLimitedUser()399     private UserInfo createLimitedUser() {
400         UserInfo newUserInfo = mUserManager.createSecondaryUser(
401                 getResources().getString(R.string.user_new_profile_name),
402                 UserInfo.FLAG_RESTRICTED);
403         int userId = newUserInfo.id;
404         UserHandle user = new UserHandle(userId);
405         mUserManager.setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user);
406         // Change the setting before applying the DISALLOW_SHARE_LOCATION restriction, otherwise
407         // the putIntForUser() will fail.
408         Secure.putIntForUser(getContentResolver(),
409                 Secure.LOCATION_MODE, Secure.LOCATION_MODE_OFF, userId);
410         mUserManager.setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, true, user);
411         assignDefaultPhoto(newUserInfo);
412         // Add shared accounts
413         AccountManager am = AccountManager.get(getActivity());
414         Account [] accounts = am.getAccounts();
415         if (accounts != null) {
416             for (Account account : accounts) {
417                 am.addSharedAccount(account, user);
418             }
419         }
420         return newUserInfo;
421     }
422 
createTrustedUser()423     private UserInfo createTrustedUser() {
424         UserInfo newUserInfo = mUserManager.createSecondaryUser(
425                 getResources().getString(R.string.user_new_user_name), 0);
426         if (newUserInfo != null) {
427             assignDefaultPhoto(newUserInfo);
428         }
429         return newUserInfo;
430     }
431 
onManageUserClicked(int userId, boolean newUser)432     private void onManageUserClicked(int userId, boolean newUser) {
433         if (userId == UserPreference.USERID_GUEST_DEFAULTS) {
434             Bundle extras = new Bundle();
435             extras.putBoolean(UserDetailsSettings.EXTRA_USER_GUEST, true);
436             ((SettingsActivity) getActivity()).startPreferencePanel(
437                     UserDetailsSettings.class.getName(),
438                     extras, R.string.user_guest, null, null, 0);
439             return;
440         }
441         UserInfo info = mUserManager.getUserInfo(userId);
442         if (info.isRestricted() && mIsOwner) {
443             Bundle extras = new Bundle();
444             extras.putInt(RestrictedProfileSettings.EXTRA_USER_ID, userId);
445             extras.putBoolean(RestrictedProfileSettings.EXTRA_NEW_USER, newUser);
446             ((SettingsActivity) getActivity()).startPreferencePanel(
447                     RestrictedProfileSettings.class.getName(),
448                     extras, R.string.user_restrictions_title, null,
449                     null, 0);
450         } else if (info.id == UserHandle.myUserId()) {
451             // Jump to owner info panel
452             Bundle extras = new Bundle();
453             if (!info.isRestricted()) {
454                 extras.putBoolean(OwnerInfoSettings.EXTRA_SHOW_NICKNAME, true);
455             }
456             int titleResId = info.id == UserHandle.USER_OWNER ? R.string.owner_info_settings_title
457                     : (info.isRestricted() ? R.string.profile_info_settings_title
458                             : R.string.user_info_settings_title);
459             ((SettingsActivity) getActivity()).startPreferencePanel(
460                     OwnerInfoSettings.class.getName(),
461                     extras, titleResId, null, null, 0);
462         } else if (mIsOwner) {
463             Bundle extras = new Bundle();
464             extras.putInt(UserDetailsSettings.EXTRA_USER_ID, userId);
465             ((SettingsActivity) getActivity()).startPreferencePanel(
466                     UserDetailsSettings.class.getName(),
467                     extras,
468                     -1, /* No title res id */
469                     info.name, /* title */
470                     null, /* resultTo */
471                     0 /* resultRequestCode */);
472         }
473     }
474 
onUserCreated(int userId)475     private void onUserCreated(int userId) {
476         mAddedUserId = userId;
477         if (mUserManager.getUserInfo(userId).isRestricted()) {
478             showDialog(DIALOG_SETUP_PROFILE);
479         } else {
480             showDialog(DIALOG_SETUP_USER);
481         }
482     }
483 
484     @Override
onDialogShowing()485     public void onDialogShowing() {
486         super.onDialogShowing();
487 
488         setOnDismissListener(this);
489     }
490 
491     @Override
onCreateDialog(int dialogId)492     public Dialog onCreateDialog(int dialogId) {
493         Context context = getActivity();
494         if (context == null) return null;
495         switch (dialogId) {
496             case DIALOG_CONFIRM_REMOVE: {
497                 Dialog dlg =
498                         Utils.createRemoveConfirmationDialog(getActivity(), mRemovingUserId,
499                                 new DialogInterface.OnClickListener() {
500                                     public void onClick(DialogInterface dialog, int which) {
501                                         removeUserNow();
502                                     }
503                                 }
504                         );
505                 return dlg;
506             }
507             case DIALOG_USER_CANNOT_MANAGE:
508                 return new AlertDialog.Builder(context)
509                     .setMessage(R.string.user_cannot_manage_message)
510                     .setPositiveButton(android.R.string.ok, null)
511                     .create();
512             case DIALOG_ADD_USER: {
513                 final SharedPreferences preferences = getActivity().getPreferences(
514                         Context.MODE_PRIVATE);
515                 final boolean longMessageDisplayed = preferences.getBoolean(
516                         KEY_ADD_USER_LONG_MESSAGE_DISPLAYED, false);
517                 final int messageResId = longMessageDisplayed
518                         ? R.string.user_add_user_message_short
519                         : R.string.user_add_user_message_long;
520                 final int userType = dialogId == DIALOG_ADD_USER
521                         ? USER_TYPE_USER : USER_TYPE_RESTRICTED_PROFILE;
522                 Dialog dlg = new AlertDialog.Builder(context)
523                     .setTitle(R.string.user_add_user_title)
524                     .setMessage(messageResId)
525                     .setPositiveButton(android.R.string.ok,
526                         new DialogInterface.OnClickListener() {
527                             public void onClick(DialogInterface dialog, int which) {
528                                 addUserNow(userType);
529                                 if (!longMessageDisplayed) {
530                                     preferences.edit().putBoolean(
531                                             KEY_ADD_USER_LONG_MESSAGE_DISPLAYED, true).apply();
532                                 }
533                             }
534                     })
535                     .setNegativeButton(android.R.string.cancel, null)
536                     .create();
537                 return dlg;
538             }
539             case DIALOG_SETUP_USER: {
540                 Dialog dlg = new AlertDialog.Builder(context)
541                     .setTitle(R.string.user_setup_dialog_title)
542                     .setMessage(R.string.user_setup_dialog_message)
543                     .setPositiveButton(R.string.user_setup_button_setup_now,
544                         new DialogInterface.OnClickListener() {
545                             public void onClick(DialogInterface dialog, int which) {
546                                 switchUserNow(mAddedUserId);
547                             }
548                     })
549                     .setNegativeButton(R.string.user_setup_button_setup_later, null)
550                     .create();
551                 return dlg;
552             }
553             case DIALOG_SETUP_PROFILE: {
554                 Dialog dlg = new AlertDialog.Builder(context)
555                     .setMessage(R.string.user_setup_profile_dialog_message)
556                     .setPositiveButton(android.R.string.ok,
557                         new DialogInterface.OnClickListener() {
558                             public void onClick(DialogInterface dialog, int which) {
559                                 switchUserNow(mAddedUserId);
560                             }
561                     })
562                     .setNegativeButton(android.R.string.cancel, null)
563                     .create();
564                 return dlg;
565             }
566             case DIALOG_CHOOSE_USER_TYPE: {
567                 List<HashMap<String, String>> data = new ArrayList<HashMap<String,String>>();
568                 HashMap<String,String> addUserItem = new HashMap<String,String>();
569                 addUserItem.put(KEY_TITLE, getString(R.string.user_add_user_item_title));
570                 addUserItem.put(KEY_SUMMARY, getString(R.string.user_add_user_item_summary));
571                 HashMap<String,String> addProfileItem = new HashMap<String,String>();
572                 addProfileItem.put(KEY_TITLE, getString(R.string.user_add_profile_item_title));
573                 addProfileItem.put(KEY_SUMMARY, getString(R.string.user_add_profile_item_summary));
574                 data.add(addUserItem);
575                 data.add(addProfileItem);
576                 AlertDialog.Builder builder = new AlertDialog.Builder(context);
577                 SimpleAdapter adapter = new SimpleAdapter(builder.getContext(),
578                         data, R.layout.two_line_list_item,
579                         new String[] {KEY_TITLE, KEY_SUMMARY},
580                         new int[] {R.id.title, R.id.summary});
581                 builder.setTitle(R.string.user_add_user_type_title);
582                 builder.setAdapter(adapter,
583                         new DialogInterface.OnClickListener() {
584                             @Override
585                             public void onClick(DialogInterface dialog, int which) {
586                                 onAddUserClicked(which == 0
587                                         ? USER_TYPE_USER
588                                         : USER_TYPE_RESTRICTED_PROFILE);
589                             }
590                         });
591                 return builder.create();
592             }
593             case DIALOG_NEED_LOCKSCREEN: {
594                 Dialog dlg = new AlertDialog.Builder(context)
595                         .setMessage(R.string.user_need_lock_message)
596                         .setPositiveButton(R.string.user_set_lock_button,
597                                 new DialogInterface.OnClickListener() {
598                                     @Override
599                                     public void onClick(DialogInterface dialog, int which) {
600                                         launchChooseLockscreen();
601                                     }
602                                 })
603                         .setNegativeButton(android.R.string.cancel, null)
604                         .create();
605                 return dlg;
606             }
607             case DIALOG_CONFIRM_EXIT_GUEST: {
608                 Dialog dlg = new AlertDialog.Builder(context)
609                         .setTitle(R.string.user_exit_guest_confirm_title)
610                         .setMessage(R.string.user_exit_guest_confirm_message)
611                         .setPositiveButton(R.string.user_exit_guest_dialog_remove,
612                                 new DialogInterface.OnClickListener() {
613                                     @Override
614                                     public void onClick(DialogInterface dialog, int which) {
615                                         exitGuest();
616                                     }
617                                 })
618                         .setNegativeButton(android.R.string.cancel, null)
619                         .create();
620                 return dlg;
621             }
622             case DIALOG_USER_PROFILE_EDITOR: {
623                 Dialog dlg = mEditUserInfoController.createDialog(
624                         (Fragment) this,
625                         mMePreference.getIcon(),
626                         mMePreference.getTitle(),
627                         R.string.profile_info_settings_title,
628                         this /* callback */,
629                         android.os.Process.myUserHandle());
630                 return dlg;
631             }
632             default:
633                 return null;
634         }
635     }
636 
removeUserNow()637     private void removeUserNow() {
638         if (mRemovingUserId == UserHandle.myUserId()) {
639             removeThisUser();
640         } else {
641             new Thread() {
642                 public void run() {
643                     synchronized (mUserLock) {
644                         mUserManager.removeUser(mRemovingUserId);
645                         mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
646                     }
647                 }
648             }.start();
649         }
650     }
651 
removeThisUser()652     private void removeThisUser() {
653         try {
654             ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER);
655             ((UserManager) getActivity().getSystemService(Context.USER_SERVICE))
656                     .removeUser(UserHandle.myUserId());
657         } catch (RemoteException re) {
658             Log.e(TAG, "Unable to remove self user");
659         }
660     }
661 
addUserNow(final int userType)662     private void addUserNow(final int userType) {
663         synchronized (mUserLock) {
664             mAddingUser = true;
665             //updateUserList();
666             new Thread() {
667                 public void run() {
668                     UserInfo user = null;
669                     // Could take a few seconds
670                     if (userType == USER_TYPE_USER) {
671                         user = createTrustedUser();
672                     } else {
673                         user = createLimitedUser();
674                     }
675                     synchronized (mUserLock) {
676                         mAddingUser = false;
677                         if (userType == USER_TYPE_USER) {
678                             mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
679                             mHandler.sendMessage(mHandler.obtainMessage(
680                                     MESSAGE_SETUP_USER, user.id, user.serialNumber));
681                         } else {
682                             mHandler.sendMessage(mHandler.obtainMessage(
683                                     MESSAGE_CONFIG_USER, user.id, user.serialNumber));
684                         }
685                     }
686                 }
687             }.start();
688         }
689     }
690 
switchUserNow(int userId)691     private void switchUserNow(int userId) {
692         try {
693             ActivityManagerNative.getDefault().switchUser(userId);
694         } catch (RemoteException re) {
695             // Nothing to do
696         }
697     }
698 
699     /**
700      * Erase the current user (guest) and switch to another user.
701      */
exitGuest()702     private void exitGuest() {
703         // Just to be safe
704         if (!mIsGuest) {
705             return;
706         }
707         removeThisUser();
708     }
709 
updateUserList()710     private void updateUserList() {
711         if (getActivity() == null) return;
712         List<UserInfo> users = mUserManager.getUsers(true);
713         final Context context = getActivity();
714 
715         mUserListCategory.removeAll();
716         mUserListCategory.setOrderingAsAdded(false);
717         mUserListCategory.addPreference(mMePreference);
718 
719         final boolean voiceCapable = Utils.isVoiceCapable(context);
720         final ArrayList<Integer> missingIcons = new ArrayList<Integer>();
721         for (UserInfo user : users) {
722             if (user.isManagedProfile()) {
723                 // Managed profiles appear under Accounts Settings instead
724                 continue;
725             }
726             Preference pref;
727             if (user.id == UserHandle.myUserId()) {
728                 pref = mMePreference;
729             } else if (user.isGuest()) {
730                 // Skip over Guest. We add generic Guest settings after this loop
731                 continue;
732             } else {
733                 // With Telephony:
734                 //   Secondary user: Settings
735                 //   Guest: Settings
736                 //   Restricted Profile: There is no Restricted Profile
737                 // Without Telephony:
738                 //   Secondary user: Delete
739                 //   Guest: Nothing
740                 //   Restricted Profile: Settings
741                 final boolean showSettings = mIsOwner && (voiceCapable || user.isRestricted());
742                 final boolean showDelete = mIsOwner
743                         && (!voiceCapable && !user.isRestricted() && !user.isGuest());
744                 pref = new UserPreference(context, null, user.id,
745                         showSettings ? this : null,
746                         showDelete ? this : null);
747                 pref.setOnPreferenceClickListener(this);
748                 pref.setKey("id=" + user.id);
749                 mUserListCategory.addPreference(pref);
750                 if (user.id == UserHandle.USER_OWNER) {
751                     pref.setSummary(R.string.user_owner);
752                 }
753                 pref.setTitle(user.name);
754             }
755             if (!isInitialized(user)) {
756                 if (user.isRestricted()) {
757                     pref.setSummary(R.string.user_summary_restricted_not_set_up);
758                 } else {
759                     pref.setSummary(R.string.user_summary_not_set_up);
760                 }
761             } else if (user.isRestricted()) {
762                 pref.setSummary(R.string.user_summary_restricted_profile);
763             }
764             if (user.iconPath != null) {
765                 if (mUserIcons.get(user.id) == null) {
766                     // Icon not loaded yet, print a placeholder
767                     missingIcons.add(user.id);
768                     pref.setIcon(getEncircledDefaultIcon());
769                 } else {
770                     setPhotoId(pref, user);
771                 }
772             } else {
773                 // Icon not available yet, print a placeholder
774                 pref.setIcon(getEncircledDefaultIcon());
775             }
776         }
777 
778         // Add a temporary entry for the user being created
779         if (mAddingUser) {
780             Preference pref = new UserPreference(getActivity(), null, UserPreference.USERID_UNKNOWN,
781                     null, null);
782             pref.setEnabled(false);
783             pref.setTitle(R.string.user_new_user_name);
784             pref.setIcon(getEncircledDefaultIcon());
785             mUserListCategory.addPreference(pref);
786         }
787 
788         boolean showGuestPreference = !mIsGuest;
789         // If user has DISALLOW_ADD_USER don't allow creating a guest either.
790         if (showGuestPreference && mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)) {
791             showGuestPreference = false;
792             // If guest already exists, no user creation needed.
793             for (UserInfo user : users) {
794                 if (user.isGuest()) {
795                     showGuestPreference = true;
796                     break;
797                 }
798             }
799         }
800         if (showGuestPreference) {
801             // Add a virtual Guest user for guest defaults
802             Preference pref = new UserPreference(getActivity(), null,
803                     UserPreference.USERID_GUEST_DEFAULTS,
804                     mIsOwner && voiceCapable? this : null /* settings icon handler */,
805                     null /* delete icon handler */);
806             pref.setTitle(R.string.user_guest);
807             pref.setIcon(getEncircledDefaultIcon());
808             pref.setOnPreferenceClickListener(this);
809             mUserListCategory.addPreference(pref);
810         }
811 
812         getActivity().invalidateOptionsMenu();
813 
814         // Load the icons
815         if (missingIcons.size() > 0) {
816             loadIconsAsync(missingIcons);
817         }
818         boolean moreUsers = mUserManager.canAddMoreUsers();
819         mAddUser.setEnabled(moreUsers);
820     }
821 
loadIconsAsync(List<Integer> missingIcons)822     private void loadIconsAsync(List<Integer> missingIcons) {
823         final Resources resources = getResources();
824         new AsyncTask<List<Integer>, Void, Void>() {
825             @Override
826             protected void onPostExecute(Void result) {
827                 updateUserList();
828             }
829 
830             @Override
831             protected Void doInBackground(List<Integer>... values) {
832                 for (int userId : values[0]) {
833                     Bitmap bitmap = mUserManager.getUserIcon(userId);
834                     if (bitmap == null) {
835                         bitmap = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(userId,
836                                 /* light= */ false));
837                     }
838                     mUserIcons.append(userId, bitmap);
839                 }
840                 return null;
841             }
842         }.execute(missingIcons);
843     }
844 
assignProfilePhoto(final UserInfo user)845     private void assignProfilePhoto(final UserInfo user) {
846         if (!Utils.copyMeProfilePhoto(getActivity(), user)) {
847             assignDefaultPhoto(user);
848         }
849     }
850 
assignDefaultPhoto(UserInfo user)851     private void assignDefaultPhoto(UserInfo user) {
852         Bitmap bitmap = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(user.id,
853                 /* light= */ false));
854         mUserManager.setUserIcon(user.id, bitmap);
855     }
856 
getEncircledDefaultIcon()857     private Drawable getEncircledDefaultIcon() {
858         if (mDefaultIconDrawable == null) {
859             mDefaultIconDrawable = encircle(UserIcons.convertToBitmap(
860                     UserIcons.getDefaultUserIcon(UserHandle.USER_NULL, /* light= */ false)));
861         }
862         return mDefaultIconDrawable;
863     }
864 
setPhotoId(Preference pref, UserInfo user)865     private void setPhotoId(Preference pref, UserInfo user) {
866         Bitmap bitmap = mUserIcons.get(user.id);
867         if (bitmap != null) {
868             pref.setIcon(encircle(bitmap));
869         }
870     }
871 
setUserName(String name)872     private void setUserName(String name) {
873         mUserManager.setUserName(UserHandle.myUserId(), name);
874         mNicknamePreference.setSummary(name);
875         getActivity().invalidateOptionsMenu();
876     }
877 
878     @Override
onPreferenceClick(Preference pref)879     public boolean onPreferenceClick(Preference pref) {
880         if (pref == mMePreference) {
881             if (mIsGuest) {
882                 showDialog(DIALOG_CONFIRM_EXIT_GUEST);
883                 return true;
884             }
885             // If this is a limited user, launch the user info settings instead of profile editor
886             if (mUserManager.isLinkedUser()) {
887                 onManageUserClicked(UserHandle.myUserId(), false);
888             } else {
889                 showDialog(DIALOG_USER_PROFILE_EDITOR);
890             }
891         } else if (pref instanceof UserPreference) {
892             int userId = ((UserPreference) pref).getUserId();
893             if (userId == UserPreference.USERID_GUEST_DEFAULTS) {
894                 createAndSwitchToGuestUser();
895             } else {
896                 // Get the latest status of the user
897                 UserInfo user = mUserManager.getUserInfo(userId);
898                 if (!isInitialized(user)) {
899                     mHandler.sendMessage(mHandler.obtainMessage(
900                             MESSAGE_SETUP_USER, user.id, user.serialNumber));
901                 } else {
902                     switchUserNow(userId);
903                 }
904             }
905         } else if (pref == mAddUser) {
906             // If we allow both types, show a picker, otherwise directly go to
907             // flow for full user.
908             if (mCanAddRestrictedProfile) {
909                 showDialog(DIALOG_CHOOSE_USER_TYPE);
910             } else {
911                 onAddUserClicked(USER_TYPE_USER);
912             }
913         }
914         return false;
915     }
916 
createAndSwitchToGuestUser()917     private void createAndSwitchToGuestUser() {
918         List<UserInfo> users = mUserManager.getUsers();
919         for (UserInfo user : users) {
920             if (user.isGuest()) {
921                 switchUserNow(user.id);
922                 return;
923             }
924         }
925         // No guest user. Create one, if there's no restriction.
926         // If it is not the primary user, then adding users from lockscreen must be enabled
927         if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)
928                 || (!mIsOwner && Settings.Global.getInt(getContentResolver(),
929                         Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 1)) {
930             Log.i(TAG, "Blocking guest creation because it is restricted");
931             return;
932         }
933         UserInfo guestUser = mUserManager.createGuest(getActivity(),
934                     getResources().getString(R.string.user_guest));
935         if (guestUser != null) {
936             switchUserNow(guestUser.id);
937         }
938     }
939 
isInitialized(UserInfo user)940     private boolean isInitialized(UserInfo user) {
941         return (user.flags & UserInfo.FLAG_INITIALIZED) != 0;
942     }
943 
encircle(Bitmap icon)944     private Drawable encircle(Bitmap icon) {
945         Drawable circled = CircleFramedDrawable.getInstance(getActivity(), icon);
946         return circled;
947     }
948 
949     @Override
onClick(View v)950     public void onClick(View v) {
951         if (v.getTag() instanceof UserPreference) {
952             int userId = ((UserPreference) v.getTag()).getUserId();
953             switch (v.getId()) {
954             case UserPreference.DELETE_ID:
955                 onRemoveUserClicked(userId);
956                 break;
957             case UserPreference.SETTINGS_ID:
958                 onManageUserClicked(userId, false);
959                 break;
960             }
961         }
962     }
963 
964     @Override
onDismiss(DialogInterface dialog)965     public void onDismiss(DialogInterface dialog) {
966         synchronized (mUserLock) {
967             mAddingUser = false;
968             mRemovingUserId = -1;
969             updateUserList();
970         }
971     }
972 
973     @Override
onPreferenceChange(Preference preference, Object newValue)974     public boolean onPreferenceChange(Preference preference, Object newValue) {
975         if (preference == mNicknamePreference) {
976             String value = (String) newValue;
977             if (preference == mNicknamePreference && value != null
978                     && value.length() > 0) {
979                 setUserName(value);
980             }
981             return true;
982         }
983         return false;
984     }
985 
986     @Override
getHelpResource()987     public int getHelpResource() {
988         return R.string.help_url_users;
989     }
990 
991     @Override
onPhotoChanged(Drawable photo)992     public void onPhotoChanged(Drawable photo) {
993         mMePreference.setIcon(photo);
994     }
995 
996     @Override
onLabelChanged(CharSequence label)997     public void onLabelChanged(CharSequence label) {
998         mMePreference.setTitle(label);
999     }
1000 }
1001