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