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 static android.os.UserManager.SWITCHABILITY_STATUS_OK; 20 21 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 22 import static com.android.systemui.DejankUtils.whitelistIpcs; 23 24 import android.annotation.UserIdInt; 25 import android.app.ActivityManager; 26 import android.app.AlertDialog; 27 import android.app.Dialog; 28 import android.app.IActivityManager; 29 import android.app.IActivityTaskManager; 30 import android.app.admin.DevicePolicyManager; 31 import android.content.BroadcastReceiver; 32 import android.content.Context; 33 import android.content.DialogInterface; 34 import android.content.Intent; 35 import android.content.IntentFilter; 36 import android.content.pm.UserInfo; 37 import android.database.ContentObserver; 38 import android.graphics.Bitmap; 39 import android.graphics.ColorFilter; 40 import android.graphics.ColorMatrix; 41 import android.graphics.ColorMatrixColorFilter; 42 import android.graphics.drawable.Drawable; 43 import android.os.AsyncTask; 44 import android.os.Handler; 45 import android.os.RemoteException; 46 import android.os.UserHandle; 47 import android.os.UserManager; 48 import android.provider.Settings; 49 import android.telephony.TelephonyCallback; 50 import android.util.Log; 51 import android.util.SparseArray; 52 import android.util.SparseBooleanArray; 53 import android.view.View; 54 import android.view.ViewGroup; 55 import android.view.WindowManagerGlobal; 56 import android.widget.BaseAdapter; 57 58 import androidx.annotation.Nullable; 59 60 import com.android.internal.annotations.VisibleForTesting; 61 import com.android.internal.jank.InteractionJankMonitor; 62 import com.android.internal.logging.UiEventLogger; 63 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 64 import com.android.internal.util.LatencyTracker; 65 import com.android.settingslib.RestrictedLockUtilsInternal; 66 import com.android.systemui.Dumpable; 67 import com.android.systemui.GuestResumeSessionReceiver; 68 import com.android.systemui.Prefs; 69 import com.android.systemui.Prefs.Key; 70 import com.android.systemui.R; 71 import com.android.systemui.SystemUISecondaryUserService; 72 import com.android.systemui.animation.DialogLaunchAnimator; 73 import com.android.systemui.broadcast.BroadcastDispatcher; 74 import com.android.systemui.dagger.SysUISingleton; 75 import com.android.systemui.dagger.qualifiers.Background; 76 import com.android.systemui.dagger.qualifiers.Main; 77 import com.android.systemui.dump.DumpManager; 78 import com.android.systemui.plugins.ActivityStarter; 79 import com.android.systemui.plugins.FalsingManager; 80 import com.android.systemui.plugins.qs.DetailAdapter; 81 import com.android.systemui.qs.QSUserSwitcherEvent; 82 import com.android.systemui.qs.tiles.UserDetailView; 83 import com.android.systemui.qs.user.UserSwitchDialogController.DialogShower; 84 import com.android.systemui.settings.UserTracker; 85 import com.android.systemui.statusbar.phone.NotificationShadeWindowView; 86 import com.android.systemui.statusbar.phone.SystemUIDialog; 87 import com.android.systemui.telephony.TelephonyListenerManager; 88 import com.android.systemui.user.CreateUserActivity; 89 import com.android.systemui.util.settings.SecureSettings; 90 91 import java.io.FileDescriptor; 92 import java.io.PrintWriter; 93 import java.lang.ref.WeakReference; 94 import java.util.ArrayList; 95 import java.util.List; 96 import java.util.concurrent.Executor; 97 import java.util.concurrent.atomic.AtomicBoolean; 98 99 import javax.inject.Inject; 100 import javax.inject.Provider; 101 102 /** 103 * Keeps a list of all users on the device for user switching. 104 */ 105 @SysUISingleton 106 public class UserSwitcherController implements Dumpable { 107 108 public static final float USER_SWITCH_ENABLED_ALPHA = 1.0f; 109 public static final float USER_SWITCH_DISABLED_ALPHA = 0.38f; 110 111 private static final String TAG = "UserSwitcherController"; 112 private static final boolean DEBUG = false; 113 private static final String SIMPLE_USER_SWITCHER_GLOBAL_SETTING = 114 "lockscreenSimpleUserSwitcher"; 115 private static final int PAUSE_REFRESH_USERS_TIMEOUT_MS = 3000; 116 117 private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF"; 118 private static final long MULTI_USER_JOURNEY_TIMEOUT = 20000l; 119 120 protected final Context mContext; 121 protected final UserTracker mUserTracker; 122 protected final UserManager mUserManager; 123 private final ContentObserver mSettingsObserver; 124 private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>(); 125 @VisibleForTesting 126 final GuestResumeSessionReceiver mGuestResumeSessionReceiver; 127 private final KeyguardStateController mKeyguardStateController; 128 private final DeviceProvisionedController mDeviceProvisionedController; 129 private final DevicePolicyManager mDevicePolicyManager; 130 protected final Handler mHandler; 131 private final ActivityStarter mActivityStarter; 132 private final BroadcastDispatcher mBroadcastDispatcher; 133 private final TelephonyListenerManager mTelephonyListenerManager; 134 private final IActivityTaskManager mActivityTaskManager; 135 private final InteractionJankMonitor mInteractionJankMonitor; 136 private final LatencyTracker mLatencyTracker; 137 private final DialogLaunchAnimator mDialogLaunchAnimator; 138 139 private ArrayList<UserRecord> mUsers = new ArrayList<>(); 140 @VisibleForTesting 141 AlertDialog mExitGuestDialog; 142 @VisibleForTesting 143 Dialog mAddUserDialog; 144 private int mLastNonGuestUser = UserHandle.USER_SYSTEM; 145 private boolean mResumeUserOnGuestLogout = true; 146 private boolean mSimpleUserSwitcher; 147 // When false, there won't be any visual affordance to add a new user from the keyguard even if 148 // the user is unlocked 149 private boolean mAddUsersFromLockScreen; 150 @VisibleForTesting 151 boolean mPauseRefreshUsers; 152 private int mSecondaryUser = UserHandle.USER_NULL; 153 private Intent mSecondaryUserServiceIntent; 154 private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2); 155 private final UiEventLogger mUiEventLogger; 156 private final IActivityManager mActivityManager; 157 public final DetailAdapter mUserDetailAdapter; 158 private final Executor mBgExecutor; 159 private final boolean mGuestUserAutoCreated; 160 private final AtomicBoolean mGuestIsResetting; 161 private final AtomicBoolean mGuestCreationScheduled; 162 private FalsingManager mFalsingManager; 163 private NotificationShadeWindowView mRootView; 164 165 @Inject UserSwitcherController(Context context, IActivityManager activityManager, UserManager userManager, UserTracker userTracker, KeyguardStateController keyguardStateController, DeviceProvisionedController deviceProvisionedController, DevicePolicyManager devicePolicyManager, @Main Handler handler, ActivityStarter activityStarter, BroadcastDispatcher broadcastDispatcher, UiEventLogger uiEventLogger, FalsingManager falsingManager, TelephonyListenerManager telephonyListenerManager, IActivityTaskManager activityTaskManager, UserDetailAdapter userDetailAdapter, SecureSettings secureSettings, @Background Executor bgExecutor, InteractionJankMonitor interactionJankMonitor, LatencyTracker latencyTracker, DumpManager dumpManager, DialogLaunchAnimator dialogLaunchAnimator)166 public UserSwitcherController(Context context, 167 IActivityManager activityManager, 168 UserManager userManager, 169 UserTracker userTracker, 170 KeyguardStateController keyguardStateController, 171 DeviceProvisionedController deviceProvisionedController, 172 DevicePolicyManager devicePolicyManager, 173 @Main Handler handler, 174 ActivityStarter activityStarter, 175 BroadcastDispatcher broadcastDispatcher, 176 UiEventLogger uiEventLogger, 177 FalsingManager falsingManager, 178 TelephonyListenerManager telephonyListenerManager, 179 IActivityTaskManager activityTaskManager, 180 UserDetailAdapter userDetailAdapter, 181 SecureSettings secureSettings, 182 @Background Executor bgExecutor, 183 InteractionJankMonitor interactionJankMonitor, 184 LatencyTracker latencyTracker, 185 DumpManager dumpManager, 186 DialogLaunchAnimator dialogLaunchAnimator) { 187 mContext = context; 188 mActivityManager = activityManager; 189 mUserTracker = userTracker; 190 mBroadcastDispatcher = broadcastDispatcher; 191 mTelephonyListenerManager = telephonyListenerManager; 192 mActivityTaskManager = activityTaskManager; 193 mUiEventLogger = uiEventLogger; 194 mFalsingManager = falsingManager; 195 mInteractionJankMonitor = interactionJankMonitor; 196 mLatencyTracker = latencyTracker; 197 mGuestResumeSessionReceiver = new GuestResumeSessionReceiver( 198 this, mUserTracker, mUiEventLogger, secureSettings); 199 mUserDetailAdapter = userDetailAdapter; 200 mBgExecutor = bgExecutor; 201 if (!UserManager.isGuestUserEphemeral()) { 202 mGuestResumeSessionReceiver.register(mBroadcastDispatcher); 203 } 204 mGuestUserAutoCreated = mContext.getResources().getBoolean( 205 com.android.internal.R.bool.config_guestUserAutoCreated); 206 mGuestIsResetting = new AtomicBoolean(); 207 mGuestCreationScheduled = new AtomicBoolean(); 208 mKeyguardStateController = keyguardStateController; 209 mDeviceProvisionedController = deviceProvisionedController; 210 mDevicePolicyManager = devicePolicyManager; 211 mHandler = handler; 212 mActivityStarter = activityStarter; 213 mUserManager = userManager; 214 mDialogLaunchAnimator = dialogLaunchAnimator; 215 216 IntentFilter filter = new IntentFilter(); 217 filter.addAction(Intent.ACTION_USER_ADDED); 218 filter.addAction(Intent.ACTION_USER_REMOVED); 219 filter.addAction(Intent.ACTION_USER_INFO_CHANGED); 220 filter.addAction(Intent.ACTION_USER_SWITCHED); 221 filter.addAction(Intent.ACTION_USER_STOPPED); 222 filter.addAction(Intent.ACTION_USER_UNLOCKED); 223 mBroadcastDispatcher.registerReceiver( 224 mReceiver, filter, null /* handler */, UserHandle.SYSTEM); 225 226 mSimpleUserSwitcher = shouldUseSimpleUserSwitcher(); 227 228 mSecondaryUserServiceIntent = new Intent(context, SystemUISecondaryUserService.class); 229 230 filter = new IntentFilter(); 231 mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter, 232 PERMISSION_SELF, null /* scheduler */); 233 234 mSettingsObserver = new ContentObserver(mHandler) { 235 @Override 236 public void onChange(boolean selfChange) { 237 mSimpleUserSwitcher = shouldUseSimpleUserSwitcher(); 238 mAddUsersFromLockScreen = Settings.Global.getInt(mContext.getContentResolver(), 239 Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0; 240 refreshUsers(UserHandle.USER_NULL); 241 }; 242 }; 243 mContext.getContentResolver().registerContentObserver( 244 Settings.Global.getUriFor(SIMPLE_USER_SWITCHER_GLOBAL_SETTING), true, 245 mSettingsObserver); 246 mContext.getContentResolver().registerContentObserver( 247 Settings.Global.getUriFor(Settings.Global.ADD_USERS_WHEN_LOCKED), true, 248 mSettingsObserver); 249 mContext.getContentResolver().registerContentObserver( 250 Settings.Global.getUriFor( 251 Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED), 252 true, mSettingsObserver); 253 // Fetch initial values. 254 mSettingsObserver.onChange(false); 255 256 keyguardStateController.addCallback(mCallback); 257 listenForCallState(); 258 259 dumpManager.registerDumpable(getClass().getSimpleName(), this); 260 261 refreshUsers(UserHandle.USER_NULL); 262 } 263 264 /** 265 * Refreshes users from UserManager. 266 * 267 * The pictures are only loaded if they have not been loaded yet. 268 * 269 * @param forcePictureLoadForId forces the picture of the given user to be reloaded. 270 */ 271 @SuppressWarnings("unchecked") refreshUsers(int forcePictureLoadForId)272 private void refreshUsers(int forcePictureLoadForId) { 273 if (DEBUG) Log.d(TAG, "refreshUsers(forcePictureLoadForId=" + forcePictureLoadForId+")"); 274 if (forcePictureLoadForId != UserHandle.USER_NULL) { 275 mForcePictureLoadForUserId.put(forcePictureLoadForId, true); 276 } 277 278 if (mPauseRefreshUsers) { 279 return; 280 } 281 282 boolean forceAllUsers = mForcePictureLoadForUserId.get(UserHandle.USER_ALL); 283 SparseArray<Bitmap> bitmaps = new SparseArray<>(mUsers.size()); 284 final int N = mUsers.size(); 285 for (int i = 0; i < N; i++) { 286 UserRecord r = mUsers.get(i); 287 if (r == null || r.picture == null || r.info == null || forceAllUsers 288 || mForcePictureLoadForUserId.get(r.info.id)) { 289 continue; 290 } 291 bitmaps.put(r.info.id, r.picture); 292 } 293 mForcePictureLoadForUserId.clear(); 294 295 final boolean addUsersWhenLocked = mAddUsersFromLockScreen; 296 new AsyncTask<SparseArray<Bitmap>, Void, ArrayList<UserRecord>>() { 297 @SuppressWarnings("unchecked") 298 @Override 299 protected ArrayList<UserRecord> doInBackground(SparseArray<Bitmap>... params) { 300 final SparseArray<Bitmap> bitmaps = params[0]; 301 List<UserInfo> infos = mUserManager.getAliveUsers(); 302 if (infos == null) { 303 return null; 304 } 305 ArrayList<UserRecord> records = new ArrayList<>(infos.size()); 306 int currentId = mUserTracker.getUserId(); 307 // Check user switchability of the foreground user since SystemUI is running in 308 // User 0 309 boolean canSwitchUsers = mUserManager.getUserSwitchability( 310 UserHandle.of(mUserTracker.getUserId())) == SWITCHABILITY_STATUS_OK; 311 UserInfo currentUserInfo = null; 312 UserRecord guestRecord = null; 313 314 for (UserInfo info : infos) { 315 boolean isCurrent = currentId == info.id; 316 if (isCurrent) { 317 currentUserInfo = info; 318 } 319 boolean switchToEnabled = canSwitchUsers || isCurrent; 320 if (info.isEnabled()) { 321 if (info.isGuest()) { 322 // Tapping guest icon triggers remove and a user switch therefore 323 // the icon shouldn't be enabled even if the user is current 324 guestRecord = new UserRecord(info, null /* picture */, 325 true /* isGuest */, isCurrent, false /* isAddUser */, 326 false /* isRestricted */, canSwitchUsers); 327 } else if (info.supportsSwitchToByUser()) { 328 Bitmap picture = bitmaps.get(info.id); 329 if (picture == null) { 330 picture = mUserManager.getUserIcon(info.id); 331 332 if (picture != null) { 333 int avatarSize = mContext.getResources() 334 .getDimensionPixelSize(R.dimen.max_avatar_size); 335 picture = Bitmap.createScaledBitmap( 336 picture, avatarSize, avatarSize, true); 337 } 338 } 339 records.add(new UserRecord(info, picture, false /* isGuest */, 340 isCurrent, false /* isAddUser */, false /* isRestricted */, 341 switchToEnabled)); 342 } 343 } 344 } 345 if (records.size() > 1 || guestRecord != null) { 346 Prefs.putBoolean(mContext, Key.SEEN_MULTI_USER, true); 347 } 348 349 boolean systemCanCreateUsers = !mUserManager.hasBaseUserRestriction( 350 UserManager.DISALLOW_ADD_USER, UserHandle.SYSTEM); 351 boolean currentUserCanCreateUsers = currentUserInfo != null 352 && (currentUserInfo.isAdmin() 353 || currentUserInfo.id == UserHandle.USER_SYSTEM) 354 && systemCanCreateUsers; 355 boolean anyoneCanCreateUsers = systemCanCreateUsers && addUsersWhenLocked; 356 boolean canCreateGuest = (currentUserCanCreateUsers || anyoneCanCreateUsers) 357 && guestRecord == null; 358 boolean canCreateUser = (currentUserCanCreateUsers || anyoneCanCreateUsers) 359 && mUserManager.canAddMoreUsers(); 360 boolean createIsRestricted = !addUsersWhenLocked; 361 362 if (guestRecord == null) { 363 if (mGuestUserAutoCreated) { 364 // If mGuestIsResetting=true, the switch should be disabled since 365 // we will just use it as an indicator for "Resetting guest...". 366 // Otherwise, default to canSwitchUsers. 367 boolean isSwitchToGuestEnabled = 368 !mGuestIsResetting.get() && canSwitchUsers; 369 guestRecord = new UserRecord(null /* info */, null /* picture */, 370 true /* isGuest */, false /* isCurrent */, 371 false /* isAddUser */, false /* isRestricted */, 372 isSwitchToGuestEnabled); 373 checkIfAddUserDisallowedByAdminOnly(guestRecord); 374 records.add(guestRecord); 375 } else if (canCreateGuest) { 376 guestRecord = new UserRecord(null /* info */, null /* picture */, 377 true /* isGuest */, false /* isCurrent */, 378 false /* isAddUser */, createIsRestricted, canSwitchUsers); 379 checkIfAddUserDisallowedByAdminOnly(guestRecord); 380 records.add(guestRecord); 381 } 382 } else { 383 records.add(guestRecord); 384 } 385 386 if (canCreateUser) { 387 UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */, 388 false /* isGuest */, false /* isCurrent */, true /* isAddUser */, 389 createIsRestricted, canSwitchUsers); 390 checkIfAddUserDisallowedByAdminOnly(addUserRecord); 391 records.add(addUserRecord); 392 } 393 394 return records; 395 } 396 397 @Override 398 protected void onPostExecute(ArrayList<UserRecord> userRecords) { 399 if (userRecords != null) { 400 mUsers = userRecords; 401 notifyAdapters(); 402 } 403 } 404 }.execute((SparseArray) bitmaps); 405 } 406 pauseRefreshUsers()407 private void pauseRefreshUsers() { 408 if (!mPauseRefreshUsers) { 409 mHandler.postDelayed(mUnpauseRefreshUsers, PAUSE_REFRESH_USERS_TIMEOUT_MS); 410 mPauseRefreshUsers = true; 411 } 412 } 413 notifyAdapters()414 private void notifyAdapters() { 415 for (int i = mAdapters.size() - 1; i >= 0; i--) { 416 BaseUserAdapter adapter = mAdapters.get(i).get(); 417 if (adapter != null) { 418 adapter.notifyDataSetChanged(); 419 } else { 420 mAdapters.remove(i); 421 } 422 } 423 } 424 isSimpleUserSwitcher()425 public boolean isSimpleUserSwitcher() { 426 return mSimpleUserSwitcher; 427 } 428 useFullscreenUserSwitcher()429 public boolean useFullscreenUserSwitcher() { 430 // Use adb to override: 431 // adb shell settings put system enable_fullscreen_user_switcher 0 # Turn it off. 432 // adb shell settings put system enable_fullscreen_user_switcher 1 # Turn it on. 433 // Restart SystemUI or adb reboot. 434 final int DEFAULT = -1; 435 final int overrideUseFullscreenUserSwitcher = 436 whitelistIpcs(() -> Settings.System.getInt(mContext.getContentResolver(), 437 "enable_fullscreen_user_switcher", DEFAULT)); 438 if (overrideUseFullscreenUserSwitcher != DEFAULT) { 439 return overrideUseFullscreenUserSwitcher != 0; 440 } 441 // Otherwise default to the build setting. 442 return mContext.getResources().getBoolean(R.bool.config_enableFullscreenUserSwitcher); 443 } 444 setResumeUserOnGuestLogout(boolean resume)445 public void setResumeUserOnGuestLogout(boolean resume) { 446 mResumeUserOnGuestLogout = resume; 447 } 448 logoutCurrentUser()449 public void logoutCurrentUser() { 450 int currentUser = mUserTracker.getUserId(); 451 if (currentUser != UserHandle.USER_SYSTEM) { 452 pauseRefreshUsers(); 453 ActivityManager.logoutCurrentUser(); 454 } 455 } 456 removeUserId(int userId)457 public void removeUserId(int userId) { 458 if (userId == UserHandle.USER_SYSTEM) { 459 Log.w(TAG, "User " + userId + " could not removed."); 460 return; 461 } 462 if (mUserTracker.getUserId() == userId) { 463 switchToUserId(UserHandle.USER_SYSTEM); 464 } 465 if (mUserManager.removeUser(userId)) { 466 refreshUsers(UserHandle.USER_NULL); 467 } 468 } 469 470 @VisibleForTesting onUserListItemClicked(UserRecord record, DialogShower dialogShower)471 void onUserListItemClicked(UserRecord record, DialogShower dialogShower) { 472 int id; 473 if (record.isGuest && record.info == null) { 474 // No guest user. Create one. 475 int guestId = createGuest(); 476 if (guestId == UserHandle.USER_NULL) { 477 // This may happen if we haven't reloaded the user list yet. 478 return; 479 } 480 mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_ADD); 481 id = guestId; 482 } else if (record.isAddUser) { 483 showAddUserDialog(dialogShower); 484 return; 485 } else { 486 id = record.info.id; 487 } 488 489 int currUserId = mUserTracker.getUserId(); 490 if (currUserId == id) { 491 if (record.isGuest) { 492 showExitGuestDialog(id, dialogShower); 493 } 494 return; 495 } 496 497 if (UserManager.isGuestUserEphemeral()) { 498 // If switching from guest, we want to bring up the guest exit dialog instead of switching 499 UserInfo currUserInfo = mUserManager.getUserInfo(currUserId); 500 if (currUserInfo != null && currUserInfo.isGuest()) { 501 showExitGuestDialog(currUserId, record.resolveId(), dialogShower); 502 return; 503 } 504 } 505 if (dialogShower != null) { 506 // If we haven't morphed into another dialog, it means we have just switched users. 507 // Then, dismiss the dialog. 508 dialogShower.dismiss(); 509 } 510 switchToUserId(id); 511 } 512 switchToUserId(int id)513 protected void switchToUserId(int id) { 514 try { 515 mInteractionJankMonitor.begin(InteractionJankMonitor.Configuration.Builder 516 .withView(InteractionJankMonitor.CUJ_USER_SWITCH, mRootView) 517 .setTimeout(MULTI_USER_JOURNEY_TIMEOUT)); 518 mLatencyTracker.onActionStart(LatencyTracker.ACTION_USER_SWITCH); 519 pauseRefreshUsers(); 520 mActivityManager.switchUser(id); 521 } catch (RemoteException e) { 522 Log.e(TAG, "Couldn't switch user.", e); 523 } 524 } 525 showExitGuestDialog(int id, DialogShower dialogShower)526 private void showExitGuestDialog(int id, DialogShower dialogShower) { 527 int newId = UserHandle.USER_SYSTEM; 528 if (mResumeUserOnGuestLogout && mLastNonGuestUser != UserHandle.USER_SYSTEM) { 529 UserInfo info = mUserManager.getUserInfo(mLastNonGuestUser); 530 if (info != null && info.isEnabled() && info.supportsSwitchToByUser()) { 531 newId = info.id; 532 } 533 } 534 showExitGuestDialog(id, newId, dialogShower); 535 } 536 showExitGuestDialog(int id, int targetId, DialogShower dialogShower)537 private void showExitGuestDialog(int id, int targetId, DialogShower dialogShower) { 538 if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) { 539 mExitGuestDialog.cancel(); 540 } 541 mExitGuestDialog = new ExitGuestDialog(mContext, id, targetId); 542 if (dialogShower != null) { 543 dialogShower.showDialog(mExitGuestDialog); 544 } else { 545 mExitGuestDialog.show(); 546 } 547 } 548 showAddUserDialog(DialogShower dialogShower)549 private void showAddUserDialog(DialogShower dialogShower) { 550 if (mAddUserDialog != null && mAddUserDialog.isShowing()) { 551 mAddUserDialog.cancel(); 552 } 553 mAddUserDialog = new AddUserDialog(mContext); 554 if (dialogShower != null) { 555 dialogShower.showDialog(mAddUserDialog); 556 } else { 557 mAddUserDialog.show(); 558 } 559 } 560 listenForCallState()561 private void listenForCallState() { 562 mTelephonyListenerManager.addCallStateListener(mPhoneStateListener); 563 } 564 565 private final TelephonyCallback.CallStateListener mPhoneStateListener = 566 new TelephonyCallback.CallStateListener() { 567 private int mCallState; 568 569 @Override 570 public void onCallStateChanged(int state) { 571 if (mCallState == state) return; 572 if (DEBUG) Log.v(TAG, "Call state changed: " + state); 573 mCallState = state; 574 refreshUsers(UserHandle.USER_NULL); 575 } 576 }; 577 578 private BroadcastReceiver mReceiver = new BroadcastReceiver() { 579 @Override 580 public void onReceive(Context context, Intent intent) { 581 if (DEBUG) { 582 Log.v(TAG, "Broadcast: a=" + intent.getAction() 583 + " user=" + intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)); 584 } 585 586 boolean unpauseRefreshUsers = false; 587 int forcePictureLoadForId = UserHandle.USER_NULL; 588 589 if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) { 590 if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) { 591 mExitGuestDialog.cancel(); 592 mExitGuestDialog = null; 593 } 594 595 final int currentId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 596 final UserInfo userInfo = mUserManager.getUserInfo(currentId); 597 final int N = mUsers.size(); 598 for (int i = 0; i < N; i++) { 599 UserRecord record = mUsers.get(i); 600 if (record.info == null) continue; 601 boolean shouldBeCurrent = record.info.id == currentId; 602 if (record.isCurrent != shouldBeCurrent) { 603 mUsers.set(i, record.copyWithIsCurrent(shouldBeCurrent)); 604 } 605 if (shouldBeCurrent && !record.isGuest) { 606 mLastNonGuestUser = record.info.id; 607 } 608 if ((userInfo == null || !userInfo.isAdmin()) && record.isRestricted) { 609 // Immediately remove restricted records in case the AsyncTask is too slow. 610 mUsers.remove(i); 611 i--; 612 } 613 } 614 notifyAdapters(); 615 616 // Disconnect from the old secondary user's service 617 if (mSecondaryUser != UserHandle.USER_NULL) { 618 context.stopServiceAsUser(mSecondaryUserServiceIntent, 619 UserHandle.of(mSecondaryUser)); 620 mSecondaryUser = UserHandle.USER_NULL; 621 } 622 // Connect to the new secondary user's service (purely to ensure that a persistent 623 // SystemUI application is created for that user) 624 if (userInfo != null && userInfo.id != UserHandle.USER_SYSTEM) { 625 context.startServiceAsUser(mSecondaryUserServiceIntent, 626 UserHandle.of(userInfo.id)); 627 mSecondaryUser = userInfo.id; 628 } 629 unpauseRefreshUsers = true; 630 if (mGuestUserAutoCreated) { 631 // Guest user must be scheduled for creation AFTER switching to the target user. 632 // This avoids lock contention which will produce UX bugs on the keyguard 633 // (b/193933686). 634 // TODO(b/191067027): Move guest user recreation to system_server 635 guaranteeGuestPresent(); 636 } 637 } else if (Intent.ACTION_USER_INFO_CHANGED.equals(intent.getAction())) { 638 forcePictureLoadForId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 639 UserHandle.USER_NULL); 640 } else if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) { 641 // Unlocking the system user may require a refresh 642 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); 643 if (userId != UserHandle.USER_SYSTEM) { 644 return; 645 } 646 } 647 refreshUsers(forcePictureLoadForId); 648 if (unpauseRefreshUsers) { 649 mUnpauseRefreshUsers.run(); 650 } 651 } 652 }; 653 654 private final Runnable mUnpauseRefreshUsers = new Runnable() { 655 @Override 656 public void run() { 657 mHandler.removeCallbacks(this); 658 mPauseRefreshUsers = false; 659 refreshUsers(UserHandle.USER_NULL); 660 } 661 }; 662 663 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)664 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 665 pw.println("UserSwitcherController state:"); 666 pw.println(" mLastNonGuestUser=" + mLastNonGuestUser); 667 pw.print(" mUsers.size="); pw.println(mUsers.size()); 668 for (int i = 0; i < mUsers.size(); i++) { 669 final UserRecord u = mUsers.get(i); 670 pw.print(" "); pw.println(u.toString()); 671 } 672 pw.println("mSimpleUserSwitcher=" + mSimpleUserSwitcher); 673 pw.println("mGuestUserAutoCreated=" + mGuestUserAutoCreated); 674 } 675 676 /** Returns the name of the current user of the phone. */ getCurrentUserName()677 public String getCurrentUserName() { 678 if (mUsers.isEmpty()) return null; 679 UserRecord item = mUsers.get(0); 680 if (item == null || item.info == null) return null; 681 if (item.isGuest) return mContext.getString( 682 com.android.settingslib.R.string.guest_nickname); 683 return item.info.name; 684 } 685 onDensityOrFontScaleChanged()686 public void onDensityOrFontScaleChanged() { 687 refreshUsers(UserHandle.USER_ALL); 688 } 689 690 @VisibleForTesting addAdapter(WeakReference<BaseUserAdapter> adapter)691 public void addAdapter(WeakReference<BaseUserAdapter> adapter) { 692 mAdapters.add(adapter); 693 } 694 695 @VisibleForTesting getUsers()696 public ArrayList<UserRecord> getUsers() { 697 return mUsers; 698 } 699 700 /** 701 * Removes guest user and switches to target user. The guest must be the current user and its id 702 * must be {@code guestUserId}. 703 * 704 * <p>If {@code targetUserId} is {@link UserHandle.USER_NULL}, then create a new guest user in 705 * the foreground, and immediately switch to it. This is used for wiping the current guest and 706 * replacing it with a new one. 707 * 708 * <p>If {@code targetUserId} is specified, then remove the guest in the background while 709 * switching to {@code targetUserId}. 710 * 711 * <p>If device is configured with {@link 712 * com.android.internal.R.bool.config_guestUserAutoCreated}, then after guest user is removed, a 713 * new one is created in the background. This has no effect if {@code targetUserId} is {@link 714 * UserHandle.USER_NULL}. 715 * 716 * @param guestUserId id of the guest user to remove 717 * @param targetUserId id of the user to switch to after guest is removed. If {@link 718 * UserHandle.USER_NULL}, then switch immediately to the newly created guest user. 719 */ removeGuestUser(@serIdInt int guestUserId, @UserIdInt int targetUserId)720 public void removeGuestUser(@UserIdInt int guestUserId, @UserIdInt int targetUserId) { 721 UserInfo currentUser = mUserTracker.getUserInfo(); 722 if (currentUser.id != guestUserId) { 723 Log.w(TAG, "User requesting to start a new session (" + guestUserId + ")" 724 + " is not current user (" + currentUser.id + ")"); 725 return; 726 } 727 if (!currentUser.isGuest()) { 728 Log.w(TAG, "User requesting to start a new session (" + guestUserId + ")" 729 + " is not a guest"); 730 return; 731 } 732 733 boolean marked = mUserManager.markGuestForDeletion(currentUser.id); 734 if (!marked) { 735 Log.w(TAG, "Couldn't mark the guest for deletion for user " + guestUserId); 736 return; 737 } 738 739 try { 740 if (targetUserId == UserHandle.USER_NULL) { 741 // Create a new guest in the foreground, and then immediately switch to it 742 int newGuestId = createGuest(); 743 if (newGuestId == UserHandle.USER_NULL) { 744 Log.e(TAG, "Could not create new guest, switching back to system user"); 745 switchToUserId(UserHandle.USER_SYSTEM); 746 mUserManager.removeUser(currentUser.id); 747 WindowManagerGlobal.getWindowManagerService().lockNow(/* options= */ null); 748 return; 749 } 750 switchToUserId(newGuestId); 751 mUserManager.removeUser(currentUser.id); 752 } else { 753 if (mGuestUserAutoCreated) { 754 mGuestIsResetting.set(true); 755 } 756 switchToUserId(targetUserId); 757 mUserManager.removeUser(currentUser.id); 758 } 759 } catch (RemoteException e) { 760 Log.e(TAG, "Couldn't remove guest because ActivityManager or WindowManager is dead"); 761 return; 762 } 763 } 764 scheduleGuestCreation()765 private void scheduleGuestCreation() { 766 if (!mGuestCreationScheduled.compareAndSet(false, true)) { 767 return; 768 } 769 770 mBgExecutor.execute(() -> { 771 int newGuestId = createGuest(); 772 mGuestCreationScheduled.set(false); 773 mGuestIsResetting.set(false); 774 if (newGuestId == UserHandle.USER_NULL) { 775 Log.w(TAG, "Could not create new guest while exiting existing guest"); 776 // Refresh users so that we still display "Guest" if 777 // config_guestUserAutoCreated=true 778 refreshUsers(UserHandle.USER_NULL); 779 } 780 }); 781 782 } 783 784 /** 785 * Guarantee guest is present only if the device is provisioned. Otherwise, create a content 786 * observer to wait until the device is provisioned, then schedule the guest creation. 787 */ schedulePostBootGuestCreation()788 public void schedulePostBootGuestCreation() { 789 if (isDeviceAllowedToAddGuest()) { 790 guaranteeGuestPresent(); 791 } else { 792 mDeviceProvisionedController.addCallback(mGuaranteeGuestPresentAfterProvisioned); 793 } 794 } 795 isDeviceAllowedToAddGuest()796 private boolean isDeviceAllowedToAddGuest() { 797 return mDeviceProvisionedController.isDeviceProvisioned() 798 && !mDevicePolicyManager.isDeviceManaged(); 799 } 800 801 /** 802 * If there is no guest on the device, schedule creation of a new guest user in the background. 803 */ guaranteeGuestPresent()804 private void guaranteeGuestPresent() { 805 if (isDeviceAllowedToAddGuest() && mUserManager.findCurrentGuestUser() == null) { 806 scheduleGuestCreation(); 807 } 808 } 809 810 /** 811 * Creates a guest user and return its multi-user user ID. 812 * 813 * This method does not check if a guest already exists before it makes a call to 814 * {@link UserManager} to create a new one. 815 * 816 * @return The multi-user user ID of the newly created guest user, or 817 * {@link UserHandle.USER_NULL} if the guest couldn't be created. 818 */ createGuest()819 public @UserIdInt int createGuest() { 820 UserInfo guest; 821 try { 822 guest = mUserManager.createGuest(mContext, 823 mContext.getString(com.android.settingslib.R.string.guest_nickname)); 824 } catch (UserManager.UserOperationException e) { 825 Log.e(TAG, "Couldn't create guest user", e); 826 return UserHandle.USER_NULL; 827 } 828 if (guest == null) { 829 Log.e(TAG, "Couldn't create guest, most likely because there already exists one"); 830 return UserHandle.USER_NULL; 831 } 832 return guest.id; 833 } 834 init(NotificationShadeWindowView notificationShadeWindowView)835 public void init(NotificationShadeWindowView notificationShadeWindowView) { 836 mRootView = notificationShadeWindowView; 837 } 838 839 public static abstract class BaseUserAdapter extends BaseAdapter { 840 841 final UserSwitcherController mController; 842 private final KeyguardStateController mKeyguardStateController; 843 BaseUserAdapter(UserSwitcherController controller)844 protected BaseUserAdapter(UserSwitcherController controller) { 845 mController = controller; 846 mKeyguardStateController = controller.mKeyguardStateController; 847 controller.addAdapter(new WeakReference<>(this)); 848 } 849 getUsers()850 protected ArrayList<UserRecord> getUsers() { 851 return mController.getUsers(); 852 } 853 getUserCount()854 public int getUserCount() { 855 return countUsers(false); 856 } 857 858 @Override getCount()859 public int getCount() { 860 return countUsers(true); 861 } 862 countUsers(boolean includeGuest)863 private int countUsers(boolean includeGuest) { 864 boolean keyguardShowing = mKeyguardStateController.isShowing(); 865 final int userSize = getUsers().size(); 866 int count = 0; 867 for (int i = 0; i < userSize; i++) { 868 if (getUsers().get(i).isGuest && !includeGuest) { 869 continue; 870 } 871 if (getUsers().get(i).isRestricted && keyguardShowing) { 872 break; 873 } 874 count++; 875 } 876 return count; 877 } 878 879 @Override getItem(int position)880 public UserRecord getItem(int position) { 881 return getUsers().get(position); 882 } 883 884 @Override getItemId(int position)885 public long getItemId(int position) { 886 return position; 887 } 888 889 /** 890 * It handles click events on user list items. 891 * 892 * If the user switcher is hosted in a dialog, passing a non-null {@link DialogShower} 893 * will allow animation to and from the parent dialog. 894 * 895 */ onUserListItemClicked(UserRecord record, @Nullable DialogShower dialogShower)896 public void onUserListItemClicked(UserRecord record, @Nullable DialogShower dialogShower) { 897 mController.onUserListItemClicked(record, dialogShower); 898 } 899 onUserListItemClicked(UserRecord record)900 public void onUserListItemClicked(UserRecord record) { 901 onUserListItemClicked(record, null); 902 } 903 getName(Context context, UserRecord item)904 public String getName(Context context, UserRecord item) { 905 if (item.isGuest) { 906 if (item.isCurrent) { 907 return context.getString(mController.mGuestUserAutoCreated 908 ? com.android.settingslib.R.string.guest_reset_guest 909 : com.android.settingslib.R.string.guest_exit_guest); 910 } else { 911 if (item.info != null) { 912 return context.getString(com.android.settingslib.R.string.guest_nickname); 913 } else { 914 if (mController.mGuestUserAutoCreated) { 915 // If mGuestIsResetting=true, we expect the guest user to be created 916 // shortly, so display a "Resetting guest..." as an indicator that we 917 // are busy. Otherwise, if mGuestIsResetting=false, we probably failed 918 // to create a guest at some point. In this case, always show guest 919 // nickname instead of "Add guest" to make it seem as though the device 920 // always has a guest ready for use. 921 return context.getString( 922 mController.mGuestIsResetting.get() 923 ? com.android.settingslib.R.string.guest_resetting 924 : com.android.settingslib.R.string.guest_nickname); 925 } else { 926 return context.getString( 927 com.android.settingslib.R.string.guest_new_guest); 928 } 929 } 930 } 931 } else if (item.isAddUser) { 932 return context.getString(R.string.user_add_user); 933 } else { 934 return item.info.name; 935 } 936 } 937 getDisabledUserAvatarColorFilter()938 protected static ColorFilter getDisabledUserAvatarColorFilter() { 939 ColorMatrix matrix = new ColorMatrix(); 940 matrix.setSaturation(0f); // 0 - grayscale 941 return new ColorMatrixColorFilter(matrix); 942 } 943 getIconDrawable(Context context, UserRecord item)944 protected static Drawable getIconDrawable(Context context, UserRecord item) { 945 int iconRes; 946 if (item.isAddUser) { 947 iconRes = R.drawable.ic_add_circle; 948 } else if (item.isGuest) { 949 iconRes = R.drawable.ic_avatar_guest_user; 950 } else { 951 iconRes = R.drawable.ic_avatar_user; 952 } 953 954 return context.getDrawable(iconRes); 955 } 956 refresh()957 public void refresh() { 958 mController.refreshUsers(UserHandle.USER_NULL); 959 } 960 } 961 checkIfAddUserDisallowedByAdminOnly(UserRecord record)962 private void checkIfAddUserDisallowedByAdminOnly(UserRecord record) { 963 EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(mContext, 964 UserManager.DISALLOW_ADD_USER, mUserTracker.getUserId()); 965 if (admin != null && !RestrictedLockUtilsInternal.hasBaseUserRestriction(mContext, 966 UserManager.DISALLOW_ADD_USER, mUserTracker.getUserId())) { 967 record.isDisabledByAdmin = true; 968 record.enforcedAdmin = admin; 969 } else { 970 record.isDisabledByAdmin = false; 971 record.enforcedAdmin = null; 972 } 973 } 974 shouldUseSimpleUserSwitcher()975 private boolean shouldUseSimpleUserSwitcher() { 976 int defaultSimpleUserSwitcher = mContext.getResources().getBoolean( 977 com.android.internal.R.bool.config_expandLockScreenUserSwitcher) ? 1 : 0; 978 return Settings.Global.getInt(mContext.getContentResolver(), 979 SIMPLE_USER_SWITCHER_GLOBAL_SETTING, defaultSimpleUserSwitcher) != 0; 980 } 981 startActivity(Intent intent)982 public void startActivity(Intent intent) { 983 mActivityStarter.startActivity(intent, true); 984 } 985 986 public static final class UserRecord { 987 public final UserInfo info; 988 public final Bitmap picture; 989 public final boolean isGuest; 990 public final boolean isCurrent; 991 public final boolean isAddUser; 992 /** If true, the record is only visible to the owner and only when unlocked. */ 993 public final boolean isRestricted; 994 public boolean isDisabledByAdmin; 995 public EnforcedAdmin enforcedAdmin; 996 public boolean isSwitchToEnabled; 997 UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent, boolean isAddUser, boolean isRestricted, boolean isSwitchToEnabled)998 public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent, 999 boolean isAddUser, boolean isRestricted, boolean isSwitchToEnabled) { 1000 this.info = info; 1001 this.picture = picture; 1002 this.isGuest = isGuest; 1003 this.isCurrent = isCurrent; 1004 this.isAddUser = isAddUser; 1005 this.isRestricted = isRestricted; 1006 this.isSwitchToEnabled = isSwitchToEnabled; 1007 } 1008 copyWithIsCurrent(boolean _isCurrent)1009 public UserRecord copyWithIsCurrent(boolean _isCurrent) { 1010 return new UserRecord(info, picture, isGuest, _isCurrent, isAddUser, isRestricted, 1011 isSwitchToEnabled); 1012 } 1013 resolveId()1014 public int resolveId() { 1015 if (isGuest || info == null) { 1016 return UserHandle.USER_NULL; 1017 } 1018 return info.id; 1019 } 1020 toString()1021 public String toString() { 1022 StringBuilder sb = new StringBuilder(); 1023 sb.append("UserRecord("); 1024 if (info != null) { 1025 sb.append("name=\"").append(info.name).append("\" id=").append(info.id); 1026 } else { 1027 if (isGuest) { 1028 sb.append("<add guest placeholder>"); 1029 } else if (isAddUser) { 1030 sb.append("<add user placeholder>"); 1031 } 1032 } 1033 if (isGuest) sb.append(" <isGuest>"); 1034 if (isAddUser) sb.append(" <isAddUser>"); 1035 if (isCurrent) sb.append(" <isCurrent>"); 1036 if (picture != null) sb.append(" <hasPicture>"); 1037 if (isRestricted) sb.append(" <isRestricted>"); 1038 if (isDisabledByAdmin) { 1039 sb.append(" <isDisabledByAdmin>"); 1040 sb.append(" enforcedAdmin=").append(enforcedAdmin); 1041 } 1042 if (isSwitchToEnabled) { 1043 sb.append(" <isSwitchToEnabled>"); 1044 } 1045 sb.append(')'); 1046 return sb.toString(); 1047 } 1048 } 1049 1050 public static class UserDetailAdapter implements DetailAdapter { 1051 private final Intent USER_SETTINGS_INTENT = new Intent(Settings.ACTION_USER_SETTINGS); 1052 1053 private final Context mContext; 1054 private final Provider<UserDetailView.Adapter> mUserDetailViewAdapterProvider; 1055 1056 @Inject UserDetailAdapter(Context context, Provider<UserDetailView.Adapter> userDetailViewAdapterProvider)1057 UserDetailAdapter(Context context, 1058 Provider<UserDetailView.Adapter> userDetailViewAdapterProvider) { 1059 mContext = context; 1060 mUserDetailViewAdapterProvider = userDetailViewAdapterProvider; 1061 } 1062 1063 @Override getTitle()1064 public CharSequence getTitle() { 1065 return mContext.getString(R.string.quick_settings_user_title); 1066 } 1067 1068 @Override createDetailView(Context context, View convertView, ViewGroup parent)1069 public View createDetailView(Context context, View convertView, ViewGroup parent) { 1070 UserDetailView v; 1071 if (!(convertView instanceof UserDetailView)) { 1072 v = UserDetailView.inflate(context, parent, false); 1073 v.setAdapter(mUserDetailViewAdapterProvider.get()); 1074 } else { 1075 v = (UserDetailView) convertView; 1076 } 1077 v.refreshAdapter(); 1078 return v; 1079 } 1080 1081 @Override getSettingsIntent()1082 public Intent getSettingsIntent() { 1083 return USER_SETTINGS_INTENT; 1084 } 1085 1086 @Override getSettingsText()1087 public int getSettingsText() { 1088 return R.string.quick_settings_more_user_settings; 1089 } 1090 1091 @Override getToggleState()1092 public Boolean getToggleState() { 1093 return null; 1094 } 1095 1096 @Override setToggleState(boolean state)1097 public void setToggleState(boolean state) { 1098 } 1099 1100 @Override getMetricsCategory()1101 public int getMetricsCategory() { 1102 return MetricsEvent.QS_USERDETAIL; 1103 } 1104 1105 @Override openDetailEvent()1106 public UiEventLogger.UiEventEnum openDetailEvent() { 1107 return QSUserSwitcherEvent.QS_USER_DETAIL_OPEN; 1108 } 1109 1110 @Override closeDetailEvent()1111 public UiEventLogger.UiEventEnum closeDetailEvent() { 1112 return QSUserSwitcherEvent.QS_USER_DETAIL_CLOSE; 1113 } 1114 1115 @Override moreSettingsEvent()1116 public UiEventLogger.UiEventEnum moreSettingsEvent() { 1117 return QSUserSwitcherEvent.QS_USER_MORE_SETTINGS; 1118 } 1119 }; 1120 1121 private final KeyguardStateController.Callback mCallback = 1122 new KeyguardStateController.Callback() { 1123 @Override 1124 public void onKeyguardShowingChanged() { 1125 1126 // When Keyguard is going away, we don't need to update our items immediately 1127 // which 1128 // helps making the transition faster. 1129 if (!mKeyguardStateController.isShowing()) { 1130 mHandler.post(UserSwitcherController.this::notifyAdapters); 1131 } else { 1132 notifyAdapters(); 1133 } 1134 } 1135 }; 1136 1137 private final DeviceProvisionedController.DeviceProvisionedListener 1138 mGuaranteeGuestPresentAfterProvisioned = 1139 new DeviceProvisionedController.DeviceProvisionedListener() { 1140 @Override 1141 public void onDeviceProvisionedChanged() { 1142 if (isDeviceAllowedToAddGuest()) { 1143 mBgExecutor.execute( 1144 () -> mDeviceProvisionedController.removeCallback( 1145 mGuaranteeGuestPresentAfterProvisioned)); 1146 guaranteeGuestPresent(); 1147 } 1148 } 1149 }; 1150 1151 1152 private final class ExitGuestDialog extends SystemUIDialog implements 1153 DialogInterface.OnClickListener { 1154 1155 private final int mGuestId; 1156 private final int mTargetId; 1157 ExitGuestDialog(Context context, int guestId, int targetId)1158 public ExitGuestDialog(Context context, int guestId, int targetId) { 1159 super(context); 1160 setTitle(mGuestUserAutoCreated 1161 ? com.android.settingslib.R.string.guest_reset_guest_dialog_title 1162 : R.string.guest_exit_guest_dialog_title); 1163 setMessage(context.getString(R.string.guest_exit_guest_dialog_message)); 1164 setButton(DialogInterface.BUTTON_NEUTRAL, 1165 context.getString(android.R.string.cancel), this); 1166 setButton(DialogInterface.BUTTON_POSITIVE, 1167 context.getString(mGuestUserAutoCreated 1168 ? com.android.settingslib.R.string.guest_reset_guest_confirm_button 1169 : R.string.guest_exit_guest_dialog_remove), this); 1170 SystemUIDialog.setWindowOnTop(this); 1171 setCanceledOnTouchOutside(false); 1172 mGuestId = guestId; 1173 mTargetId = targetId; 1174 } 1175 1176 @Override onClick(DialogInterface dialog, int which)1177 public void onClick(DialogInterface dialog, int which) { 1178 int penalty = which == BUTTON_NEGATIVE ? FalsingManager.NO_PENALTY 1179 : FalsingManager.HIGH_PENALTY; 1180 if (mFalsingManager.isFalseTap(penalty)) { 1181 return; 1182 } 1183 if (which == BUTTON_NEUTRAL) { 1184 cancel(); 1185 } else { 1186 mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE); 1187 mDialogLaunchAnimator.dismissStack(this); 1188 removeGuestUser(mGuestId, mTargetId); 1189 } 1190 } 1191 } 1192 1193 @VisibleForTesting 1194 final class AddUserDialog extends SystemUIDialog implements 1195 DialogInterface.OnClickListener { 1196 AddUserDialog(Context context)1197 public AddUserDialog(Context context) { 1198 super(context); 1199 setTitle(R.string.user_add_user_title); 1200 setMessage(context.getString(R.string.user_add_user_message_short)); 1201 setButton(DialogInterface.BUTTON_NEUTRAL, 1202 context.getString(android.R.string.cancel), this); 1203 setButton(DialogInterface.BUTTON_POSITIVE, 1204 context.getString(android.R.string.ok), this); 1205 SystemUIDialog.setWindowOnTop(this); 1206 } 1207 1208 @Override onClick(DialogInterface dialog, int which)1209 public void onClick(DialogInterface dialog, int which) { 1210 int penalty = which == BUTTON_NEGATIVE ? FalsingManager.NO_PENALTY 1211 : FalsingManager.MODERATE_PENALTY; 1212 if (mFalsingManager.isFalseTap(penalty)) { 1213 return; 1214 } 1215 if (which == BUTTON_NEUTRAL) { 1216 cancel(); 1217 } else { 1218 mDialogLaunchAnimator.dismissStack(this); 1219 if (ActivityManager.isUserAMonkey()) { 1220 return; 1221 } 1222 Intent intent = CreateUserActivity.createIntentForStart(getContext()); 1223 1224 // There are some differences between ActivityStarter and ActivityTaskManager in 1225 // terms of how they start an activity. ActivityStarter hides the notification bar 1226 // before starting the activity to make sure nothing is in front of the new 1227 // activity. ActivityStarter also tries to unlock the device if it's locked. 1228 // When locked with PIN/pattern/password then it shows the prompt, if there are no 1229 // security steps then it dismisses the keyguard and then starts the activity. 1230 // ActivityTaskManager doesn't hide the notification bar or unlocks the device, but 1231 // it can start an activity on top of the locked screen. 1232 if (!mKeyguardStateController.isUnlocked() 1233 && !mKeyguardStateController.canDismissLockScreen()) { 1234 // Device is locked and can't be unlocked without a PIN/pattern/password so we 1235 // need to use ActivityTaskManager to start the activity on top of the locked 1236 // screen. 1237 try { 1238 mActivityTaskManager.startActivity(null, 1239 mContext.getBasePackageName(), mContext.getAttributionTag(), intent, 1240 intent.resolveTypeIfNeeded(mContext.getContentResolver()), null, 1241 null, 0, 0, null, null); 1242 } catch (RemoteException e) { 1243 e.printStackTrace(); 1244 Log.e(TAG, "Couldn't start create user activity", e); 1245 } 1246 } else { 1247 mActivityStarter.startActivity(intent, true); 1248 } 1249 } 1250 } 1251 } 1252 } 1253