Home | History | Annotate | Download | only in policy
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package com.android.systemui.statusbar.policy;
     18 
     19 import android.app.ActivityManager;
     20 import android.app.ActivityManagerNative;
     21 import android.app.Dialog;
     22 import android.app.Notification;
     23 import android.app.NotificationManager;
     24 import android.app.PendingIntent;
     25 import android.content.BroadcastReceiver;
     26 import android.content.Context;
     27 import android.content.DialogInterface;
     28 import android.content.Intent;
     29 import android.content.IntentFilter;
     30 import android.content.pm.UserInfo;
     31 import android.database.ContentObserver;
     32 import android.graphics.Bitmap;
     33 import android.graphics.drawable.Drawable;
     34 import android.os.AsyncTask;
     35 import android.os.Handler;
     36 import android.os.RemoteException;
     37 import android.os.UserHandle;
     38 import android.os.UserManager;
     39 import android.provider.Settings;
     40 import android.util.Log;
     41 import android.util.SparseArray;
     42 import android.util.SparseBooleanArray;
     43 import android.util.SparseIntArray;
     44 import android.view.View;
     45 import android.view.ViewGroup;
     46 import android.widget.BaseAdapter;
     47 
     48 import com.android.internal.logging.MetricsLogger;
     49 import com.android.internal.util.UserIcons;
     50 import com.android.systemui.BitmapHelper;
     51 import com.android.systemui.GuestResumeSessionReceiver;
     52 import com.android.systemui.R;
     53 import com.android.systemui.qs.QSTile;
     54 import com.android.systemui.qs.tiles.UserDetailView;
     55 import com.android.systemui.statusbar.phone.SystemUIDialog;
     56 
     57 import java.io.FileDescriptor;
     58 import java.io.PrintWriter;
     59 import java.lang.ref.WeakReference;
     60 import java.util.ArrayList;
     61 import java.util.List;
     62 
     63 /**
     64  * Keeps a list of all users on the device for user switching.
     65  */
     66 public class UserSwitcherController {
     67 
     68     private static final String TAG = "UserSwitcherController";
     69     private static final boolean DEBUG = false;
     70     private static final String SIMPLE_USER_SWITCHER_GLOBAL_SETTING =
     71             "lockscreenSimpleUserSwitcher";
     72     private static final String ACTION_REMOVE_GUEST = "com.android.systemui.REMOVE_GUEST";
     73     private static final int PAUSE_REFRESH_USERS_TIMEOUT_MS = 3000;
     74 
     75     private static final int ID_REMOVE_GUEST = 1010;
     76     private static final String TAG_REMOVE_GUEST = "remove_guest";
     77     private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
     78 
     79     private final Context mContext;
     80     private final UserManager mUserManager;
     81     private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>();
     82     private final GuestResumeSessionReceiver mGuestResumeSessionReceiver
     83             = new GuestResumeSessionReceiver();
     84     private final KeyguardMonitor mKeyguardMonitor;
     85     private final Handler mHandler;
     86 
     87     private ArrayList<UserRecord> mUsers = new ArrayList<>();
     88     private Dialog mExitGuestDialog;
     89     private Dialog mAddUserDialog;
     90     private int mLastNonGuestUser = UserHandle.USER_OWNER;
     91     private boolean mSimpleUserSwitcher;
     92     private boolean mAddUsersWhenLocked;
     93     private boolean mPauseRefreshUsers;
     94     private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
     95 
     96     public UserSwitcherController(Context context, KeyguardMonitor keyguardMonitor,
     97             Handler handler) {
     98         mContext = context;
     99         mGuestResumeSessionReceiver.register(context);
    100         mKeyguardMonitor = keyguardMonitor;
    101         mHandler = handler;
    102         mUserManager = UserManager.get(context);
    103         IntentFilter filter = new IntentFilter();
    104         filter.addAction(Intent.ACTION_USER_ADDED);
    105         filter.addAction(Intent.ACTION_USER_REMOVED);
    106         filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
    107         filter.addAction(Intent.ACTION_USER_SWITCHED);
    108         filter.addAction(Intent.ACTION_USER_STOPPING);
    109         mContext.registerReceiverAsUser(mReceiver, UserHandle.OWNER, filter,
    110                 null /* permission */, null /* scheduler */);
    111 
    112         filter = new IntentFilter();
    113         filter.addAction(ACTION_REMOVE_GUEST);
    114         mContext.registerReceiverAsUser(mReceiver, UserHandle.OWNER, filter,
    115                 PERMISSION_SELF, null /* scheduler */);
    116 
    117         mContext.getContentResolver().registerContentObserver(
    118                 Settings.Global.getUriFor(SIMPLE_USER_SWITCHER_GLOBAL_SETTING), true,
    119                 mSettingsObserver);
    120         mContext.getContentResolver().registerContentObserver(
    121                 Settings.Global.getUriFor(Settings.Global.ADD_USERS_WHEN_LOCKED), true,
    122                 mSettingsObserver);
    123         // Fetch initial values.
    124         mSettingsObserver.onChange(false);
    125 
    126         keyguardMonitor.addCallback(mCallback);
    127 
    128         refreshUsers(UserHandle.USER_NULL);
    129     }
    130 
    131     /**
    132      * Refreshes users from UserManager.
    133      *
    134      * The pictures are only loaded if they have not been loaded yet.
    135      *
    136      * @param forcePictureLoadForId forces the picture of the given user to be reloaded.
    137      */
    138     @SuppressWarnings("unchecked")
    139     private void refreshUsers(int forcePictureLoadForId) {
    140         if (DEBUG) Log.d(TAG, "refreshUsers(forcePictureLoadForId=" + forcePictureLoadForId+")");
    141         if (forcePictureLoadForId != UserHandle.USER_NULL) {
    142             mForcePictureLoadForUserId.put(forcePictureLoadForId, true);
    143         }
    144 
    145         if (mPauseRefreshUsers) {
    146             return;
    147         }
    148 
    149         SparseArray<Bitmap> bitmaps = new SparseArray<>(mUsers.size());
    150         final int N = mUsers.size();
    151         for (int i = 0; i < N; i++) {
    152             UserRecord r = mUsers.get(i);
    153             if (r == null || r.picture == null ||
    154                     r.info == null || mForcePictureLoadForUserId.get(r.info.id)) {
    155                 continue;
    156             }
    157             bitmaps.put(r.info.id, r.picture);
    158         }
    159         mForcePictureLoadForUserId.clear();
    160 
    161         final boolean addUsersWhenLocked = mAddUsersWhenLocked;
    162         new AsyncTask<SparseArray<Bitmap>, Void, ArrayList<UserRecord>>() {
    163             @SuppressWarnings("unchecked")
    164             @Override
    165             protected ArrayList<UserRecord> doInBackground(SparseArray<Bitmap>... params) {
    166                 final SparseArray<Bitmap> bitmaps = params[0];
    167                 List<UserInfo> infos = mUserManager.getUsers(true);
    168                 if (infos == null) {
    169                     return null;
    170                 }
    171                 ArrayList<UserRecord> records = new ArrayList<>(infos.size());
    172                 int currentId = ActivityManager.getCurrentUser();
    173                 UserRecord guestRecord = null;
    174                 int avatarSize = mContext.getResources()
    175                         .getDimensionPixelSize(R.dimen.max_avatar_size);
    176 
    177                 for (UserInfo info : infos) {
    178                     boolean isCurrent = currentId == info.id;
    179                     if (info.isGuest()) {
    180                         guestRecord = new UserRecord(info, null /* picture */,
    181                                 true /* isGuest */, isCurrent, false /* isAddUser */,
    182                                 false /* isRestricted */);
    183                     } else if (info.supportsSwitchTo()) {
    184                         Bitmap picture = bitmaps.get(info.id);
    185                         if (picture == null) {
    186                             picture = mUserManager.getUserIcon(info.id);
    187 
    188                             if (picture != null) {
    189                                 picture = BitmapHelper.createCircularClip(
    190                                         picture, avatarSize, avatarSize);
    191                             }
    192                         }
    193                         int index = isCurrent ? 0 : records.size();
    194                         records.add(index, new UserRecord(info, picture, false /* isGuest */,
    195                                 isCurrent, false /* isAddUser */, false /* isRestricted */));
    196                     }
    197                 }
    198 
    199                 boolean ownerCanCreateUsers = !mUserManager.hasUserRestriction(
    200                         UserManager.DISALLOW_ADD_USER, UserHandle.OWNER);
    201                 boolean currentUserCanCreateUsers =
    202                         (currentId == UserHandle.USER_OWNER) && ownerCanCreateUsers;
    203                 boolean anyoneCanCreateUsers = ownerCanCreateUsers && addUsersWhenLocked;
    204                 boolean canCreateGuest = (currentUserCanCreateUsers || anyoneCanCreateUsers)
    205                         && guestRecord == null;
    206                 boolean canCreateUser = (currentUserCanCreateUsers || anyoneCanCreateUsers)
    207                         && mUserManager.canAddMoreUsers();
    208                 boolean createIsRestricted = !addUsersWhenLocked;
    209 
    210                 if (!mSimpleUserSwitcher) {
    211                     if (guestRecord == null) {
    212                         if (canCreateGuest) {
    213                             records.add(new UserRecord(null /* info */, null /* picture */,
    214                                     true /* isGuest */, false /* isCurrent */,
    215                                     false /* isAddUser */, createIsRestricted));
    216                         }
    217                     } else {
    218                         int index = guestRecord.isCurrent ? 0 : records.size();
    219                         records.add(index, guestRecord);
    220                     }
    221                 }
    222 
    223                 if (!mSimpleUserSwitcher && canCreateUser) {
    224                     records.add(new UserRecord(null /* info */, null /* picture */,
    225                             false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
    226                             createIsRestricted));
    227                 }
    228 
    229                 return records;
    230             }
    231 
    232             @Override
    233             protected void onPostExecute(ArrayList<UserRecord> userRecords) {
    234                 if (userRecords != null) {
    235                     mUsers = userRecords;
    236                     notifyAdapters();
    237                 }
    238             }
    239         }.execute((SparseArray) bitmaps);
    240     }
    241 
    242     private void pauseRefreshUsers() {
    243         if (!mPauseRefreshUsers) {
    244             mHandler.postDelayed(mUnpauseRefreshUsers, PAUSE_REFRESH_USERS_TIMEOUT_MS);
    245             mPauseRefreshUsers = true;
    246         }
    247     }
    248 
    249     private void notifyAdapters() {
    250         for (int i = mAdapters.size() - 1; i >= 0; i--) {
    251             BaseUserAdapter adapter = mAdapters.get(i).get();
    252             if (adapter != null) {
    253                 adapter.notifyDataSetChanged();
    254             } else {
    255                 mAdapters.remove(i);
    256             }
    257         }
    258     }
    259 
    260     public boolean isSimpleUserSwitcher() {
    261         return mSimpleUserSwitcher;
    262     }
    263 
    264     public void switchTo(UserRecord record) {
    265         int id;
    266         if (record.isGuest && record.info == null) {
    267             // No guest user. Create one.
    268             UserInfo guest = mUserManager.createGuest(
    269                     mContext, mContext.getString(R.string.guest_nickname));
    270             if (guest == null) {
    271                 // Couldn't create guest, most likely because there already exists one, we just
    272                 // haven't reloaded the user list yet.
    273                 return;
    274             }
    275             id = guest.id;
    276         } else if (record.isAddUser) {
    277             showAddUserDialog();
    278             return;
    279         } else {
    280             id = record.info.id;
    281         }
    282 
    283         if (ActivityManager.getCurrentUser() == id) {
    284             if (record.isGuest) {
    285                 showExitGuestDialog(id);
    286             }
    287             return;
    288         }
    289 
    290         switchToUserId(id);
    291     }
    292 
    293     private void switchToUserId(int id) {
    294         try {
    295             pauseRefreshUsers();
    296             ActivityManagerNative.getDefault().switchUser(id);
    297         } catch (RemoteException e) {
    298             Log.e(TAG, "Couldn't switch user.", e);
    299         }
    300     }
    301 
    302     private void showExitGuestDialog(int id) {
    303         if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
    304             mExitGuestDialog.cancel();
    305         }
    306         mExitGuestDialog = new ExitGuestDialog(mContext, id);
    307         mExitGuestDialog.show();
    308     }
    309 
    310     private void showAddUserDialog() {
    311         if (mAddUserDialog != null && mAddUserDialog.isShowing()) {
    312             mAddUserDialog.cancel();
    313         }
    314         mAddUserDialog = new AddUserDialog(mContext);
    315         mAddUserDialog.show();
    316     }
    317 
    318     private void exitGuest(int id) {
    319         int newId = UserHandle.USER_OWNER;
    320         if (mLastNonGuestUser != UserHandle.USER_OWNER) {
    321             UserInfo info = mUserManager.getUserInfo(mLastNonGuestUser);
    322             if (info != null && info.isEnabled() && info.supportsSwitchTo()) {
    323                 newId = info.id;
    324             }
    325         }
    326         switchToUserId(newId);
    327         mUserManager.removeUser(id);
    328     }
    329 
    330     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
    331         @Override
    332         public void onReceive(Context context, Intent intent) {
    333             if (DEBUG) {
    334                 Log.v(TAG, "Broadcast: a=" + intent.getAction()
    335                        + " user=" + intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
    336             }
    337 
    338             boolean unpauseRefreshUsers = false;
    339             int forcePictureLoadForId = UserHandle.USER_NULL;
    340 
    341             if (ACTION_REMOVE_GUEST.equals(intent.getAction())) {
    342                 int currentUser = ActivityManager.getCurrentUser();
    343                 UserInfo userInfo = mUserManager.getUserInfo(currentUser);
    344                 if (userInfo != null && userInfo.isGuest()) {
    345                     showExitGuestDialog(currentUser);
    346                 }
    347                 return;
    348             } else if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
    349                 final int currentId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
    350                 UserInfo userInfo = mUserManager.getUserInfo(currentId);
    351                 if (userInfo != null && userInfo.isGuest()) {
    352                     showGuestNotification(currentId);
    353                 }
    354             } else if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
    355                 if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
    356                     mExitGuestDialog.cancel();
    357                     mExitGuestDialog = null;
    358                 }
    359 
    360                 final int currentId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
    361                 final int N = mUsers.size();
    362                 for (int i = 0; i < N; i++) {
    363                     UserRecord record = mUsers.get(i);
    364                     if (record.info == null) continue;
    365                     boolean shouldBeCurrent = record.info.id == currentId;
    366                     if (record.isCurrent != shouldBeCurrent) {
    367                         mUsers.set(i, record.copyWithIsCurrent(shouldBeCurrent));
    368                     }
    369                     if (shouldBeCurrent && !record.isGuest) {
    370                         mLastNonGuestUser = record.info.id;
    371                     }
    372                     if (currentId != UserHandle.USER_OWNER && record.isRestricted) {
    373                         // Immediately remove restricted records in case the AsyncTask is too slow.
    374                         mUsers.remove(i);
    375                         i--;
    376                     }
    377                 }
    378                 notifyAdapters();
    379                 unpauseRefreshUsers = true;
    380             } else if (Intent.ACTION_USER_INFO_CHANGED.equals(intent.getAction())) {
    381                 forcePictureLoadForId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
    382                         UserHandle.USER_NULL);
    383             }
    384             refreshUsers(forcePictureLoadForId);
    385             if (unpauseRefreshUsers) {
    386                 mUnpauseRefreshUsers.run();
    387             }
    388         }
    389 
    390         private void showGuestNotification(int guestUserId) {
    391             PendingIntent removeGuestPI = PendingIntent.getBroadcastAsUser(mContext,
    392                     0, new Intent(ACTION_REMOVE_GUEST), 0, UserHandle.OWNER);
    393             Notification notification = new Notification.Builder(mContext)
    394                     .setVisibility(Notification.VISIBILITY_SECRET)
    395                     .setPriority(Notification.PRIORITY_MIN)
    396                     .setSmallIcon(R.drawable.ic_person)
    397                     .setContentTitle(mContext.getString(R.string.guest_notification_title))
    398                     .setContentText(mContext.getString(R.string.guest_notification_text))
    399                     .setShowWhen(false)
    400                     .addAction(R.drawable.ic_delete,
    401                             mContext.getString(R.string.guest_notification_remove_action),
    402                             removeGuestPI)
    403                     .build();
    404             NotificationManager.from(mContext).notifyAsUser(TAG_REMOVE_GUEST, ID_REMOVE_GUEST,
    405                     notification, new UserHandle(guestUserId));
    406         }
    407     };
    408 
    409     private final Runnable mUnpauseRefreshUsers = new Runnable() {
    410         @Override
    411         public void run() {
    412             mHandler.removeCallbacks(this);
    413             mPauseRefreshUsers = false;
    414             refreshUsers(UserHandle.USER_NULL);
    415         }
    416     };
    417 
    418     private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
    419         public void onChange(boolean selfChange) {
    420             mSimpleUserSwitcher = Settings.Global.getInt(mContext.getContentResolver(),
    421                     SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0;
    422             mAddUsersWhenLocked = Settings.Global.getInt(mContext.getContentResolver(),
    423                     Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0;
    424             refreshUsers(UserHandle.USER_NULL);
    425         };
    426     };
    427 
    428     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    429         pw.println("UserSwitcherController state:");
    430         pw.println("  mLastNonGuestUser=" + mLastNonGuestUser);
    431         pw.print("  mUsers.size="); pw.println(mUsers.size());
    432         for (int i = 0; i < mUsers.size(); i++) {
    433             final UserRecord u = mUsers.get(i);
    434             pw.print("    "); pw.println(u.toString());
    435         }
    436     }
    437 
    438     public String getCurrentUserName(Context context) {
    439         if (mUsers.isEmpty()) return null;
    440         UserRecord item = mUsers.get(0);
    441         if (item == null || item.info == null) return null;
    442         if (item.isGuest) return context.getString(R.string.guest_nickname);
    443         return item.info.name;
    444     }
    445 
    446     public static abstract class BaseUserAdapter extends BaseAdapter {
    447 
    448         final UserSwitcherController mController;
    449 
    450         protected BaseUserAdapter(UserSwitcherController controller) {
    451             mController = controller;
    452             controller.mAdapters.add(new WeakReference<>(this));
    453         }
    454 
    455         @Override
    456         public int getCount() {
    457             boolean secureKeyguardShowing = mController.mKeyguardMonitor.isShowing()
    458                     && mController.mKeyguardMonitor.isSecure()
    459                     && !mController.mKeyguardMonitor.canSkipBouncer();
    460             if (!secureKeyguardShowing) {
    461                 return mController.mUsers.size();
    462             }
    463             // The lock screen is secure and showing. Filter out restricted records.
    464             final int N = mController.mUsers.size();
    465             int count = 0;
    466             for (int i = 0; i < N; i++) {
    467                 if (mController.mUsers.get(i).isRestricted) {
    468                     break;
    469                 } else {
    470                     count++;
    471                 }
    472             }
    473             return count;
    474         }
    475 
    476         @Override
    477         public UserRecord getItem(int position) {
    478             return mController.mUsers.get(position);
    479         }
    480 
    481         @Override
    482         public long getItemId(int position) {
    483             return position;
    484         }
    485 
    486         public void switchTo(UserRecord record) {
    487             mController.switchTo(record);
    488         }
    489 
    490         public String getName(Context context, UserRecord item) {
    491             if (item.isGuest) {
    492                 if (item.isCurrent) {
    493                     return context.getString(R.string.guest_exit_guest);
    494                 } else {
    495                     return context.getString(
    496                             item.info == null ? R.string.guest_new_guest : R.string.guest_nickname);
    497                 }
    498             } else if (item.isAddUser) {
    499                 return context.getString(R.string.user_add_user);
    500             } else {
    501                 return item.info.name;
    502             }
    503         }
    504 
    505         public Drawable getDrawable(Context context, UserRecord item) {
    506             if (item.isAddUser) {
    507                 return context.getDrawable(R.drawable.ic_add_circle_qs);
    508             }
    509             return UserIcons.getDefaultUserIcon(item.isGuest ? UserHandle.USER_NULL : item.info.id,
    510                     /* light= */ true);
    511         }
    512 
    513         public void refresh() {
    514             mController.refreshUsers(UserHandle.USER_NULL);
    515         }
    516     }
    517 
    518     public static final class UserRecord {
    519         public final UserInfo info;
    520         public final Bitmap picture;
    521         public final boolean isGuest;
    522         public final boolean isCurrent;
    523         public final boolean isAddUser;
    524         /** If true, the record is only visible to the owner and only when unlocked. */
    525         public final boolean isRestricted;
    526 
    527         public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent,
    528                 boolean isAddUser, boolean isRestricted) {
    529             this.info = info;
    530             this.picture = picture;
    531             this.isGuest = isGuest;
    532             this.isCurrent = isCurrent;
    533             this.isAddUser = isAddUser;
    534             this.isRestricted = isRestricted;
    535         }
    536 
    537         public UserRecord copyWithIsCurrent(boolean _isCurrent) {
    538             return new UserRecord(info, picture, isGuest, _isCurrent, isAddUser, isRestricted);
    539         }
    540 
    541         public String toString() {
    542             StringBuilder sb = new StringBuilder();
    543             sb.append("UserRecord(");
    544             if (info != null) {
    545                 sb.append("name=\"" + info.name + "\" id=" + info.id);
    546             } else {
    547                 if (isGuest) {
    548                     sb.append("<add guest placeholder>");
    549                 } else if (isAddUser) {
    550                     sb.append("<add user placeholder>");
    551                 }
    552             }
    553             if (isGuest) sb.append(" <isGuest>");
    554             if (isAddUser) sb.append(" <isAddUser>");
    555             if (isCurrent) sb.append(" <isCurrent>");
    556             if (picture != null) sb.append(" <hasPicture>");
    557             if (isRestricted) sb.append(" <isRestricted>");
    558             sb.append(')');
    559             return sb.toString();
    560         }
    561     }
    562 
    563     public final QSTile.DetailAdapter userDetailAdapter = new QSTile.DetailAdapter() {
    564         private final Intent USER_SETTINGS_INTENT = new Intent("android.settings.USER_SETTINGS");
    565 
    566         @Override
    567         public int getTitle() {
    568             return R.string.quick_settings_user_title;
    569         }
    570 
    571         @Override
    572         public View createDetailView(Context context, View convertView, ViewGroup parent) {
    573             UserDetailView v;
    574             if (!(convertView instanceof UserDetailView)) {
    575                 v = UserDetailView.inflate(context, parent, false);
    576                 v.createAndSetAdapter(UserSwitcherController.this);
    577             } else {
    578                 v = (UserDetailView) convertView;
    579             }
    580             v.refreshAdapter();
    581             return v;
    582         }
    583 
    584         @Override
    585         public Intent getSettingsIntent() {
    586             return USER_SETTINGS_INTENT;
    587         }
    588 
    589         @Override
    590         public Boolean getToggleState() {
    591             return null;
    592         }
    593 
    594         @Override
    595         public void setToggleState(boolean state) {
    596         }
    597 
    598         @Override
    599         public int getMetricsCategory() {
    600             return MetricsLogger.QS_USERDETAIL;
    601         }
    602     };
    603 
    604     private final KeyguardMonitor.Callback mCallback = new KeyguardMonitor.Callback() {
    605         @Override
    606         public void onKeyguardChanged() {
    607             notifyAdapters();
    608         }
    609     };
    610 
    611     private final class ExitGuestDialog extends SystemUIDialog implements
    612             DialogInterface.OnClickListener {
    613 
    614         private final int mGuestId;
    615 
    616         public ExitGuestDialog(Context context, int guestId) {
    617             super(context);
    618             setTitle(R.string.guest_exit_guest_dialog_title);
    619             setMessage(context.getString(R.string.guest_exit_guest_dialog_message));
    620             setButton(DialogInterface.BUTTON_NEGATIVE,
    621                     context.getString(android.R.string.cancel), this);
    622             setButton(DialogInterface.BUTTON_POSITIVE,
    623                     context.getString(R.string.guest_exit_guest_dialog_remove), this);
    624             setCanceledOnTouchOutside(false);
    625             mGuestId = guestId;
    626         }
    627 
    628         @Override
    629         public void onClick(DialogInterface dialog, int which) {
    630             if (which == BUTTON_NEGATIVE) {
    631                 cancel();
    632             } else {
    633                 dismiss();
    634                 exitGuest(mGuestId);
    635             }
    636         }
    637     }
    638 
    639     private final class AddUserDialog extends SystemUIDialog implements
    640             DialogInterface.OnClickListener {
    641 
    642         public AddUserDialog(Context context) {
    643             super(context);
    644             setTitle(R.string.user_add_user_title);
    645             setMessage(context.getString(R.string.user_add_user_message_short));
    646             setButton(DialogInterface.BUTTON_NEGATIVE,
    647                     context.getString(android.R.string.cancel), this);
    648             setButton(DialogInterface.BUTTON_POSITIVE,
    649                     context.getString(android.R.string.ok), this);
    650         }
    651 
    652         @Override
    653         public void onClick(DialogInterface dialog, int which) {
    654             if (which == BUTTON_NEGATIVE) {
    655                 cancel();
    656             } else {
    657                 dismiss();
    658                 if (ActivityManager.isUserAMonkey()) {
    659                     return;
    660                 }
    661                 UserInfo user = mUserManager.createSecondaryUser(
    662                         mContext.getString(R.string.user_new_user_name), 0 /* flags */);
    663                 if (user == null) {
    664                     // Couldn't create user, most likely because there are too many, but we haven't
    665                     // been able to reload the list yet.
    666                     return;
    667                 }
    668                 int id = user.id;
    669                 Bitmap icon = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(
    670                         id, /* light= */ false));
    671                 mUserManager.setUserIcon(id, icon);
    672                 switchToUserId(id);
    673             }
    674         }
    675     }
    676 
    677     public static boolean isUserSwitcherAvailable(UserManager um) {
    678         return UserManager.supportsMultipleUsers() && um.isUserSwitcherEnabled();
    679     }
    680 
    681 }
    682