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