diff options
7 files changed, 123 insertions, 9 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java index 21a70d59419e..d1bc14fa52cf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java @@ -89,6 +89,18 @@ public interface NotificationLockscreenUserManager { */ boolean userAllowsNotificationsInPublic(int userId); + /** + * Adds a {@link NotificationStateChangedListener} to be notified of any state changes that + * would affect presentation of notifications. + */ + void addNotificationStateChangedListener(NotificationStateChangedListener listener); + + /** + * Removes a {@link NotificationStateChangedListener} that was previously registered with + * {@link #addNotificationStateChangedListener(NotificationStateChangedListener)}. + */ + void removeNotificationStateChangedListener(NotificationStateChangedListener listener); + /** Notified when the current user changes. */ interface UserChangedListener { default void onUserChanged(int userId) {} @@ -100,4 +112,12 @@ public interface NotificationLockscreenUserManager { interface KeyguardNotificationSuppressor { boolean shouldSuppressOnKeyguard(NotificationEntry entry); } + + /** + * Notified when any state pertaining to Notifications has changed; any methods pertaining to + * notifications should be re-queried. + */ + interface NotificationStateChangedListener { + void onNotificationStateChanged(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index ecbe32f1b737..38a208b72edc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -60,6 +60,7 @@ 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; @@ -110,6 +111,8 @@ public class NotificationLockscreenUserManagerImpl implements protected KeyguardManager mKeyguardManager; private int mState = StatusBarState.SHADE; private List<KeyguardNotificationSuppressor> mKeyguardSuppressors = new ArrayList<>(); + private final ListenerSet<NotificationStateChangedListener> mNotifStateChangedListeners = + new ListenerSet<>(); protected final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() { @Override @@ -121,6 +124,8 @@ public class NotificationLockscreenUserManagerImpl implements mUsersAllowingPrivateNotifications.clear(); updateLockscreenNotificationSetting(); getEntryManager().updateNotifications("ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED"); + // TODO(b/231976036): Consolidate pipeline invalidations related to this event + // notifyNotificationStateChanged(); } } }; @@ -254,6 +259,7 @@ public class NotificationLockscreenUserManagerImpl implements updateLockscreenNotificationSetting(); getEntryManager().updateNotifications("LOCK_SCREEN_SHOW_NOTIFICATIONS," + " or LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS change"); + notifyNotificationStateChanged(); } }; @@ -264,6 +270,8 @@ public class NotificationLockscreenUserManagerImpl implements if (mDeviceProvisionedController.isDeviceProvisioned()) { getEntryManager().updateNotifications("LOCK_SCREEN_ALLOW_REMOTE_INPUT" + " or ZEN_MODE change"); + // TODO(b/231976036): Consolidate pipeline invalidations related to this event + // notifyNotificationStateChanged(); } } }; @@ -651,6 +659,8 @@ public class NotificationLockscreenUserManagerImpl implements mUsersWithSeparateWorkChallenge.put(userId, needsSeparateChallenge); } getEntryManager().updateNotifications("NotificationLockscreenUserManager.updatePublicMode"); + // TODO(b/234738798): Migrate KeyguardNotificationVisibilityProvider to use this listener + // notifyNotificationStateChanged(); } @Override @@ -668,6 +678,22 @@ public class NotificationLockscreenUserManagerImpl implements mListeners.remove(listener); } + @Override + public void addNotificationStateChangedListener(NotificationStateChangedListener listener) { + mNotifStateChangedListeners.addIfAbsent(listener); + } + + @Override + public void removeNotificationStateChangedListener(NotificationStateChangedListener listener) { + mNotifStateChangedListeners.remove(listener); + } + + private void notifyNotificationStateChanged() { + for (NotificationStateChangedListener listener : mNotifStateChangedListeners) { + listener.onNotificationStateChanged(); + } + } + // public void updatePublicMode() { // //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns // // false when it should be true. Therefore, if we are not on the SHADE, don't even bother diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java index 35fe0ee7cdb1..210fe8fd0421 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java @@ -147,6 +147,7 @@ public class PreparationCoordinator implements Coordinator { @Override public void attach(NotifPipeline pipeline) { mNotifErrorManager.addInflationErrorListener(mInflationErrorListener); + mAdjustmentProvider.addDirtyListener(mNotifInflatingFilter::invalidateList); pipeline.addCollectionListener(mNotifCollectionListener); // Inflate after grouping/sorting since that affects what views to inflate. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt index 9d86b7831f18..3475fcf7c12f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt @@ -31,7 +31,8 @@ class NotifUiAdjustment internal constructor( val smartActions: List<Notification.Action>, val smartReplies: List<CharSequence>, val isConversation: Boolean, - val isMinimized: Boolean + val isMinimized: Boolean, + val needsRedaction: Boolean, ) { companion object { @JvmStatic @@ -42,6 +43,7 @@ class NotifUiAdjustment internal constructor( oldAdjustment === newAdjustment -> false oldAdjustment.isConversation != newAdjustment.isConversation -> true oldAdjustment.isMinimized != newAdjustment.isMinimized -> true + oldAdjustment.needsRedaction != newAdjustment.needsRedaction -> true areDifferent(oldAdjustment.smartActions, newAdjustment.smartActions) -> true newAdjustment.smartReplies != oldAdjustment.smartReplies -> true else -> false 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 497691d18844..f7b6376c717c 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 @@ -17,9 +17,11 @@ package com.android.systemui.statusbar.notification.collection.inflation import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.notification.SectionClassifier import com.android.systemui.statusbar.notification.collection.GroupEntry import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.util.ListenerSet import javax.inject.Inject /** @@ -27,9 +29,30 @@ import javax.inject.Inject * to ensure that notifications are reinflated when ranking-derived information changes. */ @SysUISingleton -open class NotifUiAdjustmentProvider @Inject constructor( - private val sectionClassifier: SectionClassifier +class NotifUiAdjustmentProvider @Inject constructor( + private val lockscreenUserManager: NotificationLockscreenUserManager, + private val sectionClassifier: SectionClassifier, ) { + private val dirtyListeners = ListenerSet<Runnable>() + + fun addDirtyListener(listener: Runnable) { + if (dirtyListeners.isEmpty()) { + lockscreenUserManager.addNotificationStateChangedListener(notifStateChangedListener) + } + dirtyListeners.addIfAbsent(listener) + } + + fun removeDirtyListener(listener: Runnable) { + dirtyListeners.remove(listener) + if (dirtyListeners.isEmpty()) { + lockscreenUserManager.removeNotificationStateChangedListener(notifStateChangedListener) + } + } + + private val notifStateChangedListener = + NotificationLockscreenUserManager.NotificationStateChangedListener { + dirtyListeners.forEach(Runnable::run) + } private fun isEntryMinimized(entry: NotificationEntry): Boolean { val section = entry.section ?: error("Entry must have a section to determine if minimized") @@ -42,14 +65,15 @@ open class NotifUiAdjustmentProvider @Inject constructor( /** * Returns a adjustment object for the given entry. This can be compared to a previous instance - * from the same notification using [NotifUiAdjustment.needReinflate] to determine if it - * should be reinflated. + * from the same notification using [NotifUiAdjustment.needReinflate] to determine if it should + * be reinflated. */ fun calculateAdjustment(entry: NotificationEntry) = NotifUiAdjustment( key = entry.key, smartActions = entry.ranking.smartActions, smartReplies = entry.ranking.smartReplies, isConversation = entry.ranking.isConversation, - isMinimized = isEntryMinimized(entry) + isMinimized = isEntryMinimized(entry), + needsRedaction = lockscreenUserManager.needsRedaction(entry), ) }
\ No newline at end of file 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 3b034f7af9a6..d327be4c436a 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 @@ -40,6 +40,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.notification.SectionClassifier; import com.android.systemui.statusbar.notification.collection.GroupEntry; @@ -95,10 +96,11 @@ public class PreparationCoordinatorTest extends SysuiTestCase { @Mock private NotifPipeline mNotifPipeline; @Mock private IStatusBarService mService; @Mock private BindEventManagerImpl mBindEventManagerImpl; + @Mock private NotificationLockscreenUserManager mLockscreenUserManager; @Spy private FakeNotifInflater mNotifInflater = new FakeNotifInflater(); private final SectionClassifier mSectionClassifier = new SectionClassifier(); - private final NotifUiAdjustmentProvider mAdjustmentProvider = - new NotifUiAdjustmentProvider(mSectionClassifier); + + private NotifUiAdjustmentProvider mAdjustmentProvider; @NonNull private NotificationEntryBuilder getNotificationEntryBuilder() { @@ -108,7 +110,8 @@ public class PreparationCoordinatorTest extends SysuiTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); - + mAdjustmentProvider = + new NotifUiAdjustmentProvider(mLockscreenUserManager, mSectionClassifier); mEntry = getNotificationEntryBuilder().setParent(ROOT_ENTRY).build(); mInflationError = new Exception(TEST_MESSAGE); mErrorManager = new NotifInflationErrorManager(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt new file mode 100644 index 000000000000..dd15caebf9e6 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt @@ -0,0 +1,38 @@ +package com.android.systemui.statusbar.notification.collection.inflation + +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.NotificationLockscreenUserManager +import com.android.systemui.statusbar.notification.SectionClassifier +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.withArgCaptor +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.verify + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@RunWithLooper +class NotifUiAdjustmentProviderTest : SysuiTestCase() { + private val lockscreenUserManager: NotificationLockscreenUserManager = mock() + private val sectionClassifier: SectionClassifier = mock() + + private val adjustmentProvider = NotifUiAdjustmentProvider( + lockscreenUserManager, + sectionClassifier, + ) + + @Test + fun notifLockscreenStateChangeWillNotifDirty() { + val dirtyListener = mock<Runnable>() + adjustmentProvider.addDirtyListener(dirtyListener) + val notifLocksreenStateChangeListener = + withArgCaptor<NotificationLockscreenUserManager.NotificationStateChangedListener> { + verify(lockscreenUserManager).addNotificationStateChangedListener(capture()) + } + notifLocksreenStateChangeListener.onNotificationStateChanged() + verify(dirtyListener).run(); + } +} |