Don't show "Clear All" w/ redacted notifs

The logic that determined when to show the Clear All Silent button in the
Silent notification header was occurring when the Silent (and Minimized)
sections update. At this time, there was no up-to-date information about
whether or not the notification has senstive content
(SensitiveContentCoordinator occurs later in the pipeline), and no
information about whether or not sensitive content can even be shown or
must be redacted (handled by NotificationStackScrollLayoutController).

Additionally, the visibility of the Clear All button in the shade footer
wasn't being adjusted at all under the new pipeline.

To remedy this, the following changes were made in this CL:

1. `boolean NotificationEntry#isSensitive()` has been dismantled. Rather
than relying on some separate code to properly set this value at some
point, instead the concept of "Sensitive Content" is derived directly
from the SBN + Ranking, and is kept separate from the state of the
user's settings, as well as the state of the lockscreen (whether we
would currently need to redact).

2. NotificationLockscreenUserMananger is the de-facto place for tracking
and querying redaction state. This includes checking if the user's
settings *would* require redaction (#needsRedactionInPublic), and
whether a user is actually public (#isLockscreenPublicMode).

3. In order to keep clients in sync, a new observable interface is
exposed on NotificationLockscreenUserManager that clients can use to be
notified when to requery #needsRedactionInPublic, due to user settings
changes. This replaces NotificationEntry#OnSensitivityChangedListener

4. SensitiveContentCoordinator has been removed entirely; the pipeline
no longer needs to invoke NotificationEntry#setSenstive, since it no
longer exists.

5. NotifStats has been updated to include additional information
extracted from the NotifCollection necessary to dynamically query for
redaction in the View layer, without needed to re-process the entire
list; specifically, we track a Set of users that currently have
sensitive notifications in the shade. This set is tested against the
user's settings (tracked separately from the pipeline in
NotifLockscreenUserManager).

Test: atest
Test: 1. Turn on notification redaction (no sensitive contents on lockscreen)
      2. Receive a silent sensitive notification
      3. Lock the device
      4. Double tap camera
      5. expand shade
      Observe: Clear all hidden in footer and in silent header

Fixes: 213443266
Fixes: 230581048
Change-Id: Ibc66576d28a48f7c82cad875ed2dcb57a7b23f10
Merged-In: Ibc66576d28a48f7c82cad875ed2dcb57a7b23f10
This commit is contained in:
Steve Elliott
2022-02-15 12:09:02 -05:00
parent 7bc9ba3bc5
commit 63122cbde2
35 changed files with 570 additions and 803 deletions

View File

@@ -29,7 +29,6 @@ import com.android.keyguard.AlphaOptimizedLinearLayout;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry.OnSensitivityChangedListener;
import java.util.ArrayList; import java.util.ArrayList;
@@ -49,6 +48,7 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
private TextView mTextView; private TextView mTextView;
private NotificationEntry mShowingEntry; private NotificationEntry mShowingEntry;
private Runnable mOnDrawingRectChangedListener; private Runnable mOnDrawingRectChangedListener;
private boolean mRedactSensitiveContent;
public HeadsUpStatusBarView(Context context) { public HeadsUpStatusBarView(Context context) {
this(context, null); this(context, null);
@@ -111,29 +111,28 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
} }
public void setEntry(NotificationEntry entry) { public void setEntry(NotificationEntry entry) {
if (mShowingEntry != null) {
mShowingEntry.removeOnSensitivityChangedListener(mOnSensitivityChangedListener);
}
mShowingEntry = entry; mShowingEntry = entry;
if (mShowingEntry != null) { if (mShowingEntry != null) {
CharSequence text = entry.headsUpStatusBarText; CharSequence text = entry.headsUpStatusBarText;
if (entry.isSensitive()) { if (mRedactSensitiveContent && entry.hasSensitiveContents()) {
text = entry.headsUpStatusBarTextPublic; text = entry.headsUpStatusBarTextPublic;
} }
mTextView.setText(text); mTextView.setText(text);
mShowingEntry.addOnSensitivityChangedListener(mOnSensitivityChangedListener);
} }
} }
private final OnSensitivityChangedListener mOnSensitivityChangedListener = entry -> { public void setRedactSensitiveContent(boolean redactSensitiveContent) {
if (entry != mShowingEntry) { if (mRedactSensitiveContent == redactSensitiveContent) {
throw new IllegalStateException("Got a sensitivity change for " + entry return;
+ " but mShowingEntry is " + mShowingEntry);
} }
// Update the text mRedactSensitiveContent = redactSensitiveContent;
setEntry(entry); if (mShowingEntry != null && mShowingEntry.hasSensitiveContents()) {
}; mTextView.setText(
mRedactSensitiveContent
? mShowingEntry.headsUpStatusBarTextPublic
: mShowingEntry.headsUpStatusBarText);
}
}
@Override @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) { protected void onLayout(boolean changed, int l, int t, int r, int b) {

View File

@@ -386,7 +386,7 @@ class LockscreenShadeTransitionController @Inject constructor(
} }
if (view is ExpandableNotificationRow) { if (view is ExpandableNotificationRow) {
// Only drag down on sensitive views, otherwise the ExpandHelper will take this // Only drag down on sensitive views, otherwise the ExpandHelper will take this
return view.entry.isSensitive return lockScreenUserManager.notifNeedsRedactionInPublic(view.entry)
} }
} }
return false return false
@@ -552,7 +552,8 @@ class LockscreenShadeTransitionController @Inject constructor(
logger.logShadeDisabledOnGoToLockedShade() logger.logShadeDisabledOnGoToLockedShade()
return return
} }
var userId: Int = lockScreenUserManager.getCurrentUserId() val currentUser = lockScreenUserManager.currentUserId
var userId: Int = currentUser
var entry: NotificationEntry? = null var entry: NotificationEntry? = null
if (expandView is ExpandableNotificationRow) { if (expandView is ExpandableNotificationRow) {
entry = expandView.entry entry = expandView.entry
@@ -562,12 +563,18 @@ class LockscreenShadeTransitionController @Inject constructor(
entry.setGroupExpansionChanging(true) entry.setGroupExpansionChanging(true)
userId = entry.sbn.userId userId = entry.sbn.userId
} }
var fullShadeNeedsBouncer = (!lockScreenUserManager.userAllowsPrivateNotificationsInPublic( val fullShadeNeedsBouncer = when {
lockScreenUserManager.getCurrentUserId()) || // No bouncer necessary if we're bypassing
!lockScreenUserManager.shouldShowLockscreenNotifications() || keyguardBypassController.bypassEnabled -> false
falsingCollector.shouldEnforceBouncer()) // Redacted notificationss are present, bouncer should be shown before un-redacting in
if (keyguardBypassController.bypassEnabled) { // the full shade
fullShadeNeedsBouncer = false lockScreenUserManager.sensitiveNotifsNeedRedactionInPublic(currentUser) -> true
// Notifications are hidden in public, bouncer should be shown before showing them in
// the full shade
!lockScreenUserManager.shouldShowLockscreenNotifications() -> true
// Bouncer is being enforced, so we need to show it
falsingCollector.shouldEnforceBouncer() -> true
else -> false
} }
if (lockScreenUserManager.isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) { if (lockScreenUserManager.isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
statusBarStateController.setLeaveOpenOnKeyguardHide(true) statusBarStateController.setLeaveOpenOnKeyguardHide(true)
@@ -911,4 +918,4 @@ class DragDownHelper(
host.getLocationOnScreen(temp2) host.getLocationOnScreen(temp2)
return expandCallback.getChildAtRawPosition(x + temp2[0], y + temp2[1]) return expandCallback.getChildAtRawPosition(x + temp2[0], y + temp2[1])
} }
} }

View File

@@ -71,17 +71,22 @@ public interface NotificationLockscreenUserManager {
boolean shouldHideNotifications(String key); boolean shouldHideNotifications(String key);
boolean shouldShowOnKeyguard(NotificationEntry entry); boolean shouldShowOnKeyguard(NotificationEntry entry);
void addOnNeedsRedactionInPublicChangedListener(Runnable listener);
void removeOnNeedsRedactionInPublicChangedListener(Runnable listener);
boolean isAnyProfilePublicMode(); boolean isAnyProfilePublicMode();
void updatePublicMode(); void updatePublicMode();
boolean needsRedaction(NotificationEntry entry); /** Does this notification require redaction if it is displayed when the device is public? */
boolean notifNeedsRedactionInPublic(NotificationEntry entry);
/** /**
* Has the given user chosen to allow their private (full) notifications to be shown even * Do all sensitive notifications belonging to the given user require redaction when they are
* when the lockscreen is in "public" (secure & locked) mode? * displayed in public?
*/ */
boolean userAllowsPrivateNotificationsInPublic(int currentUserId); boolean sensitiveNotifsNeedRedactionInPublic(int userId);
/** /**
* Has the given user chosen to allow notifications to be shown even when the lockscreen is in * Has the given user chosen to allow notifications to be shown even when the lockscreen is in

View File

@@ -24,7 +24,6 @@ import static com.android.systemui.statusbar.notification.stack.NotificationPrio
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.KeyguardManager; import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
@@ -45,7 +44,6 @@ import android.util.SparseBooleanArray;
import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable; import com.android.systemui.Dumpable;
import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.SysUISingleton;
@@ -60,6 +58,7 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.Co
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.ListenerSet;
import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.settings.SecureSettings;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -85,13 +84,12 @@ public class NotificationLockscreenUserManagerImpl implements
private final DeviceProvisionedController mDeviceProvisionedController; private final DeviceProvisionedController mDeviceProvisionedController;
private final KeyguardStateController mKeyguardStateController; private final KeyguardStateController mKeyguardStateController;
private final SecureSettings mSecureSettings; private final SecureSettings mSecureSettings;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final Lazy<OverviewProxyService> mOverviewProxyService;
private final Object mLock = new Object(); private final Object mLock = new Object();
// Lazy
private NotificationEntryManager mEntryManager;
private final Lazy<NotificationVisibilityProvider> mVisibilityProviderLazy; private final Lazy<NotificationVisibilityProvider> mVisibilityProviderLazy;
private final Lazy<CommonNotifCollection> mCommonNotifCollectionLazy; private final Lazy<CommonNotifCollection> mCommonNotifCollectionLazy;
private final Lazy<NotificationEntryManager> mEntryManagerLazy;
private final DevicePolicyManager mDevicePolicyManager; private final DevicePolicyManager mDevicePolicyManager;
private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray(); private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
private final SparseBooleanArray mUsersWithSeparateWorkChallenge = new SparseBooleanArray(); private final SparseBooleanArray mUsersWithSeparateWorkChallenge = new SparseBooleanArray();
@@ -103,13 +101,14 @@ public class NotificationLockscreenUserManagerImpl implements
private final List<UserChangedListener> mListeners = new ArrayList<>(); private final List<UserChangedListener> mListeners = new ArrayList<>();
private final BroadcastDispatcher mBroadcastDispatcher; private final BroadcastDispatcher mBroadcastDispatcher;
private final NotificationClickNotifier mClickNotifier; private final NotificationClickNotifier mClickNotifier;
private final LockPatternUtils mLockPatternUtils;
private boolean mShowLockscreenNotifications; private final List<KeyguardNotificationSuppressor> mKeyguardSuppressors = new ArrayList<>();
private boolean mAllowLockscreenRemoteInput; protected final Context mContext;
private LockPatternUtils mLockPatternUtils; private final Handler mMainHandler;
protected KeyguardManager mKeyguardManager; protected final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
private int mState = StatusBarState.SHADE; protected final SparseArray<UserInfo> mCurrentManagedProfiles = new SparseArray<>();
private List<KeyguardNotificationSuppressor> mKeyguardSuppressors = new ArrayList<>(); private final ListenerSet<Runnable> mOnSensitiveContentRedactionChangeListeners =
new ListenerSet<>();
protected final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() { protected final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
@Override @Override
@@ -120,7 +119,11 @@ public class NotificationLockscreenUserManagerImpl implements
isCurrentProfile(getSendingUserId())) { isCurrentProfile(getSendingUserId())) {
mUsersAllowingPrivateNotifications.clear(); mUsersAllowingPrivateNotifications.clear();
updateLockscreenNotificationSetting(); updateLockscreenNotificationSetting();
getEntryManager().updateNotifications("ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED"); for (Runnable listener : mOnSensitiveContentRedactionChangeListeners) {
listener.run();
}
mEntryManagerLazy.get()
.updateNotifications("ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED");
} }
} }
}; };
@@ -142,7 +145,7 @@ public class NotificationLockscreenUserManagerImpl implements
// The filtering needs to happen before the update call below in order to // The filtering needs to happen before the update call below in order to
// make sure // make sure
// the presenter has the updated notifications from the new user // the presenter has the updated notifications from the new user
getEntryManager().reapplyFilterAndSort("user switched"); mEntryManagerLazy.get().reapplyFilterAndSort("user switched");
mPresenter.onUserSwitched(mCurrentUserId); mPresenter.onUserSwitched(mCurrentUserId);
for (UserChangedListener listener : mListeners) { for (UserChangedListener listener : mListeners) {
@@ -156,7 +159,7 @@ public class NotificationLockscreenUserManagerImpl implements
break; break;
case Intent.ACTION_USER_UNLOCKED: case Intent.ACTION_USER_UNLOCKED:
// Start the overview connection to the launcher service // Start the overview connection to the launcher service
Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser(); mOverviewProxyService.get().startConnectionToCurrentUser();
break; break;
case NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION: case NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION:
final IntentSender intentSender = intent.getParcelableExtra( final IntentSender intentSender = intent.getParcelableExtra(
@@ -179,28 +182,26 @@ public class NotificationLockscreenUserManagerImpl implements
} }
}; };
protected final Context mContext; // Late-init
private final Handler mMainHandler;
protected final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
protected final SparseArray<UserInfo> mCurrentManagedProfiles = new SparseArray<>();
protected int mCurrentUserId = 0;
protected NotificationPresenter mPresenter; protected NotificationPresenter mPresenter;
protected ContentObserver mLockscreenSettingsObserver; protected ContentObserver mLockscreenSettingsObserver;
protected ContentObserver mSettingsObserver; protected ContentObserver mSettingsObserver;
private boolean mHideSilentNotificationsOnLockscreen; protected KeyguardManager mKeyguardManager;
private NotificationEntryManager getEntryManager() { protected int mCurrentUserId = 0;
if (mEntryManager == null) { private int mState = StatusBarState.SHADE;
mEntryManager = Dependency.get(NotificationEntryManager.class); private boolean mHideSilentNotificationsOnLockscreen;
} private boolean mShowLockscreenNotifications;
return mEntryManager; private boolean mAllowLockscreenRemoteInput;
}
@Inject @Inject
public NotificationLockscreenUserManagerImpl(Context context, public NotificationLockscreenUserManagerImpl(
Context context,
BroadcastDispatcher broadcastDispatcher, BroadcastDispatcher broadcastDispatcher,
DevicePolicyManager devicePolicyManager, DevicePolicyManager devicePolicyManager,
KeyguardUpdateMonitor keyguardUpdateMonitor,
Lazy<NotificationEntryManager> notificationEntryManagerLazy,
Lazy<OverviewProxyService> overviewProxyServiceLazy,
UserManager userManager, UserManager userManager,
Lazy<NotificationVisibilityProvider> visibilityProviderLazy, Lazy<NotificationVisibilityProvider> visibilityProviderLazy,
Lazy<CommonNotifCollection> commonNotifCollectionLazy, Lazy<CommonNotifCollection> commonNotifCollectionLazy,
@@ -216,9 +217,11 @@ public class NotificationLockscreenUserManagerImpl implements
mMainHandler = mainHandler; mMainHandler = mainHandler;
mDevicePolicyManager = devicePolicyManager; mDevicePolicyManager = devicePolicyManager;
mUserManager = userManager; mUserManager = userManager;
mOverviewProxyService = overviewProxyServiceLazy;
mCurrentUserId = ActivityManager.getCurrentUser(); mCurrentUserId = ActivityManager.getCurrentUser();
mVisibilityProviderLazy = visibilityProviderLazy; mVisibilityProviderLazy = visibilityProviderLazy;
mCommonNotifCollectionLazy = commonNotifCollectionLazy; mCommonNotifCollectionLazy = commonNotifCollectionLazy;
mEntryManagerLazy = notificationEntryManagerLazy;
mClickNotifier = clickNotifier; mClickNotifier = clickNotifier;
statusBarStateController.addCallback(this); statusBarStateController.addCallback(this);
mLockPatternUtils = new LockPatternUtils(context); mLockPatternUtils = new LockPatternUtils(context);
@@ -227,10 +230,12 @@ public class NotificationLockscreenUserManagerImpl implements
mDeviceProvisionedController = deviceProvisionedController; mDeviceProvisionedController = deviceProvisionedController;
mSecureSettings = secureSettings; mSecureSettings = secureSettings;
mKeyguardStateController = keyguardStateController; mKeyguardStateController = keyguardStateController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
dumpManager.registerDumpable(this); dumpManager.registerDumpable(this);
} }
@Override
public void setUpWithPresenter(NotificationPresenter presenter) { public void setUpWithPresenter(NotificationPresenter presenter) {
mPresenter = presenter; mPresenter = presenter;
@@ -243,7 +248,10 @@ public class NotificationLockscreenUserManagerImpl implements
mUsersAllowingNotifications.clear(); mUsersAllowingNotifications.clear();
// ... and refresh all the notifications // ... and refresh all the notifications
updateLockscreenNotificationSetting(); updateLockscreenNotificationSetting();
getEntryManager().updateNotifications("LOCK_SCREEN_SHOW_NOTIFICATIONS," for (Runnable listener : mOnSensitiveContentRedactionChangeListeners) {
listener.run();
}
mEntryManagerLazy.get().updateNotifications("LOCK_SCREEN_SHOW_NOTIFICATIONS,"
+ " or LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS change"); + " or LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS change");
} }
}; };
@@ -253,7 +261,7 @@ public class NotificationLockscreenUserManagerImpl implements
public void onChange(boolean selfChange) { public void onChange(boolean selfChange) {
updateLockscreenNotificationSetting(); updateLockscreenNotificationSetting();
if (mDeviceProvisionedController.isDeviceProvisioned()) { if (mDeviceProvisionedController.isDeviceProvisioned()) {
getEntryManager().updateNotifications("LOCK_SCREEN_ALLOW_REMOTE_INPUT" mEntryManagerLazy.get().updateNotifications("LOCK_SCREEN_ALLOW_REMOTE_INPUT"
+ " or ZEN_MODE change"); + " or ZEN_MODE change");
} }
} }
@@ -312,14 +320,17 @@ public class NotificationLockscreenUserManagerImpl implements
mSettingsObserver.onChange(false); // set up mSettingsObserver.onChange(false); // set up
} }
@Override
public boolean shouldShowLockscreenNotifications() { public boolean shouldShowLockscreenNotifications() {
return mShowLockscreenNotifications; return mShowLockscreenNotifications;
} }
@Override
public boolean shouldAllowLockscreenRemoteInput() { public boolean shouldAllowLockscreenRemoteInput() {
return mAllowLockscreenRemoteInput; return mAllowLockscreenRemoteInput;
} }
@Override
public boolean isCurrentProfile(int userId) { public boolean isCurrentProfile(int userId) {
synchronized (mLock) { synchronized (mLock) {
return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null; return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null;
@@ -334,7 +345,7 @@ public class NotificationLockscreenUserManagerImpl implements
if (userId == UserHandle.USER_ALL) { if (userId == UserHandle.USER_ALL) {
userId = mCurrentUserId; userId = mCurrentUserId;
} }
boolean inLockdown = Dependency.get(KeyguardUpdateMonitor.class).isUserInLockdown(userId); boolean inLockdown = mKeyguardUpdateMonitor.isUserInLockdown(userId);
mUsersInLockdownLatestResult.put(userId, inLockdown); mUsersInLockdownLatestResult.put(userId, inLockdown);
return inLockdown; return inLockdown;
} }
@@ -343,6 +354,7 @@ public class NotificationLockscreenUserManagerImpl implements
* Returns true if we're on a secure lockscreen and the user wants to hide notification data. * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
* If so, notifications should be hidden. * If so, notifications should be hidden.
*/ */
@Override
public boolean shouldHideNotifications(int userId) { public boolean shouldHideNotifications(int userId) {
boolean hide = isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId) boolean hide = isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId)
|| (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId)) || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId))
@@ -355,6 +367,7 @@ public class NotificationLockscreenUserManagerImpl implements
* Returns true if we're on a secure lockscreen and the user wants to hide notifications via * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
* package-specific override. * package-specific override.
*/ */
@Override
public boolean shouldHideNotifications(String key) { public boolean shouldHideNotifications(String key) {
if (mCommonNotifCollectionLazy.get() == null) { if (mCommonNotifCollectionLazy.get() == null) {
Log.wtf(TAG, "mCommonNotifCollectionLazy was null!", new Throwable()); Log.wtf(TAG, "mCommonNotifCollectionLazy was null!", new Throwable());
@@ -365,6 +378,7 @@ public class NotificationLockscreenUserManagerImpl implements
&& visibleEntry.getRanking().getLockscreenVisibilityOverride() == VISIBILITY_SECRET; && visibleEntry.getRanking().getLockscreenVisibilityOverride() == VISIBILITY_SECRET;
} }
@Override
public boolean shouldShowOnKeyguard(NotificationEntry entry) { public boolean shouldShowOnKeyguard(NotificationEntry entry) {
if (mCommonNotifCollectionLazy.get() == null) { if (mCommonNotifCollectionLazy.get() == null) {
Log.wtf(TAG, "mCommonNotifCollectionLazy was null!", new Throwable()); Log.wtf(TAG, "mCommonNotifCollectionLazy was null!", new Throwable());
@@ -387,14 +401,6 @@ public class NotificationLockscreenUserManagerImpl implements
return mShowLockscreenNotifications && exceedsPriorityThreshold; return mShowLockscreenNotifications && exceedsPriorityThreshold;
} }
private void setShowLockscreenNotifications(boolean show) {
mShowLockscreenNotifications = show;
}
private void setLockscreenAllowRemoteInput(boolean allowLockscreenRemoteInput) {
mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
}
protected void updateLockscreenNotificationSetting() { protected void updateLockscreenNotificationSetting() {
final boolean show = mSecureSettings.getIntForUser( final boolean show = mSecureSettings.getIntForUser(
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
@@ -408,7 +414,7 @@ public class NotificationLockscreenUserManagerImpl implements
mHideSilentNotificationsOnLockscreen = mSecureSettings.getIntForUser( mHideSilentNotificationsOnLockscreen = mSecureSettings.getIntForUser(
Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1, mCurrentUserId) == 0; Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1, mCurrentUserId) == 0;
setShowLockscreenNotifications(show && allowedByDpm); mShowLockscreenNotifications = show && allowedByDpm;
if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) { if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
final boolean remoteInput = mSecureSettings.getIntForUser( final boolean remoteInput = mSecureSettings.getIntForUser(
@@ -418,9 +424,9 @@ public class NotificationLockscreenUserManagerImpl implements
final boolean remoteInputDpm = final boolean remoteInputDpm =
(dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0; (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0;
setLockscreenAllowRemoteInput(remoteInput && remoteInputDpm); mAllowLockscreenRemoteInput = remoteInput && remoteInputDpm;
} else { } else {
setLockscreenAllowRemoteInput(false); mAllowLockscreenRemoteInput = false;
} }
} }
@@ -428,7 +434,7 @@ public class NotificationLockscreenUserManagerImpl implements
* Has the given user chosen to allow their private (full) notifications to be shown even * Has the given user chosen to allow their private (full) notifications to be shown even
* when the lockscreen is in "public" (secure & locked) mode? * when the lockscreen is in "public" (secure & locked) mode?
*/ */
public boolean userAllowsPrivateNotificationsInPublic(int userHandle) { protected boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
if (userHandle == UserHandle.USER_ALL) { if (userHandle == UserHandle.USER_ALL) {
return true; return true;
} }
@@ -473,10 +479,12 @@ public class NotificationLockscreenUserManagerImpl implements
/** /**
* Save the current "public" (locked and secure) state of the lockscreen. * Save the current "public" (locked and secure) state of the lockscreen.
*/ */
@Override
public void setLockscreenPublicMode(boolean publicMode, int userId) { public void setLockscreenPublicMode(boolean publicMode, int userId) {
mLockscreenPublicMode.put(userId, publicMode); mLockscreenPublicMode.put(userId, publicMode);
} }
@Override
public boolean isLockscreenPublicMode(int userId) { public boolean isLockscreenPublicMode(int userId) {
if (userId == UserHandle.USER_ALL) { if (userId == UserHandle.USER_ALL) {
return mLockscreenPublicMode.get(mCurrentUserId, false); return mLockscreenPublicMode.get(mCurrentUserId, false);
@@ -493,6 +501,7 @@ public class NotificationLockscreenUserManagerImpl implements
* Has the given user chosen to allow notifications to be shown even when the lockscreen is in * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
* "public" (secure & locked) mode? * "public" (secure & locked) mode?
*/ */
@Override
public boolean userAllowsNotificationsInPublic(int userHandle) { public boolean userAllowsNotificationsInPublic(int userHandle) {
if (isCurrentProfile(userHandle) && userHandle != mCurrentUserId) { if (isCurrentProfile(userHandle) && userHandle != mCurrentUserId) {
return true; return true;
@@ -513,36 +522,37 @@ public class NotificationLockscreenUserManagerImpl implements
} }
/** @return true if the entry needs redaction when on the lockscreen. */ /** @return true if the entry needs redaction when on the lockscreen. */
public boolean needsRedaction(NotificationEntry ent) { @Override
public boolean notifNeedsRedactionInPublic(NotificationEntry ent) {
int userId = ent.getSbn().getUserId(); int userId = ent.getSbn().getUserId();
return ent.hasSensitiveContents() && sensitiveNotifsNeedRedactionInPublic(userId);
}
@Override
public boolean sensitiveNotifsNeedRedactionInPublic(int userId) {
boolean isCurrentUserRedactingNotifs = boolean isCurrentUserRedactingNotifs =
!userAllowsPrivateNotificationsInPublic(mCurrentUserId); !userAllowsPrivateNotificationsInPublic(mCurrentUserId);
if (userId == mCurrentUserId) {
return isCurrentUserRedactingNotifs;
}
boolean isNotifForManagedProfile = mCurrentManagedProfiles.contains(userId); boolean isNotifForManagedProfile = mCurrentManagedProfiles.contains(userId);
boolean isNotifUserRedacted = !userAllowsPrivateNotificationsInPublic(userId); boolean isNotifUserRedacted = !userAllowsPrivateNotificationsInPublic(userId);
// redact notifications if the current user is redacting notifications; however if the // redact notifications if the current user is redacting notifications; however if the
// notification is associated with a managed profile, we rely on the managed profile // notification is associated with a managed profile, we rely on the managed profile
// setting to determine whether to redact it // setting to determine whether to redact it
boolean isNotifRedacted = (!isNotifForManagedProfile && isCurrentUserRedactingNotifs) return (!isNotifForManagedProfile && isCurrentUserRedactingNotifs) || isNotifUserRedacted;
|| isNotifUserRedacted;
boolean notificationRequestsRedaction =
ent.getSbn().getNotification().visibility == Notification.VISIBILITY_PRIVATE;
boolean userForcesRedaction = packageHasVisibilityOverride(ent.getSbn().getKey());
return userForcesRedaction || notificationRequestsRedaction && isNotifRedacted;
} }
private boolean packageHasVisibilityOverride(String key) { @Override
if (mCommonNotifCollectionLazy.get() == null) { public void addOnNeedsRedactionInPublicChangedListener(Runnable listener) {
Log.wtf(TAG, "mEntryManager was null!", new Throwable()); mOnSensitiveContentRedactionChangeListeners.addIfAbsent(listener);
return true; }
}
NotificationEntry entry = mCommonNotifCollectionLazy.get().getEntry(key); @Override
return entry != null public void removeOnNeedsRedactionInPublicChangedListener(Runnable listener) {
&& entry.getRanking().getLockscreenVisibilityOverride() mOnSensitiveContentRedactionChangeListeners.remove(listener);
== Notification.VISIBILITY_PRIVATE;
} }
private void updateCurrentProfilesCache() { private void updateCurrentProfilesCache() {
@@ -562,12 +572,16 @@ public class NotificationLockscreenUserManagerImpl implements
for (UserChangedListener listener : mListeners) { for (UserChangedListener listener : mListeners) {
listener.onCurrentProfilesChanged(mCurrentProfiles); listener.onCurrentProfilesChanged(mCurrentProfiles);
} }
for (Runnable listener : mOnSensitiveContentRedactionChangeListeners) {
listener.run();
}
}); });
} }
/** /**
* If any of the profiles are in public mode. * If any of the profiles are in public mode.
*/ */
@Override
public boolean isAnyProfilePublicMode() { public boolean isAnyProfilePublicMode() {
synchronized (mLock) { synchronized (mLock) {
for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) { for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
@@ -596,10 +610,12 @@ public class NotificationLockscreenUserManagerImpl implements
/** /**
* Returns the current user id. This can change if the user is switched. * Returns the current user id. This can change if the user is switched.
*/ */
@Override
public int getCurrentUserId() { public int getCurrentUserId() {
return mCurrentUserId; return mCurrentUserId;
} }
@Override
public SparseArray<UserInfo> getCurrentProfiles() { public SparseArray<UserInfo> getCurrentProfiles() {
return mCurrentProfiles; return mCurrentProfiles;
} }
@@ -640,7 +656,8 @@ public class NotificationLockscreenUserManagerImpl implements
setLockscreenPublicMode(isProfilePublic, userId); setLockscreenPublicMode(isProfilePublic, userId);
mUsersWithSeparateWorkChallenge.put(userId, needsSeparateChallenge); mUsersWithSeparateWorkChallenge.put(userId, needsSeparateChallenge);
} }
getEntryManager().updateNotifications("NotificationLockscreenUserManager.updatePublicMode"); mEntryManagerLazy.get()
.updateNotifications("NotificationLockscreenUserManager.updatePublicMode");
} }
@Override @Override

View File

@@ -53,6 +53,7 @@ import com.android.wm.shell.bubbles.Bubbles;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Stack; import java.util.Stack;
@@ -207,12 +208,9 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
|| !mLockscreenUserManager.needsSeparateWorkChallenge(userId))) { || !mLockscreenUserManager.needsSeparateWorkChallenge(userId))) {
userPublic = false; userPublic = false;
} }
boolean needsRedaction = mLockscreenUserManager.needsRedaction(ent); boolean needsRedaction = mLockscreenUserManager.notifNeedsRedactionInPublic(ent);
boolean sensitive = userPublic && needsRedaction; boolean sensitive = userPublic && needsRedaction;
boolean deviceSensitive = devicePublic ent.getRow().setSensitive(sensitive);
&& !mLockscreenUserManager.userAllowsPrivateNotificationsInPublic(
currentUserId);
ent.setSensitive(sensitive, deviceSensitive);
ent.getRow().setNeedsRedaction(needsRedaction); ent.getRow().setNeedsRedaction(needsRedaction);
mLowPriorityInflationHelper.recheckLowPriorityViewAndInflate(ent, ent.getRow()); mLowPriorityInflationHelper.recheckLowPriorityViewAndInflate(ent, ent.getRow());
boolean isChildInGroup = mGroupManager.isChildInGroup(ent); boolean isChildInGroup = mGroupManager.isChildInGroup(ent);
@@ -365,6 +363,8 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
boolean hasClearableAlertingNotifs = false; boolean hasClearableAlertingNotifs = false;
boolean hasNonClearableSilentNotifs = false; boolean hasNonClearableSilentNotifs = false;
boolean hasClearableSilentNotifs = false; boolean hasClearableSilentNotifs = false;
HashSet<Integer> clearableAlertingSensitiveNotifUsers = new HashSet<>();
HashSet<Integer> clearableSilentSensitiveNotifUsers = new HashSet<>();
final int childCount = mListContainer.getContainerChildCount(); final int childCount = mListContainer.getContainerChildCount();
int visibleTopLevelEntries = 0; int visibleTopLevelEntries = 0;
for (int i = 0; i < childCount; i++) { for (int i = 0; i < childCount; i++) {
@@ -376,10 +376,11 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
continue; continue;
} }
final ExpandableNotificationRow row = (ExpandableNotificationRow) child; final ExpandableNotificationRow row = (ExpandableNotificationRow) child;
boolean isSilent = row.getEntry().getBucket() == BUCKET_SILENT; NotificationEntry entry = row.getEntry();
boolean isSilent = entry.getBucket() == BUCKET_SILENT;
// NOTE: NotificationEntry.isClearable() will internally check group children to ensure // NOTE: NotificationEntry.isClearable() will internally check group children to ensure
// the group itself definitively clearable. // the group itself definitively clearable.
boolean isClearable = row.getEntry().isClearable(); boolean isClearable = entry.isClearable();
visibleTopLevelEntries++; visibleTopLevelEntries++;
if (isSilent) { if (isSilent) {
if (isClearable) { if (isClearable) {
@@ -394,13 +395,24 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
hasNonClearableAlertingNotifs = true; hasNonClearableAlertingNotifs = true;
} }
} }
if (isClearable && entry.hasSensitiveContents()) {
int userId = entry.getSbn().getUserId();
if (isSilent) {
clearableSilentSensitiveNotifUsers.add(userId);
} else {
clearableAlertingSensitiveNotifUsers.add(userId);
}
}
} }
mStackController.setNotifStats(new NotifStats( mStackController.setNotifStats(new NotifStats(
visibleTopLevelEntries /* numActiveNotifs */, visibleTopLevelEntries /* numActiveNotifs */,
hasNonClearableAlertingNotifs /* hasNonClearableAlertingNotifs */, hasNonClearableAlertingNotifs /* hasNonClearableAlertingNotifs */,
hasClearableAlertingNotifs /* hasClearableAlertingNotifs */, hasClearableAlertingNotifs /* hasClearableAlertingNotifs */,
hasNonClearableSilentNotifs /* hasNonClearableSilentNotifs */, hasNonClearableSilentNotifs /* hasNonClearableSilentNotifs */,
hasClearableSilentNotifs /* hasClearableSilentNotifs */ hasClearableSilentNotifs /* hasClearableSilentNotifs */,
clearableAlertingSensitiveNotifUsers /* clearableAlertingSensitiveNotifUsers */,
clearableSilentSensitiveNotifUsers /* clearableSilentSensitiveNotifUsers */
)); ));
Trace.endSection(); Trace.endSection();
} }

View File

@@ -80,7 +80,7 @@ public class DynamicPrivacyController implements KeyguardStateController.Callbac
@VisibleForTesting @VisibleForTesting
boolean isDynamicPrivacyEnabled() { boolean isDynamicPrivacyEnabled() {
return !mLockscreenUserManager.userAllowsPrivateNotificationsInPublic( return mLockscreenUserManager.sensitiveNotifsNeedRedactionInPublic(
mLockscreenUserManager.getCurrentUserId()); mLockscreenUserManager.getCurrentUserId());
} }
@@ -95,6 +95,10 @@ public class DynamicPrivacyController implements KeyguardStateController.Callbac
mListeners.add(listener); mListeners.add(listener);
} }
public void removeListener(Listener listener) {
mListeners.remove(listener);
}
/** /**
* Is the notification shade currently in a locked down mode where it's fully showing but the * Is the notification shade currently in a locked down mode where it's fully showing but the
* contents aren't revealed yet? * contents aren't revealed yet?

View File

@@ -169,9 +169,6 @@ public final class NotificationEntry extends ListEntry {
*/ */
private boolean hasSentReply; private boolean hasSentReply;
private boolean mSensitive = true;
private List<OnSensitivityChangedListener> mOnSensitivityChangedListeners = new ArrayList<>();
private boolean mAutoHeadsUp; private boolean mAutoHeadsUp;
private boolean mPulseSupressed; private boolean mPulseSupressed;
private int mBucket = BUCKET_ALERTING; private int mBucket = BUCKET_ALERTING;
@@ -867,33 +864,29 @@ public final class NotificationEntry extends ListEntry {
} }
/** /**
* Set this notification to be sensitive. * Returns the visibility of this notification on the lockscreen, taking into account both the
* * notification's defined visibility, as well as the visibility override as determined by the
* @param sensitive true if the content of this notification is sensitive right now * device policy.
* @param deviceSensitive true if the device in general is sensitive right now
*/ */
public void setSensitive(boolean sensitive, boolean deviceSensitive) { public int getLockscreenVisibility() {
getRow().setSensitive(sensitive, deviceSensitive); int setting = mRanking.getLockscreenVisibilityOverride();
if (sensitive != mSensitive) { if (setting == Ranking.VISIBILITY_NO_OVERRIDE) {
mSensitive = sensitive; setting = mSbn.getNotification().visibility;
for (int i = 0; i < mOnSensitivityChangedListeners.size(); i++) {
mOnSensitivityChangedListeners.get(i).onSensitivityChanged(this);
}
} }
return setting;
} }
public boolean isSensitive() { /**
return mSensitive; * Does this notification contain sensitive content? If the user's settings specify, then this
} * content would need to be redacted when the device this public.
*
/** Add a listener to be notified when the entry's sensitivity changes. */ * NOTE: If the notification's visibility setting is VISIBILITY_SECRET, then this will return
public void addOnSensitivityChangedListener(OnSensitivityChangedListener listener) { * false; SECRET notifications are omitted entirely when the device is public, so effectively
mOnSensitivityChangedListeners.add(listener); * the contents of the notification are not sensitive whenever the notification is actually
} * visible.
*/
/** Remove a listener that was registered above. */ public boolean hasSensitiveContents() {
public void removeOnSensitivityChangedListener(OnSensitivityChangedListener listener) { return getLockscreenVisibility() == Notification.VISIBILITY_PRIVATE;
mOnSensitivityChangedListeners.remove(listener);
} }
public boolean isPulseSuppressed() { public boolean isPulseSuppressed() {
@@ -954,12 +947,6 @@ public final class NotificationEntry extends ListEntry {
} }
} }
/** Listener interface for {@link #addOnSensitivityChangedListener} */
public interface OnSensitivityChangedListener {
/** Called when the sensitivity changes */
void onSensitivityChanged(@NonNull NotificationEntry entry);
}
/** @see #getDismissState() */ /** @see #getDismissState() */
public enum DismissState { public enum DismissState {
/** User has not dismissed this notif or its parent */ /** User has not dismissed this notif or its parent */

View File

@@ -56,7 +56,6 @@ class NotifCoordinatorsImpl @Inject constructor(
smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator, smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator,
viewConfigCoordinator: ViewConfigCoordinator, viewConfigCoordinator: ViewConfigCoordinator,
visualStabilityCoordinator: VisualStabilityCoordinator, visualStabilityCoordinator: VisualStabilityCoordinator,
sensitiveContentCoordinator: SensitiveContentCoordinator,
activityLaunchAnimCoordinator: ActivityLaunchAnimCoordinator activityLaunchAnimCoordinator: ActivityLaunchAnimCoordinator
) : NotifCoordinators { ) : NotifCoordinators {
@@ -94,7 +93,6 @@ class NotifCoordinatorsImpl @Inject constructor(
mCoordinators.add(shadeEventCoordinator) mCoordinators.add(shadeEventCoordinator)
mCoordinators.add(viewConfigCoordinator) mCoordinators.add(viewConfigCoordinator)
mCoordinators.add(visualStabilityCoordinator) mCoordinators.add(visualStabilityCoordinator)
mCoordinators.add(sensitiveContentCoordinator)
mCoordinators.add(activityLaunchAnimCoordinator) mCoordinators.add(activityLaunchAnimCoordinator)
if (notifPipelineFlags.isSmartspaceDedupingEnabled()) { if (notifPipelineFlags.isSmartspaceDedupingEnabled()) {
mCoordinators.add(smartspaceDedupingCoordinator) mCoordinators.add(smartspaceDedupingCoordinator)

View File

@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.notification.collection.coordinator; package com.android.systemui.statusbar.notification.collection.coordinator;
import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -29,13 +28,11 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.collection.render.NodeController; import com.android.systemui.statusbar.notification.collection.render.NodeController;
import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
import com.android.systemui.statusbar.notification.dagger.AlertingHeader; import com.android.systemui.statusbar.notification.dagger.AlertingHeader;
import com.android.systemui.statusbar.notification.dagger.SilentHeader; import com.android.systemui.statusbar.notification.dagger.SilentHeader;
import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt; import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
@@ -53,10 +50,10 @@ public class RankingCoordinator implements Coordinator {
private final HighPriorityProvider mHighPriorityProvider; private final HighPriorityProvider mHighPriorityProvider;
private final SectionClassifier mSectionClassifier; private final SectionClassifier mSectionClassifier;
private final NodeController mSilentNodeController; private final NodeController mSilentNodeController;
private final SectionHeaderController mSilentHeaderController;
private final NodeController mAlertingHeaderController; private final NodeController mAlertingHeaderController;
private boolean mHasSilentEntries; private final AlertingNotifSectioner mAlertingNotifSectioner = new AlertingNotifSectioner();
private boolean mHasMinimizedEntries; private final SilentNotifSectioner mSilentNotifSectioner = new SilentNotifSectioner();
private final MinimizedNotifSectioner mMinimizedNotifSectioner = new MinimizedNotifSectioner();
@Inject @Inject
public RankingCoordinator( public RankingCoordinator(
@@ -64,14 +61,12 @@ public class RankingCoordinator implements Coordinator {
HighPriorityProvider highPriorityProvider, HighPriorityProvider highPriorityProvider,
SectionClassifier sectionClassifier, SectionClassifier sectionClassifier,
@AlertingHeader NodeController alertingHeaderController, @AlertingHeader NodeController alertingHeaderController,
@SilentHeader SectionHeaderController silentHeaderController,
@SilentHeader NodeController silentNodeController) { @SilentHeader NodeController silentNodeController) {
mStatusBarStateController = statusBarStateController; mStatusBarStateController = statusBarStateController;
mHighPriorityProvider = highPriorityProvider; mHighPriorityProvider = highPriorityProvider;
mSectionClassifier = sectionClassifier; mSectionClassifier = sectionClassifier;
mAlertingHeaderController = alertingHeaderController; mAlertingHeaderController = alertingHeaderController;
mSilentNodeController = silentNodeController; mSilentNodeController = silentNodeController;
mSilentHeaderController = silentHeaderController;
} }
@Override @Override
@@ -95,82 +90,6 @@ public class RankingCoordinator implements Coordinator {
return mMinimizedNotifSectioner; return mMinimizedNotifSectioner;
} }
private final NotifSectioner mAlertingNotifSectioner = new NotifSectioner("Alerting",
NotificationPriorityBucketKt.BUCKET_ALERTING) {
@Override
public boolean isInSection(ListEntry entry) {
return mHighPriorityProvider.isHighPriority(entry);
}
@Nullable
@Override
public NodeController getHeaderNodeController() {
// TODO: remove SHOW_ALL_SECTIONS, this redundant method, and mAlertingHeaderController
if (SHOW_ALL_SECTIONS) {
return mAlertingHeaderController;
}
return null;
}
};
private final NotifSectioner mSilentNotifSectioner = new NotifSectioner("Silent",
NotificationPriorityBucketKt.BUCKET_SILENT) {
@Override
public boolean isInSection(ListEntry entry) {
return !mHighPriorityProvider.isHighPriority(entry)
&& !entry.getRepresentativeEntry().isAmbient();
}
@Nullable
@Override
public NodeController getHeaderNodeController() {
return mSilentNodeController;
}
@Nullable
@Override
public void onEntriesUpdated(@NonNull List<ListEntry> entries) {
mHasSilentEntries = false;
for (int i = 0; i < entries.size(); i++) {
if (entries.get(i).getRepresentativeEntry().getSbn().isClearable()) {
mHasSilentEntries = true;
break;
}
}
mSilentHeaderController.setClearSectionEnabled(
mHasSilentEntries | mHasMinimizedEntries);
}
};
private final NotifSectioner mMinimizedNotifSectioner = new NotifSectioner("Minimized",
NotificationPriorityBucketKt.BUCKET_SILENT) {
@Override
public boolean isInSection(ListEntry entry) {
return !mHighPriorityProvider.isHighPriority(entry)
&& entry.getRepresentativeEntry().isAmbient();
}
@Nullable
@Override
public NodeController getHeaderNodeController() {
return mSilentNodeController;
}
@Nullable
@Override
public void onEntriesUpdated(@NonNull List<ListEntry> entries) {
mHasMinimizedEntries = false;
for (int i = 0; i < entries.size(); i++) {
if (entries.get(i).getRepresentativeEntry().getSbn().isClearable()) {
mHasMinimizedEntries = true;
break;
}
}
mSilentHeaderController.setClearSectionEnabled(
mHasSilentEntries | mHasMinimizedEntries);
}
};
/** /**
* Checks whether to filter out the given notification based the notification's Ranking object. * Checks whether to filter out the given notification based the notification's Ranking object.
* NotifListBuilder invalidates the notification list each time the ranking is updated, * NotifListBuilder invalidates the notification list each time the ranking is updated,
@@ -202,4 +121,64 @@ public class RankingCoordinator implements Coordinator {
mDndVisualEffectsFilter.invalidateList(); mDndVisualEffectsFilter.invalidateList();
} }
}; };
private class AlertingNotifSectioner extends NotifSectioner {
AlertingNotifSectioner() {
super("Alerting", NotificationPriorityBucketKt.BUCKET_ALERTING);
}
@Override
public boolean isInSection(ListEntry entry) {
return mHighPriorityProvider.isHighPriority(entry);
}
@Nullable
@Override
public NodeController getHeaderNodeController() {
// TODO: remove SHOW_ALL_SECTIONS, this redundant method, and mAlertingHeaderController
if (SHOW_ALL_SECTIONS) {
return mAlertingHeaderController;
}
return null;
}
}
private class SilentNotifSectioner extends NotifSectioner {
SilentNotifSectioner() {
super("Silent", NotificationPriorityBucketKt.BUCKET_SILENT);
}
@Override
public boolean isInSection(ListEntry entry) {
return !mHighPriorityProvider.isHighPriority(entry)
&& !entry.getRepresentativeEntry().isAmbient();
}
@Nullable
@Override
public NodeController getHeaderNodeController() {
return mSilentNodeController;
}
}
private class MinimizedNotifSectioner extends NotifSectioner {
MinimizedNotifSectioner() {
super("Minimized", NotificationPriorityBucketKt.BUCKET_SILENT);
}
@Override
public boolean isInSection(ListEntry entry) {
return !mHighPriorityProvider.isHighPriority(entry)
&& entry.getRepresentativeEntry().isAmbient();
}
@Nullable
@Override
public NodeController getHeaderNodeController() {
return mSilentNodeController;
}
}
} }

View File

@@ -1,124 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.collection.coordinator
import android.os.UserHandle
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.notification.DynamicPrivacyController
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator
import com.android.systemui.statusbar.policy.KeyguardStateController
import dagger.Binds
import dagger.Module
import javax.inject.Inject
@Module(includes = [PrivateSensitiveContentCoordinatorModule::class])
interface SensitiveContentCoordinatorModule
@Module
private interface PrivateSensitiveContentCoordinatorModule {
@Binds
fun bindCoordinator(impl: SensitiveContentCoordinatorImpl): SensitiveContentCoordinator
}
/** Coordinates re-inflation and post-processing of sensitive notification content. */
interface SensitiveContentCoordinator : Coordinator
@CoordinatorScope
private class SensitiveContentCoordinatorImpl @Inject constructor(
private val dynamicPrivacyController: DynamicPrivacyController,
private val lockscreenUserManager: NotificationLockscreenUserManager,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val statusBarStateController: StatusBarStateController,
private val keyguardStateController: KeyguardStateController
) : Invalidator("SensitiveContentInvalidator"),
SensitiveContentCoordinator,
DynamicPrivacyController.Listener,
OnBeforeRenderListListener {
override fun attach(pipeline: NotifPipeline) {
dynamicPrivacyController.addListener(this)
pipeline.addOnBeforeRenderListListener(this)
pipeline.addPreRenderInvalidator(this)
}
override fun onDynamicPrivacyChanged(): Unit = invalidateList()
override fun onBeforeRenderList(entries: List<ListEntry>) {
if (keyguardStateController.isKeyguardGoingAway() ||
statusBarStateController.getState() == StatusBarState.KEYGUARD &&
keyguardUpdateMonitor.getUserUnlockedWithBiometricAndIsBypassing(
KeyguardUpdateMonitor.getCurrentUser())) {
// don't update yet if:
// - the keyguard is currently going away
// - LS is about to be dismissed by a biometric that bypasses LS (avoid notif flash)
// TODO(b/206118999): merge this class with KeyguardCoordinator which ensures the
// dependent state changes invalidate the pipeline
return
}
val currentUserId = lockscreenUserManager.currentUserId
val devicePublic = lockscreenUserManager.isLockscreenPublicMode(currentUserId)
val deviceSensitive = devicePublic &&
!lockscreenUserManager.userAllowsPrivateNotificationsInPublic(currentUserId)
val dynamicallyUnlocked = dynamicPrivacyController.isDynamicallyUnlocked
for (entry in extractAllRepresentativeEntries(entries).filter { it.rowExists() }) {
val notifUserId = entry.sbn.user.identifier
val userLockscreen = devicePublic ||
lockscreenUserManager.isLockscreenPublicMode(notifUserId)
val userPublic = when {
// if we're not on the lockscreen, we're definitely private
!userLockscreen -> false
// we are on the lockscreen, so unless we're dynamically unlocked, we're
// definitely public
!dynamicallyUnlocked -> true
// we're dynamically unlocked, but check if the notification needs
// a separate challenge if it's from a work profile
else -> when (notifUserId) {
currentUserId -> false
UserHandle.USER_ALL -> false
else -> lockscreenUserManager.needsSeparateWorkChallenge(notifUserId)
}
}
val needsRedaction = lockscreenUserManager.needsRedaction(entry)
val isSensitive = userPublic && needsRedaction
entry.setSensitive(isSensitive, deviceSensitive)
}
}
}
private fun extractAllRepresentativeEntries(
entries: List<ListEntry>
): Sequence<NotificationEntry> =
entries.asSequence().flatMap(::extractAllRepresentativeEntries)
private fun extractAllRepresentativeEntries(listEntry: ListEntry): Sequence<NotificationEntry> =
sequence {
listEntry.representativeEntry?.let { yield(it) }
if (listEntry is GroupEntry) {
yieldAll(extractAllRepresentativeEntries(listEntry.children))
}
}

View File

@@ -50,6 +50,8 @@ class StackCoordinator @Inject internal constructor(
var hasClearableAlertingNotifs = false var hasClearableAlertingNotifs = false
var hasNonClearableSilentNotifs = false var hasNonClearableSilentNotifs = false
var hasClearableSilentNotifs = false var hasClearableSilentNotifs = false
val clearableAlertingSensitiveNotifUsers = mutableSetOf<Int>()
val clearableSilentSensitiveNotifUsers = mutableSetOf<Int>()
entries.forEach { entries.forEach {
val section = checkNotNull(it.section) { "Null section for ${it.key}" } val section = checkNotNull(it.section) { "Null section for ${it.key}" }
val entry = checkNotNull(it.representativeEntry) { "Null notif entry for ${it.key}" } val entry = checkNotNull(it.representativeEntry) { "Null notif entry for ${it.key}" }
@@ -63,13 +65,22 @@ class StackCoordinator @Inject internal constructor(
!isSilent && isClearable -> hasClearableAlertingNotifs = true !isSilent && isClearable -> hasClearableAlertingNotifs = true
!isSilent && !isClearable -> hasNonClearableAlertingNotifs = true !isSilent && !isClearable -> hasNonClearableAlertingNotifs = true
} }
if (isClearable && entry.hasSensitiveContents()) {
if (isSilent) {
clearableSilentSensitiveNotifUsers.add(entry.sbn.userId)
} else {
clearableAlertingSensitiveNotifUsers.add(entry.sbn.userId)
}
}
} }
return NotifStats( return NotifStats(
numActiveNotifs = entries.size, numActiveNotifs = entries.size,
hasNonClearableAlertingNotifs = hasNonClearableAlertingNotifs, hasNonClearableAlertingNotifs = hasNonClearableAlertingNotifs,
hasClearableAlertingNotifs = hasClearableAlertingNotifs, hasClearableAlertingNotifs = hasClearableAlertingNotifs,
hasNonClearableSilentNotifs = hasNonClearableSilentNotifs, hasNonClearableSilentNotifs = hasNonClearableSilentNotifs,
hasClearableSilentNotifs = hasClearableSilentNotifs hasClearableSilentNotifs = hasClearableSilentNotifs,
clearableAlertingSensitiveNotifUsers = clearableAlertingSensitiveNotifUsers,
clearableSilentSensitiveNotifUsers = clearableSilentSensitiveNotifUsers
) )
} }
} }

View File

@@ -20,7 +20,6 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.notification.collection.coordinator.ActivityLaunchAnimCoordinatorModule import com.android.systemui.statusbar.notification.collection.coordinator.ActivityLaunchAnimCoordinatorModule
import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators
import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinatorsImpl import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinatorsImpl
import com.android.systemui.statusbar.notification.collection.coordinator.SensitiveContentCoordinatorModule
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
@@ -50,7 +49,6 @@ interface CoordinatorsSubcomponent {
@Module(includes = [ @Module(includes = [
ActivityLaunchAnimCoordinatorModule::class, ActivityLaunchAnimCoordinatorModule::class,
SensitiveContentCoordinatorModule::class,
]) ])
private abstract class InternalCoordinatorsModule { private abstract class InternalCoordinatorsModule {
@Binds @Binds

View File

@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.collection.inflation; package com.android.systemui.statusbar.notification.collection.inflation;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
@@ -249,10 +251,13 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
RowContentBindParams params = mRowContentBindStage.getStageParams(entry); RowContentBindParams params = mRowContentBindStage.getStageParams(entry);
params.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight); params.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
params.setUseLowPriority(isLowPriority); params.setUseLowPriority(isLowPriority);
boolean needsRedaction =
// TODO: Replace this API with RowContentBindParams directly. Also move to a separate mNotificationLockscreenUserManager.notifNeedsRedactionInPublic(entry);
// redaction controller. if (needsRedaction) {
row.setNeedsRedaction(mNotificationLockscreenUserManager.needsRedaction(entry)); params.requireContentViews(FLAG_CONTENT_VIEW_PUBLIC);
} else {
params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC);
}
params.rebindAllContentViews(); params.rebindAllContentViews();
mRowContentBindStage.requestRebind(entry, en -> { mRowContentBindStage.requestRebind(entry, en -> {

View File

@@ -28,11 +28,21 @@ data class NotifStats(
val hasNonClearableAlertingNotifs: Boolean, val hasNonClearableAlertingNotifs: Boolean,
val hasClearableAlertingNotifs: Boolean, val hasClearableAlertingNotifs: Boolean,
val hasNonClearableSilentNotifs: Boolean, val hasNonClearableSilentNotifs: Boolean,
val hasClearableSilentNotifs: Boolean val hasClearableSilentNotifs: Boolean,
val clearableAlertingSensitiveNotifUsers: Set<Int>,
val clearableSilentSensitiveNotifUsers: Set<Int>
) { ) {
companion object { companion object {
@JvmStatic @JvmStatic
val empty = NotifStats(0, false, false, false, false) val empty = NotifStats(
numActiveNotifs = 0,
hasNonClearableAlertingNotifs = false,
hasClearableAlertingNotifs = false,
hasNonClearableSilentNotifs = false,
hasClearableSilentNotifs = false,
clearableAlertingSensitiveNotifUsers = emptySet(),
clearableSilentSensitiveNotifUsers = emptySet(),
)
} }
} }

View File

@@ -182,4 +182,4 @@ annotation class HeaderClickAction
@Scope @Scope
@Retention(AnnotationRetention.BINARY) @Retention(AnnotationRetention.BINARY)
annotation class SectionHeaderScope annotation class SectionHeaderScope

View File

@@ -28,6 +28,7 @@ import android.widget.ImageView
import com.android.internal.statusbar.StatusBarIcon import com.android.internal.statusbar.StatusBarIcon
import com.android.systemui.R import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.notification.InflationException import com.android.systemui.statusbar.notification.InflationException
import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -49,31 +50,29 @@ import javax.inject.Inject
class IconManager @Inject constructor( class IconManager @Inject constructor(
private val notifCollection: CommonNotifCollection, private val notifCollection: CommonNotifCollection,
private val launcherApps: LauncherApps, private val launcherApps: LauncherApps,
private val iconBuilder: IconBuilder private val iconBuilder: IconBuilder,
private val notifLockscreenUserManager: NotificationLockscreenUserManager
) : ConversationIconManager { ) : ConversationIconManager {
private var unimportantConversationKeys: Set<String> = emptySet() private var unimportantConversationKeys: Set<String> = emptySet()
fun attach() { fun attach() {
notifCollection.addCollectionListener(entryListener) notifCollection.addCollectionListener(entryListener)
notifLockscreenUserManager.addOnNeedsRedactionInPublicChangedListener(sensitivityListener)
} }
private val entryListener = object : NotifCollectionListener { private val entryListener = object : NotifCollectionListener {
override fun onEntryInit(entry: NotificationEntry) {
entry.addOnSensitivityChangedListener(sensitivityListener)
}
override fun onEntryCleanUp(entry: NotificationEntry) {
entry.removeOnSensitivityChangedListener(sensitivityListener)
}
override fun onRankingApplied() { override fun onRankingApplied() {
// rankings affect whether a conversation is important, which can change the icons // rankings affect whether a conversation is important, which can change the icons
recalculateForImportantConversationChange() recalculateForImportantConversationChange()
} }
} }
private val sensitivityListener = NotificationEntry.OnSensitivityChangedListener { private val sensitivityListener = Runnable {
entry -> updateIconsSafe(entry) for (entry in notifCollection.allNotifs) {
if (entry.hasSensitiveContents()) {
updateIconsSafe(entry)
}
}
} }
private fun recalculateForImportantConversationChange() { private fun recalculateForImportantConversationChange() {
@@ -182,12 +181,16 @@ class IconManager @Inject constructor(
} }
} }
private inline val NotificationEntry.needsRedactionInPublic: Boolean get() =
hasSensitiveContents() &&
notifLockscreenUserManager.sensitiveNotifsNeedRedactionInPublic(sbn.userId)
@Throws(InflationException::class) @Throws(InflationException::class)
private fun getIconDescriptors( private fun getIconDescriptors(
entry: NotificationEntry entry: NotificationEntry
): Pair<StatusBarIcon, StatusBarIcon> { ): Pair<StatusBarIcon, StatusBarIcon> {
val iconDescriptor = getIconDescriptor(entry, false /* redact */) val iconDescriptor = getIconDescriptor(entry, false /* redact */)
val sensitiveDescriptor = if (entry.isSensitive) { val sensitiveDescriptor = if (entry.needsRedactionInPublic) {
getIconDescriptor(entry, true /* redact */) getIconDescriptor(entry, true /* redact */)
} else { } else {
iconDescriptor iconDescriptor
@@ -310,7 +313,7 @@ class IconManager @Inject constructor(
iconView === entry.icons.shelfIcon || iconView === entry.icons.aodIcon iconView === entry.icons.shelfIcon || iconView === entry.icons.aodIcon
val isSmallIcon = iconDescriptor.icon.equals(entry.sbn.notification.smallIcon) val isSmallIcon = iconDescriptor.icon.equals(entry.sbn.notification.smallIcon)
return isImportantConversation(entry) && !isSmallIcon && return isImportantConversation(entry) && !isSmallIcon &&
(!usedInSensitiveContext || !entry.isSensitive) (!usedInSensitiveContext || !entry.needsRedactionInPublic)
} }
private fun isImportantConversation(entry: NotificationEntry): Boolean { private fun isImportantConversation(entry: NotificationEntry): Boolean {
@@ -338,4 +341,4 @@ interface ConversationIconManager {
* of a group from which the priority notification has been removed. * of a group from which the priority notification has been removed.
*/ */
fun setUnimportantConversations(keys: Collection<String>) fun setUnimportantConversations(keys: Collection<String>)
} }

View File

@@ -93,8 +93,8 @@ import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener; import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
import com.android.systemui.statusbar.notification.FeedbackIcon; import com.android.systemui.statusbar.notification.FeedbackIcon;
import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
import com.android.systemui.statusbar.notification.NotificationFadeAware; import com.android.systemui.statusbar.notification.NotificationFadeAware;
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController; import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController;
import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -206,7 +206,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
/** Are we showing the "public" version */ /** Are we showing the "public" version */
private boolean mShowingPublic; private boolean mShowingPublic;
private boolean mSensitive; private boolean mSensitive;
private boolean mSensitiveHiddenInGeneral;
private boolean mShowingPublicInitialized; private boolean mShowingPublicInitialized;
private boolean mHideSensitiveForIntrinsicHeight; private boolean mHideSensitiveForIntrinsicHeight;
private float mHeaderVisibleAmount = DEFAULT_HEADER_VISIBLE_AMOUNT; private float mHeaderVisibleAmount = DEFAULT_HEADER_VISIBLE_AMOUNT;
@@ -1560,6 +1559,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mUseIncreasedHeadsUpHeight = use; mUseIncreasedHeadsUpHeight = use;
} }
// TODO: remove this method and mNeedsRedaction entirely once the old pipeline is gone
public void setNeedsRedaction(boolean needsRedaction) { public void setNeedsRedaction(boolean needsRedaction) {
// TODO: Move inflation logic out of this call and remove this method // TODO: Move inflation logic out of this call and remove this method
if (mNeedsRedaction != needsRedaction) { if (mNeedsRedaction != needsRedaction) {
@@ -2644,9 +2644,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked()); getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
} }
public void setSensitive(boolean sensitive, boolean hideSensitive) { public void setSensitive(boolean sensitive) {
mSensitive = sensitive; mSensitive = sensitive;
mSensitiveHiddenInGeneral = hideSensitive;
} }
@Override @Override
@@ -2736,7 +2735,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
* see {@link NotificationEntry#isDismissable()}. * see {@link NotificationEntry#isDismissable()}.
*/ */
public boolean canViewBeDismissed() { public boolean canViewBeDismissed() {
return mEntry.isDismissable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral); // Entry not dismissable.
if (!mEntry.isDismissable()) {
return false;
}
// Entry shouldn't be showing the public layout, it can be dismissed.
if (!shouldShowPublic()) {
return true;
}
return false;
} }
/** /**
@@ -2745,7 +2752,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
* clearability see {@link NotificationEntry#isClearable()}. * clearability see {@link NotificationEntry#isClearable()}.
*/ */
public boolean canViewBeCleared() { public boolean canViewBeCleared() {
return mEntry.isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral); return mEntry.isClearable() && !shouldShowPublic();
} }
private boolean shouldShowPublic() { private boolean shouldShowPublic() {
@@ -3509,10 +3516,28 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
pw.print(", translation: " + getTranslation()); pw.print(", translation: " + getTranslation());
pw.print(", removed: " + isRemoved()); pw.print(", removed: " + isRemoved());
pw.print(", expandAnimationRunning: " + mExpandAnimationRunning); pw.print(", expandAnimationRunning: " + mExpandAnimationRunning);
NotificationContentView showingLayout = getShowingLayout(); pw.print(", sensitive: " + mSensitive);
pw.print(", privateShowing: " + (showingLayout == mPrivateLayout)); pw.print(", hideSensitiveForIntrinsicHeight: " + mHideSensitiveForIntrinsicHeight);
pw.println(); pw.println(", privateShowing: " + !shouldShowPublic());
showingLayout.dump(pw, args); pw.print("privateLayout: ");
if (mPrivateLayout != null) {
pw.println();
DumpUtilsKt.withIncreasedIndent(pw, () -> {
mPrivateLayout.dump(pw, args);
mPrivateLayout.dumpSmartReplies(pw);
});
} else {
pw.println("null");
}
pw.print("publicLayout: ");
if (mPublicLayout != null) {
pw.println();
DumpUtilsKt.withIncreasedIndent(pw, () -> {
mPublicLayout.dump(pw, args);
});
} else {
pw.println("null");
}
if (getViewState() != null) { if (getViewState() != null) {
getViewState().dump(pw, args); getViewState().dump(pw, args);
@@ -3538,8 +3563,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
} }
pw.decreaseIndent(); pw.decreaseIndent();
pw.println("}"); pw.println("}");
} else if (mPrivateLayout != null) {
mPrivateLayout.dumpSmartReplies(pw);
} }
}); });
} }

View File

@@ -35,6 +35,7 @@ import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.FeedbackIcon; import com.android.systemui.statusbar.notification.FeedbackIcon;
@@ -69,6 +70,7 @@ import javax.inject.Named;
public class ExpandableNotificationRowController implements NotifViewController { public class ExpandableNotificationRowController implements NotifViewController {
private static final String TAG = "NotifRowController"; private static final String TAG = "NotifRowController";
private final ExpandableNotificationRow mView; private final ExpandableNotificationRow mView;
private final NotificationLockscreenUserManager mLockscreenUserManager;
private final NotificationListContainer mListContainer; private final NotificationListContainer mListContainer;
private final RemoteInputViewSubcomponent.Factory mRemoteInputViewSubcomponentFactory; private final RemoteInputViewSubcomponent.Factory mRemoteInputViewSubcomponentFactory;
private final ActivatableNotificationViewController mActivatableNotificationViewController; private final ActivatableNotificationViewController mActivatableNotificationViewController;
@@ -86,7 +88,6 @@ public class ExpandableNotificationRowController implements NotifViewController
private final ExpandableNotificationRow.OnExpandClickListener mOnExpandClickListener; private final ExpandableNotificationRow.OnExpandClickListener mOnExpandClickListener;
private final StatusBarStateController mStatusBarStateController; private final StatusBarStateController mStatusBarStateController;
private final MetricsLogger mMetricsLogger; private final MetricsLogger mMetricsLogger;
private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger = private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger =
this::logNotificationExpansion; this::logNotificationExpansion;
private final ExpandableNotificationRow.CoordinateOnClickListener mOnFeedbackClickListener; private final ExpandableNotificationRow.CoordinateOnClickListener mOnFeedbackClickListener;
@@ -100,12 +101,12 @@ public class ExpandableNotificationRowController implements NotifViewController
private final Optional<BubblesManager> mBubblesManagerOptional; private final Optional<BubblesManager> mBubblesManagerOptional;
private final SmartReplyConstants mSmartReplyConstants; private final SmartReplyConstants mSmartReplyConstants;
private final SmartReplyController mSmartReplyController; private final SmartReplyController mSmartReplyController;
private final ExpandableNotificationRowDragController mDragController; private final ExpandableNotificationRowDragController mDragController;
@Inject @Inject
public ExpandableNotificationRowController( public ExpandableNotificationRowController(
ExpandableNotificationRow view, ExpandableNotificationRow view,
NotificationLockscreenUserManager lockscreenUserManager,
ActivatableNotificationViewController activatableNotificationViewController, ActivatableNotificationViewController activatableNotificationViewController,
RemoteInputViewSubcomponent.Factory rivSubcomponentFactory, RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
MetricsLogger metricsLogger, MetricsLogger metricsLogger,
@@ -135,6 +136,7 @@ public class ExpandableNotificationRowController implements NotifViewController
Optional<BubblesManager> bubblesManagerOptional, Optional<BubblesManager> bubblesManagerOptional,
ExpandableNotificationRowDragController dragController) { ExpandableNotificationRowDragController dragController) {
mView = view; mView = view;
mLockscreenUserManager = lockscreenUserManager;
mListContainer = listContainer; mListContainer = listContainer;
mRemoteInputViewSubcomponentFactory = rivSubcomponentFactory; mRemoteInputViewSubcomponentFactory = rivSubcomponentFactory;
mActivatableNotificationViewController = activatableNotificationViewController; mActivatableNotificationViewController = activatableNotificationViewController;
@@ -214,6 +216,10 @@ public class ExpandableNotificationRowController implements NotifViewController
mView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); mView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
} }
mLockscreenUserManager
.addOnNeedsRedactionInPublicChangedListener(mNeedsRedactionListener);
mNeedsRedactionListener.run();
mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override @Override
public void onViewAttachedToWindow(View v) { public void onViewAttachedToWindow(View v) {
@@ -232,6 +238,14 @@ public class ExpandableNotificationRowController implements NotifViewController
}); });
} }
private final Runnable mNeedsRedactionListener = new Runnable() {
@Override
public void run() {
mView.setSensitive(
mLockscreenUserManager.notifNeedsRedactionInPublic(mView.getEntry()));
}
};
private final StatusBarStateController.StateListener mStatusBarStateListener = private final StatusBarStateController.StateListener mStatusBarStateListener =
new StatusBarStateController.StateListener() { new StatusBarStateController.StateListener() {
@Override @Override
@@ -333,4 +347,5 @@ public class ExpandableNotificationRowController implements NotifViewController
public void setFeedbackIcon(@Nullable FeedbackIcon icon) { public void setFeedbackIcon(@Nullable FeedbackIcon icon) {
mView.setFeedbackIcon(icon); mView.setFeedbackIcon(icon);
} }
} }

View File

@@ -61,6 +61,7 @@ import com.android.systemui.statusbar.policy.SmartReplyStateInflaterKt;
import com.android.systemui.statusbar.policy.SmartReplyView; import com.android.systemui.statusbar.policy.SmartReplyView;
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent; import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.util.Compile; import com.android.systemui.util.Compile;
import com.android.systemui.util.DumpUtilsKt;
import com.android.systemui.wmshell.BubblesManager; import com.android.systemui.wmshell.BubblesManager;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -1994,22 +1995,33 @@ public class NotificationContentView extends FrameLayout implements Notification
} }
} }
public void dump(PrintWriter pw, String[] args) { public void dump(PrintWriter pwOriginal, String[] args) {
IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal);
pw.print("contentView visibility: " + getVisibility()); pw.print("contentView visibility: " + getVisibility());
pw.print(", alpha: " + getAlpha()); pw.print(", alpha: " + getAlpha());
pw.print(", clipBounds: " + getClipBounds()); pw.print(", clipBounds: " + getClipBounds());
pw.print(", contentHeight: " + mContentHeight); pw.print(", contentHeight: " + mContentHeight);
pw.print(", visibleType: " + mVisibleType); pw.println(", currentVisibleType: " + mVisibleType);
View view = getViewForVisibleType(mVisibleType); DumpUtilsKt.withIncreasedIndent(pw, () -> {
pw.print(", visibleView "); int[] visTypes = {
if (view != null) { VISIBLE_TYPE_CONTRACTED,
pw.print(" visibility: " + view.getVisibility()); VISIBLE_TYPE_EXPANDED,
pw.print(", alpha: " + view.getAlpha()); VISIBLE_TYPE_HEADSUP,
pw.print(", clipBounds: " + view.getClipBounds()); VISIBLE_TYPE_SINGLELINE
} else { };
pw.print("null"); for (int visType : visTypes) {
} pw.print("visType: " + visType + " :: ");
pw.println(); View view = getViewForVisibleType(visType);
if (view != null) {
pw.print("visibility: " + view.getVisibility());
pw.print(", alpha: " + view.getAlpha());
pw.print(", clipBounds: " + view.getClipBounds());
} else {
pw.print("null");
}
pw.println();
}
});
} }
/** Add any existing SmartReplyView to the dump */ /** Add any existing SmartReplyView to the dump */

View File

@@ -102,8 +102,9 @@ public final class RowContentBindParams {
* @see InflationFlag * @see InflationFlag
*/ */
public void markContentViewsFreeable(@InflationFlag int contentViews) { public void markContentViewsFreeable(@InflationFlag int contentViews) {
@InflationFlag int existingContentViews = contentViews &= mContentViews;
mContentViews &= ~contentViews; mContentViews &= ~contentViews;
mDirtyContentViews &= ~contentViews; mDirtyContentViews |= existingContentViews;
} }
public @InflationFlag int getContentViews() { public @InflationFlag int getContentViews() {

View File

@@ -216,6 +216,9 @@ public class NotificationStackScrollLayoutController {
mBarState = mStatusBarStateController.getState(); mBarState = mStatusBarStateController.getState();
mStatusBarStateController.addCallback( mStatusBarStateController.addCallback(
mStateListener, SysuiStatusBarStateController.RANK_STACK_SCROLLER); mStateListener, SysuiStatusBarStateController.RANK_STACK_SCROLLER);
mLockscreenUserManager.addOnNeedsRedactionInPublicChangedListener(
mOnNeedsRedactionInPublicChangedListener);
updateClearButtonVisibility();
} }
@Override @Override
@@ -223,6 +226,8 @@ public class NotificationStackScrollLayoutController {
mConfigurationController.removeCallback(mConfigurationListener); mConfigurationController.removeCallback(mConfigurationListener);
mZenModeController.removeCallback(mZenModeControllerCallback); mZenModeController.removeCallback(mZenModeControllerCallback);
mStatusBarStateController.removeCallback(mStateListener); mStatusBarStateController.removeCallback(mStateListener);
mLockscreenUserManager.removeOnNeedsRedactionInPublicChangedListener(
mOnNeedsRedactionInPublicChangedListener);
} }
}; };
@@ -326,6 +331,7 @@ public class NotificationStackScrollLayoutController {
mLockscreenUserManager.isAnyProfilePublicMode()); mLockscreenUserManager.isAnyProfilePublicMode());
mView.onStatePostChange(mStatusBarStateController.fromShadeLocked()); mView.onStatePostChange(mStatusBarStateController.fromShadeLocked());
mNotificationEntryManager.updateNotifications("CentralSurfaces state changed"); mNotificationEntryManager.updateNotifications("CentralSurfaces state changed");
updateClearButtonVisibility();
} }
}; };
@@ -338,6 +344,17 @@ public class NotificationStackScrollLayoutController {
} }
}; };
private final Runnable mOnNeedsRedactionInPublicChangedListener = new Runnable() {
@Override
public void run() {
// Whether or not the notification needs redaction when in public has changed, but if
// we're not actually in public, then we don't need to update anything.
if (mLockscreenUserManager.isAnyProfilePublicMode()) {
updateClearButtonVisibility();
}
}
};
/** /**
* Set the overexpansion of the panel to be applied to the view. * Set the overexpansion of the panel to be applied to the view.
*/ */
@@ -1274,12 +1291,44 @@ public class NotificationStackScrollLayoutController {
return hasNotifications(selection, true /* clearable */); return hasNotifications(selection, true /* clearable */);
} }
private boolean hasRedactedClearableSilentNotifs() {
if (!mLockscreenUserManager.isAnyProfilePublicMode()) {
return false;
}
for (int userId : mNotifStats.getClearableSilentSensitiveNotifUsers()) {
if (mLockscreenUserManager.sensitiveNotifsNeedRedactionInPublic(userId)) {
return true;
}
}
return false;
}
private boolean hasClearableSilentNotifs() {
return mNotifStats.getHasClearableSilentNotifs() && !hasRedactedClearableSilentNotifs();
}
private boolean hasRedactedClearableAlertingNotifs() {
if (!mLockscreenUserManager.isAnyProfilePublicMode()) {
return false;
}
for (int userId : mNotifStats.getClearableAlertingSensitiveNotifUsers()) {
if (mLockscreenUserManager.sensitiveNotifsNeedRedactionInPublic(userId)) {
return true;
}
}
return false;
}
private boolean hasClearableAlertingNotifs() {
return mNotifStats.getHasClearableAlertingNotifs() && !hasRedactedClearableAlertingNotifs();
}
public boolean hasNotifications(@SelectedRows int selection, boolean isClearable) { public boolean hasNotifications(@SelectedRows int selection, boolean isClearable) {
boolean hasAlertingMatchingClearable = isClearable boolean hasAlertingMatchingClearable = isClearable
? mNotifStats.getHasClearableAlertingNotifs() ? hasClearableAlertingNotifs()
: mNotifStats.getHasNonClearableAlertingNotifs(); : mNotifStats.getHasNonClearableAlertingNotifs();
boolean hasSilentMatchingClearable = isClearable boolean hasSilentMatchingClearable = isClearable
? mNotifStats.getHasClearableSilentNotifs() ? hasClearableSilentNotifs()
: mNotifStats.getHasNonClearableSilentNotifs(); : mNotifStats.getHasNonClearableSilentNotifs();
switch (selection) { switch (selection) {
case ROWS_GENTLE: case ROWS_GENTLE:
@@ -1579,6 +1628,15 @@ public class NotificationStackScrollLayoutController {
mNotificationActivityStarter = activityStarter; mNotificationActivityStarter = activityStarter;
} }
private void updateClearButtonVisibility() {
updateClearSilentButton();
updateFooter();
}
private void updateClearSilentButton() {
mSilentHeaderController.setClearSectionEnabled(hasClearableSilentNotifs());
}
/** /**
* Enum for UiEvent logged from this class * Enum for UiEvent logged from this class
*/ */
@@ -1904,6 +1962,7 @@ public class NotificationStackScrollLayoutController {
@Override @Override
public void setNotifStats(@NonNull NotifStats notifStats) { public void setNotifStats(@NonNull NotifStats notifStats) {
mNotifStats = notifStats; mNotifStats = notifStats;
updateClearSilentButton();
updateFooter(); updateFooter();
updateShowEmptyShadeView(); updateShowEmptyShadeView();
} }

View File

@@ -29,6 +29,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.HeadsUpStatusBarView; import com.android.systemui.statusbar.HeadsUpStatusBarView;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -40,8 +41,8 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.util.ViewController; import com.android.systemui.util.ViewController;
import java.util.Optional;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Optional;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -61,17 +62,17 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
private final NotificationIconAreaController mNotificationIconAreaController; private final NotificationIconAreaController mNotificationIconAreaController;
private final HeadsUpManagerPhone mHeadsUpManager; private final HeadsUpManagerPhone mHeadsUpManager;
private final NotificationStackScrollLayoutController mStackScrollerController; private final NotificationStackScrollLayoutController mStackScrollerController;
private final DarkIconDispatcher mDarkIconDispatcher; private final DarkIconDispatcher mDarkIconDispatcher;
private final NotificationPanelViewController mNotificationPanelViewController; private final NotificationPanelViewController mNotificationPanelViewController;
private final Consumer<ExpandableNotificationRow> private final Consumer<ExpandableNotificationRow> mSetTrackingHeadsUp =
mSetTrackingHeadsUp = this::setTrackingHeadsUp; this::setTrackingHeadsUp;
private final BiConsumer<Float, Float> mSetExpandedHeight = this::setAppearFraction; private final BiConsumer<Float, Float> mSetExpandedHeight = this::setAppearFraction;
private final KeyguardBypassController mBypassController; private final KeyguardBypassController mBypassController;
private final StatusBarStateController mStatusBarStateController; private final StatusBarStateController mStatusBarStateController;
private final CommandQueue mCommandQueue; private final CommandQueue mCommandQueue;
private final NotificationWakeUpCoordinator mWakeUpCoordinator; private final NotificationWakeUpCoordinator mWakeUpCoordinator;
private final NotificationLockscreenUserManager mNotifLockscreenUserManager;
private final Runnable mRedactionChanged = this::updateRedaction;
private final View mClockView; private final View mClockView;
private final Optional<View> mOperatorNameViewOptional; private final Optional<View> mOperatorNameViewOptional;
@@ -90,6 +91,13 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
}; };
private boolean mAnimationsEnabled = true; private boolean mAnimationsEnabled = true;
private final KeyguardStateController mKeyguardStateController; private final KeyguardStateController mKeyguardStateController;
private final StatusBarStateController.StateListener mStatusBarStateListener =
new StatusBarStateController.StateListener() {
@Override
public void onStatePostChange() {
updateRedaction();
}
};
@VisibleForTesting @VisibleForTesting
@Inject @Inject
@@ -98,6 +106,7 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
HeadsUpManagerPhone headsUpManager, HeadsUpManagerPhone headsUpManager,
StatusBarStateController stateController, StatusBarStateController stateController,
KeyguardBypassController bypassController, KeyguardBypassController bypassController,
NotificationLockscreenUserManager notifLockscreenUserManager,
NotificationWakeUpCoordinator wakeUpCoordinator, NotificationWakeUpCoordinator wakeUpCoordinator,
DarkIconDispatcher darkIconDispatcher, DarkIconDispatcher darkIconDispatcher,
KeyguardStateController keyguardStateController, KeyguardStateController keyguardStateController,
@@ -125,6 +134,7 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
mClockView = clockView; mClockView = clockView;
mOperatorNameViewOptional = operatorNameViewOptional; mOperatorNameViewOptional = operatorNameViewOptional;
mDarkIconDispatcher = darkIconDispatcher; mDarkIconDispatcher = darkIconDispatcher;
mNotifLockscreenUserManager = notifLockscreenUserManager;
mView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { mView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override @Override
@@ -156,6 +166,8 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
mNotificationPanelViewController.setHeadsUpAppearanceController(this); mNotificationPanelViewController.setHeadsUpAppearanceController(this);
mStackScrollerController.addOnExpandedHeightChangedListener(mSetExpandedHeight); mStackScrollerController.addOnExpandedHeightChangedListener(mSetExpandedHeight);
mDarkIconDispatcher.addDarkReceiver(this); mDarkIconDispatcher.addDarkReceiver(this);
mNotifLockscreenUserManager.addOnNeedsRedactionInPublicChangedListener(mRedactionChanged);
mStatusBarStateController.addCallback(mStatusBarStateListener);
} }
@Override @Override
@@ -167,6 +179,9 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
mNotificationPanelViewController.setHeadsUpAppearanceController(null); mNotificationPanelViewController.setHeadsUpAppearanceController(null);
mStackScrollerController.removeOnExpandedHeightChangedListener(mSetExpandedHeight); mStackScrollerController.removeOnExpandedHeightChangedListener(mSetExpandedHeight);
mDarkIconDispatcher.removeDarkReceiver(this); mDarkIconDispatcher.removeDarkReceiver(this);
mNotifLockscreenUserManager
.removeOnNeedsRedactionInPublicChangedListener(mRedactionChanged);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
} }
private void updateIsolatedIconLocation(boolean requireStateUpdate) { private void updateIsolatedIconLocation(boolean requireStateUpdate) {
@@ -180,6 +195,19 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
updateHeader(entry); updateHeader(entry);
} }
private void updateRedaction() {
NotificationEntry showingEntry = mView.getShowingEntry();
if (showingEntry == null) {
return;
}
int notifUserId = showingEntry.getSbn().getUserId();
boolean redactSensitiveContent =
mNotifLockscreenUserManager.isLockscreenPublicMode(notifUserId)
&& mNotifLockscreenUserManager
.sensitiveNotifsNeedRedactionInPublic(notifUserId);
mView.setRedactSensitiveContent(redactSensitiveContent);
}
private void updateTopEntry() { private void updateTopEntry() {
NotificationEntry newEntry = null; NotificationEntry newEntry = null;
if (shouldBeVisible()) { if (shouldBeVisible()) {

View File

@@ -31,7 +31,6 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_N
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE; import static com.android.systemui.statusbar.StatusBarState.SHADE;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_FOLD_TO_AOD; import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_FOLD_TO_AOD;
import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_CLOSED; import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_CLOSED;
import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_OPEN; import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_OPEN;
@@ -3916,10 +3915,6 @@ public class NotificationPanelViewController extends PanelViewController {
} }
} }
public boolean hasActiveClearableNotifications() {
return mNotificationStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL);
}
public RemoteInputController.Delegate createRemoteInputDelegate() { public RemoteInputController.Delegate createRemoteInputDelegate() {
return mNotificationStackScrollLayoutController.createDelegate(); return mNotificationStackScrollLayoutController.createDelegate();
} }

View File

@@ -411,8 +411,8 @@ class StatusBarNotificationPresenter implements NotificationPresenter,
if (nowExpanded) { if (nowExpanded) {
if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) { if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
mShadeTransitionController.goToLockedShade(clickedEntry.getRow()); mShadeTransitionController.goToLockedShade(clickedEntry.getRow());
} else if (clickedEntry.isSensitive() } else if (mDynamicPrivacyController.isInLockedDownShade()
&& mDynamicPrivacyController.isInLockedDownShade()) { && mLockscreenUserManager.notifNeedsRedactionInPublic(clickedEntry)) {
mStatusBarStateController.setLeaveOpenOnKeyguardHide(true); mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
mActivityStarter.dismissKeyguardThenExecute(() -> false /* dismissAction */ mActivityStarter.dismissKeyguardThenExecute(() -> false /* dismissAction */
, null /* cancelRunnable */, false /* afterKeyguardGone */); , null /* cancelRunnable */, false /* afterKeyguardGone */);
@@ -480,7 +480,7 @@ class StatusBarNotificationPresenter implements NotificationPresenter,
.isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId()); .isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
boolean userPublic = devicePublic boolean userPublic = devicePublic
|| mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId()); || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry); boolean needsRedaction = mLockscreenUserManager.notifNeedsRedactionInPublic(entry);
if (userPublic && needsRedaction) { if (userPublic && needsRedaction) {
// TODO(b/135046837): we can probably relax this with dynamic privacy // TODO(b/135046837): we can probably relax this with dynamic privacy
return true; return true;

View File

@@ -130,8 +130,8 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
whenever(statusbarStateController.state).thenReturn(StatusBarState.KEYGUARD) whenever(statusbarStateController.state).thenReturn(StatusBarState.KEYGUARD)
whenever(nsslController.isInLockedDownShade).thenReturn(false) whenever(nsslController.isInLockedDownShade).thenReturn(false)
whenever(qS.isFullyCollapsed).thenReturn(true) whenever(qS.isFullyCollapsed).thenReturn(true)
whenever(lockScreenUserManager.userAllowsPrivateNotificationsInPublic(anyInt())).thenReturn( whenever(lockScreenUserManager.sensitiveNotifsNeedRedactionInPublic(anyInt()))
true) .thenReturn(false)
whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true) whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true)
whenever(lockScreenUserManager.isLockscreenPublicMode(anyInt())).thenReturn(true) whenever(lockScreenUserManager.isLockscreenPublicMode(anyInt())).thenReturn(true)
whenever(falsingCollector.shouldEnforceBouncer()).thenReturn(false) whenever(falsingCollector.shouldEnforceBouncer()).thenReturn(false)
@@ -207,8 +207,8 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
@Test @Test
fun testTriggeringBouncerWhenPrivateNotificationsArentAllowed() { fun testTriggeringBouncerWhenPrivateNotificationsArentAllowed() {
whenever(lockScreenUserManager.userAllowsPrivateNotificationsInPublic(anyInt())).thenReturn( whenever(lockScreenUserManager.sensitiveNotifsNeedRedactionInPublic(anyInt()))
false) .thenReturn(true)
transitionController.goToLockedShade(null) transitionController.goToLockedShade(null)
verify(statusbarStateController, never()).setState(anyInt()) verify(statusbarStateController, never()).setState(anyInt())
verify(statusbarStateController).setLeaveOpenOnKeyguardHide(true) verify(statusbarStateController).setLeaveOpenOnKeyguardHide(true)

View File

@@ -53,11 +53,13 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dependency; import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager; import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.statusbar.NotificationLockscreenUserManager.KeyguardNotificationSuppressor; import com.android.systemui.statusbar.NotificationLockscreenUserManager.KeyguardNotificationSuppressor;
import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -106,6 +108,10 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
private BroadcastDispatcher mBroadcastDispatcher; private BroadcastDispatcher mBroadcastDispatcher;
@Mock @Mock
private KeyguardStateController mKeyguardStateController; private KeyguardStateController mKeyguardStateController;
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
private OverviewProxyService mOverviewProxyService;
private UserInfo mCurrentUser; private UserInfo mCurrentUser;
private UserInfo mSecondaryUser; private UserInfo mSecondaryUser;
@@ -119,7 +125,6 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
int currentUserId = ActivityManager.getCurrentUser(); int currentUserId = ActivityManager.getCurrentUser();
mSettings = new FakeSettings(); mSettings = new FakeSettings();
@@ -212,7 +217,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false); mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
// THEN current user's notification is redacted // THEN current user's notification is redacted
assertTrue(mLockscreenUserManager.needsRedaction(mCurrentUserNotif)); assertTrue(mLockscreenUserManager.notifNeedsRedactionInPublic(mCurrentUserNotif));
} }
@Test @Test
@@ -223,7 +228,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false); mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
// THEN current user's notification isn't redacted // THEN current user's notification isn't redacted
assertFalse(mLockscreenUserManager.needsRedaction(mCurrentUserNotif)); assertFalse(mLockscreenUserManager.notifNeedsRedactionInPublic(mCurrentUserNotif));
} }
@Test @Test
@@ -234,7 +239,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false); mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
// THEN work profile notification is redacted // THEN work profile notification is redacted
assertTrue(mLockscreenUserManager.needsRedaction(mWorkProfileNotif)); assertTrue(mLockscreenUserManager.notifNeedsRedactionInPublic(mWorkProfileNotif));
} }
@Test @Test
@@ -245,7 +250,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false); mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
// THEN work profile notification isn't redacted // THEN work profile notification isn't redacted
assertFalse(mLockscreenUserManager.needsRedaction(mWorkProfileNotif)); assertFalse(mLockscreenUserManager.notifNeedsRedactionInPublic(mWorkProfileNotif));
} }
@Test @Test
@@ -260,11 +265,11 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false); mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
// THEN the work profile notification doesn't need to be redacted // THEN the work profile notification doesn't need to be redacted
assertFalse(mLockscreenUserManager.needsRedaction(mWorkProfileNotif)); assertFalse(mLockscreenUserManager.notifNeedsRedactionInPublic(mWorkProfileNotif));
// THEN the current user and secondary user notifications do need to be redacted // THEN the current user and secondary user notifications do need to be redacted
assertTrue(mLockscreenUserManager.needsRedaction(mCurrentUserNotif)); assertTrue(mLockscreenUserManager.notifNeedsRedactionInPublic(mCurrentUserNotif));
assertTrue(mLockscreenUserManager.needsRedaction(mSecondaryUserNotif)); assertTrue(mLockscreenUserManager.notifNeedsRedactionInPublic(mSecondaryUserNotif));
} }
@Test @Test
@@ -279,11 +284,11 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false); mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
// THEN the work profile notification needs to be redacted // THEN the work profile notification needs to be redacted
assertTrue(mLockscreenUserManager.needsRedaction(mWorkProfileNotif)); assertTrue(mLockscreenUserManager.notifNeedsRedactionInPublic(mWorkProfileNotif));
// THEN the current user and secondary user notifications don't need to be redacted // THEN the current user and secondary user notifications don't need to be redacted
assertFalse(mLockscreenUserManager.needsRedaction(mCurrentUserNotif)); assertFalse(mLockscreenUserManager.notifNeedsRedactionInPublic(mCurrentUserNotif));
assertFalse(mLockscreenUserManager.needsRedaction(mSecondaryUserNotif)); assertFalse(mLockscreenUserManager.notifNeedsRedactionInPublic(mSecondaryUserNotif));
} }
@Test @Test
@@ -298,7 +303,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
// THEN the secondary profile notification still needs to be redacted because the current // THEN the secondary profile notification still needs to be redacted because the current
// user's setting takes precedence // user's setting takes precedence
assertTrue(mLockscreenUserManager.needsRedaction(mSecondaryUserNotif)); assertTrue(mLockscreenUserManager.notifNeedsRedactionInPublic(mSecondaryUserNotif));
} }
@Test @Test
@@ -418,9 +423,12 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
context, context,
mBroadcastDispatcher, mBroadcastDispatcher,
mDevicePolicyManager, mDevicePolicyManager,
mKeyguardUpdateMonitor,
() -> mEntryManager,
() -> mOverviewProxyService,
mUserManager, mUserManager,
(() -> mVisibilityProvider), () -> mVisibilityProvider,
(() -> mNotifCollection), () -> mNotifCollection,
mClickNotifier, mClickNotifier,
NotificationLockscreenUserManagerTest.this.mKeyguardManager, NotificationLockscreenUserManagerTest.this.mKeyguardManager,
mStatusBarStateController, mStatusBarStateController,

View File

@@ -124,8 +124,8 @@ public class DynamicPrivacyControllerTest extends SysuiTestCase {
} }
private void allowPrivateNotificationsInPublic(boolean allow) { private void allowPrivateNotificationsInPublic(boolean allow) {
when(mLockScreenUserManager.userAllowsPrivateNotificationsInPublic(anyInt())).thenReturn( when(mLockScreenUserManager.sensitiveNotifsNeedRedactionInPublic(anyInt())).thenReturn(
allow); !allow);
} }
@Test @Test

View File

@@ -23,7 +23,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@@ -33,7 +32,6 @@ import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner;
import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase;
@@ -41,7 +39,6 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder; import com.android.systemui.statusbar.SbnBuilder;
import com.android.systemui.statusbar.notification.SectionClassifier; import com.android.systemui.statusbar.notification.SectionClassifier;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -49,7 +46,6 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.collection.render.NodeController; import com.android.systemui.statusbar.notification.collection.render.NodeController;
import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -72,7 +68,6 @@ public class RankingCoordinatorTest extends SysuiTestCase {
@Mock private NotifPipeline mNotifPipeline; @Mock private NotifPipeline mNotifPipeline;
@Mock private NodeController mAlertingHeaderController; @Mock private NodeController mAlertingHeaderController;
@Mock private NodeController mSilentNodeController; @Mock private NodeController mSilentNodeController;
@Mock private SectionHeaderController mSilentHeaderController;
@Captor private ArgumentCaptor<NotifFilter> mNotifFilterCaptor; @Captor private ArgumentCaptor<NotifFilter> mNotifFilterCaptor;
@@ -94,7 +89,6 @@ public class RankingCoordinatorTest extends SysuiTestCase {
mHighPriorityProvider, mHighPriorityProvider,
mSectionClassifier, mSectionClassifier,
mAlertingHeaderController, mAlertingHeaderController,
mSilentHeaderController,
mSilentNodeController); mSilentNodeController);
mEntry = spy(new NotificationEntryBuilder().build()); mEntry = spy(new NotificationEntryBuilder().build());
mEntry.setRanking(getRankingForUnfilteredNotif().build()); mEntry.setRanking(getRankingForUnfilteredNotif().build());
@@ -111,25 +105,6 @@ public class RankingCoordinatorTest extends SysuiTestCase {
mSections.addAll(Arrays.asList(mAlertingSectioner, mSilentSectioner, mMinimizedSectioner)); mSections.addAll(Arrays.asList(mAlertingSectioner, mSilentSectioner, mMinimizedSectioner));
} }
@Test
public void testSilentHeaderClearableChildrenUpdate() {
ListEntry listEntry = new ListEntry(mEntry.getKey(), 0L) {
@Nullable
@Override
public NotificationEntry getRepresentativeEntry() {
return mEntry;
}
};
setRankingAmbient(false);
setSbnClearable(true);
mSilentSectioner.onEntriesUpdated(Arrays.asList(listEntry));
verify(mSilentHeaderController).setClearSectionEnabled(eq(true));
setSbnClearable(false);
mSilentSectioner.onEntriesUpdated(Arrays.asList(listEntry));
verify(mSilentHeaderController).setClearSectionEnabled(eq(false));
}
@Test @Test
public void testUnfilteredState() { public void testUnfilteredState() {
// GIVEN no suppressed visual effects + app not suspended // GIVEN no suppressed visual effects + app not suspended
@@ -225,46 +200,6 @@ public class RankingCoordinatorTest extends SysuiTestCase {
assertInSection(mEntry, mSilentSectioner); assertInSection(mEntry, mSilentSectioner);
} }
@Test
public void testClearableSilentSection() {
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
setSbnClearable(true);
setRankingAmbient(false);
mSilentSectioner.onEntriesUpdated(Arrays.asList(mEntry));
verify(mSilentHeaderController).setClearSectionEnabled(eq(true));
}
@Test
public void testClearableMinimizedSection() {
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
setSbnClearable(true);
setRankingAmbient(true);
mMinimizedSectioner.onEntriesUpdated(Arrays.asList(mEntry));
verify(mSilentHeaderController).setClearSectionEnabled(eq(true));
}
@Test
public void testNotClearableSilentSection() {
setSbnClearable(false);
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
setRankingAmbient(false);
mSilentSectioner.onEntriesUpdated(Arrays.asList(mEntry));
mMinimizedSectioner.onEntriesUpdated(Arrays.asList(mEntry));
mAlertingSectioner.onEntriesUpdated(Arrays.asList(mEntry));
verify(mSilentHeaderController, times(2)).setClearSectionEnabled(eq(false));
}
@Test
public void testNotClearableMinimizedSection() {
setSbnClearable(false);
when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
setRankingAmbient(true);
mSilentSectioner.onEntriesUpdated(Arrays.asList(mEntry));
mMinimizedSectioner.onEntriesUpdated(Arrays.asList(mEntry));
mAlertingSectioner.onEntriesUpdated(Arrays.asList(mEntry));
verify(mSilentHeaderController, times(2)).setClearSectionEnabled(eq(false));
}
private void assertInSection(NotificationEntry entry, NotifSectioner section) { private void assertInSection(NotificationEntry entry, NotifSectioner section) {
for (NotifSectioner current: mSections) { for (NotifSectioner current: mSections) {
if (current == section) { if (current == section) {

View File

@@ -1,268 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.collection.coordinator
import android.os.UserHandle
import android.service.notification.StatusBarNotification
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.notification.DynamicPrivacyController
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.withArgCaptor
import dagger.BindsInstance
import dagger.Component
import org.junit.Test
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
@SmallTest
class SensitiveContentCoordinatorTest : SysuiTestCase() {
val dynamicPrivacyController: DynamicPrivacyController = mock()
val lockscreenUserManager: NotificationLockscreenUserManager = mock()
val pipeline: NotifPipeline = mock()
val keyguardUpdateMonitor: KeyguardUpdateMonitor = mock()
val statusBarStateController: StatusBarStateController = mock()
val keyguardStateController: KeyguardStateController = mock()
val coordinator: SensitiveContentCoordinator =
DaggerTestSensitiveContentCoordinatorComponent
.factory()
.create(
dynamicPrivacyController,
lockscreenUserManager,
keyguardUpdateMonitor,
statusBarStateController,
keyguardStateController)
.coordinator
@Test
fun onDynamicPrivacyChanged_invokeInvalidationListener() {
coordinator.attach(pipeline)
val invalidator = withArgCaptor<Invalidator> {
verify(pipeline).addPreRenderInvalidator(capture())
}
val dynamicPrivacyListener = withArgCaptor<DynamicPrivacyController.Listener> {
verify(dynamicPrivacyController).addListener(capture())
}
val invalidationListener = mock<Pluggable.PluggableListener<Invalidator>>()
invalidator.setInvalidationListener(invalidationListener)
dynamicPrivacyListener.onDynamicPrivacyChanged()
verify(invalidationListener).onPluggableInvalidated(invalidator)
}
@Test
fun onBeforeRenderList_deviceUnlocked_notifDoesNotNeedRedaction() {
coordinator.attach(pipeline)
val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
verify(pipeline).addOnBeforeRenderListListener(capture())
}
whenever(lockscreenUserManager.currentUserId).thenReturn(1)
whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false)
whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true)
whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
val entry = fakeNotification(1, false)
onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
verify(entry.representativeEntry!!).setSensitive(false, false)
}
@Test
fun onBeforeRenderList_deviceUnlocked_notifWouldNeedRedaction() {
coordinator.attach(pipeline)
val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
verify(pipeline).addOnBeforeRenderListListener(capture())
}
whenever(lockscreenUserManager.currentUserId).thenReturn(1)
whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false)
whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true)
whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
val entry = fakeNotification(1, true)
onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
verify(entry.representativeEntry!!).setSensitive(false, false)
}
@Test
fun onBeforeRenderList_deviceLocked_userAllowsPublicNotifs() {
coordinator.attach(pipeline)
val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
verify(pipeline).addOnBeforeRenderListListener(capture())
}
whenever(lockscreenUserManager.currentUserId).thenReturn(1)
whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true)
whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
val entry = fakeNotification(1, false)
onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
verify(entry.representativeEntry!!).setSensitive(false, false)
}
@Test
fun onBeforeRenderList_deviceLocked_userDisallowsPublicNotifs_notifDoesNotNeedRedaction() {
coordinator.attach(pipeline)
val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
verify(pipeline).addOnBeforeRenderListListener(capture())
}
whenever(lockscreenUserManager.currentUserId).thenReturn(1)
whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
val entry = fakeNotification(1, false)
onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
verify(entry.representativeEntry!!).setSensitive(false, true)
}
@Test
fun onBeforeRenderList_deviceLocked_notifNeedsRedaction() {
coordinator.attach(pipeline)
val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
verify(pipeline).addOnBeforeRenderListListener(capture())
}
whenever(lockscreenUserManager.currentUserId).thenReturn(1)
whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
val entry = fakeNotification(1, true)
onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
verify(entry.representativeEntry!!).setSensitive(true, true)
}
@Test
fun onBeforeRenderList_deviceDynamicallyUnlocked_notifNeedsRedaction() {
coordinator.attach(pipeline)
val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
verify(pipeline).addOnBeforeRenderListListener(capture())
}
whenever(lockscreenUserManager.currentUserId).thenReturn(1)
whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true)
val entry = fakeNotification(1, true)
onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
verify(entry.representativeEntry!!).setSensitive(false, true)
}
@Test
fun onBeforeRenderList_deviceDynamicallyUnlocked_notifUserNeedsWorkChallenge() {
coordinator.attach(pipeline)
val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
verify(pipeline).addOnBeforeRenderListListener(capture())
}
whenever(lockscreenUserManager.currentUserId).thenReturn(1)
whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true)
whenever(lockscreenUserManager.needsSeparateWorkChallenge(2)).thenReturn(true)
val entry = fakeNotification(2, true)
onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
verify(entry.representativeEntry!!).setSensitive(true, true)
}
@Test
fun onBeforeRenderList_deviceDynamicallyUnlocked_deviceBiometricBypassingLockScreen() {
coordinator.attach(pipeline)
val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
verify(pipeline).addOnBeforeRenderListListener(capture())
}
whenever(lockscreenUserManager.currentUserId).thenReturn(1)
whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true)
whenever(statusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD)
whenever(keyguardUpdateMonitor.getUserUnlockedWithBiometricAndIsBypassing(any()))
.thenReturn(true)
val entry = fakeNotification(2, true)
onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
verify(entry.representativeEntry!!, never()).setSensitive(any(), any())
}
private fun fakeNotification(notifUserId: Int, needsRedaction: Boolean): ListEntry {
val mockUserHandle = mock<UserHandle>().apply {
whenever(identifier).thenReturn(notifUserId)
}
val mockSbn: StatusBarNotification = mock<StatusBarNotification>().apply {
whenever(user).thenReturn(mockUserHandle)
}
val mockEntry = mock<NotificationEntry>().apply {
whenever(sbn).thenReturn(mockSbn)
}
whenever(lockscreenUserManager.needsRedaction(mockEntry)).thenReturn(needsRedaction)
whenever(mockEntry.rowExists()).thenReturn(true)
return object : ListEntry("key", 0) {
override fun getRepresentativeEntry(): NotificationEntry = mockEntry
}
}
}
@CoordinatorScope
@Component(modules = [SensitiveContentCoordinatorModule::class])
interface TestSensitiveContentCoordinatorComponent {
val coordinator: SensitiveContentCoordinator
@Component.Factory
interface Factory {
fun create(
@BindsInstance dynamicPrivacyController: DynamicPrivacyController,
@BindsInstance lockscreenUserManager: NotificationLockscreenUserManager,
@BindsInstance keyguardUpdateMonitor: KeyguardUpdateMonitor,
@BindsInstance statusBarStateController: StatusBarStateController,
@BindsInstance keyguardStateController: KeyguardStateController
): TestSensitiveContentCoordinatorComponent
}
}

View File

@@ -15,6 +15,7 @@
*/ */
package com.android.systemui.statusbar.notification.collection.coordinator package com.android.systemui.statusbar.notification.collection.coordinator
import android.os.UserHandle
import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
@@ -43,6 +44,11 @@ import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidTestingRunner::class) @RunWith(AndroidTestingRunner::class)
@RunWithLooper @RunWithLooper
class StackCoordinatorTest : SysuiTestCase() { class StackCoordinatorTest : SysuiTestCase() {
companion object {
const val NOTIF_USER_ID = 0
}
private lateinit var coordinator: StackCoordinator private lateinit var coordinator: StackCoordinator
private lateinit var afterRenderListListener: OnAfterRenderListListener private lateinit var afterRenderListListener: OnAfterRenderListListener
@@ -61,7 +67,10 @@ class StackCoordinatorTest : SysuiTestCase() {
afterRenderListListener = withArgCaptor { afterRenderListListener = withArgCaptor {
verify(pipeline).addOnAfterRenderListListener(capture()) verify(pipeline).addOnAfterRenderListListener(capture())
} }
entry = NotificationEntryBuilder().setSection(section).build() entry = NotificationEntryBuilder()
.setSection(section)
.setUser(UserHandle.of(NOTIF_USER_ID))
.build()
} }
@Test @Test
@@ -74,13 +83,31 @@ class StackCoordinatorTest : SysuiTestCase() {
fun testSetNotificationStats_clearableAlerting() { fun testSetNotificationStats_clearableAlerting() {
whenever(section.bucket).thenReturn(BUCKET_ALERTING) whenever(section.bucket).thenReturn(BUCKET_ALERTING)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController) afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
verify(stackController).setNotifStats(NotifStats(1, false, true, false, false)) verify(stackController)
.setNotifStats(
NotifStats(
1,
false,
true,
false,
false,
setOf(NOTIF_USER_ID),
emptySet()))
} }
@Test @Test
fun testSetNotificationStats_clearableSilent() { fun testSetNotificationStats_clearableSilent() {
whenever(section.bucket).thenReturn(BUCKET_SILENT) whenever(section.bucket).thenReturn(BUCKET_SILENT)
afterRenderListListener.onAfterRenderList(listOf(entry), stackController) afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
verify(stackController).setNotifStats(NotifStats(1, false, false, false, true)) verify(stackController)
.setNotifStats(
NotifStats(
1,
false,
false,
false,
true,
emptySet(),
setOf(NOTIF_USER_ID)))
} }
} }

View File

@@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.systemui.statusbar.notification.icon; package com.android.systemui.statusbar.notification.icon
import android.app.ActivityManager; import android.app.ActivityManager
import android.app.Notification; import android.app.Notification
import android.app.NotificationChannel import android.app.NotificationChannel
import android.app.NotificationManager.IMPORTANCE_DEFAULT import android.app.NotificationManager.IMPORTANCE_DEFAULT
import android.app.Person import android.app.Person
@@ -27,11 +27,12 @@ import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon import android.graphics.drawable.Icon
import android.os.SystemClock import android.os.SystemClock
import android.os.UserHandle import android.os.UserHandle
import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner
import androidx.test.InstrumentationRegistry import androidx.test.InstrumentationRegistry
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.controller.AuxiliaryPersistenceWrapperTest.Companion.any import com.android.systemui.controls.controller.AuxiliaryPersistenceWrapperTest.Companion.any
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
@@ -40,7 +41,7 @@ import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith; import org.junit.runner.RunWith
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.`when` import org.mockito.Mockito.`when`
import org.mockito.Mockito.anyInt import org.mockito.Mockito.anyInt
@@ -48,15 +49,14 @@ import org.mockito.MockitoAnnotations
@SmallTest @SmallTest
@RunWith(AndroidTestingRunner::class) @RunWith(AndroidTestingRunner::class)
class IconManagerTest: SysuiTestCase() { class IconManagerTest : SysuiTestCase() {
companion object { companion object {
private const val TEST_PACKAGE_NAME = "test"; private const val TEST_PACKAGE_NAME = "test"
private const val TEST_UID = 0; private const val TEST_UID = 0
} }
private var id = 0 private var id = 0
private val context = InstrumentationRegistry.getTargetContext(); private val context = InstrumentationRegistry.getTargetContext()
@Mock private lateinit var shortcut: ShortcutInfo @Mock private lateinit var shortcut: ShortcutInfo
@Mock private lateinit var shortcutIc: Icon @Mock private lateinit var shortcutIc: Icon
@Mock private lateinit var messageIc: Icon @Mock private lateinit var messageIc: Icon
@@ -65,6 +65,7 @@ class IconManagerTest: SysuiTestCase() {
@Mock private lateinit var drawable: Drawable @Mock private lateinit var drawable: Drawable
@Mock private lateinit var row: ExpandableNotificationRow @Mock private lateinit var row: ExpandableNotificationRow
@Mock private lateinit var notifLockscreenUserManager: NotificationLockscreenUserManager
@Mock private lateinit var notifCollection: CommonNotifCollection @Mock private lateinit var notifCollection: CommonNotifCollection
@Mock private lateinit var launcherApps: LauncherApps @Mock private lateinit var launcherApps: LauncherApps
@@ -83,13 +84,16 @@ class IconManagerTest: SysuiTestCase() {
`when`(shortcut.icon).thenReturn(shortcutIc) `when`(shortcut.icon).thenReturn(shortcutIc)
`when`(launcherApps.getShortcutIcon(shortcut)).thenReturn(shortcutIc) `when`(launcherApps.getShortcutIcon(shortcut)).thenReturn(shortcutIc)
`when`(notifLockscreenUserManager.sensitiveNotifsNeedRedactionInPublic(TEST_UID))
.thenReturn(true)
iconManager = IconManager(notifCollection, launcherApps, iconBuilder) iconManager =
IconManager(notifCollection, launcherApps, iconBuilder, notifLockscreenUserManager)
} }
@Test @Test
fun testCreateIcons_importantConversation_shortcutIcon() { fun testCreateIcons_importantConversation_shortcutIcon() {
val entry = notificationEntry(true, true, true) val entry = notificationEntry()
entry?.channel?.isImportantConversation = true entry?.channel?.isImportantConversation = true
entry?.let { entry?.let {
iconManager.createIcons(it) iconManager.createIcons(it)
@@ -99,7 +103,7 @@ class IconManagerTest: SysuiTestCase() {
@Test @Test
fun testCreateIcons_importantConversation_messageIcon() { fun testCreateIcons_importantConversation_messageIcon() {
val entry = notificationEntry(false, true, true) val entry = notificationEntry(hasShortcut = false)
entry?.channel?.isImportantConversation = true entry?.channel?.isImportantConversation = true
entry?.let { entry?.let {
iconManager.createIcons(it) iconManager.createIcons(it)
@@ -109,7 +113,7 @@ class IconManagerTest: SysuiTestCase() {
@Test @Test
fun testCreateIcons_importantConversation_largeIcon() { fun testCreateIcons_importantConversation_largeIcon() {
val entry = notificationEntry(false, false, true) val entry = notificationEntry(hasShortcut = false, hasMessage = false)
entry?.channel?.isImportantConversation = true entry?.channel?.isImportantConversation = true
entry?.let { entry?.let {
iconManager.createIcons(it) iconManager.createIcons(it)
@@ -119,7 +123,7 @@ class IconManagerTest: SysuiTestCase() {
@Test @Test
fun testCreateIcons_importantConversation_smallIcon() { fun testCreateIcons_importantConversation_smallIcon() {
val entry = notificationEntry(false, false, false) val entry = notificationEntry(hasShortcut = false, hasMessage = false, hasLargeIcon = false)
entry?.channel?.isImportantConversation = true entry?.channel?.isImportantConversation = true
entry?.let { entry?.let {
iconManager.createIcons(it) iconManager.createIcons(it)
@@ -129,7 +133,7 @@ class IconManagerTest: SysuiTestCase() {
@Test @Test
fun testCreateIcons_notImportantConversation() { fun testCreateIcons_notImportantConversation() {
val entry = notificationEntry(true, true, true) val entry = notificationEntry()
entry?.let { entry?.let {
iconManager.createIcons(it) iconManager.createIcons(it)
} }
@@ -138,8 +142,10 @@ class IconManagerTest: SysuiTestCase() {
@Test @Test
fun testCreateIcons_sensitiveImportantConversation() { fun testCreateIcons_sensitiveImportantConversation() {
val entry = notificationEntry(true, false, false) val entry = notificationEntry(
entry?.setSensitive(true, true); hasMessage = false,
hasLargeIcon = false,
hasSensitiveContent = true)
entry?.channel?.isImportantConversation = true entry?.channel?.isImportantConversation = true
entry?.let { entry?.let {
iconManager.createIcons(it) iconManager.createIcons(it)
@@ -151,14 +157,17 @@ class IconManagerTest: SysuiTestCase() {
@Test @Test
fun testUpdateIcons_sensitivityChange() { fun testUpdateIcons_sensitivityChange() {
val entry = notificationEntry(true, false, false) val entry = notificationEntry(
hasMessage = false,
hasLargeIcon = false,
hasSensitiveContent = true)
entry?.channel?.isImportantConversation = true entry?.channel?.isImportantConversation = true
entry?.setSensitive(true, true);
entry?.let { entry?.let {
iconManager.createIcons(it) iconManager.createIcons(it)
} }
assertEquals(entry?.icons?.aodIcon?.sourceIcon, smallIc) assertEquals(entry?.icons?.aodIcon?.sourceIcon, smallIc)
entry?.setSensitive(false, false); `when`(notifLockscreenUserManager.sensitiveNotifsNeedRedactionInPublic(TEST_UID))
.thenReturn(false)
entry?.let { entry?.let {
iconManager.updateIcons(it) iconManager.updateIcons(it)
} }
@@ -166,14 +175,19 @@ class IconManagerTest: SysuiTestCase() {
} }
private fun notificationEntry( private fun notificationEntry(
hasShortcut: Boolean, hasShortcut: Boolean = true,
hasMessage: Boolean, hasMessage: Boolean = true,
hasLargeIcon: Boolean hasLargeIcon: Boolean = true,
hasSensitiveContent: Boolean = false
): NotificationEntry? { ): NotificationEntry? {
val n = Notification.Builder(mContext, "id") val n = Notification.Builder(mContext, "id")
.setSmallIcon(smallIc) .setSmallIcon(smallIc)
.setContentTitle("Title") .setContentTitle("Title")
.setContentText("Text") .setContentText("Text")
.setVisibility(
if (hasSensitiveContent)
Notification.VISIBILITY_PRIVATE
else Notification.VISIBILITY_PUBLIC)
if (hasMessage) { if (hasMessage) {
n.style = Notification.MessagingStyle("") n.style = Notification.MessagingStyle("")
@@ -203,7 +217,6 @@ class IconManagerTest: SysuiTestCase() {
val entry = builder.build() val entry = builder.build()
entry.row = row entry.row = row
entry.setSensitive(false, true);
return entry return entry
} }
} }

View File

@@ -91,7 +91,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
@Test @Test
public void testGroupSummaryNotShowingIconWhenPublic() { public void testGroupSummaryNotShowingIconWhenPublic() {
mGroupRow.setSensitive(true, true); mGroupRow.setSensitive(true);
mGroupRow.setHideSensitiveForIntrinsicHeight(true); mGroupRow.setHideSensitiveForIntrinsicHeight(true);
assertTrue(mGroupRow.isSummaryWithChildren()); assertTrue(mGroupRow.isSummaryWithChildren());
assertFalse(mGroupRow.isShowingIcon()); assertFalse(mGroupRow.isShowingIcon());
@@ -99,7 +99,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
@Test @Test
public void testNotificationHeaderVisibleWhenAnimating() { public void testNotificationHeaderVisibleWhenAnimating() {
mGroupRow.setSensitive(true, true); mGroupRow.setSensitive(true);
mGroupRow.setHideSensitive(true, false, 0, 0); mGroupRow.setHideSensitive(true, false, 0, 0);
mGroupRow.setHideSensitive(false, true, 0, 0); mGroupRow.setHideSensitive(false, true, 0, 0);
assertEquals(View.VISIBLE, mGroupRow.getChildrenContainer().getVisibleWrapper() assertEquals(View.VISIBLE, mGroupRow.getChildrenContainer().getVisibleWrapper()
@@ -130,7 +130,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
public void testIconColorShouldBeUpdatedWhenSensitive() throws Exception { public void testIconColorShouldBeUpdatedWhenSensitive() throws Exception {
ExpandableNotificationRow row = spy(mNotificationTestHelper.createRow( ExpandableNotificationRow row = spy(mNotificationTestHelper.createRow(
FLAG_CONTENT_VIEW_ALL)); FLAG_CONTENT_VIEW_ALL));
row.setSensitive(true, true); row.setSensitive(true);
row.setHideSensitive(true, false, 0, 0); row.setHideSensitive(true, false, 0, 0);
verify(row).updateShelfIconColor(); verify(row).updateShelfIconColor();
} }
@@ -214,7 +214,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
@Test @Test
public void testFeedback_noHeader() { public void testFeedback_noHeader() {
// public notification is custom layout - no header // public notification is custom layout - no header
mGroupRow.setSensitive(true, true); mGroupRow.setSensitive(true);
mGroupRow.setOnFeedbackClickListener(null); mGroupRow.setOnFeedbackClickListener(null);
mGroupRow.setFeedbackIcon(null); mGroupRow.setFeedbackIcon(null);
} }

View File

@@ -78,7 +78,6 @@ import com.android.systemui.statusbar.notification.collection.legacy.Notificatio
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.icon.IconBuilder; import com.android.systemui.statusbar.notification.icon.IconBuilder;
import com.android.systemui.statusbar.notification.icon.IconManager; import com.android.systemui.statusbar.notification.icon.IconManager;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent; import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
@@ -132,7 +131,6 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
@Mock private NotificationEntryListener mEntryListener; @Mock private NotificationEntryListener mEntryListener;
@Mock private NotificationRowBinderImpl.BindRowCallback mBindCallback; @Mock private NotificationRowBinderImpl.BindRowCallback mBindCallback;
@Mock private HeadsUpManager mHeadsUpManager; @Mock private HeadsUpManager mHeadsUpManager;
@Mock private NotificationInterruptStateProvider mNotificationInterruptionStateProvider;
@Mock private NotificationLockscreenUserManager mLockscreenUserManager; @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private NotificationGutsManager mGutsManager; @Mock private NotificationGutsManager mGutsManager;
@Mock private NotificationRemoteInputManager mRemoteInputManager; @Mock private NotificationRemoteInputManager mRemoteInputManager;
@@ -254,6 +252,7 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
.thenAnswer((Answer<ExpandableNotificationRowController>) invocation -> .thenAnswer((Answer<ExpandableNotificationRowController>) invocation ->
new ExpandableNotificationRowController( new ExpandableNotificationRowController(
viewCaptor.getValue(), viewCaptor.getValue(),
mLockscreenUserManager,
mock(ActivatableNotificationViewController.class), mock(ActivatableNotificationViewController.class),
mock(RemoteInputViewSubcomponent.Factory.class), mock(RemoteInputViewSubcomponent.Factory.class),
mock(MetricsLogger.class), mock(MetricsLogger.class),
@@ -300,7 +299,8 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
new IconManager( new IconManager(
mEntryManager, mEntryManager,
mock(LauncherApps.class), mock(LauncherApps.class),
new IconBuilder(mContext)), new IconBuilder(mContext),
mLockscreenUserManager),
mock(LowPriorityInflationHelper.class), mock(LowPriorityInflationHelper.class),
mNotifPipelineFlags); mNotifPipelineFlags);

View File

@@ -52,6 +52,7 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.MediaFeatureFlag; import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.media.dialog.MediaOutputDialogFactory; import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -152,7 +153,8 @@ public class NotificationTestHelper {
mIconManager = new IconManager( mIconManager = new IconManager(
mock(CommonNotifCollection.class), mock(CommonNotifCollection.class),
mock(LauncherApps.class), mock(LauncherApps.class),
new IconBuilder(mContext)); new IconBuilder(mContext),
mock(NotificationLockscreenUserManager.class));
NotificationContentInflater contentBinder = new NotificationContentInflater( NotificationContentInflater contentBinder = new NotificationContentInflater(
mock(NotifRemoteViewCache.class), mock(NotifRemoteViewCache.class),

View File

@@ -36,6 +36,7 @@ import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.HeadsUpStatusBarView; import com.android.systemui.statusbar.HeadsUpStatusBarView;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper; import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -57,9 +58,12 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
private final NotificationStackScrollLayoutController mStackScrollerController = private final NotificationStackScrollLayoutController mStackScrollerController =
mock(NotificationStackScrollLayoutController.class); mock(NotificationStackScrollLayoutController.class);
private final NotificationPanelViewController mPanelView = private final NotificationPanelViewController mPanelViewController =
mock(NotificationPanelViewController.class); mock(NotificationPanelViewController.class);
private final DarkIconDispatcher mDarkIconDispatcher = mock(DarkIconDispatcher.class); private final DarkIconDispatcher mDarkIconDispatcher = mock(DarkIconDispatcher.class);
private final NotificationLockscreenUserManager mLockscreenUserManager =
mock(NotificationLockscreenUserManager.class);
private HeadsUpAppearanceController mHeadsUpAppearanceController; private HeadsUpAppearanceController mHeadsUpAppearanceController;
private ExpandableNotificationRow mFirst; private ExpandableNotificationRow mFirst;
private HeadsUpStatusBarView mHeadsUpStatusBarView; private HeadsUpStatusBarView mHeadsUpStatusBarView;
@@ -93,12 +97,13 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
mHeadsUpManager, mHeadsUpManager,
mStatusbarStateController, mStatusbarStateController,
mBypassController, mBypassController,
mLockscreenUserManager,
mWakeUpCoordinator, mWakeUpCoordinator,
mDarkIconDispatcher, mDarkIconDispatcher,
mKeyguardStateController, mKeyguardStateController,
mCommandQueue, mCommandQueue,
mStackScrollerController, mStackScrollerController,
mPanelView, mPanelViewController,
mHeadsUpStatusBarView, mHeadsUpStatusBarView,
new Clock(mContext, null), new Clock(mContext, null),
Optional.of(mOperatorNameView)); Optional.of(mOperatorNameView));
@@ -175,12 +180,13 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
mHeadsUpManager, mHeadsUpManager,
mStatusbarStateController, mStatusbarStateController,
mBypassController, mBypassController,
mLockscreenUserManager,
mWakeUpCoordinator, mWakeUpCoordinator,
mDarkIconDispatcher, mDarkIconDispatcher,
mKeyguardStateController, mKeyguardStateController,
mCommandQueue, mCommandQueue,
mStackScrollerController, mStackScrollerController,
mPanelView, mPanelViewController,
mHeadsUpStatusBarView, mHeadsUpStatusBarView,
new Clock(mContext, null), new Clock(mContext, null),
Optional.empty()); Optional.empty());
@@ -193,15 +199,15 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
public void testDestroy() { public void testDestroy() {
reset(mHeadsUpManager); reset(mHeadsUpManager);
reset(mDarkIconDispatcher); reset(mDarkIconDispatcher);
reset(mPanelView); reset(mPanelViewController);
reset(mStackScrollerController); reset(mStackScrollerController);
mHeadsUpAppearanceController.onViewDetached(); mHeadsUpAppearanceController.onViewDetached();
verify(mHeadsUpManager).removeListener(any()); verify(mHeadsUpManager).removeListener(any());
verify(mDarkIconDispatcher).removeDarkReceiver((DarkIconDispatcher.DarkReceiver) any()); verify(mDarkIconDispatcher).removeDarkReceiver((DarkIconDispatcher.DarkReceiver) any());
verify(mPanelView).removeTrackingHeadsUpListener(any()); verify(mPanelViewController).removeTrackingHeadsUpListener(any());
verify(mPanelView).setHeadsUpAppearanceController(isNull()); verify(mPanelViewController).setHeadsUpAppearanceController(isNull());
verify(mStackScrollerController).removeOnExpandedHeightChangedListener(any()); verify(mStackScrollerController).removeOnExpandedHeightChangedListener(any());
} }
} }