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 
UserSwitcherController(Context context, KeyguardMonitor keyguardMonitor, Handler handler)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")
refreshUsers(int forcePictureLoadForId)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 
pauseRefreshUsers()242     private void pauseRefreshUsers() {
243         if (!mPauseRefreshUsers) {
244             mHandler.postDelayed(mUnpauseRefreshUsers, PAUSE_REFRESH_USERS_TIMEOUT_MS);
245             mPauseRefreshUsers = true;
246         }
247     }
248 
notifyAdapters()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 
isSimpleUserSwitcher()260     public boolean isSimpleUserSwitcher() {
261         return mSimpleUserSwitcher;
262     }
263 
switchTo(UserRecord record)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 
switchToUserId(int id)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 
showExitGuestDialog(int id)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 
showAddUserDialog()310     private void showAddUserDialog() {
311         if (mAddUserDialog != null && mAddUserDialog.isShowing()) {
312             mAddUserDialog.cancel();
313         }
314         mAddUserDialog = new AddUserDialog(mContext);
315         mAddUserDialog.show();
316     }
317 
exitGuest(int id)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 
dump(FileDescriptor fd, PrintWriter pw, String[] args)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 
getCurrentUserName(Context context)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 
BaseUserAdapter(UserSwitcherController controller)450         protected BaseUserAdapter(UserSwitcherController controller) {
451             mController = controller;
452             controller.mAdapters.add(new WeakReference<>(this));
453         }
454 
455         @Override
getCount()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
getItem(int position)477         public UserRecord getItem(int position) {
478             return mController.mUsers.get(position);
479         }
480 
481         @Override
getItemId(int position)482         public long getItemId(int position) {
483             return position;
484         }
485 
switchTo(UserRecord record)486         public void switchTo(UserRecord record) {
487             mController.switchTo(record);
488         }
489 
getName(Context context, UserRecord item)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 
getDrawable(Context context, UserRecord item)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 
refresh()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 
UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent, boolean isAddUser, boolean isRestricted)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 
copyWithIsCurrent(boolean _isCurrent)537         public UserRecord copyWithIsCurrent(boolean _isCurrent) {
538             return new UserRecord(info, picture, isGuest, _isCurrent, isAddUser, isRestricted);
539         }
540 
toString()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 
ExitGuestDialog(Context context, int guestId)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
onClick(DialogInterface dialog, int which)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 
AddUserDialog(Context context)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
onClick(DialogInterface dialog, int which)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 
isUserSwitcherAvailable(UserManager um)677     public static boolean isUserSwitcherAvailable(UserManager um) {
678         return UserManager.supportsMultipleUsers() && um.isUserSwitcherEnabled();
679     }
680 
681 }
682