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