blob: d38f1b99cb9ad14f9e63a8001edc18810b9dace9 [file] [log] [blame]
Jason Monk297c04e2018-08-23 17:16:59 -04001/*
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 */
16package com.android.systemui.statusbar;
17
Evan Laird181de622019-10-24 09:53:02 -040018import static android.app.Notification.VISIBILITY_SECRET;
Jason Monk297c04e2018-08-23 17:16:59 -040019import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
20
Lucas Dupin8968f6a2019-08-09 17:41:15 -070021import static com.android.systemui.DejankUtils.whitelistIpcs;
Evan Laird25f02752019-08-14 19:25:06 -040022import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
Lucas Dupin8968f6a2019-08-09 17:41:15 -070023
Jason Monk297c04e2018-08-23 17:16:59 -040024import android.app.ActivityManager;
25import android.app.KeyguardManager;
26import android.app.Notification;
27import android.app.admin.DevicePolicyManager;
28import android.content.BroadcastReceiver;
29import android.content.Context;
30import android.content.Intent;
31import android.content.IntentFilter;
32import android.content.IntentSender;
33import android.content.pm.UserInfo;
34import android.database.ContentObserver;
Dave Mankoff9427d1f2019-11-19 21:52:51 -050035import android.os.Handler;
Jason Monk297c04e2018-08-23 17:16:59 -040036import android.os.RemoteException;
Jason Monk297c04e2018-08-23 17:16:59 -040037import android.os.UserHandle;
38import android.os.UserManager;
39import android.provider.Settings;
Jason Monk297c04e2018-08-23 17:16:59 -040040import android.util.Log;
41import android.util.SparseArray;
42import android.util.SparseBooleanArray;
43
44import com.android.internal.statusbar.IStatusBarService;
45import com.android.internal.statusbar.NotificationVisibility;
46import com.android.internal.widget.LockPatternUtils;
47import com.android.keyguard.KeyguardUpdateMonitor;
48import com.android.systemui.Dependency;
49import com.android.systemui.Dumpable;
Fabian Kozynski5ca7a512019-10-16 19:56:11 +000050import com.android.systemui.broadcast.BroadcastDispatcher;
Dave Mankoff00e8a2f2019-12-18 16:59:49 -050051import com.android.systemui.dagger.qualifiers.Main;
Beverly8fdb5332019-02-04 14:29:49 -050052import com.android.systemui.plugins.statusbar.StatusBarStateController;
53import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
Winson Chung2dbcf092018-10-24 13:00:41 -070054import com.android.systemui.recents.OverviewProxyService;
Jason Monk297c04e2018-08-23 17:16:59 -040055import com.android.systemui.statusbar.notification.NotificationEntryManager;
Gus Prevas415376b2018-11-08 10:43:27 -050056import com.android.systemui.statusbar.notification.NotificationUtils;
Ned Burnsf81c4c42019-01-07 14:10:43 -050057import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Gustav Senntonf892fe92019-01-22 15:31:42 +000058import com.android.systemui.statusbar.notification.logging.NotificationLogger;
Jason Monk297c04e2018-08-23 17:16:59 -040059import com.android.systemui.statusbar.policy.DeviceProvisionedController;
Lucas Dupinc8f16e82019-09-17 18:24:50 -040060import com.android.systemui.statusbar.policy.KeyguardStateController;
Jason Monk297c04e2018-08-23 17:16:59 -040061
62import java.io.FileDescriptor;
63import java.io.PrintWriter;
Gus Prevasa18dc572019-01-14 16:11:22 -050064import java.util.ArrayList;
65import java.util.List;
Jason Monk297c04e2018-08-23 17:16:59 -040066
Govinda Wasserman2e86fb62019-08-13 11:35:44 -040067import javax.inject.Inject;
68import javax.inject.Singleton;
69
Jason Monk297c04e2018-08-23 17:16:59 -040070/**
71 * Handles keeping track of the current user, profiles, and various things related to hiding
72 * contents, redacting notifications, and the lockscreen.
73 */
Govinda Wasserman2e86fb62019-08-13 11:35:44 -040074@Singleton
Jason Monk297c04e2018-08-23 17:16:59 -040075public 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
Dave Mankoff9427d1f2019-11-19 21:52:51 -050080 private final DeviceProvisionedController mDeviceProvisionedController;
81 private final KeyguardStateController mKeyguardStateController;
Lucas Dupin960b7e7f2020-01-24 15:47:28 -080082 private final Object mLock = new Object();
Jason Monk297c04e2018-08-23 17:16:59 -040083
84 // Lazy
85 private NotificationEntryManager mEntryManager;
86
87 private final DevicePolicyManager mDevicePolicyManager;
88 private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
Selim Cinek6f0a62a2019-04-09 18:40:12 -070089 private final SparseBooleanArray mUsersWithSeperateWorkChallenge = new SparseBooleanArray();
Jason Monk297c04e2018-08-23 17:16:59 -040090 private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
91 private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
92 private final UserManager mUserManager;
93 private final IStatusBarService mBarService;
Gus Prevasa18dc572019-01-14 16:11:22 -050094 private final List<UserChangedListener> mListeners = new ArrayList<>();
Fabian Kozynski5ca7a512019-10-16 19:56:11 +000095 private final BroadcastDispatcher mBroadcastDispatcher;
Jason Monk297c04e2018-08-23 17:16:59 -040096
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();
Beverly85d4c192019-09-30 11:40:39 -0400112 getEntryManager().updateNotifications("ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED");
Jason Monk297c04e2018-08-23 17:16:59 -0400113 }
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();
Steve Elliottb47f1c72019-12-19 12:39:26 -0500121 switch (action) {
122 case Intent.ACTION_USER_SWITCHED:
123 mCurrentUserId = intent.getIntExtra(
124 Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL);
125 updateCurrentProfilesCache();
Jason Monk297c04e2018-08-23 17:16:59 -0400126
Steve Elliottb47f1c72019-12-19 12:39:26 -0500127 Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
Gus Prevasa18dc572019-01-14 16:11:22 -0500128
Steve Elliottb47f1c72019-12-19 12:39:26 -0500129 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);
Jason Monk297c04e2018-08-23 17:16:59 -0400139 }
Steve Elliottb47f1c72019-12-19 12:39:26 -0500140 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 }
Jason Monk297c04e2018-08-23 17:16:59 -0400160 }
Steve Elliottb47f1c72019-12-19 12:39:26 -0500161 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 try {
172 mBarService.onNotificationClick(notificationKey, nv);
173 } catch (RemoteException exception) {
174 /* ignore */
175 }
176 }
177 break;
Jason Monk297c04e2018-08-23 17:16:59 -0400178 }
179 }
180 };
181
182 protected final Context mContext;
Dave Mankoff9427d1f2019-11-19 21:52:51 -0500183 private final Handler mMainHandler;
Jason Monk297c04e2018-08-23 17:16:59 -0400184 protected final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
Lucas Dupin960b7e7f2020-01-24 15:47:28 -0800185 protected final ArrayList<UserInfo> mCurrentManagedProfiles = new ArrayList<>();
Jason Monk297c04e2018-08-23 17:16:59 -0400186
187 protected int mCurrentUserId = 0;
188 protected NotificationPresenter mPresenter;
189 protected ContentObserver mLockscreenSettingsObserver;
190 protected ContentObserver mSettingsObserver;
191
192 private NotificationEntryManager getEntryManager() {
193 if (mEntryManager == null) {
194 mEntryManager = Dependency.get(NotificationEntryManager.class);
195 }
196 return mEntryManager;
197 }
198
Govinda Wasserman2e86fb62019-08-13 11:35:44 -0400199 @Inject
Fabian Kozynski5ca7a512019-10-16 19:56:11 +0000200 public NotificationLockscreenUserManagerImpl(Context context,
Dave Mankoff9427d1f2019-11-19 21:52:51 -0500201 BroadcastDispatcher broadcastDispatcher,
202 DevicePolicyManager devicePolicyManager,
203 UserManager userManager,
204 IStatusBarService iStatusBarService,
205 KeyguardManager keyguardManager,
206 StatusBarStateController statusBarStateController,
Dave Mankoff00e8a2f2019-12-18 16:59:49 -0500207 @Main Handler mainHandler,
Dave Mankoff9427d1f2019-11-19 21:52:51 -0500208 DeviceProvisionedController deviceProvisionedController,
209 KeyguardStateController keyguardStateController) {
Jason Monk297c04e2018-08-23 17:16:59 -0400210 mContext = context;
Dave Mankoff9427d1f2019-11-19 21:52:51 -0500211 mMainHandler = mainHandler;
212 mDevicePolicyManager = devicePolicyManager;
213 mUserManager = userManager;
Jason Monk297c04e2018-08-23 17:16:59 -0400214 mCurrentUserId = ActivityManager.getCurrentUser();
Dave Mankoff9427d1f2019-11-19 21:52:51 -0500215 mBarService = iStatusBarService;
216 statusBarStateController.addCallback(this);
Jason Monk297c04e2018-08-23 17:16:59 -0400217 mLockPatternUtils = new LockPatternUtils(context);
Dave Mankoff9427d1f2019-11-19 21:52:51 -0500218 mKeyguardManager = keyguardManager;
Fabian Kozynski5ca7a512019-10-16 19:56:11 +0000219 mBroadcastDispatcher = broadcastDispatcher;
Dave Mankoff9427d1f2019-11-19 21:52:51 -0500220 mDeviceProvisionedController = deviceProvisionedController;
221 mKeyguardStateController = keyguardStateController;
Jason Monk297c04e2018-08-23 17:16:59 -0400222 }
223
224 public void setUpWithPresenter(NotificationPresenter presenter) {
225 mPresenter = presenter;
226
Dave Mankoff9427d1f2019-11-19 21:52:51 -0500227 mLockscreenSettingsObserver = new ContentObserver(mMainHandler) {
Jason Monk297c04e2018-08-23 17:16:59 -0400228 @Override
229 public void onChange(boolean selfChange) {
230 // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS or
231 // LOCK_SCREEN_SHOW_NOTIFICATIONS, so we just dump our cache ...
232 mUsersAllowingPrivateNotifications.clear();
233 mUsersAllowingNotifications.clear();
234 // ... and refresh all the notifications
235 updateLockscreenNotificationSetting();
Beverly85d4c192019-09-30 11:40:39 -0400236 getEntryManager().updateNotifications("LOCK_SCREEN_SHOW_NOTIFICATIONS,"
237 + " or LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS change");
Jason Monk297c04e2018-08-23 17:16:59 -0400238 }
239 };
240
Dave Mankoff9427d1f2019-11-19 21:52:51 -0500241 mSettingsObserver = new ContentObserver(mMainHandler) {
Jason Monk297c04e2018-08-23 17:16:59 -0400242 @Override
243 public void onChange(boolean selfChange) {
244 updateLockscreenNotificationSetting();
245 if (mDeviceProvisionedController.isDeviceProvisioned()) {
Beverly85d4c192019-09-30 11:40:39 -0400246 getEntryManager().updateNotifications("LOCK_SCREEN_ALLOW_REMOTE_INPUT"
247 + " or ZEN_MODE change");
Jason Monk297c04e2018-08-23 17:16:59 -0400248 }
249 }
250 };
251
252 mContext.getContentResolver().registerContentObserver(
253 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
254 mLockscreenSettingsObserver,
255 UserHandle.USER_ALL);
256
257 mContext.getContentResolver().registerContentObserver(
258 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
259 true,
260 mLockscreenSettingsObserver,
261 UserHandle.USER_ALL);
262
263 mContext.getContentResolver().registerContentObserver(
264 Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
265 mSettingsObserver);
266
267 if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
268 mContext.getContentResolver().registerContentObserver(
269 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT),
270 false,
271 mSettingsObserver,
272 UserHandle.USER_ALL);
273 }
274
Fabian Kozynski5ca7a512019-10-16 19:56:11 +0000275 mBroadcastDispatcher.registerReceiver(mAllUsersReceiver,
Jason Monk297c04e2018-08-23 17:16:59 -0400276 new IntentFilter(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
Fabian Kozynski5ca7a512019-10-16 19:56:11 +0000277 null /* handler */, UserHandle.ALL);
Jason Monk297c04e2018-08-23 17:16:59 -0400278
279 IntentFilter filter = new IntentFilter();
280 filter.addAction(Intent.ACTION_USER_SWITCHED);
281 filter.addAction(Intent.ACTION_USER_ADDED);
282 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Steve Elliottb47f1c72019-12-19 12:39:26 -0500283 filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
284 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
Fabian Kozynski5ca7a512019-10-16 19:56:11 +0000285 mBroadcastDispatcher.registerReceiver(mBaseBroadcastReceiver, filter);
Jason Monk297c04e2018-08-23 17:16:59 -0400286
287 IntentFilter internalFilter = new IntentFilter();
288 internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
289 mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
290
291 updateCurrentProfilesCache();
292
293 mSettingsObserver.onChange(false); // set up
294 }
295
296 public boolean shouldShowLockscreenNotifications() {
297 return mShowLockscreenNotifications;
298 }
299
300 public boolean shouldAllowLockscreenRemoteInput() {
301 return mAllowLockscreenRemoteInput;
302 }
303
304 public boolean isCurrentProfile(int userId) {
Lucas Dupin960b7e7f2020-01-24 15:47:28 -0800305 synchronized (mLock) {
Jason Monk297c04e2018-08-23 17:16:59 -0400306 return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
307 }
308 }
309
310 /**
311 * Returns true if notifications are temporarily disabled for this user for security reasons,
312 * regardless of the normal settings for that user.
313 */
314 private boolean shouldTemporarilyHideNotifications(int userId) {
315 if (userId == UserHandle.USER_ALL) {
316 userId = mCurrentUserId;
317 }
Dave Mankoffe2294692019-08-14 11:53:13 -0400318 return Dependency.get(KeyguardUpdateMonitor.class).isUserInLockdown(userId);
Jason Monk297c04e2018-08-23 17:16:59 -0400319 }
320
321 /**
322 * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
323 * If so, notifications should be hidden.
324 */
325 public boolean shouldHideNotifications(int userId) {
326 return isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId)
327 || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId))
328 || shouldTemporarilyHideNotifications(userId);
329 }
330
331 /**
332 * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
333 * package-specific override.
334 */
335 public boolean shouldHideNotifications(String key) {
336 if (getEntryManager() == null) {
337 Log.wtf(TAG, "mEntryManager was null!", new Throwable());
338 return true;
339 }
Evan Laird181de622019-10-24 09:53:02 -0400340 NotificationEntry visibleEntry = getEntryManager().getActiveNotificationUnfiltered(key);
341 return isLockscreenPublicMode(mCurrentUserId) && visibleEntry != null
342 && visibleEntry.getRanking().getVisibilityOverride() == VISIBILITY_SECRET;
Jason Monk297c04e2018-08-23 17:16:59 -0400343 }
344
Ned Burns8c1b7632019-07-19 14:26:15 -0400345 public boolean shouldShowOnKeyguard(NotificationEntry entry) {
Jason Monk297c04e2018-08-23 17:16:59 -0400346 if (getEntryManager() == null) {
347 Log.wtf(TAG, "mEntryManager was null!", new Throwable());
348 return false;
349 }
Gus Prevasdddef392018-11-02 15:41:43 -0400350 boolean exceedsPriorityThreshold;
Julia Reynolds5b655c32019-04-24 14:40:17 -0400351 if (NotificationUtils.useNewInterruptionModel(mContext)
352 && hideSilentNotificationsOnLockscreen()) {
Evan Laird25f02752019-08-14 19:25:06 -0400353 exceedsPriorityThreshold = entry.getBucket() != BUCKET_SILENT;
Gus Prevasdddef392018-11-02 15:41:43 -0400354 } else {
Evan Laird181de622019-10-24 09:53:02 -0400355 exceedsPriorityThreshold = !entry.getRanking().isAmbient();
Gus Prevasdddef392018-11-02 15:41:43 -0400356 }
357 return mShowLockscreenNotifications && exceedsPriorityThreshold;
Jason Monk297c04e2018-08-23 17:16:59 -0400358 }
359
Julia Reynolds5b655c32019-04-24 14:40:17 -0400360 private boolean hideSilentNotificationsOnLockscreen() {
Lucas Dupin8968f6a2019-08-09 17:41:15 -0700361 return whitelistIpcs(() -> Settings.Secure.getInt(mContext.getContentResolver(),
362 Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1) == 0);
Julia Reynolds5b655c32019-04-24 14:40:17 -0400363 }
364
Jason Monk297c04e2018-08-23 17:16:59 -0400365 private void setShowLockscreenNotifications(boolean show) {
366 mShowLockscreenNotifications = show;
367 }
368
369 private void setLockscreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
370 mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
371 }
372
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 */
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
Lucas Dupin960b7e7f2020-01-24 15:47:28 -0800422 /**
423 * If all managed profiles (work profiles) can show private data in public (secure & locked.)
424 */
425 public boolean allowsManagedPrivateNotificationsInPublic() {
426 synchronized (mLock) {
427 for (UserInfo profile : mCurrentManagedProfiles) {
428 if (!userAllowsPrivateNotificationsInPublic(profile.id)) {
429 return false;
430 }
431 }
432 }
433 return true;
434 }
435
Jason Monk297c04e2018-08-23 17:16:59 -0400436 private boolean adminAllowsKeyguardFeature(int userHandle, int feature) {
437 if (userHandle == UserHandle.USER_ALL) {
438 return true;
439 }
440 final int dpmFlags =
441 mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */, userHandle);
442 return (dpmFlags & feature) == 0;
443 }
444
445 /**
446 * Save the current "public" (locked and secure) state of the lockscreen.
447 */
448 public void setLockscreenPublicMode(boolean publicMode, int userId) {
449 mLockscreenPublicMode.put(userId, publicMode);
450 }
451
452 public boolean isLockscreenPublicMode(int userId) {
453 if (userId == UserHandle.USER_ALL) {
454 return mLockscreenPublicMode.get(mCurrentUserId, false);
455 }
456 return mLockscreenPublicMode.get(userId, false);
457 }
458
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700459 @Override
460 public boolean needsSeparateWorkChallenge(int userId) {
461 return mUsersWithSeperateWorkChallenge.get(userId, false);
462 }
463
Jason Monk297c04e2018-08-23 17:16:59 -0400464 /**
465 * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
466 * "public" (secure & locked) mode?
467 */
Beverlyaf16ee02019-11-25 10:38:56 -0500468 public boolean userAllowsNotificationsInPublic(int userHandle) {
Jason Monk297c04e2018-08-23 17:16:59 -0400469 if (isCurrentProfile(userHandle) && userHandle != mCurrentUserId) {
470 return true;
471 }
472
473 if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
474 final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
475 mContext.getContentResolver(),
476 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
477 final boolean allowedByDpm = adminAllowsKeyguardFeature(userHandle,
478 DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
Zimuzob3b9c262018-10-31 11:54:20 +0000479 final boolean allowedBySystem = mKeyguardManager.getPrivateNotificationsAllowed();
480 final boolean allowed = allowedByUser && allowedByDpm && allowedBySystem;
Jason Monk297c04e2018-08-23 17:16:59 -0400481 mUsersAllowingNotifications.append(userHandle, allowed);
482 return allowed;
483 }
484
485 return mUsersAllowingNotifications.get(userHandle);
486 }
487
488 /** @return true if the entry needs redaction when on the lockscreen. */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500489 public boolean needsRedaction(NotificationEntry ent) {
Ned Burns00b4b2d2019-10-17 22:09:27 -0400490 int userId = ent.getSbn().getUserId();
Jason Monk297c04e2018-08-23 17:16:59 -0400491
492 boolean currentUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(mCurrentUserId);
493 boolean notiUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(userId);
494 boolean redactedLockscreen = currentUserWantsRedaction || notiUserWantsRedaction;
495
496 boolean notificationRequestsRedaction =
Ned Burns00b4b2d2019-10-17 22:09:27 -0400497 ent.getSbn().getNotification().visibility == Notification.VISIBILITY_PRIVATE;
498 boolean userForcesRedaction = packageHasVisibilityOverride(ent.getSbn().getKey());
Jason Monk297c04e2018-08-23 17:16:59 -0400499
500 return userForcesRedaction || notificationRequestsRedaction && redactedLockscreen;
501 }
502
503 private boolean packageHasVisibilityOverride(String key) {
504 if (getEntryManager() == null) {
505 Log.wtf(TAG, "mEntryManager was null!", new Throwable());
506 return true;
507 }
Evan Laird181de622019-10-24 09:53:02 -0400508 NotificationEntry entry = getEntryManager().getActiveNotificationUnfiltered(key);
509 return entry != null
510 && entry.getRanking().getVisibilityOverride() == Notification.VISIBILITY_PRIVATE;
Jason Monk297c04e2018-08-23 17:16:59 -0400511 }
512
513 private void updateCurrentProfilesCache() {
Lucas Dupin960b7e7f2020-01-24 15:47:28 -0800514 synchronized (mLock) {
Jason Monk297c04e2018-08-23 17:16:59 -0400515 mCurrentProfiles.clear();
Lucas Dupin960b7e7f2020-01-24 15:47:28 -0800516 mCurrentManagedProfiles.clear();
Jason Monk297c04e2018-08-23 17:16:59 -0400517 if (mUserManager != null) {
518 for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
519 mCurrentProfiles.put(user.id, user);
Lucas Dupin960b7e7f2020-01-24 15:47:28 -0800520 if (UserManager.USER_TYPE_PROFILE_MANAGED.equals(user.userType)) {
521 mCurrentManagedProfiles.add(user);
522 }
Jason Monk297c04e2018-08-23 17:16:59 -0400523 }
524 }
525 }
Steve Elliottb47f1c72019-12-19 12:39:26 -0500526 mMainHandler.post(() -> {
527 for (UserChangedListener listener : mListeners) {
528 listener.onCurrentProfilesChanged(mCurrentProfiles);
529 }
530 });
Jason Monk297c04e2018-08-23 17:16:59 -0400531 }
532
Lucas Dupin960b7e7f2020-01-24 15:47:28 -0800533 /**
534 * If any of the profiles are in public mode.
535 */
Jason Monk297c04e2018-08-23 17:16:59 -0400536 public boolean isAnyProfilePublicMode() {
Lucas Dupin960b7e7f2020-01-24 15:47:28 -0800537 synchronized (mLock) {
538 for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
539 if (isLockscreenPublicMode(mCurrentProfiles.valueAt(i).id)) {
540 return true;
541 }
542 }
543 }
544 return false;
545 }
546
547 /**
548 * If any managed/work profiles are in public mode.
549 */
550 public boolean isAnyManagedProfilePublicMode() {
551 synchronized (mLock) {
552 for (int i = mCurrentManagedProfiles.size() - 1; i >= 0; i--) {
553 if (isLockscreenPublicMode(mCurrentManagedProfiles.get(i).id)) {
554 return true;
555 }
Jason Monk297c04e2018-08-23 17:16:59 -0400556 }
557 }
558 return false;
559 }
560
561 /**
562 * Returns the current user id. This can change if the user is switched.
563 */
564 public int getCurrentUserId() {
565 return mCurrentUserId;
566 }
567
568 public SparseArray<UserInfo> getCurrentProfiles() {
569 return mCurrentProfiles;
570 }
571
572 @Override
573 public void onStateChanged(int newState) {
574 mState = newState;
575 updatePublicMode();
576 }
577
578 public void updatePublicMode() {
579 //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns
580 // false when it should be true. Therefore, if we are not on the SHADE, don't even bother
581 // asking if the keyguard is showing. We still need to check it though because showing the
582 // camera on the keyguard has a state of SHADE but the keyguard is still showing.
583 final boolean showingKeyguard = mState != StatusBarState.SHADE
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400584 || mKeyguardStateController.isShowing();
585 final boolean devicePublic = showingKeyguard && mKeyguardStateController.isMethodSecure();
Jason Monk297c04e2018-08-23 17:16:59 -0400586
587
588 // Look for public mode users. Users are considered public in either case of:
589 // - device keyguard is shown in secure mode;
590 // - profile is locked with a work challenge.
591 SparseArray<UserInfo> currentProfiles = getCurrentProfiles();
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700592 mUsersWithSeperateWorkChallenge.clear();
Jason Monk297c04e2018-08-23 17:16:59 -0400593 for (int i = currentProfiles.size() - 1; i >= 0; i--) {
594 final int userId = currentProfiles.valueAt(i).id;
595 boolean isProfilePublic = devicePublic;
Lucas Dupin8968f6a2019-08-09 17:41:15 -0700596 // TODO(b/140058091)
597 boolean needsSeparateChallenge = whitelistIpcs(() ->
598 mLockPatternUtils.isSeparateProfileChallengeEnabled(userId));
Pavel Grafov85384122019-05-23 15:39:49 +0100599 if (!devicePublic && userId != getCurrentUserId()
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400600 && needsSeparateChallenge && mLockPatternUtils.isSecure(userId)) {
Pavel Grafov85384122019-05-23 15:39:49 +0100601 // Keyguard.isDeviceLocked is updated asynchronously, assume that all profiles
602 // with separate challenge are locked when keyguard is visible to avoid race.
603 isProfilePublic = showingKeyguard || mKeyguardManager.isDeviceLocked(userId);
Jason Monk297c04e2018-08-23 17:16:59 -0400604 }
605 setLockscreenPublicMode(isProfilePublic, userId);
Selim Cinek6f0a62a2019-04-09 18:40:12 -0700606 mUsersWithSeperateWorkChallenge.put(userId, needsSeparateChallenge);
Jason Monk297c04e2018-08-23 17:16:59 -0400607 }
Beverly85d4c192019-09-30 11:40:39 -0400608 getEntryManager().updateNotifications("NotificationLockscreenUserManager.updatePublicMode");
Jason Monk297c04e2018-08-23 17:16:59 -0400609 }
610
Gus Prevasa18dc572019-01-14 16:11:22 -0500611 @Override
612 public void addUserChangedListener(UserChangedListener listener) {
613 mListeners.add(listener);
614 }
Jason Monk297c04e2018-08-23 17:16:59 -0400615
Steve Elliottb47f1c72019-12-19 12:39:26 -0500616 @Override
617 public void removeUserChangedListener(UserChangedListener listener) {
618 mListeners.remove(listener);
619 }
620
Jason Monk297c04e2018-08-23 17:16:59 -0400621// public void updatePublicMode() {
622// //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns
623// // false when it should be true. Therefore, if we are not on the SHADE, don't even bother
624// // asking if the keyguard is showing. We still need to check it though because showing the
625// // camera on the keyguard has a state of SHADE but the keyguard is still showing.
626// final boolean showingKeyguard = mState != StatusBarState.SHADE
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400627// || mKeyguardStateController.isShowing();
Jason Monk297c04e2018-08-23 17:16:59 -0400628// final boolean devicePublic = showingKeyguard && isSecure(getCurrentUserId());
629//
630//
631// // Look for public mode users. Users are considered public in either case of:
632// // - device keyguard is shown in secure mode;
633// // - profile is locked with a work challenge.
634// SparseArray<UserInfo> currentProfiles = getCurrentProfiles();
635// for (int i = currentProfiles.size() - 1; i >= 0; i--) {
636// final int userId = currentProfiles.valueAt(i).id;
637// boolean isProfilePublic = devicePublic;
638// if (!devicePublic && userId != getCurrentUserId()) {
639// // We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge
640// // due to a race condition where this code could be called before
641// // TrustManagerService updates its internal records, resulting in an incorrect
642// // state being cached in mLockscreenPublicMode. (b/35951989)
643// if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
644// && isSecure(userId)) {
645// isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
646// }
647// }
648// setLockscreenPublicMode(isProfilePublic, userId);
649// }
650// }
651
Jason Monk297c04e2018-08-23 17:16:59 -0400652 @Override
653 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
654 pw.println("NotificationLockscreenUserManager state:");
655 pw.print(" mCurrentUserId=");
656 pw.println(mCurrentUserId);
657 pw.print(" mShowLockscreenNotifications=");
658 pw.println(mShowLockscreenNotifications);
659 pw.print(" mAllowLockscreenRemoteInput=");
660 pw.println(mAllowLockscreenRemoteInput);
661 pw.print(" mCurrentProfiles=");
Lucas Dupin960b7e7f2020-01-24 15:47:28 -0800662 synchronized (mLock) {
663 for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
664 final int userId = mCurrentProfiles.valueAt(i).id;
665 pw.print("" + userId + " ");
666 }
667 }
668 pw.print(" mCurrentManagedProfiles=");
669 synchronized (mLock) {
670 for (UserInfo userInfo : mCurrentManagedProfiles) {
671 pw.print("" + userInfo.id + " ");
672 }
Jason Monk297c04e2018-08-23 17:16:59 -0400673 }
674 pw.println();
675 }
676}