• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.users;
18 
19 import static com.android.settingslib.Utils.getColorAttrDefaultColor;
20 
21 import android.Manifest;
22 import android.annotation.Nullable;
23 import android.annotation.RequiresPermission;
24 import android.app.Activity;
25 import android.app.ActivityManager;
26 import android.app.Dialog;
27 import android.app.admin.DevicePolicyManager;
28 import android.app.settings.SettingsEnums;
29 import android.content.BroadcastReceiver;
30 import android.content.Context;
31 import android.content.DialogInterface;
32 import android.content.Intent;
33 import android.content.IntentFilter;
34 import android.content.pm.UserInfo;
35 import android.content.res.Resources;
36 import android.graphics.Bitmap;
37 import android.graphics.BitmapFactory;
38 import android.graphics.BlendMode;
39 import android.graphics.drawable.Drawable;
40 import android.graphics.drawable.LayerDrawable;
41 import android.multiuser.Flags;
42 import android.net.Uri;
43 import android.os.AsyncTask;
44 import android.os.Bundle;
45 import android.os.Handler;
46 import android.os.Message;
47 import android.os.Process;
48 import android.os.RemoteException;
49 import android.os.Trace;
50 import android.os.UserHandle;
51 import android.os.UserManager;
52 import android.provider.ContactsContract;
53 import android.provider.Settings;
54 import android.text.TextUtils;
55 import android.util.Log;
56 import android.util.SparseArray;
57 import android.view.Gravity;
58 import android.view.Menu;
59 import android.view.MenuInflater;
60 import android.view.MenuItem;
61 import android.view.WindowManagerGlobal;
62 import android.widget.SimpleAdapter;
63 import android.widget.Toast;
64 
65 import androidx.annotation.VisibleForTesting;
66 import androidx.annotation.WorkerThread;
67 import androidx.appcompat.app.AlertDialog;
68 import androidx.preference.Preference;
69 import androidx.preference.PreferenceGroup;
70 import androidx.preference.PreferenceScreen;
71 
72 import com.android.internal.util.UserIcons;
73 import com.android.internal.widget.LockPatternUtils;
74 import com.android.settings.R;
75 import com.android.settings.SettingsActivity;
76 import com.android.settings.SettingsPreferenceFragment;
77 import com.android.settings.Utils;
78 import com.android.settings.core.SubSettingLauncher;
79 import com.android.settings.password.ChooseLockGeneric;
80 import com.android.settings.search.BaseSearchIndexProvider;
81 import com.android.settings.widget.MainSwitchBarController;
82 import com.android.settings.widget.SettingsMainSwitchBar;
83 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
84 import com.android.settingslib.RestrictedLockUtilsInternal;
85 import com.android.settingslib.RestrictedPreference;
86 import com.android.settingslib.drawable.CircleFramedDrawable;
87 import com.android.settingslib.search.SearchIndexable;
88 import com.android.settingslib.search.SearchIndexableRaw;
89 import com.android.settingslib.users.CreateUserActivity;
90 import com.android.settingslib.users.CreateUserDialogController;
91 import com.android.settingslib.users.EditUserInfoController;
92 import com.android.settingslib.users.GrantAdminDialogController;
93 import com.android.settingslib.users.UserCreatingDialog;
94 import com.android.settingslib.utils.ThreadUtils;
95 
96 import com.google.android.setupcompat.util.WizardManagerHelper;
97 
98 import java.io.File;
99 import java.io.IOException;
100 import java.io.InputStream;
101 import java.util.ArrayList;
102 import java.util.Collections;
103 import java.util.HashMap;
104 import java.util.List;
105 import java.util.concurrent.ExecutorService;
106 import java.util.concurrent.Executors;
107 import java.util.concurrent.Future;
108 import java.util.concurrent.atomic.AtomicBoolean;
109 import java.util.stream.Collectors;
110 
111 /**
112  * Screen that manages the list of users on the device.
113  * Secondary users and a guest user can be created if there is no restriction.
114  *
115  * The first user in the list is always the current user.
116  * Owner is the primary user.
117  */
118 @SearchIndexable
119 public class UserSettings extends SettingsPreferenceFragment
120         implements Preference.OnPreferenceClickListener,
121         MultiUserSwitchBarController.OnMultiUserSwitchChangedListener,
122         DialogInterface.OnDismissListener {
123 
124     private static final String TAG = "UserSettings";
125 
126     /** UserId of the user being removed */
127     private static final String SAVE_REMOVING_USER = "removing_user";
128     private static final String SAVE_CREATE_USER = "create_user";
129 
130     private static final String KEY_USER_LIST = "user_list";
131     private static final String KEY_USER_ME = "user_me";
132     private static final String KEY_USER_GUEST = "user_guest";
133     private static final String KEY_ADD_GUEST = "guest_add";
134     private static final String KEY_ADD_USER = "user_add";
135     private static final String KEY_ADD_SUPERVISED_USER = "supervised_user_add";
136     private static final String KEY_ADD_USER_WHEN_LOCKED = "user_settings_add_users_when_locked";
137     private static final String KEY_ENABLE_GUEST_TELEPHONY = "enable_guest_calling";
138     private static final String KEY_MULTIUSER_TOP_INTRO = "multiuser_top_intro";
139     private static final String KEY_TIMEOUT_TO_DOCK_USER = "timeout_to_dock_user_preference";
140     private static final String KEY_GUEST_CATEGORY = "guest_category";
141     private static final String KEY_GUEST_RESET = "guest_reset";
142     private static final String KEY_GUEST_EXIT = "guest_exit";
143     private static final String KEY_REMOVE_GUEST_ON_EXIT = "remove_guest_on_exit";
144     private static final String KEY_GUEST_USER_CATEGORY = "guest_user_category";
145     private static final String KEY_ALLOW_MULTIPLE_USERS = "allow_multiple_users";
146     private static final String KEY_USER_SETTINGS_SCREEN = "user_settings_screen";
147 
148     private static final String SETTING_GUEST_HAS_LOGGED_IN = "systemui.guest_has_logged_in";
149 
150     private static final int MENU_REMOVE_USER = Menu.FIRST;
151 
152     private static final IntentFilter USER_REMOVED_INTENT_FILTER;
153 
154     private static final int DIALOG_CONFIRM_REMOVE = 1;
155     private static final int DIALOG_ADD_USER = 2;
156     // Dialogs with id 3 and 4 got removed
157     private static final int DIALOG_USER_CANNOT_MANAGE = 5;
158     private static final int DIALOG_CHOOSE_USER_TYPE = 6;
159     private static final int DIALOG_NEED_LOCKSCREEN = 7;
160     private static final int DIALOG_CONFIRM_REMOVE_GUEST = 8;
161     private static final int DIALOG_USER_PROFILE_EDITOR = 9;
162     private static final int DIALOG_USER_PROFILE_EDITOR_ADD_USER = 10;
163     private static final int DIALOG_USER_PROFILE_EDITOR_ADD_RESTRICTED_PROFILE = 11;
164     private static final int DIALOG_CONFIRM_REMOVE_GUEST_WITH_AUTO_CREATE = 12;
165     private static final int DIALOG_CONFIRM_RESET_AND_RESTART_GUEST = 13;
166     private static final int DIALOG_CONFIRM_EXIT_GUEST_EPHEMERAL = 14;
167     private static final int DIALOG_CONFIRM_EXIT_GUEST_NON_EPHEMERAL = 15;
168     private static final int DIALOG_GRANT_ADMIN = 16;
169 
170     private static final int MESSAGE_UPDATE_LIST = 1;
171     private static final int MESSAGE_USER_CREATED = 2;
172     static final int MESSAGE_REMOVE_GUEST_ON_EXIT_CONTROLLER_GUEST_REMOVED = 3;
173 
174     private static final int USER_TYPE_USER = 1;
175     private static final int USER_TYPE_RESTRICTED_PROFILE = 2;
176 
177     private static final int REQUEST_CHOOSE_LOCK = 10;
178     private static final int REQUEST_EDIT_GUEST = 11;
179     private static final int REQUEST_ADD_USER = 12;
180 
181     static final int RESULT_GUEST_REMOVED = 100;
182 
183     private static final String KEY_TITLE = "title";
184     private static final String KEY_SUMMARY = "summary";
185 
186     private static final String EXTRA_OPEN_DIALOG_USER_PROFILE_EDITOR =
187             "EXTRA_OPEN_DIALOG_USER_PROFILE_EDITOR";
188 
189     static {
190         USER_REMOVED_INTENT_FILTER = new IntentFilter(Intent.ACTION_USER_REMOVED);
191         USER_REMOVED_INTENT_FILTER.addAction(Intent.ACTION_USER_INFO_CHANGED);
192     }
193 
194     @VisibleForTesting
195     PreferenceGroup mUserListCategory;
196     @VisibleForTesting
197     PreferenceGroup mGuestUserCategory;
198     @VisibleForTesting
199     PreferenceGroup mGuestCategory;
200     @VisibleForTesting
201     Preference mGuestResetPreference;
202     @VisibleForTesting
203     Preference mGuestExitPreference;
204     @VisibleForTesting
205     UserPreference mMePreference;
206     @VisibleForTesting
207     RestrictedPreference mAddGuest;
208     @VisibleForTesting
209     RestrictedPreference mAddUser;
210     @VisibleForTesting
211     RestrictedPreference mAddSupervisedUser;
212     @VisibleForTesting
213     SparseArray<Bitmap> mUserIcons = new SparseArray<>();
214     private int mRemovingUserId = -1;
215     private boolean mAddingUser;
216     private boolean mGuestUserAutoCreated;
217     private String mConfigSupervisedUserCreationPackage;
218     private String mAddingUserName;
219     private UserCapabilities mUserCaps;
220     private boolean mShouldUpdateUserList = true;
221     private final Object mUserLock = new Object();
222     private UserManager mUserManager;
223     private static SparseArray<Bitmap> sDarkDefaultUserBitmapCache = new SparseArray<>();
224 
225     private MultiUserSwitchBarController mSwitchBarController;
226 
227     private GrantAdminDialogController mGrantAdminDialogController =
228             new GrantAdminDialogController();
229     private EditUserInfoController mEditUserInfoController =
230             new EditUserInfoController(Utils.FILE_PROVIDER_AUTHORITY);
231     private CreateUserDialogController mCreateUserDialogController =
232             new CreateUserDialogController(Utils.FILE_PROVIDER_AUTHORITY);
233     private AddUserWhenLockedPreferenceController mAddUserWhenLockedPreferenceController;
234     private GuestTelephonyPreferenceController mGuestTelephonyPreferenceController;
235     private RemoveGuestOnExitPreferenceController mRemoveGuestOnExitPreferenceController;
236     private MultiUserTopIntroPreferenceController mMultiUserTopIntroPreferenceController;
237     private TimeoutToDockUserPreferenceController mTimeoutToDockUserPreferenceController;
238     private UserCreatingDialog mUserCreatingDialog;
239     private final AtomicBoolean mGuestCreationScheduled = new AtomicBoolean();
240     private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
241 
242     private CharSequence mPendingUserName;
243     @Nullable
244     private String mPendingUserIconPath;
245     private Drawable mPendingUserIcon;
246     private boolean mPendingUserIsAdmin;
247 
248     // A place to cache the generated default avatar
249     private Drawable mDefaultIconDrawable;
250 
251     // TODO:   Replace current Handler solution to something that doesn't leak memory and works
252     // TODO:   during a configuration change
253     private Handler mHandler = new Handler() {
254         @Override
255         public void handleMessage(Message msg) {
256             switch (msg.what) {
257                 case MESSAGE_UPDATE_LIST:
258                     updateUserList();
259                     break;
260                 case MESSAGE_REMOVE_GUEST_ON_EXIT_CONTROLLER_GUEST_REMOVED:
261                     updateUserList();
262                     if (mGuestUserAutoCreated) {
263                         scheduleGuestCreation();
264                     }
265                     break;
266             }
267         }
268     };
269 
270     private BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {
271         @Override
272         public void onReceive(Context context, Intent intent) {
273             if (intent.getAction().equals(Intent.ACTION_USER_REMOVED)) {
274                 mRemovingUserId = -1;
275             } else if (intent.getAction().equals(Intent.ACTION_USER_INFO_CHANGED)) {
276                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
277                 if (userHandle != -1) {
278                     mUserIcons.remove(userHandle);
279                 }
280             }
281             mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
282         }
283     };
284 
285     @Override
getMetricsCategory()286     public int getMetricsCategory() {
287         return SettingsEnums.USER;
288     }
289 
290     @Override
onActivityCreated(Bundle savedInstanceState)291     public void onActivityCreated(Bundle savedInstanceState) {
292         super.onActivityCreated(savedInstanceState);
293         // Assume we are in a SettingsActivity. This is only safe because we currently use
294         // SettingsActivity as base for all preference fragments.
295         final SettingsActivity activity = (SettingsActivity) getActivity();
296         final SettingsMainSwitchBar switchBar = activity.getSwitchBar();
297         switchBar.setTitle(getContext().getString(R.string.multiple_users_main_switch_title));
298         if (!mUserCaps.mIsGuest && mUserCaps.mUserSwitchingUiEnabled) {
299             switchBar.show();
300         } else {
301             switchBar.hide();
302         }
303         mSwitchBarController = new MultiUserSwitchBarController(activity,
304                 new MainSwitchBarController(switchBar), this /* listener */);
305         getSettingsLifecycle().addObserver(mSwitchBarController);
306         boolean openUserEditDialog = getIntent().getBooleanExtra(
307                 EXTRA_OPEN_DIALOG_USER_PROFILE_EDITOR, false);
308         if (switchBar.isChecked() && openUserEditDialog) {
309             showDialog(DIALOG_USER_PROFILE_EDITOR);
310         }
311     }
312 
313     @Override
onCreate(Bundle icicle)314     public void onCreate(Bundle icicle) {
315         super.onCreate(icicle);
316         addPreferencesFromResource(R.xml.user_settings);
317         final Activity activity = getActivity();
318         if (!WizardManagerHelper.isDeviceProvisioned(activity)) {
319             activity.finish();
320             return;
321         }
322 
323         mGuestUserAutoCreated = getPrefContext().getResources().getBoolean(
324                 com.android.internal.R.bool.config_guestUserAutoCreated);
325 
326         mAddUserWhenLockedPreferenceController = new AddUserWhenLockedPreferenceController(
327                 activity, KEY_ADD_USER_WHEN_LOCKED);
328 
329         mGuestTelephonyPreferenceController = new GuestTelephonyPreferenceController(
330                 activity, KEY_ENABLE_GUEST_TELEPHONY);
331 
332         mRemoveGuestOnExitPreferenceController = new RemoveGuestOnExitPreferenceController(
333                 activity, KEY_REMOVE_GUEST_ON_EXIT, this, mHandler);
334 
335         mMultiUserTopIntroPreferenceController = new MultiUserTopIntroPreferenceController(activity,
336                 KEY_MULTIUSER_TOP_INTRO);
337 
338         mTimeoutToDockUserPreferenceController = new TimeoutToDockUserPreferenceController(
339                 activity, KEY_TIMEOUT_TO_DOCK_USER);
340 
341         final PreferenceScreen screen = getPreferenceScreen();
342         mAddUserWhenLockedPreferenceController.displayPreference(screen);
343         mGuestTelephonyPreferenceController.displayPreference(screen);
344         mRemoveGuestOnExitPreferenceController.displayPreference(screen);
345         mMultiUserTopIntroPreferenceController.displayPreference(screen);
346         mTimeoutToDockUserPreferenceController.displayPreference(screen);
347 
348         screen.findPreference(mAddUserWhenLockedPreferenceController.getPreferenceKey())
349                 .setOnPreferenceChangeListener(mAddUserWhenLockedPreferenceController);
350 
351         screen.findPreference(mGuestTelephonyPreferenceController.getPreferenceKey())
352                 .setOnPreferenceChangeListener(mGuestTelephonyPreferenceController);
353 
354         screen.findPreference(mRemoveGuestOnExitPreferenceController.getPreferenceKey())
355                 .setOnPreferenceChangeListener(mRemoveGuestOnExitPreferenceController);
356 
357         if (icicle != null) {
358             if (icicle.containsKey(SAVE_REMOVING_USER)) {
359                 mRemovingUserId = icicle.getInt(SAVE_REMOVING_USER);
360             }
361             if (icicle.containsKey(SAVE_CREATE_USER)) {
362                 mCreateUserDialogController.onRestoreInstanceState(icicle);
363             } else {
364                 mEditUserInfoController.onRestoreInstanceState(icicle);
365             }
366         }
367 
368         mUserCaps = UserCapabilities.create(activity);
369         mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE);
370         if (!mUserCaps.mEnabled) {
371             return;
372         }
373 
374         final int myUserId = UserHandle.myUserId();
375 
376         mUserListCategory = (PreferenceGroup) findPreference(KEY_USER_LIST);
377         mMePreference = new UserPreference(getPrefContext(), null /* attrs */, myUserId);
378         mMePreference.setKey(KEY_USER_ME);
379         mMePreference.setOnPreferenceClickListener(this);
380 
381         mGuestCategory = findPreference(KEY_GUEST_CATEGORY);
382 
383         mGuestResetPreference = findPreference(KEY_GUEST_RESET);
384         mGuestResetPreference.setOnPreferenceClickListener(this);
385 
386         mGuestExitPreference = findPreference(KEY_GUEST_EXIT);
387         mGuestExitPreference.setOnPreferenceClickListener(this);
388 
389         mGuestUserCategory = findPreference(KEY_GUEST_USER_CATEGORY);
390 
391         mAddGuest = findPreference(KEY_ADD_GUEST);
392         mAddGuest.setOnPreferenceClickListener(this);
393 
394         mAddUser = findPreference(KEY_ADD_USER);
395         if (!mUserCaps.mCanAddRestrictedProfile) {
396             // Label should only mention adding a "user", not a "profile"
397             mAddUser.setTitle(com.android.settingslib.R.string.user_add_user);
398         }
399         mAddUser.setOnPreferenceClickListener(this);
400 
401         setConfigSupervisedUserCreationPackage();
402         mAddSupervisedUser = findPreference(KEY_ADD_SUPERVISED_USER);
403         mAddSupervisedUser.setOnPreferenceClickListener(this);
404 
405         activity.registerReceiverAsUser(
406                 mUserChangeReceiver, UserHandle.ALL, USER_REMOVED_INTENT_FILTER, null, mHandler,
407                 Context.RECEIVER_EXPORTED_UNAUDITED);
408 
409         updateUI();
410         mShouldUpdateUserList = false;
411     }
412 
413     @Override
onResume()414     public void onResume() {
415         super.onResume();
416 
417         if (!mUserCaps.mEnabled) {
418             return;
419         }
420         final PreferenceScreen screen = getPreferenceScreen();
421 
422         mAddUserWhenLockedPreferenceController.updateState(screen.findPreference(
423                 mAddUserWhenLockedPreferenceController.getPreferenceKey()));
424         mGuestTelephonyPreferenceController.updateState(screen.findPreference(
425                 mGuestTelephonyPreferenceController.getPreferenceKey()));
426         mTimeoutToDockUserPreferenceController.updateState(screen.findPreference(
427                 mTimeoutToDockUserPreferenceController.getPreferenceKey()));
428         mRemoveGuestOnExitPreferenceController.updateState(screen.findPreference(
429                 mRemoveGuestOnExitPreferenceController.getPreferenceKey()));
430         mSwitchBarController.updateState();
431         if (mShouldUpdateUserList) {
432             updateUI();
433         }
434     }
435 
436     @Override
onPause()437     public void onPause() {
438         mShouldUpdateUserList = true;
439         super.onPause();
440     }
441 
442     @Override
onDestroy()443     public void onDestroy() {
444         super.onDestroy();
445 
446         if (mUserCaps == null || !mUserCaps.mEnabled) {
447             return;
448         }
449 
450         getActivity().unregisterReceiver(mUserChangeReceiver);
451     }
452 
453     @Override
onSaveInstanceState(Bundle outState)454     public void onSaveInstanceState(Bundle outState) {
455         if (mCreateUserDialogController.isActive()) {
456             outState.putBoolean(SAVE_CREATE_USER, mCreateUserDialogController.isActive());
457             mCreateUserDialogController.onSaveInstanceState(outState);
458         } else {
459             mEditUserInfoController.onSaveInstanceState(outState);
460         }
461         outState.putInt(SAVE_REMOVING_USER, mRemovingUserId);
462         super.onSaveInstanceState(outState);
463     }
464 
465     @Override
startActivityForResult(Intent intent, int requestCode)466     public void startActivityForResult(Intent intent, int requestCode) {
467         mEditUserInfoController.startingActivityForResult();
468         mCreateUserDialogController.startingActivityForResult();
469         super.startActivityForResult(intent, requestCode);
470     }
471 
472     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)473     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
474         int pos = 0;
475         if (!isCurrentUserAdmin() && (canSwitchUserNow() || Flags.newMultiuserSettingsUx())
476                 && !isCurrentUserGuest() && !mUserManager.isProfile()) {
477             String nickname = mUserManager.getUserName();
478             MenuItem removeThisUser = menu.add(0, MENU_REMOVE_USER, pos++,
479                     getResources().getString(R.string.user_remove_user_menu, nickname));
480             removeThisUser.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
481 
482             final EnforcedAdmin disallowRemoveUserAdmin =
483                     RestrictedLockUtilsInternal.checkIfRestrictionEnforced(getContext(),
484                             UserManager.DISALLOW_REMOVE_USER, UserHandle.myUserId());
485             RestrictedLockUtilsInternal.setMenuItemAsDisabledByAdmin(getContext(), removeThisUser,
486                     disallowRemoveUserAdmin);
487         }
488         super.onCreateOptionsMenu(menu, inflater);
489     }
490 
491     @Override
onOptionsItemSelected(MenuItem item)492     public boolean onOptionsItemSelected(MenuItem item) {
493         final int itemId = item.getItemId();
494         if (itemId == MENU_REMOVE_USER) {
495             onRemoveUserClicked(UserHandle.myUserId());
496             return true;
497         } else {
498             return super.onOptionsItemSelected(item);
499         }
500     }
501 
502     @Override
onMultiUserSwitchChanged(boolean newState)503     public void onMultiUserSwitchChanged(boolean newState) {
504         updateUI();
505     }
506 
updateUI()507     private void updateUI() {
508         mUserCaps.updateAddUserCapabilities(getActivity());
509         loadProfile();
510         updateUserList();
511     }
512 
513     /**
514      * Loads profile information for the current user.
515      */
loadProfile()516     private void loadProfile() {
517         if (isCurrentUserGuest()) {
518             // No need to load profile information
519             mMePreference.setIcon(getEncircledDefaultIcon());
520             mMePreference.setTitle(mGuestUserAutoCreated
521                     ? com.android.settingslib.R.string.guest_reset_guest
522                     : com.android.settingslib.R.string.guest_exit_guest);
523             mMePreference.setSelectable(true);
524             // removing a guest will result in switching back to the admin user
525             mMePreference.setEnabled(canSwitchUserNow());
526             return;
527         }
528 
529         new AsyncTask<Void, Void, String>() {
530             @Override
531             protected void onPostExecute(String result) {
532                 finishLoadProfile(result);
533             }
534 
535             @Override
536             protected String doInBackground(Void... values) {
537                 UserInfo user = mUserManager.getUserInfo(UserHandle.myUserId());
538                 if (user.iconPath == null || user.iconPath.equals("")) {
539                     // Assign profile photo.
540                     copyMeProfilePhoto(getActivity(), user);
541                 }
542                 return user.name;
543             }
544         }.execute();
545     }
546 
finishLoadProfile(String profileName)547     private void finishLoadProfile(String profileName) {
548         if (getActivity() == null) {
549             return;
550         }
551         mMePreference.setTitle(getString(R.string.user_you, profileName));
552         int myUserId = UserHandle.myUserId();
553         Bitmap b = mUserManager.getUserIcon(myUserId);
554         if (b != null) {
555             mMePreference.setIcon(encircleUserIcon(b));
556             mUserIcons.put(myUserId, b);
557         }
558     }
559 
hasLockscreenSecurity()560     private boolean hasLockscreenSecurity() {
561         LockPatternUtils lpu = new LockPatternUtils(getActivity());
562         return lpu.isSecure(UserHandle.myUserId());
563     }
564 
launchChooseLockscreen()565     private void launchChooseLockscreen() {
566         Intent chooseLockIntent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD)
567                 .setPackage(getContext().getPackageName());
568         chooseLockIntent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS,
569                 true);
570         startActivityForResult(chooseLockIntent, REQUEST_CHOOSE_LOCK);
571     }
572 
573     @Override
onActivityResult(int requestCode, int resultCode, Intent data)574     public void onActivityResult(int requestCode, int resultCode, Intent data) {
575         super.onActivityResult(requestCode, resultCode, data);
576 
577         if (requestCode == REQUEST_CHOOSE_LOCK) {
578             if (resultCode != Activity.RESULT_CANCELED && hasLockscreenSecurity()) {
579                 addUserNow(USER_TYPE_RESTRICTED_PROFILE);
580             }
581         } else if (Flags.placeAddUserDialogWithinActivity() && requestCode == REQUEST_ADD_USER) {
582             if (resultCode == Activity.RESULT_OK) {
583                 mPendingUserName = data.getStringExtra(CreateUserActivity.EXTRA_USER_NAME);
584                 mPendingUserIsAdmin = data.getBooleanExtra(CreateUserActivity.EXTRA_IS_ADMIN,
585                         false);
586                 mPendingUserIconPath = data.getStringExtra(CreateUserActivity.EXTRA_USER_ICON_PATH);
587                 addUserNow(USER_TYPE_USER);
588             }
589         } else if (mGuestUserAutoCreated && requestCode == REQUEST_EDIT_GUEST
590                 && resultCode == RESULT_GUEST_REMOVED) {
591             scheduleGuestCreation();
592         } else {
593             mCreateUserDialogController.onActivityResult(requestCode, resultCode, data);
594             mEditUserInfoController.onActivityResult(requestCode, resultCode, data);
595         }
596     }
597 
onAddUserClicked(int userType)598     private void onAddUserClicked(int userType) {
599         synchronized (mUserLock) {
600             if (mRemovingUserId == -1 && !mAddingUser) {
601                 switch (userType) {
602                     case USER_TYPE_USER:
603                         showDialog(DIALOG_ADD_USER);
604                         break;
605                     case USER_TYPE_RESTRICTED_PROFILE:
606                         if (hasLockscreenSecurity()) {
607                             showDialog(DIALOG_USER_PROFILE_EDITOR_ADD_RESTRICTED_PROFILE);
608                         } else {
609                             showDialog(DIALOG_NEED_LOCKSCREEN);
610                         }
611                         break;
612                 }
613             }
614         }
615     }
616 
onAddSupervisedUserClicked()617     private void onAddSupervisedUserClicked() {
618         final Intent intent = new Intent()
619                 .setAction(UserManager.ACTION_CREATE_SUPERVISED_USER)
620                 .setPackage(mConfigSupervisedUserCreationPackage)
621                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
622 
623         startActivity(intent);
624     }
625 
onAddGuestClicked()626     private void onAddGuestClicked() {
627         Context context = getContext();
628         final UserCreatingDialog guestCreatingDialog =
629                 new UserCreatingDialog(getActivity(), /* isGuest= */ true);
630         guestCreatingDialog.show();
631 
632         ThreadUtils.postOnBackgroundThread(() -> {
633             mMetricsFeatureProvider.action(getActivity(), SettingsEnums.ACTION_USER_GUEST_ADD);
634             Trace.beginSection("UserSettings.addGuest");
635             final UserInfo guest = mUserManager.createGuest(context);
636             Trace.endSection();
637 
638             ThreadUtils.postOnMainThread(() -> {
639                 guestCreatingDialog.dismiss();
640                 if (guest == null) {
641                     Toast.makeText(context,
642                             com.android.settingslib.R.string.add_guest_failed,
643                             Toast.LENGTH_SHORT).show();
644                     return;
645                 }
646                 openUserDetails(guest, true, context);
647             });
648         });
649     }
650 
onRemoveUserClicked(int userId)651     private void onRemoveUserClicked(int userId) {
652         synchronized (mUserLock) {
653             if (mRemovingUserId == -1 && !mAddingUser) {
654                 mRemovingUserId = userId;
655                 showDialog(DIALOG_CONFIRM_REMOVE);
656             }
657         }
658     }
659 
onUserCreated(UserInfo userInfo, Context context)660     private void onUserCreated(UserInfo userInfo, Context context) {
661         hideUserCreatingDialog();
662         mAddingUser = false;
663         openUserDetails(userInfo, true, context);
664     }
665 
hideUserCreatingDialog()666     private void hideUserCreatingDialog() {
667         if (mUserCreatingDialog != null && mUserCreatingDialog.isShowing()) {
668             mUserCreatingDialog.dismiss();
669         }
670     }
671 
onUserCreationFailed()672     private void onUserCreationFailed() {
673         Toast.makeText(getContext(),
674                 com.android.settingslib.R.string.add_user_failed,
675                 Toast.LENGTH_SHORT).show();
676         hideUserCreatingDialog();
677     }
678 
openUserDetails(UserInfo userInfo, boolean newUser)679     private void openUserDetails(UserInfo userInfo, boolean newUser) {
680         openUserDetails(userInfo, newUser, getContext());
681     }
682 
openUserDetails(UserInfo userInfo, boolean newUser, Context context)683     private void openUserDetails(UserInfo userInfo, boolean newUser, Context context) {
684         // to prevent a crash when config changes during user creation,
685         // we simply ignore this redirection step
686         if (context == null) {
687             return;
688         }
689 
690         Bundle extras = new Bundle();
691         extras.putInt(UserDetailsSettings.EXTRA_USER_ID, userInfo.id);
692         extras.putBoolean(AppRestrictionsFragment.EXTRA_NEW_USER, newUser);
693 
694         SubSettingLauncher launcher = new SubSettingLauncher(context)
695                 .setDestination(UserDetailsSettings.class.getName())
696                 .setArguments(extras)
697                 .setTitleText(userInfo.name)
698                 .setSourceMetricsCategory(getMetricsCategory());
699         if (mGuestUserAutoCreated && userInfo.isGuest()) {
700             launcher.setResultListener(this, REQUEST_EDIT_GUEST);
701         }
702         launcher.launch();
703     }
704 
705     @Override
onDialogShowing()706     public void onDialogShowing() {
707         super.onDialogShowing();
708 
709         setOnDismissListener(this);
710     }
711 
712     @Override
onCreateDialog(int dialogId)713     public Dialog onCreateDialog(int dialogId) {
714         Context context = getActivity();
715         if (context == null) {
716             return null;
717         }
718         switch (dialogId) {
719             case DIALOG_CONFIRM_REMOVE: {
720                 Dialog dlg =
721                         UserDialogs.createRemoveDialog(getActivity(), mRemovingUserId,
722                                 new DialogInterface.OnClickListener() {
723                                     public void onClick(DialogInterface dialog, int which) {
724                                         removeUserNow();
725                                     }
726                                 }
727                         );
728                 return dlg;
729             }
730             case DIALOG_USER_CANNOT_MANAGE:
731                 return new AlertDialog.Builder(context)
732                         .setMessage(R.string.user_cannot_manage_message)
733                         .setPositiveButton(android.R.string.ok, null)
734                         .create();
735             case DIALOG_ADD_USER: {
736                 synchronized (mUserLock) {
737                     mPendingUserName = getString(
738                             com.android.settingslib.R.string.user_new_user_name);
739                     mPendingUserIcon = null;
740                 }
741                 return buildAddUserDialog(USER_TYPE_USER);
742             }
743             case DIALOG_CHOOSE_USER_TYPE: {
744                 List<HashMap<String, String>> data = new ArrayList<HashMap<String, String>>();
745                 HashMap<String, String> addUserItem = new HashMap<String, String>();
746                 addUserItem.put(KEY_TITLE, getString(
747                         com.android.settingslib.R.string.user_add_user_item_title));
748                 addUserItem.put(KEY_SUMMARY, getString(
749                         com.android.settingslib.R.string.user_add_user_item_summary));
750                 HashMap<String, String> addProfileItem = new HashMap<String, String>();
751                 addProfileItem.put(KEY_TITLE, getString(
752                         com.android.settingslib.R.string.user_add_profile_item_title));
753                 addProfileItem.put(KEY_SUMMARY, getString(
754                         com.android.settingslib.R.string.user_add_profile_item_summary));
755                 data.add(addUserItem);
756                 data.add(addProfileItem);
757                 AlertDialog.Builder builder = new AlertDialog.Builder(context);
758                 SimpleAdapter adapter = new SimpleAdapter(builder.getContext(),
759                         data, R.layout.two_line_list_item,
760                         new String[]{KEY_TITLE, KEY_SUMMARY},
761                         new int[]{R.id.title, R.id.summary});
762                 builder.setTitle(com.android.settingslib.R.string.user_add_user_type_title);
763                 builder.setAdapter(adapter,
764                         new DialogInterface.OnClickListener() {
765                             @Override
766                             public void onClick(DialogInterface dialog, int which) {
767                                 onAddUserClicked(which == 0
768                                         ? USER_TYPE_USER
769                                         : USER_TYPE_RESTRICTED_PROFILE);
770                             }
771                         });
772                 return builder.create();
773             }
774             case DIALOG_NEED_LOCKSCREEN: {
775                 Dialog dlg = new AlertDialog.Builder(context)
776                         .setMessage(com.android.settingslib.R.string.user_need_lock_message)
777                         .setPositiveButton(com.android.settingslib.R.string.user_set_lock_button,
778                                 new DialogInterface.OnClickListener() {
779                                     @Override
780                                     public void onClick(DialogInterface dialog, int which) {
781                                         launchChooseLockscreen();
782                                     }
783                                 })
784                         .setNegativeButton(android.R.string.cancel, null)
785                         .create();
786                 return dlg;
787             }
788             case DIALOG_CONFIRM_REMOVE_GUEST: {
789                 Dialog dlg = new AlertDialog.Builder(context)
790                         .setTitle(com.android.settingslib.R.string.guest_remove_guest_dialog_title)
791                         .setMessage(R.string.user_exit_guest_confirm_message)
792                         .setPositiveButton(R.string.user_exit_guest_dialog_remove,
793                                 new DialogInterface.OnClickListener() {
794                                     @Override
795                                     public void onClick(DialogInterface dialog, int which) {
796                                         clearAndExitGuest();
797                                     }
798                                 })
799                         .setNegativeButton(android.R.string.cancel, null)
800                         .create();
801                 return dlg;
802             }
803             case DIALOG_CONFIRM_EXIT_GUEST_EPHEMERAL: {
804                 Dialog dlg = new AlertDialog.Builder(context)
805                         .setTitle(com.android.settingslib.R.string.guest_exit_dialog_title)
806                         .setMessage(com.android.settingslib.R.string.guest_exit_dialog_message)
807                         .setPositiveButton(
808                                 com.android.settingslib.R.string.guest_exit_dialog_button,
809                                 new DialogInterface.OnClickListener() {
810                                     @Override
811                                     public void onClick(DialogInterface dialog, int which) {
812                                         clearAndExitGuest();
813                                     }
814                                 })
815                         .setNeutralButton(android.R.string.cancel, null)
816                         .create();
817                 return dlg;
818             }
819             case DIALOG_CONFIRM_EXIT_GUEST_NON_EPHEMERAL: {
820                 Dialog dlg = new AlertDialog.Builder(context)
821                         .setTitle(
822                             com.android.settingslib.R.string.guest_exit_dialog_title_non_ephemeral)
823                         .setMessage(
824                             com.android.settingslib
825                                 .R.string.guest_exit_dialog_message_non_ephemeral)
826                         .setPositiveButton(
827                             com.android.settingslib.R.string.guest_exit_save_data_button,
828                                 new DialogInterface.OnClickListener() {
829                                     @Override
830                                     public void onClick(DialogInterface dialog, int which) {
831                                         exitGuest();
832                                     }
833                                 })
834                         .setNegativeButton(
835                             com.android.settingslib.R.string.guest_exit_clear_data_button,
836                                 new DialogInterface.OnClickListener() {
837                                     @Override
838                                     public void onClick(DialogInterface dialog, int which) {
839                                         clearAndExitGuest();
840                                     }
841                                 })
842                         .setNeutralButton(android.R.string.cancel, null)
843                         .create();
844                 return dlg;
845             }
846             case DIALOG_USER_PROFILE_EDITOR: {
847                 return buildEditCurrentUserDialog();
848             }
849             case DIALOG_USER_PROFILE_EDITOR_ADD_USER: {
850                 synchronized (mUserLock) {
851                     mPendingUserName = getString(
852                             com.android.settingslib.R.string.user_new_user_name);
853                     mPendingUserIcon = null;
854                 }
855                 return buildAddUserDialog(USER_TYPE_USER);
856             }
857             case DIALOG_USER_PROFILE_EDITOR_ADD_RESTRICTED_PROFILE: {
858                 synchronized (mUserLock) {
859                     mPendingUserName = getString(
860                             com.android.settingslib.R.string.user_new_profile_name);
861                     mPendingUserIcon = null;
862                 }
863                 return buildAddUserDialog(USER_TYPE_RESTRICTED_PROFILE);
864             }
865             case DIALOG_CONFIRM_REMOVE_GUEST_WITH_AUTO_CREATE: {
866                 return UserDialogs.createResetGuestDialog(getActivity(),
867                         (dialog, which) -> clearAndExitGuest());
868             }
869             case DIALOG_CONFIRM_RESET_AND_RESTART_GUEST: {
870                 Dialog dlg = new AlertDialog.Builder(context)
871                         .setTitle(
872                             com.android.settingslib.R.string.guest_reset_and_restart_dialog_title)
873                         .setMessage(
874                             com.android.settingslib.R.string.guest_reset_and_restart_dialog_message)
875                         .setPositiveButton(
876                             com.android.settingslib.R.string.guest_reset_guest_confirm_button,
877                                 new DialogInterface.OnClickListener() {
878                                     @Override
879                                     public void onClick(DialogInterface dialog, int which) {
880                                         resetAndRestartGuest();
881                                     }
882                                 })
883                         .setNeutralButton(android.R.string.cancel, null)
884                         .create();
885                 return dlg;
886             }
887             default:
888                 return null;
889         }
890     }
891 
buildEditCurrentUserDialog()892     private Dialog buildEditCurrentUserDialog() {
893         final Activity activity = getActivity();
894         if (activity == null) {
895             return null;
896         }
897 
898         UserInfo user = mUserManager.getUserInfo(Process.myUserHandle().getIdentifier());
899         Drawable userIcon = Utils.getUserIcon(activity, mUserManager, user);
900 
901         return mEditUserInfoController.createDialog(
902                 activity,
903                 this::startActivityForResult,
904                 userIcon,
905                 user.name,
906                 (newUserName, newUserIcon) -> {
907                     if (newUserIcon != userIcon) {
908                         ThreadUtils.postOnBackgroundThread(() ->
909                                 mUserManager.setUserIcon(user.id,
910                                         UserIcons.convertToBitmapAtUserIconSize(
911                                                 activity.getResources(), newUserIcon)));
912                         mMePreference.setIcon(newUserIcon);
913                         if (Flags.avatarSync()) {
914                             final String pkg = getString(R.string.config_avatar_picker_package);
915                             final String action = pkg + ".set.confirm";
916                             activity.sendBroadcast(new Intent(action).setPackage(pkg));
917                         }
918                     }
919 
920                     if (!TextUtils.isEmpty(newUserName) && !newUserName.equals(user.name)) {
921                         mMePreference.setTitle(newUserName);
922                         mUserManager.setUserName(user.id, newUserName);
923                     }
924                 }, () -> {
925                     if (Flags.avatarSync()) {
926                         final String pkg = getString(R.string.config_avatar_picker_package);
927                         final String action = pkg + ".set.cancel";
928                         activity.sendBroadcast(new Intent(action).setPackage(pkg));
929                     }
930                 });
931     }
932 
933     private Dialog buildAddUserDialog(int userType) {
934         Dialog d;
935         synchronized (mUserLock) {
936             d = mCreateUserDialogController.createDialog(
937                     getActivity(),
938                     this::startActivityForResult,
939                     canCreateAdminUser(),
940                     (userName, userIcon, iconPath, isAdmin) -> {
941                         mPendingUserIcon = userIcon;
942                         mPendingUserName = userName;
943                         mPendingUserIsAdmin = isAdmin;
944                         addUserNow(userType);
945                     },
946                     () -> {
947                         synchronized (mUserLock) {
948                             mPendingUserIcon = null;
949                             mPendingUserName = null;
950                         }
951                     }
952             );
953         }
954         return d;
955     }
956 
957     /**
958      * Checks if the creation of a new admin user is allowed.
959      * @return {@code true} if creating a new admin is allowed, {@code false} otherwise.
960      */
961     private boolean canCreateAdminUser() {
962         if (Flags.unicornModeRefactoringForHsumReadOnly()) {
963             return UserManager.isMultipleAdminEnabled()
964                     && !mUserManager.hasUserRestriction(UserManager.DISALLOW_GRANT_ADMIN);
965         } else {
966             return UserManager.isMultipleAdminEnabled();
967         }
968     }
969 
970     @Override
971     public int getDialogMetricsCategory(int dialogId) {
972         switch (dialogId) {
973             case DIALOG_CONFIRM_REMOVE:
974                 return SettingsEnums.DIALOG_USER_REMOVE;
975             case DIALOG_USER_CANNOT_MANAGE:
976                 return SettingsEnums.DIALOG_USER_CANNOT_MANAGE;
977             case DIALOG_GRANT_ADMIN:
978                 return SettingsEnums.DIALOG_GRANT_USER_ADMIN;
979             case DIALOG_ADD_USER:
980                 return SettingsEnums.DIALOG_USER_ADD;
981             case DIALOG_CHOOSE_USER_TYPE:
982                 return SettingsEnums.DIALOG_USER_CHOOSE_TYPE;
983             case DIALOG_NEED_LOCKSCREEN:
984                 return SettingsEnums.DIALOG_USER_NEED_LOCKSCREEN;
985             case DIALOG_CONFIRM_REMOVE_GUEST:
986             case DIALOG_CONFIRM_REMOVE_GUEST_WITH_AUTO_CREATE:
987             case DIALOG_CONFIRM_EXIT_GUEST_EPHEMERAL:
988             case DIALOG_CONFIRM_EXIT_GUEST_NON_EPHEMERAL:
989             case DIALOG_CONFIRM_RESET_AND_RESTART_GUEST:
990                 return SettingsEnums.DIALOG_USER_CONFIRM_EXIT_GUEST;
991             case DIALOG_USER_PROFILE_EDITOR:
992             case DIALOG_USER_PROFILE_EDITOR_ADD_USER:
993             case DIALOG_USER_PROFILE_EDITOR_ADD_RESTRICTED_PROFILE:
994                 return SettingsEnums.DIALOG_USER_EDIT_PROFILE;
995             default:
996                 return 0;
997         }
998     }
999 
1000     private void removeUserNow() {
1001         if (mRemovingUserId == UserHandle.myUserId()) {
1002             removeThisUser();
1003         } else {
1004             ThreadUtils.postOnBackgroundThread(new Runnable() {
1005                 @Override
1006                 public void run() {
1007                     synchronized (mUserLock) {
1008                         mUserManager.removeUser(mRemovingUserId);
1009                         mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
1010                     }
1011                 }
1012             });
1013         }
1014     }
1015 
1016     private void removeThisUser() {
1017         if (!canSwitchUserNow()) {
1018             Log.w(TAG, "Cannot remove current user when switching is disabled");
1019             return;
1020         }
1021         try {
1022             mUserManager.removeUserWhenPossible(
1023                     UserHandle.of(UserHandle.myUserId()), /* overrideDevicePolicy= */ false);
1024             ActivityManager.getService().switchUser(
1025                     mUserManager.getPreviousForegroundUser().getIdentifier());
1026         } catch (RemoteException re) {
1027             Log.e(TAG, "Unable to remove self user");
1028         }
1029     }
1030 
1031     private void switchToUserId(int userId) {
1032         if (!canSwitchUserNow()) {
1033             Log.w(TAG, "Cannot switch current user when switching is disabled");
1034             return;
1035         }
1036         try {
1037             ActivityManager.getService().switchUser(userId);
1038         } catch (RemoteException re) {
1039             Log.e(TAG, "Unable to switch user");
1040         }
1041     }
1042 
1043     private void addUserNow(final int userType) {
1044         Trace.beginAsyncSection("UserSettings.addUserNow", 0);
1045         synchronized (mUserLock) {
1046             mAddingUser = true;
1047             mAddingUserName = userType == USER_TYPE_USER
1048                     ? (mPendingUserName != null ? mPendingUserName.toString()
1049                     : getString(com.android.settingslib.R.string.user_new_user_name))
1050                     : (mPendingUserName != null ? mPendingUserName.toString()
1051                             : getString(com.android.settingslib.R.string.user_new_profile_name));
1052         }
1053 
1054         mUserCreatingDialog = new UserCreatingDialog(getActivity());
1055         mUserCreatingDialog.show();
1056         createUser(userType, mAddingUserName);
1057     }
1058 
1059     @RequiresPermission(allOf = {Manifest.permission.MANAGE_USERS,
1060             Manifest.permission.INTERACT_ACROSS_USERS_FULL})
1061     @VisibleForTesting
1062     void createUser(final int userType, String userName) {
1063         Context context = getContext();
1064         Resources resources = getResources();
1065         final Drawable selectedUserIcon = mPendingUserIcon;
1066         Future<?> unusedCreateUserFuture = ThreadUtils.postOnBackgroundThread(() -> {
1067             UserInfo user;
1068 
1069             if (userType == USER_TYPE_USER) {
1070                 user = mUserManager.createUser(
1071                         userName,
1072                         mUserManager.USER_TYPE_FULL_SECONDARY,
1073                         0);
1074                 if (mPendingUserIsAdmin) {
1075                     mUserManager.setUserAdmin(user.id);
1076                 }
1077             } else {
1078                 user = mUserManager.createRestrictedProfile(userName);
1079             }
1080 
1081             ThreadUtils.postOnMainThread(() -> {
1082                 if (user == null) {
1083                     mAddingUser = false;
1084                     mPendingUserIcon = null;
1085                     mPendingUserName = null;
1086                     mPendingUserIconPath = null;
1087                     onUserCreationFailed();
1088                     return;
1089                 }
1090 
1091                 Future<?> unusedSettingIconFuture = ThreadUtils.postOnBackgroundThread(() -> {
1092                     if (Flags.placeAddUserDialogWithinActivity() && mPendingUserIconPath != null) {
1093                         Bitmap bitmap = BitmapFactory.decodeFile(mPendingUserIconPath);
1094                         mUserManager.setUserIcon(user.id, bitmap);
1095                         new File(mPendingUserIconPath).delete();
1096                         mPendingUserIconPath = null;
1097                     } else {
1098                         Drawable newUserIcon = selectedUserIcon;
1099                         if (newUserIcon == null) {
1100                             newUserIcon = UserIcons.getDefaultUserIcon(resources, user.id, false);
1101                         }
1102                         mUserManager.setUserIcon(user.id, UserIcons.convertToBitmapAtUserIconSize(
1103                                 resources, newUserIcon));
1104                     }
1105                 });
1106 
1107                 mPendingUserIcon = null;
1108                 mPendingUserName = null;
1109 
1110                 onUserCreated(user, context);
1111             });
1112         });
1113     }
1114 
1115 
1116     /**
1117      * Erase the current user (guest) and switch to another user.
1118      */
1119     @VisibleForTesting
1120     void clearAndExitGuest() {
1121         // Just to be safe
1122         if (!isCurrentUserGuest()) {
1123             return;
1124         }
1125         mMetricsFeatureProvider.action(getActivity(),
1126                 SettingsEnums.ACTION_USER_GUEST_EXIT_CONFIRMED);
1127 
1128         int guestUserId = UserHandle.myUserId();
1129         // Using markGuestForDeletion allows us to create a new guest before this one is
1130         // fully removed.
1131         boolean marked = mUserManager.markGuestForDeletion(guestUserId);
1132         if (!marked) {
1133             Log.w(TAG, "Couldn't mark the guest for deletion for user " + guestUserId);
1134             return;
1135         }
1136 
1137         removeThisUser();
1138         if (mGuestUserAutoCreated) {
1139             scheduleGuestCreation();
1140         }
1141     }
1142 
1143     /**
1144      * Switch to another user.
1145      */
1146     private void exitGuest() {
1147         // Just to be safe
1148         if (!isCurrentUserGuest()) {
1149             return;
1150         }
1151         mMetricsFeatureProvider.action(getActivity(),
1152                 SettingsEnums.ACTION_USER_GUEST_EXIT_CONFIRMED);
1153         switchToUserId(mUserManager.getPreviousForegroundUser().getIdentifier());
1154     }
1155 
1156     private int createGuest() {
1157         UserInfo guest;
1158         Context context = getPrefContext();
1159         try {
1160             guest = mUserManager.createGuest(context);
1161         } catch (UserManager.UserOperationException e) {
1162             Log.e(TAG, "Couldn't create guest user", e);
1163             return UserHandle.USER_NULL;
1164         }
1165         if (guest == null) {
1166             Log.e(TAG, "Couldn't create guest, most likely because there already exists one");
1167             return UserHandle.USER_NULL;
1168         }
1169         return guest.id;
1170     }
1171 
1172     /**
1173      * Remove current guest and start a new guest session
1174      */
1175     private void resetAndRestartGuest() {
1176         // Just to be safe
1177         if (!isCurrentUserGuest()) {
1178             return;
1179         }
1180         int oldGuestUserId = UserHandle.myUserId();
1181         // Using markGuestForDeletion allows us to create a new guest before this one is
1182         // fully removed.
1183         boolean marked = mUserManager.markGuestForDeletion(oldGuestUserId);
1184         if (!marked) {
1185             Log.w(TAG, "Couldn't mark the guest for deletion for user " + oldGuestUserId);
1186             return;
1187         }
1188 
1189         try {
1190             // Create a new guest in the foreground, and then immediately switch to it
1191             int newGuestUserId = createGuest();
1192             if (newGuestUserId == UserHandle.USER_NULL) {
1193                 Log.e(TAG, "Could not create new guest, switching back to previous user");
1194                 switchToUserId(mUserManager.getPreviousForegroundUser().getIdentifier());
1195                 mUserManager.removeUser(oldGuestUserId);
1196                 WindowManagerGlobal.getWindowManagerService().lockNow(/* options= */ null);
1197                 return;
1198             }
1199             switchToUserId(newGuestUserId);
1200             mUserManager.removeUser(oldGuestUserId);
1201         } catch (RemoteException e) {
1202             Log.e(TAG, "Couldn't remove guest because ActivityManager or WindowManager is dead");
1203             return;
1204         }
1205     }
1206 
1207     /**
1208      * Create a guest user in the background
1209      */
1210     @VisibleForTesting
1211     void scheduleGuestCreation() {
1212         // TODO(b/191067027): Move guest recreation to system_server
1213         if (mGuestCreationScheduled.compareAndSet(/* expect= */ false, /* update= */ true)) {
1214             // Once mGuestCreationScheduled=true, mAddGuest needs to be updated so that it shows
1215             // "Resetting guest..."
1216             mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
1217             mExecutor.execute(() -> {
1218                 UserInfo guest = mUserManager.createGuest(getContext());
1219                 mGuestCreationScheduled.set(false);
1220                 if (guest == null) {
1221                     Log.e(TAG, "Unable to automatically recreate guest user");
1222                 }
1223                 // The list needs to be updated whether or not guest creation worked. If guest
1224                 // creation failed, the list needs to update so that "Add guest" is displayed.
1225                 // Otherwise, the UX could be stuck in a state where there is no way to switch to
1226                 // the guest user (e.g. Guest would not be selectable, and it would be stuck
1227                 // saying "Resetting guest...")
1228                 mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST);
1229             });
1230         }
1231     }
1232 
1233     @VisibleForTesting
1234     void updateUserList() {
1235         final Context context = getActivity();
1236         if (context == null) {
1237             return;
1238         }
1239 
1240         List<UserInfo> users;
1241         if (Flags.newMultiuserSettingsUx()) {
1242             // Only users that can be switched to should show up here.
1243             // e.g. Managed profiles appear under Accounts Settings instead
1244             users = mUserManager.getAliveUsers().stream()
1245                     .filter(UserInfo::supportsSwitchToByUser)
1246                     .collect(Collectors.toList());
1247         } else {
1248             if (mUserCaps.mUserSwitcherEnabled) {
1249                 // Only users that can be switched to should show up here.
1250                 // e.g. Managed profiles appear under Accounts Settings instead
1251                 users = mUserManager.getAliveUsers().stream()
1252                         .filter(UserInfo::supportsSwitchToByUser)
1253                         .collect(Collectors.toList());
1254             } else {
1255                 // Only current user will be displayed in case of multi-user switch is disabled
1256                 users = List.of(mUserManager.getUserInfo(context.getUserId()));
1257             }
1258         }
1259 
1260         final ArrayList<Integer> missingIcons = new ArrayList<>();
1261         final ArrayList<UserPreference> userPreferences = new ArrayList<>();
1262 
1263         // mMePreference shows a icon for current user. However when current user is a guest, we
1264         // don't show the guest user icon, instead we show two preferences for guest user to
1265         // exit and reset itself. Hence we don't add mMePreference, i.e. guest user to the
1266         // list of users visible in the UI.
1267         if (!isCurrentUserGuest()) {
1268             userPreferences.add(mMePreference);
1269         }
1270 
1271         boolean canOpenUserDetails =
1272                 isCurrentUserAdmin() || (canSwitchUserNow() && !mUserCaps.mDisallowSwitchUser);
1273         for (UserInfo user : users) {
1274             if (user.isGuest()) {
1275                 // Guest user is added to guest category via updateGuestCategory
1276                 // and not to user list so skip guest here
1277                 continue;
1278             }
1279             UserPreference pref;
1280             if (user.id == UserHandle.myUserId()) {
1281                 pref = mMePreference;
1282             } else {
1283                 pref = new UserPreference(getPrefContext(), null, user.id);
1284                 pref.setTitle(user.name);
1285                 userPreferences.add(pref);
1286                 pref.setOnPreferenceClickListener(this);
1287                 pref.setEnabled(canOpenUserDetails);
1288                 pref.setSelectable(true);
1289                 pref.setKey("id=" + user.id);
1290             }
1291             if (pref == null) {
1292                 continue;
1293             }
1294             if (user.isMain()) {
1295                 pref.setSummary(R.string.user_owner);
1296             } else if (user.isAdmin()) {
1297                 pref.setSummary(R.string.user_admin);
1298             }
1299             if (user.id != UserHandle.myUserId() && !user.isGuest() && !user.isInitialized()) {
1300                 // sometimes after creating a guest the initialized flag isn't immediately set
1301                 // and we don't want to show "Not set up" summary for them
1302                 if (user.isRestricted()) {
1303                     pref.setSummary(R.string.user_summary_restricted_not_set_up);
1304                 } else {
1305                     pref.setSummary(R.string.user_summary_not_set_up);
1306                     // Disallow setting up user which results in user switching when the
1307                     // restriction is set.
1308                     // If newMultiuserSettingsUx flag is enabled, allow opening user details page
1309                     // since switch to user will be disabled
1310                     pref.setEnabled((!mUserCaps.mDisallowSwitchUser && canSwitchUserNow())
1311                             || Flags.newMultiuserSettingsUx());
1312                 }
1313             } else if (user.isRestricted()) {
1314                 pref.setSummary(R.string.user_summary_restricted_profile);
1315             }
1316             if (user.iconPath != null) {
1317                 if (mUserIcons.get(user.id) == null) {
1318                     // Icon not loaded yet, print a placeholder
1319                     missingIcons.add(user.id);
1320                     pref.setIcon(getEncircledDefaultIcon());
1321                 } else {
1322                     setPhotoId(pref, user);
1323                 }
1324             } else {
1325                 // Icon not available yet, print a placeholder
1326                 pref.setIcon(getEncircledDefaultIcon());
1327             }
1328         }
1329 
1330         // Add a temporary entry for the user being created
1331         if (mAddingUser) {
1332             UserPreference pref = new UserPreference(getPrefContext(), null,
1333                     UserPreference.USERID_UNKNOWN);
1334             pref.setEnabled(false);
1335             pref.setTitle(mAddingUserName);
1336             pref.setIcon(getEncircledDefaultIcon());
1337             userPreferences.add(pref);
1338         }
1339 
1340         // Sort list of users by serialNum
1341         Collections.sort(userPreferences, UserPreference.SERIAL_NUMBER_COMPARATOR);
1342 
1343         getActivity().invalidateOptionsMenu();
1344 
1345         // Load the icons
1346         if (missingIcons.size() > 0) {
1347             loadIconsAsync(missingIcons);
1348         }
1349 
1350         // If restricted profiles are supported, mUserListCategory will have a special title
1351         if (mUserCaps.mCanAddRestrictedProfile) {
1352             mUserListCategory.setTitle(R.string.user_list_title);
1353         } else if (isCurrentUserGuest()) {
1354             mUserListCategory.setTitle(R.string.other_user_category_title);
1355         } else {
1356             mUserListCategory.setTitle(R.string.user_category_title);
1357         }
1358 
1359         // Remove everything from mUserListCategory and add new users.
1360         mUserListCategory.removeAll();
1361 
1362         final Preference addUserOnLockScreen = getPreferenceScreen().findPreference(
1363                 mAddUserWhenLockedPreferenceController.getPreferenceKey());
1364         mAddUserWhenLockedPreferenceController.updateState(addUserOnLockScreen);
1365 
1366         final Preference guestCallPreference = getPreferenceScreen().findPreference(
1367                 mGuestTelephonyPreferenceController.getPreferenceKey());
1368         mGuestTelephonyPreferenceController.updateState(guestCallPreference);
1369 
1370         final Preference multiUserTopIntroPreference = getPreferenceScreen().findPreference(
1371                 mMultiUserTopIntroPreferenceController.getPreferenceKey());
1372         mMultiUserTopIntroPreferenceController.updateState(multiUserTopIntroPreference);
1373         updateGuestPreferences();
1374         updateGuestCategory(context, users);
1375         updateAddUser(context);
1376         updateAddSupervisedUser(context);
1377 
1378         for (UserPreference userPreference : userPreferences) {
1379             userPreference.setOrder(Preference.DEFAULT_ORDER);
1380             mUserListCategory.addPreference(userPreference);
1381         }
1382 
1383     }
1384 
1385     @VisibleForTesting
1386     void setConfigSupervisedUserCreationPackage() {
1387         mConfigSupervisedUserCreationPackage = getPrefContext().getString(
1388                 com.android.internal.R.string.config_supervisedUserCreationPackage);
1389     }
1390 
1391     private boolean isCurrentUserGuest() {
1392         return mUserCaps.mIsGuest;
1393     }
1394 
1395     private boolean isCurrentUserAdmin() {
1396         return mUserCaps.mIsAdmin;
1397     }
1398 
1399     private boolean canSwitchUserNow() {
1400         return mUserManager.getUserSwitchability() == UserManager.SWITCHABILITY_STATUS_OK;
1401     }
1402 
1403     private void updateGuestPreferences() {
1404         // reset guest and exit guest preferences are shown only in guest mode.
1405         // For all other users these are not visible.
1406         mGuestCategory.setVisible(false);
1407         mGuestResetPreference.setVisible(false);
1408         mGuestExitPreference.setVisible(false);
1409         if (!isCurrentUserGuest()) {
1410             return;
1411         }
1412         mGuestCategory.setVisible(true);
1413         mGuestExitPreference.setVisible(true);
1414         mGuestResetPreference.setVisible(true);
1415 
1416         boolean isGuestFirstLogin = Settings.Secure.getIntForUser(
1417                 getContext().getContentResolver(),
1418                 SETTING_GUEST_HAS_LOGGED_IN,
1419                 0,
1420                 UserHandle.myUserId()) <= 1;
1421         String guestExitSummary;
1422         if (mUserCaps.mIsEphemeral) {
1423             guestExitSummary = getContext().getString(
1424                     com.android.settingslib.R.string.guest_notification_ephemeral);
1425         } else if (isGuestFirstLogin) {
1426             guestExitSummary = getContext().getString(
1427                     com.android.settingslib.R.string.guest_notification_non_ephemeral);
1428         } else {
1429             guestExitSummary = getContext().getString(
1430                     com.android.settingslib.R
1431                             .string.guest_notification_non_ephemeral_non_first_login);
1432         }
1433         mGuestExitPreference.setSummary(guestExitSummary);
1434     }
1435 
1436     private void updateGuestCategory(Context context, List<UserInfo> users) {
1437         // show guest category title and related guest preferences
1438         // - if guest is created, then show guest user preference
1439         // - if guest is not created and its allowed to create guest,
1440         //   then show "add guest" preference
1441         // - if allowed, show "reset guest on exit" preference
1442         // - if there is nothing to show, then make the guest category as not visible
1443         // - guest category is not visible for guest user.
1444         UserPreference pref = null;
1445         boolean isGuestAlreadyCreated = false;
1446         boolean canOpenUserDetails =
1447                 isCurrentUserAdmin() || (canSwitchUserNow() && !mUserCaps.mDisallowSwitchUser);
1448 
1449         mGuestUserCategory.removeAll();
1450         mGuestUserCategory.setVisible(false);
1451         for (UserInfo user : users) {
1452             if (!user.isGuest() || !user.isEnabled()) {
1453                 // Only look at enabled, guest users
1454                 continue;
1455             }
1456             final Context prefContext = getPrefContext();
1457             pref = new UserPreference(prefContext, null, user.id);
1458             pref.setTitle(user.name);
1459             pref.setOnPreferenceClickListener(this);
1460             pref.setEnabled(canOpenUserDetails);
1461             pref.setSelectable(true);
1462             Drawable icon = getContext().getDrawable(
1463                     com.android.settingslib.R.drawable.ic_account_circle_outline);
1464             icon.setTint(
1465                     getColorAttrDefaultColor(getContext(), android.R.attr.colorControlNormal));
1466             pref.setIcon(encircleUserIcon(
1467                     UserIcons.convertToBitmapAtUserIconSize(
1468                             getContext().getResources(), icon)));
1469             pref.setKey(KEY_USER_GUEST);
1470             pref.setOrder(Preference.DEFAULT_ORDER);
1471             if (mUserCaps.mDisallowSwitchUser && !Flags.newMultiuserSettingsUx()) {
1472                 pref.setDisabledByAdmin(
1473                         RestrictedLockUtilsInternal.getDeviceOwner(context));
1474             } else {
1475                 pref.setDisabledByAdmin(null);
1476             }
1477             if (Flags.newMultiuserSettingsUx()) {
1478                 mGuestUserCategory.addPreference(pref);
1479                 // guest user preference is shown hence also make guest category visible
1480                 mGuestUserCategory.setVisible(true);
1481             } else {
1482                 if (mUserCaps.mUserSwitcherEnabled) {
1483                     mGuestUserCategory.addPreference(pref);
1484                     // guest user preference is shown hence also make guest category visible
1485                     mGuestUserCategory.setVisible(true);
1486                 }
1487             }
1488             isGuestAlreadyCreated = true;
1489         }
1490         boolean isVisible = updateAddGuestPreference(context, isGuestAlreadyCreated);
1491         if (isVisible) {
1492             // "add guest" preference is shown hence also make guest category visible
1493             mGuestUserCategory.setVisible(true);
1494         }
1495         final Preference removeGuestOnExit = getPreferenceScreen().findPreference(
1496                 mRemoveGuestOnExitPreferenceController.getPreferenceKey());
1497         mRemoveGuestOnExitPreferenceController.updateState(removeGuestOnExit);
1498         if (mRemoveGuestOnExitPreferenceController.isAvailable()) {
1499             // "reset guest on exit" preference is shown hence also make guest category visible
1500             mGuestUserCategory.setVisible(true);
1501         }
1502         if (isCurrentUserGuest()) {
1503             // guest category is not visible for guest user.
1504             mGuestUserCategory.setVisible(false);
1505         }
1506     }
1507 
1508     private boolean updateAddGuestPreference(Context context, boolean isGuestAlreadyCreated) {
1509         boolean isVisible = false;
1510         if (!isGuestAlreadyCreated && (mUserCaps.mCanAddGuest
1511                 || (Flags.newMultiuserSettingsUx() && mUserCaps.mDisallowAddUser))
1512                 && mUserManager.canAddMoreUsers(UserManager.USER_TYPE_FULL_GUEST)
1513                 && WizardManagerHelper.isDeviceProvisioned(context)
1514                 && (mUserCaps.mUserSwitcherEnabled || Flags.newMultiuserSettingsUx())) {
1515             Drawable icon = context.getDrawable(
1516                     com.android.settingslib.R.drawable.ic_account_circle);
1517             mAddGuest.setIcon(centerAndTint(icon));
1518             isVisible = true;
1519             mAddGuest.setVisible(true);
1520             mAddGuest.setSelectable(true);
1521             if (mGuestUserAutoCreated && mGuestCreationScheduled.get()) {
1522                 mAddGuest.setTitle(com.android.internal.R.string.guest_name);
1523                 mAddGuest.setSummary(com.android.settingslib.R.string.guest_resetting);
1524                 mAddGuest.setEnabled(false);
1525             } else {
1526                 mAddGuest.setTitle(com.android.settingslib.R.string.guest_new_guest);
1527                 if (Flags.newMultiuserSettingsUx()
1528                         && mUserCaps.mDisallowAddUserSetByAdmin) {
1529                     mAddGuest.setDisabledByAdmin(mUserCaps.mEnforcedAdmin);
1530                 } else if (Flags.newMultiuserSettingsUx() && mUserCaps.mDisallowAddUser) {
1531                     final List<UserManager.EnforcingUser> enforcingUsers =
1532                             mUserManager.getUserRestrictionSources(UserManager.DISALLOW_ADD_USER,
1533                                     UserHandle.of(UserHandle.myUserId()));
1534                     if (!enforcingUsers.isEmpty()) {
1535                         final UserManager.EnforcingUser enforcingUser = enforcingUsers.get(0);
1536                         final int restrictionSource = enforcingUser.getUserRestrictionSource();
1537                         if (restrictionSource == UserManager.RESTRICTION_SOURCE_SYSTEM) {
1538                             mAddGuest.setEnabled(false);
1539                         } else {
1540                             mAddGuest.setVisible(false);
1541                         }
1542                     }
1543                 } else {
1544                     mAddGuest.setEnabled(canSwitchUserNow() || Flags.newMultiuserSettingsUx());
1545                 }
1546             }
1547         } else {
1548             mAddGuest.setVisible(false);
1549         }
1550         return isVisible;
1551     }
1552 
1553     private void updateAddUser(Context context) {
1554         updateAddUserCommon(context, mAddUser, mUserCaps.mCanAddRestrictedProfile);
1555         Drawable icon = context.getDrawable(
1556                 com.android.settingslib.R.drawable.ic_account_circle_filled);
1557         mAddUser.setIcon(centerAndTint(icon));
1558     }
1559 
1560     private void updateAddSupervisedUser(Context context) {
1561         if (!TextUtils.isEmpty(mConfigSupervisedUserCreationPackage)) {
1562             updateAddUserCommon(context, mAddSupervisedUser, false);
1563             Drawable icon = context.getDrawable(
1564                     com.android.settingslib.R.drawable.ic_add_supervised_user);
1565             mAddSupervisedUser.setIcon(centerAndTint(icon));
1566         } else {
1567             mAddSupervisedUser.setVisible(false);
1568         }
1569     }
1570 
1571     private void updateAddUserCommon(Context context, RestrictedPreference addUser,
1572             boolean canAddRestrictedProfile) {
1573         if ((mUserCaps.mCanAddUser
1574                 && !(mUserCaps.mDisallowAddUserSetByAdmin && Flags.newMultiuserSettingsUx()))
1575                 && WizardManagerHelper.isDeviceProvisioned(context)
1576                 && (mUserCaps.mUserSwitcherEnabled || Flags.newMultiuserSettingsUx())) {
1577             addUser.setVisible(true);
1578             addUser.setSelectable(true);
1579             final boolean canAddMoreUsers =
1580                     mUserManager.canAddMoreUsers(UserManager.USER_TYPE_FULL_SECONDARY)
1581                             || (canAddRestrictedProfile
1582                             && mUserManager.canAddMoreUsers(UserManager.USER_TYPE_FULL_RESTRICTED));
1583             addUser.setEnabled(canAddMoreUsers && !mAddingUser
1584                     && (canSwitchUserNow() || Flags.newMultiuserSettingsUx()));
1585 
1586             if (!canAddMoreUsers) {
1587                 addUser.setSummary(getString(R.string.user_add_max_count));
1588             } else {
1589                 addUser.setSummary(null);
1590             }
1591             if (addUser.isEnabled()) {
1592                 addUser.setDisabledByAdmin(
1593                         mUserCaps.mDisallowAddUser ? mUserCaps.mEnforcedAdmin : null);
1594             }
1595         } else if (Flags.newMultiuserSettingsUx() && mUserCaps.mDisallowAddUserSetByAdmin) {
1596             addUser.setVisible(true);
1597             addUser.setDisabledByAdmin(mUserCaps.mEnforcedAdmin);
1598         } else if (Flags.newMultiuserSettingsUx() && mUserCaps.mDisallowAddUser) {
1599             final List<UserManager.EnforcingUser> enforcingUsers =
1600                     mUserManager.getUserRestrictionSources(UserManager.DISALLOW_ADD_USER,
1601                             UserHandle.of(UserHandle.myUserId()));
1602             if (!enforcingUsers.isEmpty()) {
1603                 final UserManager.EnforcingUser enforcingUser = enforcingUsers.get(0);
1604                 final int restrictionSource = enforcingUser.getUserRestrictionSource();
1605                 if (restrictionSource == UserManager.RESTRICTION_SOURCE_SYSTEM) {
1606                     addUser.setVisible(true);
1607                     addUser.setEnabled(false);
1608                 } else {
1609                     addUser.setVisible(false);
1610                 }
1611             }
1612         } else {
1613             addUser.setVisible(false);
1614         }
1615     }
1616 
1617     private Drawable centerAndTint(Drawable icon) {
1618         icon.setTintBlendMode(BlendMode.SRC_IN);
1619         icon.setTint(getColorAttrDefaultColor(getContext(), android.R.attr.textColorPrimary));
1620 
1621         Drawable bg = getContext().getDrawable(com.android.settingslib.R.drawable.user_avatar_bg)
1622                 .mutate();
1623         LayerDrawable ld = new LayerDrawable(new Drawable[] {bg, icon});
1624         int size = getContext().getResources().getDimensionPixelSize(
1625                 R.dimen.multiple_users_avatar_size);
1626         int bgSize = getContext().getResources().getDimensionPixelSize(
1627                 R.dimen.multiple_users_user_icon_size);
1628         ld.setLayerSize(1, size, size);
1629         ld.setLayerSize(0, bgSize, bgSize);
1630         ld.setLayerGravity(1, Gravity.CENTER);
1631 
1632         return ld;
1633     }
1634 
1635     /**
1636      * @return number of non-guest non-managed users
1637      */
1638     @VisibleForTesting
1639     int getRealUsersCount() {
1640         return (int) mUserManager.getUsers()
1641                 .stream()
1642                 .filter(user -> !user.isGuest() && !user.isProfile())
1643                 .count();
1644     }
1645 
1646     private void loadIconsAsync(List<Integer> missingIcons) {
1647         new AsyncTask<List<Integer>, Void, Void>() {
1648             @Override
1649             protected void onPostExecute(Void result) {
1650                 updateUserList();
1651             }
1652 
1653             @Override
1654             protected Void doInBackground(List<Integer>... values) {
1655                 for (int userId : values[0]) {
1656                     Bitmap bitmap = mUserManager.getUserIcon(userId);
1657                     if (bitmap == null) {
1658                         bitmap = getDefaultUserIconAsBitmap(getContext().getResources(), userId);
1659                     }
1660                     mUserIcons.append(userId, bitmap);
1661                 }
1662                 return null;
1663             }
1664         }.execute(missingIcons);
1665     }
1666 
1667     private Drawable getEncircledDefaultIcon() {
1668         if (mDefaultIconDrawable == null) {
1669             mDefaultIconDrawable = encircleUserIcon(
1670                     getDefaultUserIconAsBitmap(getContext().getResources(), UserHandle.USER_NULL));
1671         }
1672         return mDefaultIconDrawable;
1673     }
1674 
1675     private void setPhotoId(Preference pref, UserInfo user) {
1676         Bitmap bitmap = mUserIcons.get(user.id);
1677         if (bitmap != null) {
1678             pref.setIcon(encircleUserIcon(bitmap));
1679         }
1680     }
1681 
1682     @Override
1683     public boolean onPreferenceClick(Preference pref) {
1684         mMetricsFeatureProvider.logSettingsTileClick(pref.getKey(), getMetricsCategory());
1685         if (isCurrentUserGuest()) {
1686             if (mGuestResetPreference != null && pref == mGuestResetPreference) {
1687                 showDialog(DIALOG_CONFIRM_RESET_AND_RESTART_GUEST);
1688                 return true;
1689             }
1690             if (mGuestExitPreference != null && pref == mGuestExitPreference) {
1691                 if (mUserCaps.mIsEphemeral) {
1692                     showDialog(DIALOG_CONFIRM_EXIT_GUEST_EPHEMERAL);
1693                 } else {
1694                     showDialog(DIALOG_CONFIRM_EXIT_GUEST_NON_EPHEMERAL);
1695                 }
1696                 return true;
1697             }
1698         }
1699         if (pref == mMePreference) {
1700             if (!isCurrentUserGuest()) {
1701                 showDialog(DIALOG_USER_PROFILE_EDITOR);
1702                 return true;
1703             }
1704         } else if (pref instanceof UserPreference) {
1705             UserInfo userInfo = mUserManager.getUserInfo(((UserPreference) pref).getUserId());
1706             openUserDetails(userInfo, false);
1707             return true;
1708         } else if (pref == mAddUser) {
1709             mMetricsFeatureProvider.action(getActivity(), SettingsEnums.ACTION_USER_ADD);
1710             // If we allow both types, show a picker, otherwise directly go to
1711             // flow for full user.
1712             if (mUserCaps.mCanAddRestrictedProfile) {
1713                 showDialog(DIALOG_CHOOSE_USER_TYPE);
1714             } else {
1715                 if (Flags.placeAddUserDialogWithinActivity()) {
1716                     startActivityForResult(CreateUserActivity.createIntentForStart(getActivity(),
1717                                     canCreateAdminUser(), Utils.FILE_PROVIDER_AUTHORITY),
1718                             REQUEST_ADD_USER);
1719                 } else {
1720                     onAddUserClicked(USER_TYPE_USER);
1721                 }
1722             }
1723             return true;
1724         } else if (pref == mAddSupervisedUser) {
1725             mMetricsFeatureProvider.action(getActivity(), SettingsEnums.ACTION_USER_SUPERVISED_ADD);
1726             Trace.beginSection("UserSettings.addSupervisedUser");
1727             onAddSupervisedUserClicked();
1728             Trace.endSection();
1729             return true;
1730         } else if (pref == mAddGuest) {
1731             mAddGuest.setEnabled(false); // prevent multiple tap issue
1732             onAddGuestClicked();
1733             return true;
1734         }
1735         return false;
1736     }
1737 
1738     private Drawable encircleUserIcon(Bitmap icon) {
1739         return new CircleFramedDrawable(
1740                 icon,
1741                 getActivity().getResources().getDimensionPixelSize(
1742                         R.dimen.multiple_users_user_icon_size));
1743     }
1744 
1745     @Override
1746     public void onDismiss(DialogInterface dialog) {
1747         synchronized (mUserLock) {
1748             mRemovingUserId = -1;
1749             updateUserList();
1750             if (mCreateUserDialogController.isActive()) {
1751                 mCreateUserDialogController.finish();
1752             }
1753         }
1754     }
1755 
1756     @Override
1757     public int getHelpResource() {
1758         return R.string.help_url_users;
1759     }
1760 
1761     /**
1762      * Returns a default user icon (as a {@link Bitmap}) for the given user.
1763      *
1764      * Note that for guest users, you should pass in {@code UserHandle.USER_NULL}.
1765      *
1766      * @param resources resources object to fetch the user icon.
1767      * @param userId    the user id or {@code UserHandle.USER_NULL} for a non-user specific icon
1768      */
1769     private static Bitmap getDefaultUserIconAsBitmap(Resources resources, int userId) {
1770         Bitmap bitmap = null;
1771         // Try finding the corresponding bitmap in the dark bitmap cache
1772         bitmap = sDarkDefaultUserBitmapCache.get(userId);
1773         if (bitmap == null) {
1774             bitmap = UserIcons.convertToBitmapAtUserIconSize(resources,
1775                     UserIcons.getDefaultUserIcon(resources, userId, false));
1776             // Save it to cache
1777             sDarkDefaultUserBitmapCache.put(userId, bitmap);
1778         }
1779         return bitmap;
1780     }
1781 
1782     /**
1783      * Assign the default photo to user with {@paramref userId}
1784      *
1785      * @param context used to get the {@link UserManager}
1786      * @param userId  used to get the icon bitmap
1787      * @return true if assign photo successfully, false if failed
1788      */
1789     @VisibleForTesting
1790     static boolean assignDefaultPhoto(Context context, int userId) {
1791         if (context == null) {
1792             return false;
1793         }
1794         UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
1795         Bitmap bitmap = getDefaultUserIconAsBitmap(context.getResources(), userId);
1796         um.setUserIcon(userId, bitmap);
1797 
1798         return true;
1799     }
1800 
1801     @WorkerThread
1802     static void copyMeProfilePhoto(Context context, UserInfo user) {
1803         Uri contactUri = ContactsContract.Profile.CONTENT_URI;
1804 
1805         int userId = user != null ? user.id : UserHandle.myUserId();
1806 
1807         InputStream avatarDataStream = ContactsContract.Contacts.openContactPhotoInputStream(
1808                 context.getContentResolver(),
1809                 contactUri, true);
1810         // If there's no profile photo, assign a default avatar
1811         if (avatarDataStream == null) {
1812             assignDefaultPhoto(context, userId);
1813             return;
1814         }
1815 
1816         UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
1817         Bitmap decodedIcon = BitmapFactory.decodeStream(avatarDataStream);
1818         CircleFramedDrawable drawable = CircleFramedDrawable.getInstance(context, decodedIcon);
1819         Bitmap icon = UserIcons.convertToBitmapAtUserIconSize(context.getResources(), drawable);
1820 
1821         um.setUserIcon(userId, icon);
1822         try {
1823             avatarDataStream.close();
1824         } catch (IOException ioe) {
1825         }
1826     }
1827 
1828     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
1829             new BaseSearchIndexProvider(R.xml.user_settings) {
1830 
1831                 @Override
1832                 protected boolean isPageSearchEnabled(Context context) {
1833                     final UserCapabilities userCaps = UserCapabilities.create(context);
1834                     return userCaps.mEnabled;
1835                 }
1836 
1837                 @Override
1838                 public List<SearchIndexableRaw> getRawDataToIndex(Context context,
1839                         boolean enabled) {
1840                     final List<SearchIndexableRaw> rawData = new ArrayList<>();
1841                     if (!UserManager.supportsMultipleUsers()) {
1842                         return rawData;
1843                     }
1844 
1845                     SearchIndexableRaw multipleUsersData = new SearchIndexableRaw(context);
1846                     multipleUsersData.key = KEY_USER_SETTINGS_SCREEN;
1847                     multipleUsersData.title =
1848                             context.getString(R.string.user_settings_title);
1849                     multipleUsersData.keywords =
1850                             context.getString(R.string.multiple_users_title_keywords);
1851                     multipleUsersData.screenTitle =
1852                             context.getString(R.string.user_settings_title);
1853                     rawData.add(multipleUsersData);
1854 
1855                     SearchIndexableRaw allowMultipleUsersResult = new SearchIndexableRaw(context);
1856 
1857                     allowMultipleUsersResult.key = KEY_ALLOW_MULTIPLE_USERS;
1858                     allowMultipleUsersResult.title =
1859                             context.getString(R.string.multiple_users_main_switch_title);
1860                     allowMultipleUsersResult.keywords =
1861                             context.getString(R.string.multiple_users_main_switch_keywords);
1862                     allowMultipleUsersResult.screenTitle =
1863                             context.getString(R.string.user_settings_title);
1864                     allowMultipleUsersResult.className =
1865                             MultiUserSwitchBarController.class.getName();
1866 
1867                     rawData.add(allowMultipleUsersResult);
1868 
1869                     SearchIndexableRaw addUserData = new SearchIndexableRaw(context);
1870                     addUserData.key = KEY_ADD_USER;
1871 
1872                     // Dynamically set the title of addUser preference
1873                     final UserCapabilities userCaps = UserCapabilities.create(context);
1874                     if (!userCaps.mCanAddRestrictedProfile) {
1875                         addUserData.title = context.getString(
1876                                 com.android.settingslib.R.string.user_add_user);
1877                     } else {
1878                         addUserData.title = context.getString(
1879                                 R.string.user_add_user_or_profile_menu);
1880                     }
1881                     addUserData.screenTitle = context.getString(R.string.user_settings_title);
1882                     addUserData.iconResId = R.drawable.ic_add_40dp;
1883 
1884                     rawData.add(addUserData);
1885 
1886                     return rawData;
1887                 }
1888 
1889                 @Override
1890                 public List<String> getNonIndexableKeysFromXml(Context context, int xmlResId,
1891                         boolean suppressAllPage) {
1892                     final List<String> niks = super.getNonIndexableKeysFromXml(context, xmlResId,
1893                             suppressAllPage);
1894                     if (TextUtils.isEmpty(context.getString(
1895                             com.android.internal.R.string.config_supervisedUserCreationPackage))) {
1896                         niks.add(KEY_ADD_SUPERVISED_USER);
1897                     }
1898                     AddUserWhenLockedPreferenceController controller =
1899                             new AddUserWhenLockedPreferenceController(
1900                                     context, KEY_ADD_USER_WHEN_LOCKED);
1901                     controller.updateNonIndexableKeys(niks);
1902                     new AutoSyncDataPreferenceController(context, null /* parent */)
1903                             .updateNonIndexableKeys(niks);
1904                     new AutoSyncPersonalDataPreferenceController(context, null /* parent */)
1905                             .updateNonIndexableKeys(niks);
1906                     new AutoSyncWorkDataPreferenceController(context, null /* parent */)
1907                             .updateNonIndexableKeys(niks);
1908                     if (suppressAllPage) {
1909                         niks.add(KEY_ALLOW_MULTIPLE_USERS);
1910                     }
1911                     return niks;
1912                 }
1913             };
1914 }
1915