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