Merge "Revert "Don't show "Clear All" w/ redacted notifs"" into tm-dev am: 95d2e13cc1
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18437717 Change-Id: I1d8e4258b84dceedd2500446af94307ab89aa867 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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 -> {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -182,4 +182,4 @@ annotation class HeaderClickAction
|
||||
|
||||
@Scope
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class SectionHeaderScope
|
||||
annotation class SectionHeaderScope
|
||||
@@ -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>)
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user