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