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