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