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