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 android.app.Activity; 20 import android.app.ActivityManagerNative; 21 import android.app.AlertDialog; 22 import android.app.Dialog; 23 import android.app.admin.DevicePolicyManager; 24 import android.content.BroadcastReceiver; 25 import android.content.Context; 26 import android.content.DialogInterface; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.content.SharedPreferences; 30 import android.content.pm.ResolveInfo; 31 import android.content.pm.UserInfo; 32 import android.content.res.Resources; 33 import android.graphics.Bitmap; 34 import android.graphics.drawable.Drawable; 35 import android.os.AsyncTask; 36 import android.os.Bundle; 37 import android.os.Handler; 38 import android.os.Message; 39 import android.os.RemoteException; 40 import android.os.UserHandle; 41 import android.os.UserManager; 42 import android.provider.Settings; 43 import android.support.v7.preference.Preference; 44 import android.support.v7.preference.Preference.OnPreferenceClickListener; 45 import android.support.v7.preference.PreferenceGroup; 46 import android.support.v7.preference.PreferenceScreen; 47 import android.util.Log; 48 import android.util.SparseArray; 49 import android.view.Menu; 50 import android.view.MenuInflater; 51 import android.view.MenuItem; 52 import android.view.View; 53 import android.view.View.OnClickListener; 54 import android.widget.SimpleAdapter; 55 56 import com.android.internal.logging.MetricsProto.MetricsEvent; 57 import com.android.internal.widget.LockPatternUtils; 58 import com.android.settings.ChooseLockGeneric; 59 import com.android.settings.DimmableIconPreference; 60 import com.android.settings.OwnerInfoSettings; 61 import com.android.settings.R; 62 import com.android.settings.SettingsActivity; 63 import com.android.settings.SettingsPreferenceFragment; 64 import com.android.settings.Utils; 65 import com.android.settings.dashboard.SummaryLoader; 66 import com.android.settings.search.BaseSearchIndexProvider; 67 import com.android.settings.search.Indexable; 68 import com.android.settings.search.SearchIndexableRaw; 69 import com.android.settingslib.RestrictedLockUtils; 70 import com.android.settingslib.RestrictedSwitchPreference; 71 import com.android.settingslib.drawable.CircleFramedDrawable; 72 73 import java.util.ArrayList; 74 import java.util.Collections; 75 import java.util.HashMap; 76 import java.util.List; 77 78 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 79 80 /** 81 * Screen that manages the list of users on the device. 82 * Guest user is an always visible entry, even if the guest is not currently 83 * active/created. It is meant for controlling properties of a guest user. 84 * 85 * The first one is always the current user. 86 * Owner is the primary user. 87 */ 88 public class UserSettings extends SettingsPreferenceFragment 89 implements OnPreferenceClickListener, OnClickListener, DialogInterface.OnDismissListener, 90 Preference.OnPreferenceChangeListener, 91 EditUserInfoController.OnContentChangedCallback, Indexable { 92 93 private static final String TAG = "UserSettings"; 94 95 /** UserId of the user being removed */ 96 private static final String SAVE_REMOVING_USER = "removing_user"; 97 /** UserId of the user that was just added */ 98 private static final String SAVE_ADDING_USER = "adding_user"; 99 100 private static final String KEY_USER_LIST = "user_list"; 101 private static final String KEY_USER_ME = "user_me"; 102 private static final String KEY_ADD_USER = "user_add"; 103 private static final String KEY_EMERGENCY_INFO = "emergency_info"; 104 105 private static final String ACTION_EDIT_EMERGENCY_INFO = "android.settings.EDIT_EMERGENGY_INFO"; 106 107 private static final int MENU_REMOVE_USER = Menu.FIRST; 108 109 private static final int DIALOG_CONFIRM_REMOVE = 1; 110 private static final int DIALOG_ADD_USER = 2; 111 private static final int DIALOG_SETUP_USER = 3; 112 private static final int DIALOG_SETUP_PROFILE = 4; 113 private static final int DIALOG_USER_CANNOT_MANAGE = 5; 114 private static final int DIALOG_CHOOSE_USER_TYPE = 6; 115 private static final int DIALOG_NEED_LOCKSCREEN = 7; 116 private static final int DIALOG_CONFIRM_EXIT_GUEST = 8; 117 private static final int DIALOG_USER_PROFILE_EDITOR = 9; 118 119 private static final int MESSAGE_UPDATE_LIST = 1; 120 private static final int MESSAGE_SETUP_USER = 2; 121 private static final int MESSAGE_CONFIG_USER = 3; 122 123 private static final int USER_TYPE_USER = 1; 124 private static final int USER_TYPE_RESTRICTED_PROFILE = 2; 125 126 private static final int REQUEST_CHOOSE_LOCK = 10; 127 128 private static final String KEY_ADD_USER_LONG_MESSAGE_DISPLAYED = 129 "key_add_user_long_message_displayed"; 130 131 private static final String KEY_TITLE = "title"; 132 private static final String KEY_SUMMARY = "summary"; 133 134 private PreferenceGroup mUserListCategory; 135 private UserPreference mMePreference; 136 private DimmableIconPreference mAddUser; 137 private PreferenceGroup mLockScreenSettings; 138 private RestrictedSwitchPreference mAddUserWhenLocked; 139 private Preference mEmergencyInfoPreference; 140 private int mRemovingUserId = -1; 141 private int mAddedUserId = 0; 142 private boolean mAddingUser; 143 private String mAddingUserName; 144 private UserCapabilities mUserCaps; 145 private boolean mShouldUpdateUserList = true; 146 private final Object mUserLock = new Object(); 147 private UserManager mUserManager; 148 private SparseArray<Bitmap> mUserIcons = new SparseArray<Bitmap>(); 149 150 private EditUserInfoController mEditUserInfoController = 151 new EditUserInfoController(); 152 153 // A place to cache the generated default avatar 154 private Drawable mDefaultIconDrawable; 155 156 private Handler mHandler = new Handler() { 157 @Override 158 public void handleMessage(Message msg) { 159 switch (msg.what) { 160 case MESSAGE_UPDATE_LIST: 161 updateUserList(); 162 break; 163 case MESSAGE_SETUP_USER: 164 onUserCreated(msg.arg1); 165 break; 166 case MESSAGE_CONFIG_USER: 167 onManageUserClicked(msg.arg1, true); 168 break; 169 } 170 } 171 }; 172 173 private BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() { 174 @Override 175 public void onReceive(Context context, Intent intent) { 176 if (intent.getAction().equals(Intent.ACTION_USER_REMOVED)) { 177 mRemovingUserId = -1; 178 } else if (intent.getAction().equals(Intent.ACTION_USER_INFO_CHANGED)) { 179 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 180 if (userHandle != -1) { 181 mUserIcons.remove(userHandle); 182 } 183 } 184 mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST); 185 } 186 }; 187 188 @Override getMetricsCategory()189 protected int getMetricsCategory() { 190 return MetricsEvent.USER; 191 } 192 193 @Override onCreate(Bundle icicle)194 public void onCreate(Bundle icicle) { 195 super.onCreate(icicle); 196 197 if (icicle != null) { 198 if (icicle.containsKey(SAVE_ADDING_USER)) { 199 mAddedUserId = icicle.getInt(SAVE_ADDING_USER); 200 } 201 if (icicle.containsKey(SAVE_REMOVING_USER)) { 202 mRemovingUserId = icicle.getInt(SAVE_REMOVING_USER); 203 } 204 mEditUserInfoController.onRestoreInstanceState(icicle); 205 } 206 final Context context = getActivity(); 207 mUserCaps = UserCapabilities.create(context); 208 mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 209 if (!mUserCaps.mEnabled) { 210 return; 211 } 212 213 final int myUserId = UserHandle.myUserId(); 214 215 addPreferencesFromResource(R.xml.user_settings); 216 mUserListCategory = (PreferenceGroup) findPreference(KEY_USER_LIST); 217 mMePreference = new UserPreference(getPrefContext(), null /* attrs */, myUserId, 218 null /* settings icon handler */, 219 null /* delete icon handler */); 220 mMePreference.setKey(KEY_USER_ME); 221 mMePreference.setOnPreferenceClickListener(this); 222 if (mUserCaps.mIsAdmin) { 223 mMePreference.setSummary(R.string.user_admin); 224 } 225 mAddUser = (DimmableIconPreference) findPreference(KEY_ADD_USER); 226 // Determine if add user/profile button should be visible 227 if (mUserCaps.mCanAddUser && Utils.isDeviceProvisioned(getActivity())) { 228 mAddUser.setOnPreferenceClickListener(this); 229 // change label to only mention user, if restricted profiles are not supported 230 if (!mUserCaps.mCanAddRestrictedProfile) { 231 mAddUser.setTitle(R.string.user_add_user_menu); 232 } 233 } 234 mLockScreenSettings = (PreferenceGroup) findPreference("lock_screen_settings"); 235 mAddUserWhenLocked = (RestrictedSwitchPreference) findPreference("add_users_when_locked"); 236 mEmergencyInfoPreference = findPreference(KEY_EMERGENCY_INFO); 237 setHasOptionsMenu(true); 238 IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED); 239 filter.addAction(Intent.ACTION_USER_INFO_CHANGED); 240 context.registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null, mHandler); 241 loadProfile(); 242 updateUserList(); 243 mShouldUpdateUserList = false; 244 } 245 246 @Override onResume()247 public void onResume() { 248 super.onResume(); 249 250 if (!mUserCaps.mEnabled) return; 251 if (mShouldUpdateUserList) { 252 mUserCaps.updateAddUserCapabilities(getActivity()); 253 loadProfile(); 254 updateUserList(); 255 } 256 } 257 258 @Override onPause()259 public void onPause() { 260 mShouldUpdateUserList = true; 261 super.onPause(); 262 } 263 264 @Override onDestroy()265 public void onDestroy() { 266 super.onDestroy(); 267 268 if (!mUserCaps.mEnabled) return; 269 270 getActivity().unregisterReceiver(mUserChangeReceiver); 271 } 272 273 @Override onSaveInstanceState(Bundle outState)274 public void onSaveInstanceState(Bundle outState) { 275 super.onSaveInstanceState(outState); 276 mEditUserInfoController.onSaveInstanceState(outState); 277 outState.putInt(SAVE_ADDING_USER, mAddedUserId); 278 outState.putInt(SAVE_REMOVING_USER, mRemovingUserId); 279 } 280 281 @Override startActivityForResult(Intent intent, int requestCode)282 public void startActivityForResult(Intent intent, int requestCode) { 283 mEditUserInfoController.startingActivityForResult(); 284 super.startActivityForResult(intent, requestCode); 285 } 286 287 @Override onCreateOptionsMenu(Menu menu, MenuInflater inflater)288 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 289 int pos = 0; 290 UserManager um = getContext().getSystemService(UserManager.class); 291 boolean allowRemoveUser = !um.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER); 292 boolean canSwitchUsers = um.canSwitchUsers(); 293 if (!mUserCaps.mIsAdmin && allowRemoveUser && canSwitchUsers) { 294 String nickname = mUserManager.getUserName(); 295 MenuItem removeThisUser = menu.add(0, MENU_REMOVE_USER, pos++, 296 getResources().getString(R.string.user_remove_user_menu, nickname)); 297 removeThisUser.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); 298 } 299 super.onCreateOptionsMenu(menu, inflater); 300 } 301 302 @Override onOptionsItemSelected(MenuItem item)303 public boolean onOptionsItemSelected(MenuItem item) { 304 final int itemId = item.getItemId(); 305 if (itemId == MENU_REMOVE_USER) { 306 onRemoveUserClicked(UserHandle.myUserId()); 307 return true; 308 } else { 309 return super.onOptionsItemSelected(item); 310 } 311 } 312 313 /** 314 * Loads profile information for the current user. 315 */ loadProfile()316 private void loadProfile() { 317 if (mUserCaps.mIsGuest) { 318 // No need to load profile information 319 mMePreference.setIcon(getEncircledDefaultIcon()); 320 mMePreference.setTitle(R.string.user_exit_guest_title); 321 return; 322 } 323 324 new AsyncTask<Void, Void, String>() { 325 @Override 326 protected void onPostExecute(String result) { 327 finishLoadProfile(result); 328 } 329 330 @Override 331 protected String doInBackground(Void... values) { 332 UserInfo user = mUserManager.getUserInfo(UserHandle.myUserId()); 333 if (user.iconPath == null || user.iconPath.equals("")) { 334 // Assign profile photo. 335 Utils.copyMeProfilePhoto(getActivity(), user); 336 } 337 return user.name; 338 } 339 }.execute(); 340 } 341 finishLoadProfile(String profileName)342 private void finishLoadProfile(String profileName) { 343 if (getActivity() == null) return; 344 mMePreference.setTitle(getString(R.string.user_you, profileName)); 345 int myUserId = UserHandle.myUserId(); 346 Bitmap b = mUserManager.getUserIcon(myUserId); 347 if (b != null) { 348 mMePreference.setIcon(encircle(b)); 349 mUserIcons.put(myUserId, b); 350 } 351 } 352 hasLockscreenSecurity()353 private boolean hasLockscreenSecurity() { 354 LockPatternUtils lpu = new LockPatternUtils(getActivity()); 355 return lpu.isSecure(UserHandle.myUserId()); 356 } 357 launchChooseLockscreen()358 private void launchChooseLockscreen() { 359 Intent chooseLockIntent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD); 360 chooseLockIntent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, 361 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); 362 startActivityForResult(chooseLockIntent, REQUEST_CHOOSE_LOCK); 363 } 364 365 @Override onActivityResult(int requestCode, int resultCode, Intent data)366 public void onActivityResult(int requestCode, int resultCode, Intent data) { 367 super.onActivityResult(requestCode, resultCode, data); 368 369 if (requestCode == REQUEST_CHOOSE_LOCK) { 370 if (resultCode != Activity.RESULT_CANCELED && hasLockscreenSecurity()) { 371 addUserNow(USER_TYPE_RESTRICTED_PROFILE); 372 } 373 } else { 374 mEditUserInfoController.onActivityResult(requestCode, resultCode, data); 375 } 376 } 377 onAddUserClicked(int userType)378 private void onAddUserClicked(int userType) { 379 synchronized (mUserLock) { 380 if (mRemovingUserId == -1 && !mAddingUser) { 381 switch (userType) { 382 case USER_TYPE_USER: 383 showDialog(DIALOG_ADD_USER); 384 break; 385 case USER_TYPE_RESTRICTED_PROFILE: 386 if (hasLockscreenSecurity()) { 387 addUserNow(USER_TYPE_RESTRICTED_PROFILE); 388 } else { 389 showDialog(DIALOG_NEED_LOCKSCREEN); 390 } 391 break; 392 } 393 } 394 } 395 } 396 onRemoveUserClicked(int userId)397 private void onRemoveUserClicked(int userId) { 398 synchronized (mUserLock) { 399 if (mRemovingUserId == -1 && !mAddingUser) { 400 mRemovingUserId = userId; 401 showDialog(DIALOG_CONFIRM_REMOVE); 402 } 403 } 404 } 405 createRestrictedProfile()406 private UserInfo createRestrictedProfile() { 407 UserInfo newUserInfo = mUserManager.createRestrictedProfile(mAddingUserName); 408 Utils.assignDefaultPhoto(getActivity(), newUserInfo.id); 409 return newUserInfo; 410 } 411 createTrustedUser()412 private UserInfo createTrustedUser() { 413 UserInfo newUserInfo = mUserManager.createUser(mAddingUserName, 0); 414 if (newUserInfo != null) { 415 Utils.assignDefaultPhoto(getActivity(), newUserInfo.id); 416 } 417 return newUserInfo; 418 } 419 onManageUserClicked(int userId, boolean newUser)420 private void onManageUserClicked(int userId, boolean newUser) { 421 mAddingUser = false; 422 if (userId == UserPreference.USERID_GUEST_DEFAULTS) { 423 Bundle extras = new Bundle(); 424 extras.putBoolean(UserDetailsSettings.EXTRA_USER_GUEST, true); 425 ((SettingsActivity) getActivity()).startPreferencePanel( 426 UserDetailsSettings.class.getName(), 427 extras, R.string.user_guest, null, null, 0); 428 return; 429 } 430 UserInfo info = mUserManager.getUserInfo(userId); 431 if (info.isRestricted() && mUserCaps.mIsAdmin) { 432 Bundle extras = new Bundle(); 433 extras.putInt(RestrictedProfileSettings.EXTRA_USER_ID, userId); 434 extras.putBoolean(RestrictedProfileSettings.EXTRA_NEW_USER, newUser); 435 ((SettingsActivity) getActivity()).startPreferencePanel( 436 RestrictedProfileSettings.class.getName(), 437 extras, R.string.user_restrictions_title, null, 438 null, 0); 439 } else if (info.id == UserHandle.myUserId()) { 440 // Jump to owner info panel 441 OwnerInfoSettings.show(this); 442 } else if (mUserCaps.mIsAdmin) { 443 Bundle extras = new Bundle(); 444 extras.putInt(UserDetailsSettings.EXTRA_USER_ID, userId); 445 ((SettingsActivity) getActivity()).startPreferencePanel( 446 UserDetailsSettings.class.getName(), 447 extras, 448 -1, /* No title res id */ 449 info.name, /* title */ 450 null, /* resultTo */ 451 0 /* resultRequestCode */); 452 } 453 } 454 onUserCreated(int userId)455 private void onUserCreated(int userId) { 456 mAddedUserId = userId; 457 mAddingUser = false; 458 if (mUserManager.getUserInfo(userId).isRestricted()) { 459 showDialog(DIALOG_SETUP_PROFILE); 460 } else { 461 showDialog(DIALOG_SETUP_USER); 462 } 463 } 464 465 @Override onDialogShowing()466 public void onDialogShowing() { 467 super.onDialogShowing(); 468 469 setOnDismissListener(this); 470 } 471 472 @Override onCreateDialog(int dialogId)473 public Dialog onCreateDialog(int dialogId) { 474 Context context = getActivity(); 475 if (context == null) return null; 476 switch (dialogId) { 477 case DIALOG_CONFIRM_REMOVE: { 478 Dialog dlg = 479 UserDialogs.createRemoveDialog(getActivity(), mRemovingUserId, 480 new DialogInterface.OnClickListener() { 481 public void onClick(DialogInterface dialog, int which) { 482 removeUserNow(); 483 } 484 } 485 ); 486 return dlg; 487 } 488 case DIALOG_USER_CANNOT_MANAGE: 489 return new AlertDialog.Builder(context) 490 .setMessage(R.string.user_cannot_manage_message) 491 .setPositiveButton(android.R.string.ok, null) 492 .create(); 493 case DIALOG_ADD_USER: { 494 final SharedPreferences preferences = getActivity().getPreferences( 495 Context.MODE_PRIVATE); 496 final boolean longMessageDisplayed = preferences.getBoolean( 497 KEY_ADD_USER_LONG_MESSAGE_DISPLAYED, false); 498 final int messageResId = longMessageDisplayed 499 ? R.string.user_add_user_message_short 500 : R.string.user_add_user_message_long; 501 final int userType = dialogId == DIALOG_ADD_USER 502 ? USER_TYPE_USER : USER_TYPE_RESTRICTED_PROFILE; 503 Dialog dlg = new AlertDialog.Builder(context) 504 .setTitle(R.string.user_add_user_title) 505 .setMessage(messageResId) 506 .setPositiveButton(android.R.string.ok, 507 new DialogInterface.OnClickListener() { 508 public void onClick(DialogInterface dialog, int which) { 509 addUserNow(userType); 510 if (!longMessageDisplayed) { 511 preferences.edit().putBoolean( 512 KEY_ADD_USER_LONG_MESSAGE_DISPLAYED, true).apply(); 513 } 514 } 515 }) 516 .setNegativeButton(android.R.string.cancel, null) 517 .create(); 518 return dlg; 519 } 520 case DIALOG_SETUP_USER: { 521 Dialog dlg = new AlertDialog.Builder(context) 522 .setTitle(R.string.user_setup_dialog_title) 523 .setMessage(R.string.user_setup_dialog_message) 524 .setPositiveButton(R.string.user_setup_button_setup_now, 525 new DialogInterface.OnClickListener() { 526 public void onClick(DialogInterface dialog, int which) { 527 switchUserNow(mAddedUserId); 528 } 529 }) 530 .setNegativeButton(R.string.user_setup_button_setup_later, null) 531 .create(); 532 return dlg; 533 } 534 case DIALOG_SETUP_PROFILE: { 535 Dialog dlg = new AlertDialog.Builder(context) 536 .setMessage(R.string.user_setup_profile_dialog_message) 537 .setPositiveButton(android.R.string.ok, 538 new DialogInterface.OnClickListener() { 539 public void onClick(DialogInterface dialog, int which) { 540 switchUserNow(mAddedUserId); 541 } 542 }) 543 .setNegativeButton(android.R.string.cancel, null) 544 .create(); 545 return dlg; 546 } 547 case DIALOG_CHOOSE_USER_TYPE: { 548 List<HashMap<String, String>> data = new ArrayList<HashMap<String,String>>(); 549 HashMap<String,String> addUserItem = new HashMap<String,String>(); 550 addUserItem.put(KEY_TITLE, getString(R.string.user_add_user_item_title)); 551 addUserItem.put(KEY_SUMMARY, getString(R.string.user_add_user_item_summary)); 552 HashMap<String,String> addProfileItem = new HashMap<String,String>(); 553 addProfileItem.put(KEY_TITLE, getString(R.string.user_add_profile_item_title)); 554 addProfileItem.put(KEY_SUMMARY, getString(R.string.user_add_profile_item_summary)); 555 data.add(addUserItem); 556 data.add(addProfileItem); 557 AlertDialog.Builder builder = new AlertDialog.Builder(context); 558 SimpleAdapter adapter = new SimpleAdapter(builder.getContext(), 559 data, R.layout.two_line_list_item, 560 new String[] {KEY_TITLE, KEY_SUMMARY}, 561 new int[] {R.id.title, R.id.summary}); 562 builder.setTitle(R.string.user_add_user_type_title); 563 builder.setAdapter(adapter, 564 new DialogInterface.OnClickListener() { 565 @Override 566 public void onClick(DialogInterface dialog, int which) { 567 onAddUserClicked(which == 0 568 ? USER_TYPE_USER 569 : USER_TYPE_RESTRICTED_PROFILE); 570 } 571 }); 572 return builder.create(); 573 } 574 case DIALOG_NEED_LOCKSCREEN: { 575 Dialog dlg = new AlertDialog.Builder(context) 576 .setMessage(R.string.user_need_lock_message) 577 .setPositiveButton(R.string.user_set_lock_button, 578 new DialogInterface.OnClickListener() { 579 @Override 580 public void onClick(DialogInterface dialog, int which) { 581 launchChooseLockscreen(); 582 } 583 }) 584 .setNegativeButton(android.R.string.cancel, null) 585 .create(); 586 return dlg; 587 } 588 case DIALOG_CONFIRM_EXIT_GUEST: { 589 Dialog dlg = new AlertDialog.Builder(context) 590 .setTitle(R.string.user_exit_guest_confirm_title) 591 .setMessage(R.string.user_exit_guest_confirm_message) 592 .setPositiveButton(R.string.user_exit_guest_dialog_remove, 593 new DialogInterface.OnClickListener() { 594 @Override 595 public void onClick(DialogInterface dialog, int which) { 596 exitGuest(); 597 } 598 }) 599 .setNegativeButton(android.R.string.cancel, null) 600 .create(); 601 return dlg; 602 } 603 case DIALOG_USER_PROFILE_EDITOR: { 604 Dialog dlg = mEditUserInfoController.createDialog( 605 this, 606 mMePreference.getIcon(), 607 mMePreference.getTitle(), 608 R.string.profile_info_settings_title, 609 this /* callback */, 610 android.os.Process.myUserHandle()); 611 return dlg; 612 } 613 default: 614 return null; 615 } 616 } 617 emergencyInfoActivityPresent()618 private boolean emergencyInfoActivityPresent() { 619 Intent intent = new Intent(ACTION_EDIT_EMERGENCY_INFO).setPackage("com.android.emergency"); 620 List<ResolveInfo> infos = getContext().getPackageManager().queryIntentActivities(intent, 0); 621 if (infos == null || infos.isEmpty()) { 622 return false; 623 } 624 return true; 625 } 626 removeUserNow()627 private void removeUserNow() { 628 if (mRemovingUserId == UserHandle.myUserId()) { 629 removeThisUser(); 630 } else { 631 new Thread() { 632 public void run() { 633 synchronized (mUserLock) { 634 mUserManager.removeUser(mRemovingUserId); 635 mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST); 636 } 637 } 638 }.start(); 639 } 640 } 641 removeThisUser()642 private void removeThisUser() { 643 if (!mUserManager.canSwitchUsers()) { 644 Log.w(TAG, "Cannot remove current user when switching is disabled"); 645 return; 646 } 647 try { 648 ActivityManagerNative.getDefault().switchUser(UserHandle.USER_SYSTEM); 649 getContext().getSystemService(UserManager.class).removeUser(UserHandle.myUserId()); 650 } catch (RemoteException re) { 651 Log.e(TAG, "Unable to remove self user"); 652 } 653 } 654 addUserNow(final int userType)655 private void addUserNow(final int userType) { 656 synchronized (mUserLock) { 657 mAddingUser = true; 658 mAddingUserName = userType == USER_TYPE_USER ? getString(R.string.user_new_user_name) 659 : getString(R.string.user_new_profile_name); 660 //updateUserList(); 661 new Thread() { 662 public void run() { 663 UserInfo user; 664 // Could take a few seconds 665 if (userType == USER_TYPE_USER) { 666 user = createTrustedUser(); 667 } else { 668 user = createRestrictedProfile(); 669 } 670 if (user == null) { 671 mAddingUser = false; 672 return; 673 } 674 synchronized (mUserLock) { 675 if (userType == USER_TYPE_USER) { 676 mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST); 677 mHandler.sendMessage(mHandler.obtainMessage( 678 MESSAGE_SETUP_USER, user.id, user.serialNumber)); 679 } else { 680 mHandler.sendMessage(mHandler.obtainMessage( 681 MESSAGE_CONFIG_USER, user.id, user.serialNumber)); 682 } 683 } 684 } 685 }.start(); 686 } 687 } 688 switchUserNow(int userId)689 private void switchUserNow(int userId) { 690 try { 691 ActivityManagerNative.getDefault().switchUser(userId); 692 } catch (RemoteException re) { 693 // Nothing to do 694 } 695 } 696 697 /** 698 * Erase the current user (guest) and switch to another user. 699 */ exitGuest()700 private void exitGuest() { 701 // Just to be safe 702 if (!mUserCaps.mIsGuest) { 703 return; 704 } 705 removeThisUser(); 706 } 707 updateUserList()708 private void updateUserList() { 709 if (getActivity() == null) return; 710 List<UserInfo> users = mUserManager.getUsers(true); 711 final Context context = getActivity(); 712 713 final boolean voiceCapable = Utils.isVoiceCapable(context); 714 final ArrayList<Integer> missingIcons = new ArrayList<>(); 715 final ArrayList<UserPreference> userPreferences = new ArrayList<>(); 716 userPreferences.add(mMePreference); 717 718 for (UserInfo user : users) { 719 if (!user.supportsSwitchToByUser()) { 720 // Only users that can be switched to should show up here. 721 // e.g. Managed profiles appear under Accounts Settings instead 722 continue; 723 } 724 UserPreference pref; 725 if (user.id == UserHandle.myUserId()) { 726 pref = mMePreference; 727 } else if (user.isGuest()) { 728 // Skip over Guest. We add generic Guest settings after this loop 729 continue; 730 } else { 731 // With Telephony: 732 // Secondary user: Settings 733 // Guest: Settings 734 // Restricted Profile: There is no Restricted Profile 735 // Without Telephony: 736 // Secondary user: Delete 737 // Guest: Nothing 738 // Restricted Profile: Settings 739 final boolean showSettings = mUserCaps.mIsAdmin 740 && (voiceCapable || user.isRestricted()); 741 final boolean showDelete = mUserCaps.mIsAdmin 742 && (!voiceCapable && !user.isRestricted() && !user.isGuest()); 743 pref = new UserPreference(getPrefContext(), null, user.id, 744 showSettings ? this : null, 745 showDelete ? this : null); 746 pref.setKey("id=" + user.id); 747 userPreferences.add(pref); 748 if (user.isAdmin()) { 749 pref.setSummary(R.string.user_admin); 750 } 751 pref.setTitle(user.name); 752 pref.setSelectable(false); 753 } 754 if (pref == null) { 755 continue; 756 } 757 if (!isInitialized(user)) { 758 if (user.isRestricted()) { 759 pref.setSummary(R.string.user_summary_restricted_not_set_up); 760 } else { 761 pref.setSummary(R.string.user_summary_not_set_up); 762 } 763 pref.setOnPreferenceClickListener(this); 764 pref.setSelectable(true); 765 } else if (user.isRestricted()) { 766 pref.setSummary(R.string.user_summary_restricted_profile); 767 } 768 if (user.iconPath != null) { 769 if (mUserIcons.get(user.id) == null) { 770 // Icon not loaded yet, print a placeholder 771 missingIcons.add(user.id); 772 pref.setIcon(getEncircledDefaultIcon()); 773 } else { 774 setPhotoId(pref, user); 775 } 776 } else { 777 // Icon not available yet, print a placeholder 778 pref.setIcon(getEncircledDefaultIcon()); 779 } 780 } 781 782 // Add a temporary entry for the user being created 783 if (mAddingUser) { 784 UserPreference pref = new UserPreference(getPrefContext(), null, 785 UserPreference.USERID_UNKNOWN, null, null); 786 pref.setEnabled(false); 787 pref.setTitle(mAddingUserName); 788 pref.setIcon(getEncircledDefaultIcon()); 789 userPreferences.add(pref); 790 } 791 792 // Check if Guest tile should be added. 793 if (!mUserCaps.mIsGuest && (mUserCaps.mCanAddGuest || 794 mUserCaps.mDisallowAddUserSetByAdmin)) { 795 // Add a virtual Guest user for guest defaults 796 UserPreference pref = new UserPreference(getPrefContext(), null, 797 UserPreference.USERID_GUEST_DEFAULTS, 798 mUserCaps.mIsAdmin && voiceCapable? this : null /* settings icon handler */, 799 null /* delete icon handler */); 800 pref.setTitle(R.string.user_guest); 801 pref.setIcon(getEncircledDefaultIcon()); 802 userPreferences.add(pref); 803 pref.setDisabledByAdmin( 804 mUserCaps.mDisallowAddUser ? mUserCaps.mEnforcedAdmin : null); 805 pref.setSelectable(false); 806 } 807 808 // Sort list of users by serialNum 809 Collections.sort(userPreferences, UserPreference.SERIAL_NUMBER_COMPARATOR); 810 811 getActivity().invalidateOptionsMenu(); 812 813 // Load the icons 814 if (missingIcons.size() > 0) { 815 loadIconsAsync(missingIcons); 816 } 817 818 PreferenceScreen preferenceScreen = getPreferenceScreen(); 819 preferenceScreen.removeAll(); 820 821 // If profiles are supported, userPreferences will be added to the category labeled 822 // "User & Profiles", otherwise the category is skipped and elements are added directly 823 // to preferenceScreen 824 PreferenceGroup groupToAddUsers; 825 if (mUserCaps.mCanAddRestrictedProfile) { 826 mUserListCategory.removeAll(); 827 mUserListCategory.setOrder(Preference.DEFAULT_ORDER); 828 preferenceScreen.addPreference(mUserListCategory); 829 groupToAddUsers = mUserListCategory; 830 } else { 831 groupToAddUsers = preferenceScreen; 832 } 833 for (UserPreference userPreference : userPreferences) { 834 userPreference.setOrder(Preference.DEFAULT_ORDER); 835 groupToAddUsers.addPreference(userPreference); 836 } 837 838 // Append Add user to the end of the list 839 if ((mUserCaps.mCanAddUser || mUserCaps.mDisallowAddUserSetByAdmin) && 840 Utils.isDeviceProvisioned(getActivity())) { 841 boolean moreUsers = mUserManager.canAddMoreUsers(); 842 mAddUser.setOrder(Preference.DEFAULT_ORDER); 843 preferenceScreen.addPreference(mAddUser); 844 mAddUser.setEnabled(moreUsers && !mAddingUser); 845 if (!moreUsers) { 846 mAddUser.setSummary(getString(R.string.user_add_max_count, getMaxRealUsers())); 847 } else { 848 mAddUser.setSummary(null); 849 } 850 if (mAddUser.isEnabled()) { 851 mAddUser.setDisabledByAdmin( 852 mUserCaps.mDisallowAddUser ? mUserCaps.mEnforcedAdmin : null); 853 } 854 } 855 if (mUserCaps.mIsAdmin && 856 (!mUserCaps.mDisallowAddUser || mUserCaps.mDisallowAddUserSetByAdmin)) { 857 mLockScreenSettings.setOrder(Preference.DEFAULT_ORDER); 858 preferenceScreen.addPreference(mLockScreenSettings); 859 mAddUserWhenLocked.setChecked(Settings.Global.getInt(getContentResolver(), 860 Settings.Global.ADD_USERS_WHEN_LOCKED, 0) == 1); 861 mAddUserWhenLocked.setOnPreferenceChangeListener(this); 862 mAddUserWhenLocked.setDisabledByAdmin( 863 mUserCaps.mDisallowAddUser ? mUserCaps.mEnforcedAdmin : null); 864 } 865 866 if (emergencyInfoActivityPresent()) { 867 mEmergencyInfoPreference.setOnPreferenceClickListener(this); 868 mEmergencyInfoPreference.setOrder(Preference.DEFAULT_ORDER); 869 preferenceScreen.addPreference(mEmergencyInfoPreference); 870 } 871 } 872 getMaxRealUsers()873 private int getMaxRealUsers() { 874 // guest is not counted against getMaxSupportedUsers() number 875 final int maxUsersAndGuest = UserManager.getMaxSupportedUsers() + 1; 876 final List<UserInfo> users = mUserManager.getUsers(); 877 // managed profiles are counted against getMaxSupportedUsers() 878 int managedProfiles = 0; 879 for (UserInfo user : users) { 880 if (user.isManagedProfile()) { 881 managedProfiles++; 882 } 883 } 884 return maxUsersAndGuest - managedProfiles; 885 } 886 loadIconsAsync(List<Integer> missingIcons)887 private void loadIconsAsync(List<Integer> missingIcons) { 888 new AsyncTask<List<Integer>, Void, Void>() { 889 @Override 890 protected void onPostExecute(Void result) { 891 updateUserList(); 892 } 893 894 @Override 895 protected Void doInBackground(List<Integer>... values) { 896 for (int userId : values[0]) { 897 Bitmap bitmap = mUserManager.getUserIcon(userId); 898 if (bitmap == null) { 899 bitmap = Utils.getDefaultUserIconAsBitmap(userId); 900 } 901 mUserIcons.append(userId, bitmap); 902 } 903 return null; 904 } 905 }.execute(missingIcons); 906 } 907 getEncircledDefaultIcon()908 private Drawable getEncircledDefaultIcon() { 909 if (mDefaultIconDrawable == null) { 910 mDefaultIconDrawable = encircle(Utils.getDefaultUserIconAsBitmap(UserHandle.USER_NULL)); 911 } 912 return mDefaultIconDrawable; 913 } 914 setPhotoId(Preference pref, UserInfo user)915 private void setPhotoId(Preference pref, UserInfo user) { 916 Bitmap bitmap = mUserIcons.get(user.id); 917 if (bitmap != null) { 918 pref.setIcon(encircle(bitmap)); 919 } 920 } 921 922 @Override onPreferenceClick(Preference pref)923 public boolean onPreferenceClick(Preference pref) { 924 if (pref == mMePreference) { 925 if (mUserCaps.mIsGuest) { 926 showDialog(DIALOG_CONFIRM_EXIT_GUEST); 927 return true; 928 } 929 // If this is a limited user, launch the user info settings instead of profile editor 930 if (mUserManager.isLinkedUser()) { 931 onManageUserClicked(UserHandle.myUserId(), false); 932 } else { 933 showDialog(DIALOG_USER_PROFILE_EDITOR); 934 } 935 } else if (pref instanceof UserPreference) { 936 int userId = ((UserPreference) pref).getUserId(); 937 // Get the latest status of the user 938 UserInfo user = mUserManager.getUserInfo(userId); 939 if (!isInitialized(user)) { 940 mHandler.sendMessage(mHandler.obtainMessage( 941 MESSAGE_SETUP_USER, user.id, user.serialNumber)); 942 } 943 } else if (pref == mAddUser) { 944 // If we allow both types, show a picker, otherwise directly go to 945 // flow for full user. 946 if (mUserCaps.mCanAddRestrictedProfile) { 947 showDialog(DIALOG_CHOOSE_USER_TYPE); 948 } else { 949 onAddUserClicked(USER_TYPE_USER); 950 } 951 } else if (pref == mEmergencyInfoPreference) { 952 Intent intent = new Intent(ACTION_EDIT_EMERGENCY_INFO); 953 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 954 startActivity(intent); 955 } 956 return false; 957 } 958 isInitialized(UserInfo user)959 private boolean isInitialized(UserInfo user) { 960 return (user.flags & UserInfo.FLAG_INITIALIZED) != 0; 961 } 962 encircle(Bitmap icon)963 private Drawable encircle(Bitmap icon) { 964 Drawable circled = CircleFramedDrawable.getInstance(getActivity(), icon); 965 return circled; 966 } 967 968 @Override onClick(View v)969 public void onClick(View v) { 970 if (v.getTag() instanceof UserPreference) { 971 int userId = ((UserPreference) v.getTag()).getUserId(); 972 switch (v.getId()) { 973 case UserPreference.DELETE_ID: 974 final EnforcedAdmin removeDisallowedAdmin = 975 RestrictedLockUtils.checkIfRestrictionEnforced(getContext(), 976 UserManager.DISALLOW_REMOVE_USER, UserHandle.myUserId()); 977 if (removeDisallowedAdmin != null) { 978 RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(), 979 removeDisallowedAdmin); 980 } else { 981 onRemoveUserClicked(userId); 982 } 983 break; 984 case UserPreference.SETTINGS_ID: 985 onManageUserClicked(userId, false); 986 break; 987 } 988 } 989 } 990 991 @Override onDismiss(DialogInterface dialog)992 public void onDismiss(DialogInterface dialog) { 993 synchronized (mUserLock) { 994 mRemovingUserId = -1; 995 updateUserList(); 996 } 997 } 998 999 @Override onPreferenceChange(Preference preference, Object newValue)1000 public boolean onPreferenceChange(Preference preference, Object newValue) { 1001 if (preference == mAddUserWhenLocked) { 1002 Boolean value = (Boolean) newValue; 1003 Settings.Global.putInt(getContentResolver(), Settings.Global.ADD_USERS_WHEN_LOCKED, 1004 value != null && value ? 1 : 0); 1005 return true; 1006 } 1007 1008 return false; 1009 } 1010 1011 @Override getHelpResource()1012 public int getHelpResource() { 1013 return R.string.help_url_users; 1014 } 1015 1016 @Override onPhotoChanged(Drawable photo)1017 public void onPhotoChanged(Drawable photo) { 1018 mMePreference.setIcon(photo); 1019 } 1020 1021 @Override onLabelChanged(CharSequence label)1022 public void onLabelChanged(CharSequence label) { 1023 mMePreference.setTitle(label); 1024 } 1025 1026 private static class UserCapabilities { 1027 boolean mEnabled = true; 1028 boolean mCanAddUser = true; 1029 boolean mCanAddRestrictedProfile = true; 1030 boolean mIsAdmin; 1031 boolean mIsGuest; 1032 boolean mCanAddGuest; 1033 boolean mDisallowAddUser; 1034 boolean mDisallowAddUserSetByAdmin; 1035 EnforcedAdmin mEnforcedAdmin; 1036 UserCapabilities()1037 private UserCapabilities() {} 1038 create(Context context)1039 public static UserCapabilities create(Context context) { 1040 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 1041 UserCapabilities caps = new UserCapabilities(); 1042 if (!UserManager.supportsMultipleUsers() || Utils.isMonkeyRunning()) { 1043 caps.mEnabled = false; 1044 return caps; 1045 } 1046 1047 final UserInfo myUserInfo = userManager.getUserInfo(UserHandle.myUserId()); 1048 caps.mIsGuest = myUserInfo.isGuest(); 1049 caps.mIsAdmin = myUserInfo.isAdmin(); 1050 DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( 1051 Context.DEVICE_POLICY_SERVICE); 1052 // No restricted profiles for tablets with a device owner, or phones. 1053 if (dpm.isDeviceManaged() || Utils.isVoiceCapable(context)) { 1054 caps.mCanAddRestrictedProfile = false; 1055 } 1056 caps.updateAddUserCapabilities(context); 1057 return caps; 1058 } 1059 updateAddUserCapabilities(Context context)1060 public void updateAddUserCapabilities(Context context) { 1061 mEnforcedAdmin = RestrictedLockUtils.checkIfRestrictionEnforced(context, 1062 UserManager.DISALLOW_ADD_USER, UserHandle.myUserId()); 1063 final boolean hasBaseUserRestriction = RestrictedLockUtils.hasBaseUserRestriction( 1064 context, UserManager.DISALLOW_ADD_USER, UserHandle.myUserId()); 1065 mDisallowAddUserSetByAdmin = 1066 mEnforcedAdmin != null && !hasBaseUserRestriction; 1067 mDisallowAddUser = 1068 (mEnforcedAdmin != null || hasBaseUserRestriction); 1069 mCanAddUser = true; 1070 if (!mIsAdmin || UserManager.getMaxSupportedUsers() < 2 1071 || !UserManager.supportsMultipleUsers() 1072 || mDisallowAddUser) { 1073 mCanAddUser = false; 1074 } 1075 1076 final boolean canAddUsersWhenLocked = mIsAdmin || Settings.Global.getInt( 1077 context.getContentResolver(), Settings.Global.ADD_USERS_WHEN_LOCKED, 0) == 1; 1078 mCanAddGuest = !mIsGuest && !mDisallowAddUser && canAddUsersWhenLocked; 1079 } 1080 1081 @Override toString()1082 public String toString() { 1083 return "UserCapabilities{" + 1084 "mEnabled=" + mEnabled + 1085 ", mCanAddUser=" + mCanAddUser + 1086 ", mCanAddRestrictedProfile=" + mCanAddRestrictedProfile + 1087 ", mIsAdmin=" + mIsAdmin + 1088 ", mIsGuest=" + mIsGuest + 1089 ", mCanAddGuest=" + mCanAddGuest + 1090 ", mDisallowAddUser=" + mDisallowAddUser + 1091 ", mEnforcedAdmin=" + mEnforcedAdmin + 1092 '}'; 1093 } 1094 } 1095 1096 private static class SummaryProvider implements SummaryLoader.SummaryProvider { 1097 1098 private final Context mContext; 1099 private final SummaryLoader mSummaryLoader; 1100 SummaryProvider(Context context, SummaryLoader summaryLoader)1101 public SummaryProvider(Context context, SummaryLoader summaryLoader) { 1102 mContext = context; 1103 mSummaryLoader = summaryLoader; 1104 } 1105 1106 @Override setListening(boolean listening)1107 public void setListening(boolean listening) { 1108 if (listening) { 1109 UserInfo info = mContext.getSystemService(UserManager.class).getUserInfo( 1110 UserHandle.myUserId()); 1111 mSummaryLoader.setSummary(this, mContext.getString(R.string.user_summary, 1112 info.name)); 1113 } 1114 } 1115 } 1116 1117 public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY 1118 = new SummaryLoader.SummaryProviderFactory() { 1119 @Override 1120 public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity, 1121 SummaryLoader summaryLoader) { 1122 return new SummaryProvider(activity, summaryLoader); 1123 } 1124 }; 1125 1126 public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 1127 new BaseSearchIndexProvider() { 1128 @Override 1129 public List<SearchIndexableRaw> getRawDataToIndex(Context context, 1130 boolean enabled) { 1131 final List<SearchIndexableRaw> result = new ArrayList<>(); 1132 final UserCapabilities userCaps = UserCapabilities.create(context); 1133 if (!userCaps.mEnabled) { 1134 return result; 1135 } 1136 final Resources res = context.getResources(); 1137 SearchIndexableRaw data = new SearchIndexableRaw(context); 1138 data.title = res.getString(R.string.user_settings_title); 1139 data.screenTitle = res.getString(R.string.user_settings_title); 1140 result.add(data); 1141 1142 if (userCaps.mCanAddUser || userCaps.mDisallowAddUserSetByAdmin) { 1143 data = new SearchIndexableRaw(context); 1144 data.title = res.getString(userCaps.mCanAddRestrictedProfile ? 1145 R.string.user_add_user_or_profile_menu 1146 : R.string.user_add_user_menu); 1147 data.screenTitle = res.getString(R.string.user_settings_title); 1148 result.add(data); 1149 } 1150 return result; 1151 } 1152 }; 1153 1154 } 1155