1 /* 2 * Copyright (C) 2018 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 package com.android.systemui.statusbar; 17 18 import static android.app.Notification.VISIBILITY_SECRET; 19 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED; 20 21 import static com.android.systemui.DejankUtils.whitelistIpcs; 22 import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_MEDIA_CONTROLS; 23 import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT; 24 25 import android.app.ActivityManager; 26 import android.app.KeyguardManager; 27 import android.app.Notification; 28 import android.app.NotificationManager; 29 import android.app.admin.DevicePolicyManager; 30 import android.content.BroadcastReceiver; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.content.IntentFilter; 34 import android.content.IntentSender; 35 import android.content.pm.UserInfo; 36 import android.database.ContentObserver; 37 import android.os.Handler; 38 import android.os.UserHandle; 39 import android.os.UserManager; 40 import android.provider.Settings; 41 import android.util.Log; 42 import android.util.SparseArray; 43 import android.util.SparseBooleanArray; 44 45 import com.android.internal.statusbar.NotificationVisibility; 46 import com.android.internal.widget.LockPatternUtils; 47 import com.android.keyguard.KeyguardUpdateMonitor; 48 import com.android.systemui.Dependency; 49 import com.android.systemui.Dumpable; 50 import com.android.systemui.broadcast.BroadcastDispatcher; 51 import com.android.systemui.dagger.qualifiers.Main; 52 import com.android.systemui.plugins.statusbar.StatusBarStateController; 53 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; 54 import com.android.systemui.recents.OverviewProxyService; 55 import com.android.systemui.statusbar.notification.NotificationEntryManager; 56 import com.android.systemui.statusbar.notification.NotificationUtils; 57 import com.android.systemui.statusbar.notification.collection.NotificationEntry; 58 import com.android.systemui.statusbar.notification.logging.NotificationLogger; 59 import com.android.systemui.statusbar.policy.DeviceProvisionedController; 60 import com.android.systemui.statusbar.policy.KeyguardStateController; 61 62 import java.io.FileDescriptor; 63 import java.io.PrintWriter; 64 import java.util.ArrayList; 65 import java.util.List; 66 67 import javax.inject.Inject; 68 import javax.inject.Singleton; 69 70 /** 71 * Handles keeping track of the current user, profiles, and various things related to hiding 72 * contents, redacting notifications, and the lockscreen. 73 */ 74 @Singleton 75 public class NotificationLockscreenUserManagerImpl implements 76 Dumpable, NotificationLockscreenUserManager, StateListener { 77 private static final String TAG = "LockscreenUserManager"; 78 private static final boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false; 79 80 private final DeviceProvisionedController mDeviceProvisionedController; 81 private final KeyguardStateController mKeyguardStateController; 82 private final Object mLock = new Object(); 83 84 // Lazy 85 private NotificationEntryManager mEntryManager; 86 87 private final DevicePolicyManager mDevicePolicyManager; 88 private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray(); 89 private final SparseBooleanArray mUsersWithSeperateWorkChallenge = new SparseBooleanArray(); 90 private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray(); 91 private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray(); 92 private final UserManager mUserManager; 93 private final List<UserChangedListener> mListeners = new ArrayList<>(); 94 private final BroadcastDispatcher mBroadcastDispatcher; 95 private final NotificationClickNotifier mClickNotifier; 96 97 private boolean mShowLockscreenNotifications; 98 private boolean mAllowLockscreenRemoteInput; 99 private LockPatternUtils mLockPatternUtils; 100 protected KeyguardManager mKeyguardManager; 101 private int mState = StatusBarState.SHADE; 102 103 protected final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() { 104 @Override 105 public void onReceive(Context context, Intent intent) { 106 final String action = intent.getAction(); 107 108 if (ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) && 109 isCurrentProfile(getSendingUserId())) { 110 mUsersAllowingPrivateNotifications.clear(); 111 updateLockscreenNotificationSetting(); 112 getEntryManager().updateNotifications("ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED"); 113 } 114 } 115 }; 116 117 protected final BroadcastReceiver mBaseBroadcastReceiver = new BroadcastReceiver() { 118 @Override 119 public void onReceive(Context context, Intent intent) { 120 String action = intent.getAction(); 121 switch (action) { 122 case Intent.ACTION_USER_SWITCHED: 123 mCurrentUserId = intent.getIntExtra( 124 Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL); 125 updateCurrentProfilesCache(); 126 127 Log.v(TAG, "userId " + mCurrentUserId + " is in the house"); 128 129 updateLockscreenNotificationSetting(); 130 updatePublicMode(); 131 // The filtering needs to happen before the update call below in order to 132 // make sure 133 // the presenter has the updated notifications from the new user 134 getEntryManager().reapplyFilterAndSort("user switched"); 135 mPresenter.onUserSwitched(mCurrentUserId); 136 137 for (UserChangedListener listener : mListeners) { 138 listener.onUserChanged(mCurrentUserId); 139 } 140 break; 141 case Intent.ACTION_USER_ADDED: 142 case Intent.ACTION_MANAGED_PROFILE_AVAILABLE: 143 case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE: 144 updateCurrentProfilesCache(); 145 break; 146 case Intent.ACTION_USER_UNLOCKED: 147 // Start the overview connection to the launcher service 148 Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser(); 149 break; 150 case NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION: 151 final IntentSender intentSender = intent.getParcelableExtra( 152 Intent.EXTRA_INTENT); 153 final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX); 154 if (intentSender != null) { 155 try { 156 mContext.startIntentSender(intentSender, null, 0, 0, 0); 157 } catch (IntentSender.SendIntentException e) { 158 /* ignore */ 159 } 160 } 161 if (notificationKey != null) { 162 NotificationEntry entry = 163 getEntryManager().getActiveNotificationUnfiltered(notificationKey); 164 final int count = getEntryManager().getActiveNotificationsCount(); 165 final int rank = entry != null ? entry.getRanking().getRank() : 0; 166 NotificationVisibility.NotificationLocation location = 167 NotificationLogger.getNotificationLocation(entry); 168 final NotificationVisibility nv = NotificationVisibility.obtain( 169 notificationKey, 170 rank, count, true, location); 171 mClickNotifier.onNotificationClick(notificationKey, nv); 172 } 173 break; 174 } 175 } 176 }; 177 178 protected final Context mContext; 179 private final Handler mMainHandler; 180 protected final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>(); 181 protected final SparseArray<UserInfo> mCurrentManagedProfiles = new SparseArray<>(); 182 183 protected int mCurrentUserId = 0; 184 protected NotificationPresenter mPresenter; 185 protected ContentObserver mLockscreenSettingsObserver; 186 protected ContentObserver mSettingsObserver; 187 getEntryManager()188 private NotificationEntryManager getEntryManager() { 189 if (mEntryManager == null) { 190 mEntryManager = Dependency.get(NotificationEntryManager.class); 191 } 192 return mEntryManager; 193 } 194 195 @Inject NotificationLockscreenUserManagerImpl(Context context, BroadcastDispatcher broadcastDispatcher, DevicePolicyManager devicePolicyManager, UserManager userManager, NotificationClickNotifier clickNotifier, KeyguardManager keyguardManager, StatusBarStateController statusBarStateController, @Main Handler mainHandler, DeviceProvisionedController deviceProvisionedController, KeyguardStateController keyguardStateController)196 public NotificationLockscreenUserManagerImpl(Context context, 197 BroadcastDispatcher broadcastDispatcher, 198 DevicePolicyManager devicePolicyManager, 199 UserManager userManager, 200 NotificationClickNotifier clickNotifier, 201 KeyguardManager keyguardManager, 202 StatusBarStateController statusBarStateController, 203 @Main Handler mainHandler, 204 DeviceProvisionedController deviceProvisionedController, 205 KeyguardStateController keyguardStateController) { 206 mContext = context; 207 mMainHandler = mainHandler; 208 mDevicePolicyManager = devicePolicyManager; 209 mUserManager = userManager; 210 mCurrentUserId = ActivityManager.getCurrentUser(); 211 mClickNotifier = clickNotifier; 212 statusBarStateController.addCallback(this); 213 mLockPatternUtils = new LockPatternUtils(context); 214 mKeyguardManager = keyguardManager; 215 mBroadcastDispatcher = broadcastDispatcher; 216 mDeviceProvisionedController = deviceProvisionedController; 217 mKeyguardStateController = keyguardStateController; 218 } 219 setUpWithPresenter(NotificationPresenter presenter)220 public void setUpWithPresenter(NotificationPresenter presenter) { 221 mPresenter = presenter; 222 223 mLockscreenSettingsObserver = new ContentObserver(mMainHandler) { 224 @Override 225 public void onChange(boolean selfChange) { 226 // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS or 227 // LOCK_SCREEN_SHOW_NOTIFICATIONS, so we just dump our cache ... 228 mUsersAllowingPrivateNotifications.clear(); 229 mUsersAllowingNotifications.clear(); 230 // ... and refresh all the notifications 231 updateLockscreenNotificationSetting(); 232 getEntryManager().updateNotifications("LOCK_SCREEN_SHOW_NOTIFICATIONS," 233 + " or LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS change"); 234 } 235 }; 236 237 mSettingsObserver = new ContentObserver(mMainHandler) { 238 @Override 239 public void onChange(boolean selfChange) { 240 updateLockscreenNotificationSetting(); 241 if (mDeviceProvisionedController.isDeviceProvisioned()) { 242 getEntryManager().updateNotifications("LOCK_SCREEN_ALLOW_REMOTE_INPUT" 243 + " or ZEN_MODE change"); 244 } 245 } 246 }; 247 248 mContext.getContentResolver().registerContentObserver( 249 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false, 250 mLockscreenSettingsObserver, 251 UserHandle.USER_ALL); 252 253 mContext.getContentResolver().registerContentObserver( 254 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS), 255 true, 256 mLockscreenSettingsObserver, 257 UserHandle.USER_ALL); 258 259 mContext.getContentResolver().registerContentObserver( 260 Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false, 261 mSettingsObserver); 262 263 if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) { 264 mContext.getContentResolver().registerContentObserver( 265 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT), 266 false, 267 mSettingsObserver, 268 UserHandle.USER_ALL); 269 } 270 271 mBroadcastDispatcher.registerReceiver(mAllUsersReceiver, 272 new IntentFilter(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), 273 null /* handler */, UserHandle.ALL); 274 275 IntentFilter filter = new IntentFilter(); 276 filter.addAction(Intent.ACTION_USER_SWITCHED); 277 filter.addAction(Intent.ACTION_USER_ADDED); 278 filter.addAction(Intent.ACTION_USER_UNLOCKED); 279 filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE); 280 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); 281 mBroadcastDispatcher.registerReceiver(mBaseBroadcastReceiver, filter, 282 null /* executor */, UserHandle.ALL); 283 284 IntentFilter internalFilter = new IntentFilter(); 285 internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION); 286 mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null); 287 288 updateCurrentProfilesCache(); 289 290 mSettingsObserver.onChange(false); // set up 291 } 292 shouldShowLockscreenNotifications()293 public boolean shouldShowLockscreenNotifications() { 294 return mShowLockscreenNotifications; 295 } 296 shouldAllowLockscreenRemoteInput()297 public boolean shouldAllowLockscreenRemoteInput() { 298 return mAllowLockscreenRemoteInput; 299 } 300 isCurrentProfile(int userId)301 public boolean isCurrentProfile(int userId) { 302 synchronized (mLock) { 303 return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null; 304 } 305 } 306 307 /** 308 * Returns true if notifications are temporarily disabled for this user for security reasons, 309 * regardless of the normal settings for that user. 310 */ shouldTemporarilyHideNotifications(int userId)311 private boolean shouldTemporarilyHideNotifications(int userId) { 312 if (userId == UserHandle.USER_ALL) { 313 userId = mCurrentUserId; 314 } 315 return Dependency.get(KeyguardUpdateMonitor.class).isUserInLockdown(userId); 316 } 317 318 /** 319 * Returns true if we're on a secure lockscreen and the user wants to hide notification data. 320 * If so, notifications should be hidden. 321 */ shouldHideNotifications(int userId)322 public boolean shouldHideNotifications(int userId) { 323 return isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId) 324 || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId)) 325 || shouldTemporarilyHideNotifications(userId); 326 } 327 328 /** 329 * Returns true if we're on a secure lockscreen and the user wants to hide notifications via 330 * package-specific override. 331 */ shouldHideNotifications(String key)332 public boolean shouldHideNotifications(String key) { 333 if (getEntryManager() == null) { 334 Log.wtf(TAG, "mEntryManager was null!", new Throwable()); 335 return true; 336 } 337 NotificationEntry visibleEntry = getEntryManager().getActiveNotificationUnfiltered(key); 338 return isLockscreenPublicMode(mCurrentUserId) && visibleEntry != null 339 && visibleEntry.getRanking().getVisibilityOverride() == VISIBILITY_SECRET; 340 } 341 shouldShowOnKeyguard(NotificationEntry entry)342 public boolean shouldShowOnKeyguard(NotificationEntry entry) { 343 if (getEntryManager() == null) { 344 Log.wtf(TAG, "mEntryManager was null!", new Throwable()); 345 return false; 346 } 347 boolean exceedsPriorityThreshold; 348 if (NotificationUtils.useNewInterruptionModel(mContext) 349 && hideSilentNotificationsOnLockscreen()) { 350 exceedsPriorityThreshold = 351 entry.getBucket() == BUCKET_MEDIA_CONTROLS 352 || (entry.getBucket() != BUCKET_SILENT 353 && entry.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT); 354 } else { 355 exceedsPriorityThreshold = !entry.getRanking().isAmbient(); 356 } 357 return mShowLockscreenNotifications && exceedsPriorityThreshold; 358 } 359 hideSilentNotificationsOnLockscreen()360 private boolean hideSilentNotificationsOnLockscreen() { 361 return whitelistIpcs(() -> Settings.Secure.getInt(mContext.getContentResolver(), 362 Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1) == 0); 363 } 364 setShowLockscreenNotifications(boolean show)365 private void setShowLockscreenNotifications(boolean show) { 366 mShowLockscreenNotifications = show; 367 } 368 setLockscreenAllowRemoteInput(boolean allowLockscreenRemoteInput)369 private void setLockscreenAllowRemoteInput(boolean allowLockscreenRemoteInput) { 370 mAllowLockscreenRemoteInput = allowLockscreenRemoteInput; 371 } 372 updateLockscreenNotificationSetting()373 protected void updateLockscreenNotificationSetting() { 374 final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(), 375 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 376 1, 377 mCurrentUserId) != 0; 378 final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures( 379 null /* admin */, mCurrentUserId); 380 final boolean allowedByDpm = (dpmFlags 381 & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0; 382 383 setShowLockscreenNotifications(show && allowedByDpm); 384 385 if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) { 386 final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(), 387 Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT, 388 0, 389 mCurrentUserId) != 0; 390 final boolean remoteInputDpm = 391 (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0; 392 393 setLockscreenAllowRemoteInput(remoteInput && remoteInputDpm); 394 } else { 395 setLockscreenAllowRemoteInput(false); 396 } 397 } 398 399 /** 400 * Has the given user chosen to allow their private (full) notifications to be shown even 401 * when the lockscreen is in "public" (secure & locked) mode? 402 */ userAllowsPrivateNotificationsInPublic(int userHandle)403 public boolean userAllowsPrivateNotificationsInPublic(int userHandle) { 404 if (userHandle == UserHandle.USER_ALL) { 405 return true; 406 } 407 408 if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) { 409 final boolean allowedByUser = 0 != Settings.Secure.getIntForUser( 410 mContext.getContentResolver(), 411 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle); 412 final boolean allowedByDpm = adminAllowsKeyguardFeature(userHandle, 413 DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS); 414 final boolean allowed = allowedByUser && allowedByDpm; 415 mUsersAllowingPrivateNotifications.append(userHandle, allowed); 416 return allowed; 417 } 418 419 return mUsersAllowingPrivateNotifications.get(userHandle); 420 } 421 422 /** 423 * If all managed profiles (work profiles) can show private data in public (secure & locked.) 424 */ allowsManagedPrivateNotificationsInPublic()425 public boolean allowsManagedPrivateNotificationsInPublic() { 426 synchronized (mLock) { 427 for (int i = mCurrentManagedProfiles.size() - 1; i >= 0; i--) { 428 if (!userAllowsPrivateNotificationsInPublic( 429 mCurrentManagedProfiles.valueAt(i).id)) { 430 return false; 431 } 432 } 433 } 434 return true; 435 } 436 adminAllowsKeyguardFeature(int userHandle, int feature)437 private boolean adminAllowsKeyguardFeature(int userHandle, int feature) { 438 if (userHandle == UserHandle.USER_ALL) { 439 return true; 440 } 441 final int dpmFlags = 442 mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */, userHandle); 443 return (dpmFlags & feature) == 0; 444 } 445 446 /** 447 * Save the current "public" (locked and secure) state of the lockscreen. 448 */ setLockscreenPublicMode(boolean publicMode, int userId)449 public void setLockscreenPublicMode(boolean publicMode, int userId) { 450 mLockscreenPublicMode.put(userId, publicMode); 451 } 452 isLockscreenPublicMode(int userId)453 public boolean isLockscreenPublicMode(int userId) { 454 if (userId == UserHandle.USER_ALL) { 455 return mLockscreenPublicMode.get(mCurrentUserId, false); 456 } 457 return mLockscreenPublicMode.get(userId, false); 458 } 459 460 @Override needsSeparateWorkChallenge(int userId)461 public boolean needsSeparateWorkChallenge(int userId) { 462 return mUsersWithSeperateWorkChallenge.get(userId, false); 463 } 464 465 /** 466 * Has the given user chosen to allow notifications to be shown even when the lockscreen is in 467 * "public" (secure & locked) mode? 468 */ userAllowsNotificationsInPublic(int userHandle)469 public boolean userAllowsNotificationsInPublic(int userHandle) { 470 if (isCurrentProfile(userHandle) && userHandle != mCurrentUserId) { 471 return true; 472 } 473 474 if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) { 475 final boolean allowedByUser = 0 != Settings.Secure.getIntForUser( 476 mContext.getContentResolver(), 477 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle); 478 final boolean allowedByDpm = adminAllowsKeyguardFeature(userHandle, 479 DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS); 480 final boolean allowedBySystem = mKeyguardManager.getPrivateNotificationsAllowed(); 481 final boolean allowed = allowedByUser && allowedByDpm && allowedBySystem; 482 mUsersAllowingNotifications.append(userHandle, allowed); 483 return allowed; 484 } 485 486 return mUsersAllowingNotifications.get(userHandle); 487 } 488 489 /** @return true if the entry needs redaction when on the lockscreen. */ needsRedaction(NotificationEntry ent)490 public boolean needsRedaction(NotificationEntry ent) { 491 int userId = ent.getSbn().getUserId(); 492 493 boolean isCurrentUserRedactingNotifs = 494 !userAllowsPrivateNotificationsInPublic(mCurrentUserId); 495 boolean isNotifForManagedProfile = mCurrentManagedProfiles.contains(userId); 496 boolean isNotifUserRedacted = !userAllowsPrivateNotificationsInPublic(userId); 497 498 // redact notifications if the current user is redacting notifications; however if the 499 // notification is associated with a managed profile, we rely on the managed profile 500 // setting to determine whether to redact it 501 boolean isNotifRedacted = (!isNotifForManagedProfile && isCurrentUserRedactingNotifs) 502 || isNotifUserRedacted; 503 504 boolean notificationRequestsRedaction = 505 ent.getSbn().getNotification().visibility == Notification.VISIBILITY_PRIVATE; 506 boolean userForcesRedaction = packageHasVisibilityOverride(ent.getSbn().getKey()); 507 508 return userForcesRedaction || notificationRequestsRedaction && isNotifRedacted; 509 } 510 packageHasVisibilityOverride(String key)511 private boolean packageHasVisibilityOverride(String key) { 512 if (getEntryManager() == null) { 513 Log.wtf(TAG, "mEntryManager was null!", new Throwable()); 514 return true; 515 } 516 NotificationEntry entry = getEntryManager().getActiveNotificationUnfiltered(key); 517 return entry != null 518 && entry.getRanking().getVisibilityOverride() == Notification.VISIBILITY_PRIVATE; 519 } 520 updateCurrentProfilesCache()521 private void updateCurrentProfilesCache() { 522 synchronized (mLock) { 523 mCurrentProfiles.clear(); 524 mCurrentManagedProfiles.clear(); 525 if (mUserManager != null) { 526 for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) { 527 mCurrentProfiles.put(user.id, user); 528 if (UserManager.USER_TYPE_PROFILE_MANAGED.equals(user.userType)) { 529 mCurrentManagedProfiles.put(user.id, user); 530 } 531 } 532 } 533 } 534 mMainHandler.post(() -> { 535 for (UserChangedListener listener : mListeners) { 536 listener.onCurrentProfilesChanged(mCurrentProfiles); 537 } 538 }); 539 } 540 541 /** 542 * If any of the profiles are in public mode. 543 */ isAnyProfilePublicMode()544 public boolean isAnyProfilePublicMode() { 545 synchronized (mLock) { 546 for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) { 547 if (isLockscreenPublicMode(mCurrentProfiles.valueAt(i).id)) { 548 return true; 549 } 550 } 551 } 552 return false; 553 } 554 555 /** 556 * If any managed/work profiles are in public mode. 557 */ isAnyManagedProfilePublicMode()558 public boolean isAnyManagedProfilePublicMode() { 559 synchronized (mLock) { 560 for (int i = mCurrentManagedProfiles.size() - 1; i >= 0; i--) { 561 if (isLockscreenPublicMode(mCurrentManagedProfiles.valueAt(i).id)) { 562 return true; 563 } 564 } 565 } 566 return false; 567 } 568 569 /** 570 * Returns the current user id. This can change if the user is switched. 571 */ getCurrentUserId()572 public int getCurrentUserId() { 573 return mCurrentUserId; 574 } 575 getCurrentProfiles()576 public SparseArray<UserInfo> getCurrentProfiles() { 577 return mCurrentProfiles; 578 } 579 580 @Override onStateChanged(int newState)581 public void onStateChanged(int newState) { 582 mState = newState; 583 updatePublicMode(); 584 } 585 updatePublicMode()586 public void updatePublicMode() { 587 //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns 588 // false when it should be true. Therefore, if we are not on the SHADE, don't even bother 589 // asking if the keyguard is showing. We still need to check it though because showing the 590 // camera on the keyguard has a state of SHADE but the keyguard is still showing. 591 final boolean showingKeyguard = mState != StatusBarState.SHADE 592 || mKeyguardStateController.isShowing(); 593 final boolean devicePublic = showingKeyguard && mKeyguardStateController.isMethodSecure(); 594 595 596 // Look for public mode users. Users are considered public in either case of: 597 // - device keyguard is shown in secure mode; 598 // - profile is locked with a work challenge. 599 SparseArray<UserInfo> currentProfiles = getCurrentProfiles(); 600 mUsersWithSeperateWorkChallenge.clear(); 601 for (int i = currentProfiles.size() - 1; i >= 0; i--) { 602 final int userId = currentProfiles.valueAt(i).id; 603 boolean isProfilePublic = devicePublic; 604 // TODO(b/140058091) 605 boolean needsSeparateChallenge = whitelistIpcs(() -> 606 mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)); 607 if (!devicePublic && userId != getCurrentUserId() 608 && needsSeparateChallenge && mLockPatternUtils.isSecure(userId)) { 609 // Keyguard.isDeviceLocked is updated asynchronously, assume that all profiles 610 // with separate challenge are locked when keyguard is visible to avoid race. 611 isProfilePublic = showingKeyguard || mKeyguardManager.isDeviceLocked(userId); 612 } 613 setLockscreenPublicMode(isProfilePublic, userId); 614 mUsersWithSeperateWorkChallenge.put(userId, needsSeparateChallenge); 615 } 616 getEntryManager().updateNotifications("NotificationLockscreenUserManager.updatePublicMode"); 617 } 618 619 @Override addUserChangedListener(UserChangedListener listener)620 public void addUserChangedListener(UserChangedListener listener) { 621 mListeners.add(listener); 622 } 623 624 @Override removeUserChangedListener(UserChangedListener listener)625 public void removeUserChangedListener(UserChangedListener listener) { 626 mListeners.remove(listener); 627 } 628 629 // public void updatePublicMode() { 630 // //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns 631 // // false when it should be true. Therefore, if we are not on the SHADE, don't even bother 632 // // asking if the keyguard is showing. We still need to check it though because showing the 633 // // camera on the keyguard has a state of SHADE but the keyguard is still showing. 634 // final boolean showingKeyguard = mState != StatusBarState.SHADE 635 // || mKeyguardStateController.isShowing(); 636 // final boolean devicePublic = showingKeyguard && isSecure(getCurrentUserId()); 637 // 638 // 639 // // Look for public mode users. Users are considered public in either case of: 640 // // - device keyguard is shown in secure mode; 641 // // - profile is locked with a work challenge. 642 // SparseArray<UserInfo> currentProfiles = getCurrentProfiles(); 643 // for (int i = currentProfiles.size() - 1; i >= 0; i--) { 644 // final int userId = currentProfiles.valueAt(i).id; 645 // boolean isProfilePublic = devicePublic; 646 // if (!devicePublic && userId != getCurrentUserId()) { 647 // // We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge 648 // // due to a race condition where this code could be called before 649 // // TrustManagerService updates its internal records, resulting in an incorrect 650 // // state being cached in mLockscreenPublicMode. (b/35951989) 651 // if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId) 652 // && isSecure(userId)) { 653 // isProfilePublic = mKeyguardManager.isDeviceLocked(userId); 654 // } 655 // } 656 // setLockscreenPublicMode(isProfilePublic, userId); 657 // } 658 // } 659 660 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)661 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 662 pw.println("NotificationLockscreenUserManager state:"); 663 pw.print(" mCurrentUserId="); 664 pw.println(mCurrentUserId); 665 pw.print(" mShowLockscreenNotifications="); 666 pw.println(mShowLockscreenNotifications); 667 pw.print(" mAllowLockscreenRemoteInput="); 668 pw.println(mAllowLockscreenRemoteInput); 669 pw.print(" mCurrentProfiles="); 670 synchronized (mLock) { 671 for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) { 672 final int userId = mCurrentProfiles.valueAt(i).id; 673 pw.print("" + userId + " "); 674 } 675 } 676 pw.print(" mCurrentManagedProfiles="); 677 synchronized (mLock) { 678 for (int i = mCurrentManagedProfiles.size() - 1; i >= 0; i--) { 679 pw.print("" + mCurrentManagedProfiles.valueAt(i).id + " "); 680 } 681 } 682 pw.println(); 683 } 684 } 685