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