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