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