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