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