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