diff options
4 files changed, 58 insertions, 17 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java index c9f31bad74c0..8aeefeeac211 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java @@ -307,7 +307,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { } entriesToLocallyDismiss.add(entry); - if (!isCanceled(entry)) { + if (!entry.isCanceled()) { // send message to system server if this notification hasn't already been cancelled mBgExecutor.execute(() -> { try { @@ -387,7 +387,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { entry.setDismissState(DISMISSED); mLogger.logNotifDismissed(entry); - if (isCanceled(entry)) { + if (entry.isCanceled()) { canceledEntries.add(entry); } else { // Mark any children as dismissed as system server will auto-dismiss them as well @@ -396,7 +396,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { if (shouldAutoDismissChildren(otherEntry, entry.getSbn().getGroupKey())) { otherEntry.setDismissState(PARENT_DISMISSED); mLogger.logChildDismissed(otherEntry); - if (isCanceled(otherEntry)) { + if (otherEntry.isCanceled()) { canceledEntries.add(otherEntry); } } @@ -523,7 +523,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { + logKey(entry))); } - if (!isCanceled(entry)) { + if (!entry.isCanceled()) { throw mEulogizer.record( new IllegalStateException("Cannot remove notification " + logKey(entry) + ": has not been marked for removal")); @@ -587,7 +587,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { private void applyRanking(@NonNull RankingMap rankingMap) { ArrayMap<String, NotificationEntry> currentEntriesWithoutRankings = null; for (NotificationEntry entry : mNotificationSet.values()) { - if (!isCanceled(entry)) { + if (!entry.isCanceled()) { // TODO: (b/148791039) We should crash if we are ever handed a ranking with // incomplete entries. Right now, there's a race condition in NotificationListener @@ -815,15 +815,6 @@ public class NotifCollection implements Dumpable, PipelineDumpable { return ranking; } - /** - * True if the notification has been canceled by system server. Usually, such notifications are - * immediately removed from the collection, but can sometimes stick around due to lifetime - * extenders. - */ - private boolean isCanceled(NotificationEntry entry) { - return entry.mCancellationReason != REASON_NOT_CANCELED; - } - private boolean cannotBeLifetimeExtended(NotificationEntry entry) { final boolean locallyDismissedByUser = entry.getDismissState() != NOT_DISMISSED; final boolean systemServerReportedUserCancel = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index 3399f9df7fd5..f7790e861e27 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -321,6 +321,15 @@ public final class NotificationEntry extends ListEntry { mDismissState = requireNonNull(dismissState); } + /** + * True if the notification has been canceled by system server. Usually, such notifications are + * immediately removed from the collection, but can sometimes stick around due to lifetime + * extenders. + */ + public boolean isCanceled() { + return mCancellationReason != REASON_NOT_CANCELED; + } + @Nullable public NotifFilter getExcludingFilter() { return getAttachState().getExcludingFilter(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt index 0d9a654fa485..058545689c01 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt @@ -46,7 +46,7 @@ class NotifUiAdjustmentProvider @Inject constructor( private val userTracker: UserTracker ) { private val dirtyListeners = ListenerSet<Runnable>() - private var isSnoozeEnabled = false + private var isSnoozeSettingsEnabled = false /** * Update the snooze enabled value on user switch @@ -95,7 +95,7 @@ class NotifUiAdjustmentProvider @Inject constructor( } private fun updateSnoozeEnabled() { - isSnoozeEnabled = + isSnoozeSettingsEnabled = secureSettings.getIntForUser(SHOW_NOTIFICATION_SNOOZE, 0, UserHandle.USER_CURRENT) == 1 } @@ -118,7 +118,7 @@ class NotifUiAdjustmentProvider @Inject constructor( smartActions = entry.ranking.smartActions, smartReplies = entry.ranking.smartReplies, isConversation = entry.ranking.isConversation, - isSnoozeEnabled = isSnoozeEnabled, + isSnoozeEnabled = isSnoozeSettingsEnabled && !entry.isCanceled, isMinimized = isEntryMinimized(entry), needsRedaction = lockscreenUserManager.needsRedaction(entry), ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java index 9b6d29310d0b..b5e77e0fb693 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java @@ -16,14 +16,18 @@ package com.android.systemui.statusbar.notification.collection.coordinator; +import static android.provider.Settings.Secure.SHOW_NOTIFICATION_SNOOZE; + import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -31,6 +35,7 @@ import static org.mockito.Mockito.when; import static java.util.Objects.requireNonNull; +import android.database.ContentObserver; import android.os.Handler; import android.os.RemoteException; import android.testing.AndroidTestingRunner; @@ -295,6 +300,42 @@ public class PreparationCoordinatorTest extends SysuiTestCase { } @Test + public void testEntryCancellationWillRebindViews() { + // Configure NotifUiAdjustmentProvider to set up SHOW_NOTIFICATION_SNOOZE value + mEntry = spy(mEntry); + mAdjustmentProvider.addDirtyListener(mock(Runnable.class)); + when(mSecureSettings.getIntForUser(eq(SHOW_NOTIFICATION_SNOOZE), anyInt(), anyInt())) + .thenReturn(1); + ArgumentCaptor<ContentObserver> contentObserverCaptor = ArgumentCaptor.forClass( + ContentObserver.class); + verify(mSecureSettings).registerContentObserverForUser(eq(SHOW_NOTIFICATION_SNOOZE), + contentObserverCaptor.capture(), anyInt()); + ContentObserver contentObserver = contentObserverCaptor.getValue(); + contentObserver.onChange(false); + + // GIVEN an inflated notification + mCollectionListener.onEntryInit(mEntry); + mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry)); + verify(mNotifInflater).inflateViews(eq(mEntry), any(), any()); + mNotifInflater.invokeInflateCallbackForEntry(mEntry); + + // Verify that snooze is initially enabled: from Settings & notification is not cancelled + assertTrue(mAdjustmentProvider.calculateAdjustment(mEntry).isSnoozeEnabled()); + + // WHEN notification is cancelled, rebind views because snooze enabled value changes + when(mEntry.isCanceled()).thenReturn(true); + mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry)); + + assertFalse(mAdjustmentProvider.calculateAdjustment(mEntry).isSnoozeEnabled()); + + // THEN we rebind it + verify(mNotifInflater).rebindViews(eq(mEntry), any(), any()); + + // THEN we do not filter it because it's not the first inflation. + assertFalse(mUninflatedFilter.shouldFilterOut(mEntry, 0)); + } + + @Test public void testDoesntFilterInflatedNotifs() { // GIVEN an inflated notification mCollectionListener.onEntryInit(mEntry); |