Merge "Revert "Don't show "Clear All" w/ redacted notifs"" into tm-dev am: 95d2e13cc1 am: 8cd9a061f3

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18437717

Change-Id: I6374a11c16ed2c9e71592c7401e2b93c6554f366
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Steve Elliott
2022-05-19 14:39:54 +00:00
committed by Automerger Merge Worker
35 changed files with 803 additions and 570 deletions

View File

@@ -29,6 +29,7 @@ import com.android.keyguard.AlphaOptimizedLinearLayout;
import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry.OnSensitivityChangedListener;
import java.util.ArrayList;
@@ -48,7 +49,6 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
private TextView mTextView;
private NotificationEntry mShowingEntry;
private Runnable mOnDrawingRectChangedListener;
private boolean mRedactSensitiveContent;
public HeadsUpStatusBarView(Context context) {
this(context, null);
@@ -111,28 +111,29 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
}
public void setEntry(NotificationEntry entry) {
if (mShowingEntry != null) {
mShowingEntry.removeOnSensitivityChangedListener(mOnSensitivityChangedListener);
}
mShowingEntry = entry;
if (mShowingEntry != null) {
CharSequence text = entry.headsUpStatusBarText;
if (mRedactSensitiveContent && entry.hasSensitiveContents()) {
if (entry.isSensitive()) {
text = entry.headsUpStatusBarTextPublic;
}
mTextView.setText(text);
mShowingEntry.addOnSensitivityChangedListener(mOnSensitivityChangedListener);
}
}
public void setRedactSensitiveContent(boolean redactSensitiveContent) {
if (mRedactSensitiveContent == redactSensitiveContent) {
return;
private final OnSensitivityChangedListener mOnSensitivityChangedListener = entry -> {
if (entry != mShowingEntry) {
throw new IllegalStateException("Got a sensitivity change for " + entry
+ " but mShowingEntry is " + mShowingEntry);
}
mRedactSensitiveContent = redactSensitiveContent;
if (mShowingEntry != null && mShowingEntry.hasSensitiveContents()) {
mTextView.setText(
mRedactSensitiveContent
? mShowingEntry.headsUpStatusBarTextPublic
: mShowingEntry.headsUpStatusBarText);
}
}
// Update the text
setEntry(entry);
};
@Override
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) {
// Only drag down on sensitive views, otherwise the ExpandHelper will take this
return lockScreenUserManager.notifNeedsRedactionInPublic(view.entry)
return view.entry.isSensitive
}
}
return false
@@ -552,8 +552,7 @@ class LockscreenShadeTransitionController @Inject constructor(
logger.logShadeDisabledOnGoToLockedShade()
return
}
val currentUser = lockScreenUserManager.currentUserId
var userId: Int = currentUser
var userId: Int = lockScreenUserManager.getCurrentUserId()
var entry: NotificationEntry? = null
if (expandView is ExpandableNotificationRow) {
entry = expandView.entry
@@ -563,18 +562,12 @@ class LockscreenShadeTransitionController @Inject constructor(
entry.setGroupExpansionChanging(true)
userId = entry.sbn.userId
}
val fullShadeNeedsBouncer = when {
// No bouncer necessary if we're bypassing
keyguardBypassController.bypassEnabled -> false
// Redacted notificationss are present, bouncer should be shown before un-redacting in
// the full shade
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
var fullShadeNeedsBouncer = (!lockScreenUserManager.userAllowsPrivateNotificationsInPublic(
lockScreenUserManager.getCurrentUserId()) ||
!lockScreenUserManager.shouldShowLockscreenNotifications() ||
falsingCollector.shouldEnforceBouncer())
if (keyguardBypassController.bypassEnabled) {
fullShadeNeedsBouncer = false
}
if (lockScreenUserManager.isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
statusBarStateController.setLeaveOpenOnKeyguardHide(true)
@@ -918,4 +911,4 @@ class DragDownHelper(
host.getLocationOnScreen(temp2)
return expandCallback.getChildAtRawPosition(x + temp2[0], y + temp2[1])
}
}
}

View File

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

View File

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

View File

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

View File

@@ -80,7 +80,7 @@ public class DynamicPrivacyController implements KeyguardStateController.Callbac
@VisibleForTesting
boolean isDynamicPrivacyEnabled() {
return mLockscreenUserManager.sensitiveNotifsNeedRedactionInPublic(
return !mLockscreenUserManager.userAllowsPrivateNotificationsInPublic(
mLockscreenUserManager.getCurrentUserId());
}
@@ -95,10 +95,6 @@ public class DynamicPrivacyController implements KeyguardStateController.Callbac
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
* contents aren't revealed yet?

View File

@@ -169,6 +169,9 @@ public final class NotificationEntry extends ListEntry {
*/
private boolean hasSentReply;
private boolean mSensitive = true;
private List<OnSensitivityChangedListener> mOnSensitivityChangedListeners = new ArrayList<>();
private boolean mAutoHeadsUp;
private boolean mPulseSupressed;
private int mBucket = BUCKET_ALERTING;
@@ -864,29 +867,33 @@ public final class NotificationEntry extends ListEntry {
}
/**
* 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
* device policy.
* Set this notification to be sensitive.
*
* @param sensitive true if the content of this notification is sensitive right now
* @param deviceSensitive true if the device in general is sensitive right now
*/
public int getLockscreenVisibility() {
int setting = mRanking.getLockscreenVisibilityOverride();
if (setting == Ranking.VISIBILITY_NO_OVERRIDE) {
setting = mSbn.getNotification().visibility;
public void setSensitive(boolean sensitive, boolean deviceSensitive) {
getRow().setSensitive(sensitive, deviceSensitive);
if (sensitive != mSensitive) {
mSensitive = sensitive;
for (int i = 0; i < mOnSensitivityChangedListeners.size(); i++) {
mOnSensitivityChangedListeners.get(i).onSensitivityChanged(this);
}
}
return setting;
}
/**
* 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.
*
* NOTE: If the notification's visibility setting is VISIBILITY_SECRET, then this will return
* false; SECRET notifications are omitted entirely when the device is public, so effectively
* the contents of the notification are not sensitive whenever the notification is actually
* visible.
*/
public boolean hasSensitiveContents() {
return getLockscreenVisibility() == Notification.VISIBILITY_PRIVATE;
public boolean isSensitive() {
return mSensitive;
}
/** Add a listener to be notified when the entry's sensitivity changes. */
public void addOnSensitivityChangedListener(OnSensitivityChangedListener listener) {
mOnSensitivityChangedListeners.add(listener);
}
/** Remove a listener that was registered above. */
public void removeOnSensitivityChangedListener(OnSensitivityChangedListener listener) {
mOnSensitivityChangedListeners.remove(listener);
}
public boolean isPulseSuppressed() {
@@ -947,6 +954,12 @@ 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() */
public enum DismissState {
/** User has not dismissed this notif or its parent */

View File

@@ -56,6 +56,7 @@ class NotifCoordinatorsImpl @Inject constructor(
smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator,
viewConfigCoordinator: ViewConfigCoordinator,
visualStabilityCoordinator: VisualStabilityCoordinator,
sensitiveContentCoordinator: SensitiveContentCoordinator,
) : NotifCoordinators {
private val mCoordinators: MutableList<Coordinator> = ArrayList()
@@ -92,6 +93,7 @@ class NotifCoordinatorsImpl @Inject constructor(
mCoordinators.add(shadeEventCoordinator)
mCoordinators.add(viewConfigCoordinator)
mCoordinators.add(visualStabilityCoordinator)
mCoordinators.add(sensitiveContentCoordinator)
if (notifPipelineFlags.isSmartspaceDedupingEnabled()) {
mCoordinators.add(smartspaceDedupingCoordinator)
}

View File

@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -28,11 +29,13 @@ 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.provider.HighPriorityProvider;
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.SilentHeader;
import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
@@ -50,10 +53,10 @@ public class RankingCoordinator implements Coordinator {
private final HighPriorityProvider mHighPriorityProvider;
private final SectionClassifier mSectionClassifier;
private final NodeController mSilentNodeController;
private final SectionHeaderController mSilentHeaderController;
private final NodeController mAlertingHeaderController;
private final AlertingNotifSectioner mAlertingNotifSectioner = new AlertingNotifSectioner();
private final SilentNotifSectioner mSilentNotifSectioner = new SilentNotifSectioner();
private final MinimizedNotifSectioner mMinimizedNotifSectioner = new MinimizedNotifSectioner();
private boolean mHasSilentEntries;
private boolean mHasMinimizedEntries;
@Inject
public RankingCoordinator(
@@ -61,12 +64,14 @@ public class RankingCoordinator implements Coordinator {
HighPriorityProvider highPriorityProvider,
SectionClassifier sectionClassifier,
@AlertingHeader NodeController alertingHeaderController,
@SilentHeader SectionHeaderController silentHeaderController,
@SilentHeader NodeController silentNodeController) {
mStatusBarStateController = statusBarStateController;
mHighPriorityProvider = highPriorityProvider;
mSectionClassifier = sectionClassifier;
mAlertingHeaderController = alertingHeaderController;
mSilentNodeController = silentNodeController;
mSilentHeaderController = silentHeaderController;
}
@Override
@@ -90,6 +95,82 @@ public class RankingCoordinator implements Coordinator {
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.
* NotifListBuilder invalidates the notification list each time the ranking is updated,
@@ -121,64 +202,4 @@ public class RankingCoordinator implements Coordinator {
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

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

View File

@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator.dagge
import com.android.systemui.dagger.SysUISingleton
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.SensitiveContentCoordinatorModule
import dagger.Binds
import dagger.Module
import dagger.Provides
@@ -47,6 +48,7 @@ interface CoordinatorsSubcomponent {
}
@Module(includes = [
SensitiveContentCoordinatorModule::class,
])
private abstract class InternalCoordinatorsModule {
@Binds

View File

@@ -16,8 +16,6 @@
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 android.annotation.Nullable;
@@ -251,13 +249,10 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
RowContentBindParams params = mRowContentBindStage.getStageParams(entry);
params.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
params.setUseLowPriority(isLowPriority);
boolean needsRedaction =
mNotificationLockscreenUserManager.notifNeedsRedactionInPublic(entry);
if (needsRedaction) {
params.requireContentViews(FLAG_CONTENT_VIEW_PUBLIC);
} else {
params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC);
}
// TODO: Replace this API with RowContentBindParams directly. Also move to a separate
// redaction controller.
row.setNeedsRedaction(mNotificationLockscreenUserManager.needsRedaction(entry));
params.rebindAllContentViews();
mRowContentBindStage.requestRebind(entry, en -> {

View File

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

View File

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

View File

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

View File

@@ -90,8 +90,8 @@ import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
import com.android.systemui.statusbar.notification.FeedbackIcon;
import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
import com.android.systemui.statusbar.notification.FeedbackIcon;
import com.android.systemui.statusbar.notification.NotificationFadeAware;
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController;
import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -202,6 +202,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
/** Are we showing the "public" version */
private boolean mShowingPublic;
private boolean mSensitive;
private boolean mSensitiveHiddenInGeneral;
private boolean mShowingPublicInitialized;
private boolean mHideSensitiveForIntrinsicHeight;
private float mHeaderVisibleAmount = DEFAULT_HEADER_VISIBLE_AMOUNT;
@@ -1504,7 +1505,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mUseIncreasedHeadsUpHeight = use;
}
// TODO: remove this method and mNeedsRedaction entirely once the old pipeline is gone
public void setNeedsRedaction(boolean needsRedaction) {
// TODO: Move inflation logic out of this call and remove this method
if (mNeedsRedaction != needsRedaction) {
@@ -2587,8 +2587,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
}
public void setSensitive(boolean sensitive) {
public void setSensitive(boolean sensitive, boolean hideSensitive) {
mSensitive = sensitive;
mSensitiveHiddenInGeneral = hideSensitive;
}
@Override
@@ -2678,15 +2679,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
* see {@link NotificationEntry#isDismissable()}.
*/
public boolean canViewBeDismissed() {
// 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;
return mEntry.isDismissable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral);
}
/**
@@ -2695,7 +2688,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
* clearability see {@link NotificationEntry#isClearable()}.
*/
public boolean canViewBeCleared() {
return mEntry.isClearable() && !shouldShowPublic();
return mEntry.isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral);
}
private boolean shouldShowPublic() {
@@ -3459,28 +3452,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
pw.print(", translation: " + getTranslation());
pw.print(", removed: " + isRemoved());
pw.print(", expandAnimationRunning: " + mExpandAnimationRunning);
pw.print(", sensitive: " + mSensitive);
pw.print(", hideSensitiveForIntrinsicHeight: " + mHideSensitiveForIntrinsicHeight);
pw.println(", privateShowing: " + !shouldShowPublic());
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");
}
NotificationContentView showingLayout = getShowingLayout();
pw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
pw.println();
showingLayout.dump(pw, args);
if (getViewState() != null) {
getViewState().dump(pw, args);
@@ -3506,6 +3481,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
pw.decreaseIndent();
pw.println("}");
} else if (mPrivateLayout != null) {
mPrivateLayout.dumpSmartReplies(pw);
}
});
}

View File

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

View File

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

View File

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

View File

@@ -216,9 +216,6 @@ public class NotificationStackScrollLayoutController {
mBarState = mStatusBarStateController.getState();
mStatusBarStateController.addCallback(
mStateListener, SysuiStatusBarStateController.RANK_STACK_SCROLLER);
mLockscreenUserManager.addOnNeedsRedactionInPublicChangedListener(
mOnNeedsRedactionInPublicChangedListener);
updateClearButtonVisibility();
}
@Override
@@ -226,8 +223,6 @@ public class NotificationStackScrollLayoutController {
mConfigurationController.removeCallback(mConfigurationListener);
mZenModeController.removeCallback(mZenModeControllerCallback);
mStatusBarStateController.removeCallback(mStateListener);
mLockscreenUserManager.removeOnNeedsRedactionInPublicChangedListener(
mOnNeedsRedactionInPublicChangedListener);
}
};
@@ -331,7 +326,6 @@ public class NotificationStackScrollLayoutController {
mLockscreenUserManager.isAnyProfilePublicMode());
mView.onStatePostChange(mStatusBarStateController.fromShadeLocked());
mNotificationEntryManager.updateNotifications("CentralSurfaces state changed");
updateClearButtonVisibility();
}
};
@@ -344,17 +338,6 @@ 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.
*/
@@ -1291,44 +1274,12 @@ public class NotificationStackScrollLayoutController {
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) {
boolean hasAlertingMatchingClearable = isClearable
? hasClearableAlertingNotifs()
? mNotifStats.getHasClearableAlertingNotifs()
: mNotifStats.getHasNonClearableAlertingNotifs();
boolean hasSilentMatchingClearable = isClearable
? hasClearableSilentNotifs()
? mNotifStats.getHasClearableSilentNotifs()
: mNotifStats.getHasNonClearableSilentNotifs();
switch (selection) {
case ROWS_GENTLE:
@@ -1628,15 +1579,6 @@ public class NotificationStackScrollLayoutController {
mNotificationActivityStarter = activityStarter;
}
private void updateClearButtonVisibility() {
updateClearSilentButton();
updateFooter();
}
private void updateClearSilentButton() {
mSilentHeaderController.setClearSectionEnabled(hasClearableSilentNotifs());
}
/**
* Enum for UiEvent logged from this class
*/
@@ -1962,7 +1904,6 @@ public class NotificationStackScrollLayoutController {
@Override
public void setNotifStats(@NonNull NotifStats notifStats) {
mNotifStats = notifStats;
updateClearSilentButton();
updateFooter();
updateShowEmptyShadeView();
}

View File

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

View File

@@ -32,6 +32,7 @@ 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.statusbar.StatusBarState.KEYGUARD;
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.phone.panelstate.PanelExpansionStateManagerKt.STATE_CLOSED;
import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_OPEN;
@@ -3950,6 +3951,10 @@ public class NotificationPanelViewController extends PanelViewController {
}
}
public boolean hasActiveClearableNotifications() {
return mNotificationStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL);
}
public RemoteInputController.Delegate createRemoteInputDelegate() {
return mNotificationStackScrollLayoutController.createDelegate();
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -23,6 +23,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -32,6 +33,7 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.testing.AndroidTestingRunner;
import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -39,6 +41,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder;
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.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -46,6 +49,7 @@ 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.provider.HighPriorityProvider;
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.Test;
@@ -68,6 +72,7 @@ public class RankingCoordinatorTest extends SysuiTestCase {
@Mock private NotifPipeline mNotifPipeline;
@Mock private NodeController mAlertingHeaderController;
@Mock private NodeController mSilentNodeController;
@Mock private SectionHeaderController mSilentHeaderController;
@Captor private ArgumentCaptor<NotifFilter> mNotifFilterCaptor;
@@ -89,6 +94,7 @@ public class RankingCoordinatorTest extends SysuiTestCase {
mHighPriorityProvider,
mSectionClassifier,
mAlertingHeaderController,
mSilentHeaderController,
mSilentNodeController);
mEntry = spy(new NotificationEntryBuilder().build());
mEntry.setRanking(getRankingForUnfilteredNotif().build());
@@ -105,6 +111,25 @@ public class RankingCoordinatorTest extends SysuiTestCase {
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
public void testUnfilteredState() {
// GIVEN no suppressed visual effects + app not suspended
@@ -200,6 +225,46 @@ public class RankingCoordinatorTest extends SysuiTestCase {
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) {
for (NotifSectioner current: mSections) {
if (current == section) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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