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