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