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