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