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