OSDN Git Service

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