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