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