OSDN Git Service

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