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.accounts.Account; 20 import android.accounts.AccountManager; 21 import android.app.Activity; 22 import android.app.ActivityManagerNative; 23 import android.app.AlertDialog; 24 import android.app.Dialog; 25 import android.app.Fragment; 26 import android.app.admin.DevicePolicyManager; 27 import android.content.BroadcastReceiver; 28 import android.content.Context; 29 import android.content.DialogInterface; 30 import android.content.Intent; 31 import android.content.IntentFilter; 32 import android.content.SharedPreferences; 33 import android.content.pm.UserInfo; 34 import android.content.res.Resources; 35 import android.graphics.Bitmap; 36 import android.graphics.drawable.Drawable; 37 import android.os.AsyncTask; 38 import android.os.Bundle; 39 import android.os.Handler; 40 import android.os.Message; 41 import android.os.RemoteException; 42 import android.os.UserHandle; 43 import android.os.UserManager; 44 import android.preference.Preference; 45 import android.preference.Preference.OnPreferenceClickListener; 46 import android.preference.PreferenceGroup; 47 import android.provider.Settings; 48 import android.provider.Settings.Secure; 49 import android.util.Log; 50 import android.util.SparseArray; 51 import android.view.Menu; 52 import android.view.MenuInflater; 53 import android.view.MenuItem; 54 import android.view.View; 55 import android.view.View.OnClickListener; 56 import android.widget.SimpleAdapter; 57 58 import com.android.internal.util.UserIcons; 59 import com.android.internal.widget.LockPatternUtils; 60 import com.android.settings.ChooseLockGeneric; 61 import com.android.settings.OwnerInfoSettings; 62 import com.android.settings.R; 63 import com.android.settings.SelectableEditTextPreference; 64 import com.android.settings.SettingsActivity; 65 import com.android.settings.SettingsPreferenceFragment; 66 import com.android.settings.Utils; 67 import com.android.settings.drawable.CircleFramedDrawable; 68 69 import java.util.ArrayList; 70 import java.util.HashMap; 71 import 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 */ 81 public 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 onCreate(Bundle icicle)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 onResume()238 public void onResume() { 239 super.onResume(); 240 241 if (!mEnabled) return; 242 243 loadProfile(); 244 updateUserList(); 245 } 246 247 @Override onDestroy()248 public void onDestroy() { 249 super.onDestroy(); 250 251 if (!mEnabled) return; 252 253 getActivity().unregisterReceiver(mUserChangeReceiver); 254 } 255 256 @Override onSaveInstanceState(Bundle outState)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 startActivityForResult(Intent intent, int requestCode)265 public void startActivityForResult(Intent intent, int requestCode) { 266 mEditUserInfoController.startingActivityForResult(); 267 super.startActivityForResult(intent, requestCode); 268 } 269 270 @Override onCreateOptionsMenu(Menu menu, MenuInflater inflater)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 onOptionsItemSelected(MenuItem item)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 */ loadProfile()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 finishLoadProfile(String profileName)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 hasLockscreenSecurity()346 private boolean hasLockscreenSecurity() { 347 LockPatternUtils lpu = new LockPatternUtils(getActivity()); 348 return lpu.isLockPasswordEnabled() || lpu.isLockPatternEnabled(); 349 } 350 launchChooseLockscreen()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 onActivityResult(int requestCode, int resultCode, Intent data)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 onAddUserClicked(int userType)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 onRemoveUserClicked(int userId)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 createLimitedUser()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 createTrustedUser()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 onManageUserClicked(int userId, boolean newUser)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 onUserCreated(int userId)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 onDialogShowing()485 public void onDialogShowing() { 486 super.onDialogShowing(); 487 488 setOnDismissListener(this); 489 } 490 491 @Override onCreateDialog(int dialogId)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 AlertDialog.Builder builder = new AlertDialog.Builder(context); 577 SimpleAdapter adapter = new SimpleAdapter(builder.getContext(), 578 data, R.layout.two_line_list_item, 579 new String[] {KEY_TITLE, KEY_SUMMARY}, 580 new int[] {R.id.title, R.id.summary}); 581 builder.setTitle(R.string.user_add_user_type_title); 582 builder.setAdapter(adapter, 583 new DialogInterface.OnClickListener() { 584 @Override 585 public void onClick(DialogInterface dialog, int which) { 586 onAddUserClicked(which == 0 587 ? USER_TYPE_USER 588 : USER_TYPE_RESTRICTED_PROFILE); 589 } 590 }); 591 return builder.create(); 592 } 593 case DIALOG_NEED_LOCKSCREEN: { 594 Dialog dlg = new AlertDialog.Builder(context) 595 .setMessage(R.string.user_need_lock_message) 596 .setPositiveButton(R.string.user_set_lock_button, 597 new DialogInterface.OnClickListener() { 598 @Override 599 public void onClick(DialogInterface dialog, int which) { 600 launchChooseLockscreen(); 601 } 602 }) 603 .setNegativeButton(android.R.string.cancel, null) 604 .create(); 605 return dlg; 606 } 607 case DIALOG_CONFIRM_EXIT_GUEST: { 608 Dialog dlg = new AlertDialog.Builder(context) 609 .setTitle(R.string.user_exit_guest_confirm_title) 610 .setMessage(R.string.user_exit_guest_confirm_message) 611 .setPositiveButton(R.string.user_exit_guest_dialog_remove, 612 new DialogInterface.OnClickListener() { 613 @Override 614 public void onClick(DialogInterface dialog, int which) { 615 exitGuest(); 616 } 617 }) 618 .setNegativeButton(android.R.string.cancel, null) 619 .create(); 620 return dlg; 621 } 622 case DIALOG_USER_PROFILE_EDITOR: { 623 Dialog dlg = mEditUserInfoController.createDialog( 624 (Fragment) this, 625 mMePreference.getIcon(), 626 mMePreference.getTitle(), 627 R.string.profile_info_settings_title, 628 this /* callback */, 629 android.os.Process.myUserHandle()); 630 return dlg; 631 } 632 default: 633 return null; 634 } 635 } 636 removeUserNow()637 private void removeUserNow() { 638 if (mRemovingUserId == UserHandle.myUserId()) { 639 removeThisUser(); 640 } else { 641 new Thread() { 642 public void run() { 643 synchronized (mUserLock) { 644 mUserManager.removeUser(mRemovingUserId); 645 mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST); 646 } 647 } 648 }.start(); 649 } 650 } 651 removeThisUser()652 private void removeThisUser() { 653 try { 654 ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER); 655 ((UserManager) getActivity().getSystemService(Context.USER_SERVICE)) 656 .removeUser(UserHandle.myUserId()); 657 } catch (RemoteException re) { 658 Log.e(TAG, "Unable to remove self user"); 659 } 660 } 661 addUserNow(final int userType)662 private void addUserNow(final int userType) { 663 synchronized (mUserLock) { 664 mAddingUser = true; 665 //updateUserList(); 666 new Thread() { 667 public void run() { 668 UserInfo user = null; 669 // Could take a few seconds 670 if (userType == USER_TYPE_USER) { 671 user = createTrustedUser(); 672 } else { 673 user = createLimitedUser(); 674 } 675 synchronized (mUserLock) { 676 mAddingUser = false; 677 if (userType == USER_TYPE_USER) { 678 mHandler.sendEmptyMessage(MESSAGE_UPDATE_LIST); 679 mHandler.sendMessage(mHandler.obtainMessage( 680 MESSAGE_SETUP_USER, user.id, user.serialNumber)); 681 } else { 682 mHandler.sendMessage(mHandler.obtainMessage( 683 MESSAGE_CONFIG_USER, user.id, user.serialNumber)); 684 } 685 } 686 } 687 }.start(); 688 } 689 } 690 switchUserNow(int userId)691 private void switchUserNow(int userId) { 692 try { 693 ActivityManagerNative.getDefault().switchUser(userId); 694 } catch (RemoteException re) { 695 // Nothing to do 696 } 697 } 698 699 /** 700 * Erase the current user (guest) and switch to another user. 701 */ exitGuest()702 private void exitGuest() { 703 // Just to be safe 704 if (!mIsGuest) { 705 return; 706 } 707 removeThisUser(); 708 } 709 updateUserList()710 private void updateUserList() { 711 if (getActivity() == null) return; 712 List<UserInfo> users = mUserManager.getUsers(true); 713 final Context context = getActivity(); 714 715 mUserListCategory.removeAll(); 716 mUserListCategory.setOrderingAsAdded(false); 717 mUserListCategory.addPreference(mMePreference); 718 719 final boolean voiceCapable = Utils.isVoiceCapable(context); 720 final ArrayList<Integer> missingIcons = new ArrayList<Integer>(); 721 for (UserInfo user : users) { 722 if (user.isManagedProfile()) { 723 // Managed profiles appear under Accounts Settings instead 724 continue; 725 } 726 Preference pref; 727 if (user.id == UserHandle.myUserId()) { 728 pref = mMePreference; 729 } else if (user.isGuest()) { 730 // Skip over Guest. We add generic Guest settings after this loop 731 continue; 732 } else { 733 // With Telephony: 734 // Secondary user: Settings 735 // Guest: Settings 736 // Restricted Profile: There is no Restricted Profile 737 // Without Telephony: 738 // Secondary user: Delete 739 // Guest: Nothing 740 // Restricted Profile: Settings 741 final boolean showSettings = mIsOwner && (voiceCapable || user.isRestricted()); 742 final boolean showDelete = mIsOwner 743 && (!voiceCapable && !user.isRestricted() && !user.isGuest()); 744 pref = new UserPreference(context, null, user.id, 745 showSettings ? this : null, 746 showDelete ? this : null); 747 pref.setOnPreferenceClickListener(this); 748 pref.setKey("id=" + user.id); 749 mUserListCategory.addPreference(pref); 750 if (user.id == UserHandle.USER_OWNER) { 751 pref.setSummary(R.string.user_owner); 752 } 753 pref.setTitle(user.name); 754 } 755 if (!isInitialized(user)) { 756 if (user.isRestricted()) { 757 pref.setSummary(R.string.user_summary_restricted_not_set_up); 758 } else { 759 pref.setSummary(R.string.user_summary_not_set_up); 760 } 761 } else if (user.isRestricted()) { 762 pref.setSummary(R.string.user_summary_restricted_profile); 763 } 764 if (user.iconPath != null) { 765 if (mUserIcons.get(user.id) == null) { 766 // Icon not loaded yet, print a placeholder 767 missingIcons.add(user.id); 768 pref.setIcon(getEncircledDefaultIcon()); 769 } else { 770 setPhotoId(pref, user); 771 } 772 } else { 773 // Icon not available yet, print a placeholder 774 pref.setIcon(getEncircledDefaultIcon()); 775 } 776 } 777 778 // Add a temporary entry for the user being created 779 if (mAddingUser) { 780 Preference pref = new UserPreference(getActivity(), null, UserPreference.USERID_UNKNOWN, 781 null, null); 782 pref.setEnabled(false); 783 pref.setTitle(R.string.user_new_user_name); 784 pref.setIcon(getEncircledDefaultIcon()); 785 mUserListCategory.addPreference(pref); 786 } 787 788 boolean showGuestPreference = !mIsGuest; 789 // If user has DISALLOW_ADD_USER don't allow creating a guest either. 790 if (showGuestPreference && mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)) { 791 showGuestPreference = false; 792 // If guest already exists, no user creation needed. 793 for (UserInfo user : users) { 794 if (user.isGuest()) { 795 showGuestPreference = true; 796 break; 797 } 798 } 799 } 800 if (showGuestPreference) { 801 // Add a virtual Guest user for guest defaults 802 Preference pref = new UserPreference(getActivity(), null, 803 UserPreference.USERID_GUEST_DEFAULTS, 804 mIsOwner && voiceCapable? this : null /* settings icon handler */, 805 null /* delete icon handler */); 806 pref.setTitle(R.string.user_guest); 807 pref.setIcon(getEncircledDefaultIcon()); 808 pref.setOnPreferenceClickListener(this); 809 mUserListCategory.addPreference(pref); 810 } 811 812 getActivity().invalidateOptionsMenu(); 813 814 // Load the icons 815 if (missingIcons.size() > 0) { 816 loadIconsAsync(missingIcons); 817 } 818 boolean moreUsers = mUserManager.canAddMoreUsers(); 819 mAddUser.setEnabled(moreUsers); 820 } 821 loadIconsAsync(List<Integer> missingIcons)822 private void loadIconsAsync(List<Integer> missingIcons) { 823 final Resources resources = getResources(); 824 new AsyncTask<List<Integer>, Void, Void>() { 825 @Override 826 protected void onPostExecute(Void result) { 827 updateUserList(); 828 } 829 830 @Override 831 protected Void doInBackground(List<Integer>... values) { 832 for (int userId : values[0]) { 833 Bitmap bitmap = mUserManager.getUserIcon(userId); 834 if (bitmap == null) { 835 bitmap = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(userId, 836 /* light= */ false)); 837 } 838 mUserIcons.append(userId, bitmap); 839 } 840 return null; 841 } 842 }.execute(missingIcons); 843 } 844 assignProfilePhoto(final UserInfo user)845 private void assignProfilePhoto(final UserInfo user) { 846 if (!Utils.copyMeProfilePhoto(getActivity(), user)) { 847 assignDefaultPhoto(user); 848 } 849 } 850 assignDefaultPhoto(UserInfo user)851 private void assignDefaultPhoto(UserInfo user) { 852 Bitmap bitmap = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(user.id, 853 /* light= */ false)); 854 mUserManager.setUserIcon(user.id, bitmap); 855 } 856 getEncircledDefaultIcon()857 private Drawable getEncircledDefaultIcon() { 858 if (mDefaultIconDrawable == null) { 859 mDefaultIconDrawable = encircle(UserIcons.convertToBitmap( 860 UserIcons.getDefaultUserIcon(UserHandle.USER_NULL, /* light= */ false))); 861 } 862 return mDefaultIconDrawable; 863 } 864 setPhotoId(Preference pref, UserInfo user)865 private void setPhotoId(Preference pref, UserInfo user) { 866 Bitmap bitmap = mUserIcons.get(user.id); 867 if (bitmap != null) { 868 pref.setIcon(encircle(bitmap)); 869 } 870 } 871 setUserName(String name)872 private void setUserName(String name) { 873 mUserManager.setUserName(UserHandle.myUserId(), name); 874 mNicknamePreference.setSummary(name); 875 getActivity().invalidateOptionsMenu(); 876 } 877 878 @Override onPreferenceClick(Preference pref)879 public boolean onPreferenceClick(Preference pref) { 880 if (pref == mMePreference) { 881 if (mIsGuest) { 882 showDialog(DIALOG_CONFIRM_EXIT_GUEST); 883 return true; 884 } 885 // If this is a limited user, launch the user info settings instead of profile editor 886 if (mUserManager.isLinkedUser()) { 887 onManageUserClicked(UserHandle.myUserId(), false); 888 } else { 889 showDialog(DIALOG_USER_PROFILE_EDITOR); 890 } 891 } else if (pref instanceof UserPreference) { 892 int userId = ((UserPreference) pref).getUserId(); 893 if (userId == UserPreference.USERID_GUEST_DEFAULTS) { 894 createAndSwitchToGuestUser(); 895 } else { 896 // Get the latest status of the user 897 UserInfo user = mUserManager.getUserInfo(userId); 898 if (!isInitialized(user)) { 899 mHandler.sendMessage(mHandler.obtainMessage( 900 MESSAGE_SETUP_USER, user.id, user.serialNumber)); 901 } else { 902 switchUserNow(userId); 903 } 904 } 905 } else if (pref == mAddUser) { 906 // If we allow both types, show a picker, otherwise directly go to 907 // flow for full user. 908 if (mCanAddRestrictedProfile) { 909 showDialog(DIALOG_CHOOSE_USER_TYPE); 910 } else { 911 onAddUserClicked(USER_TYPE_USER); 912 } 913 } 914 return false; 915 } 916 createAndSwitchToGuestUser()917 private void createAndSwitchToGuestUser() { 918 List<UserInfo> users = mUserManager.getUsers(); 919 for (UserInfo user : users) { 920 if (user.isGuest()) { 921 switchUserNow(user.id); 922 return; 923 } 924 } 925 // No guest user. Create one, if there's no restriction. 926 // If it is not the primary user, then adding users from lockscreen must be enabled 927 if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER) 928 || (!mIsOwner && Settings.Global.getInt(getContentResolver(), 929 Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 1)) { 930 Log.i(TAG, "Blocking guest creation because it is restricted"); 931 return; 932 } 933 UserInfo guestUser = mUserManager.createGuest(getActivity(), 934 getResources().getString(R.string.user_guest)); 935 if (guestUser != null) { 936 switchUserNow(guestUser.id); 937 } 938 } 939 isInitialized(UserInfo user)940 private boolean isInitialized(UserInfo user) { 941 return (user.flags & UserInfo.FLAG_INITIALIZED) != 0; 942 } 943 encircle(Bitmap icon)944 private Drawable encircle(Bitmap icon) { 945 Drawable circled = CircleFramedDrawable.getInstance(getActivity(), icon); 946 return circled; 947 } 948 949 @Override onClick(View v)950 public void onClick(View v) { 951 if (v.getTag() instanceof UserPreference) { 952 int userId = ((UserPreference) v.getTag()).getUserId(); 953 switch (v.getId()) { 954 case UserPreference.DELETE_ID: 955 onRemoveUserClicked(userId); 956 break; 957 case UserPreference.SETTINGS_ID: 958 onManageUserClicked(userId, false); 959 break; 960 } 961 } 962 } 963 964 @Override onDismiss(DialogInterface dialog)965 public void onDismiss(DialogInterface dialog) { 966 synchronized (mUserLock) { 967 mAddingUser = false; 968 mRemovingUserId = -1; 969 updateUserList(); 970 } 971 } 972 973 @Override onPreferenceChange(Preference preference, Object newValue)974 public boolean onPreferenceChange(Preference preference, Object newValue) { 975 if (preference == mNicknamePreference) { 976 String value = (String) newValue; 977 if (preference == mNicknamePreference && value != null 978 && value.length() > 0) { 979 setUserName(value); 980 } 981 return true; 982 } 983 return false; 984 } 985 986 @Override getHelpResource()987 public int getHelpResource() { 988 return R.string.help_url_users; 989 } 990 991 @Override onPhotoChanged(Drawable photo)992 public void onPhotoChanged(Drawable photo) { 993 mMePreference.setIcon(photo); 994 } 995 996 @Override onLabelChanged(CharSequence label)997 public void onLabelChanged(CharSequence label) { 998 mMePreference.setTitle(label); 999 } 1000 } 1001