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