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