Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt +86 −64 Original line number Diff line number Diff line Loading @@ -32,6 +32,8 @@ import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.NotificationContentView import com.android.systemui.statusbar.notification.stack.StackStateAnimator Loading Loading @@ -132,12 +134,15 @@ class AnimatedImageNotificationManager @Inject constructor( /** * Tracks state related to conversation notifications, and updates the UI of existing notifications * when necessary. * TODO(b/214083332) Refactor this class to use the right coordinators and controllers */ @SysUISingleton class ConversationNotificationManager @Inject constructor( private val notificationEntryManager: NotificationEntryManager, private val notificationGroupManager: NotificationGroupManagerLegacy, private val context: Context, private val notifCollection: CommonNotifCollection, private val featureFlags: NotifPipelineFlags, @Main private val mainHandler: Handler ) { // Need this state to be thread safe, since it's accessed from the ui thread Loading @@ -146,9 +151,30 @@ class ConversationNotificationManager @Inject constructor( private var notifPanelCollapsed = true init { notificationEntryManager.addNotificationEntryListener(object : NotificationEntryListener { override fun onNotificationRankingUpdated(rankingMap: RankingMap) { private val entryManagerListener = object : NotificationEntryListener { override fun onNotificationRankingUpdated(rankingMap: RankingMap) = updateNotificationRanking(rankingMap) override fun onEntryInflated(entry: NotificationEntry) = onEntryViewBound(entry) override fun onEntryReinflated(entry: NotificationEntry) = onEntryInflated(entry) override fun onEntryRemoved( entry: NotificationEntry, visibility: NotificationVisibility?, removedByUser: Boolean, reason: Int ) = removeTrackedEntry(entry) } private val notifCollectionListener = object : NotifCollectionListener { override fun onRankingUpdate(ranking: RankingMap) = updateNotificationRanking(ranking) override fun onEntryRemoved(entry: NotificationEntry, reason: Int) { removeTrackedEntry(entry) } } private fun updateNotificationRanking(rankingMap: RankingMap) { fun getLayouts(view: NotificationContentView) = sequenceOf(view.contractedChild, view.expandedChild, view.headsUpChild) val ranking = Ranking() Loading Loading @@ -184,8 +210,7 @@ class ConversationNotificationManager @Inject constructor( } } } override fun onEntryInflated(entry: NotificationEntry) { fun onEntryViewBound(entry: NotificationEntry) { if (!entry.ranking.isConversation) { return } Loading @@ -207,15 +232,12 @@ class ConversationNotificationManager @Inject constructor( updateCount(entry.row?.isExpanded == true) } override fun onEntryReinflated(entry: NotificationEntry) = onEntryInflated(entry) override fun onEntryRemoved( entry: NotificationEntry, visibility: NotificationVisibility?, removedByUser: Boolean, reason: Int ) = removeTrackedEntry(entry) }) init { if (featureFlags.isNewPipelineEnabled()) { notifCollection.addCollectionListener(notifCollectionListener) } else { notificationEntryManager.addNotificationEntryListener(entryManagerListener) } } private fun ConversationState.shouldIncrementUnread(newBuilder: Notification.Builder) = Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java +10 −1 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.statusbar.notification.ConversationNotificationManager; import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotifPipeline; Loading Loading @@ -98,6 +99,7 @@ public class PreparationCoordinator implements Coordinator { /** How long we can delay a group while waiting for all children to inflate */ private final long mMaxGroupInflationDelay; private final ConversationNotificationManager mConversationManager; @Inject public PreparationCoordinator( Loading @@ -106,7 +108,8 @@ public class PreparationCoordinator implements Coordinator { NotifInflationErrorManager errorManager, NotifViewBarn viewBarn, NotifUiAdjustmentProvider adjustmentProvider, IStatusBarService service) { IStatusBarService service, ConversationNotificationManager conversationManager) { this( logger, notifInflater, Loading @@ -114,6 +117,7 @@ public class PreparationCoordinator implements Coordinator { viewBarn, adjustmentProvider, service, conversationManager, CHILD_BIND_CUTOFF, MAX_GROUP_INFLATION_DELAY); } Loading @@ -126,6 +130,7 @@ public class PreparationCoordinator implements Coordinator { NotifViewBarn viewBarn, NotifUiAdjustmentProvider adjustmentProvider, IStatusBarService service, ConversationNotificationManager conversationManager, int childBindCutoff, long maxGroupInflationDelay) { mLogger = logger; Loading @@ -136,6 +141,7 @@ public class PreparationCoordinator implements Coordinator { mStatusBarService = service; mChildBindCutoff = childBindCutoff; mMaxGroupInflationDelay = maxGroupInflationDelay; mConversationManager = conversationManager; } @Override Loading Loading @@ -363,6 +369,9 @@ public class PreparationCoordinator implements Coordinator { mInflatingNotifs.remove(entry); mViewBarn.registerViewForEntry(entry, controller); mInflationStates.put(entry, STATE_INFLATED); // NOTE: under the new pipeline there's no way to register for an inflation callback, // so this one method is called by the PreparationCoordinator directly. mConversationManager.onEntryViewBound(entry); mNotifInflatingFilter.invalidateList(); } Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java +10 −0 Original line number Diff line number Diff line Loading @@ -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.RankingBuilder; import com.android.systemui.statusbar.notification.ConversationNotificationManager; import com.android.systemui.statusbar.notification.SectionClassifier; import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder; Loading Loading @@ -92,6 +93,7 @@ public class PreparationCoordinatorTest extends SysuiTestCase { @Mock private NotifSection mNotifSection; @Mock private NotifPipeline mNotifPipeline; @Mock private IStatusBarService mService; @Mock private ConversationNotificationManager mConvoManager; @Spy private FakeNotifInflater mNotifInflater = new FakeNotifInflater(); private final SectionClassifier mSectionClassifier = new SectionClassifier(); private final NotifUiAdjustmentProvider mAdjustmentProvider = Loading Loading @@ -119,6 +121,7 @@ public class PreparationCoordinatorTest extends SysuiTestCase { mock(NotifViewBarn.class), mAdjustmentProvider, mService, mConvoManager, TEST_CHILD_BIND_CUTOFF, TEST_MAX_GROUP_DELAY); Loading Loading @@ -404,6 +407,13 @@ public class PreparationCoordinatorTest extends SysuiTestCase { assertFalse(mUninflatedFilter.shouldFilterOut(child1, 401)); } @Test public void testCallConversationManagerBindWhenInflated() { mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry)); mNotifInflater.getInflateCallback(mEntry).onInflationFinished(mEntry, null); verify(mConvoManager, times(1)).onEntryViewBound(eq(mEntry)); } @Test public void testPartiallyInflatedGroupsAreReleasedAfterTimeout() { // GIVEN a newly-posted group with a summary and two children Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt +86 −64 Original line number Diff line number Diff line Loading @@ -32,6 +32,8 @@ import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.NotificationContentView import com.android.systemui.statusbar.notification.stack.StackStateAnimator Loading Loading @@ -132,12 +134,15 @@ class AnimatedImageNotificationManager @Inject constructor( /** * Tracks state related to conversation notifications, and updates the UI of existing notifications * when necessary. * TODO(b/214083332) Refactor this class to use the right coordinators and controllers */ @SysUISingleton class ConversationNotificationManager @Inject constructor( private val notificationEntryManager: NotificationEntryManager, private val notificationGroupManager: NotificationGroupManagerLegacy, private val context: Context, private val notifCollection: CommonNotifCollection, private val featureFlags: NotifPipelineFlags, @Main private val mainHandler: Handler ) { // Need this state to be thread safe, since it's accessed from the ui thread Loading @@ -146,9 +151,30 @@ class ConversationNotificationManager @Inject constructor( private var notifPanelCollapsed = true init { notificationEntryManager.addNotificationEntryListener(object : NotificationEntryListener { override fun onNotificationRankingUpdated(rankingMap: RankingMap) { private val entryManagerListener = object : NotificationEntryListener { override fun onNotificationRankingUpdated(rankingMap: RankingMap) = updateNotificationRanking(rankingMap) override fun onEntryInflated(entry: NotificationEntry) = onEntryViewBound(entry) override fun onEntryReinflated(entry: NotificationEntry) = onEntryInflated(entry) override fun onEntryRemoved( entry: NotificationEntry, visibility: NotificationVisibility?, removedByUser: Boolean, reason: Int ) = removeTrackedEntry(entry) } private val notifCollectionListener = object : NotifCollectionListener { override fun onRankingUpdate(ranking: RankingMap) = updateNotificationRanking(ranking) override fun onEntryRemoved(entry: NotificationEntry, reason: Int) { removeTrackedEntry(entry) } } private fun updateNotificationRanking(rankingMap: RankingMap) { fun getLayouts(view: NotificationContentView) = sequenceOf(view.contractedChild, view.expandedChild, view.headsUpChild) val ranking = Ranking() Loading Loading @@ -184,8 +210,7 @@ class ConversationNotificationManager @Inject constructor( } } } override fun onEntryInflated(entry: NotificationEntry) { fun onEntryViewBound(entry: NotificationEntry) { if (!entry.ranking.isConversation) { return } Loading @@ -207,15 +232,12 @@ class ConversationNotificationManager @Inject constructor( updateCount(entry.row?.isExpanded == true) } override fun onEntryReinflated(entry: NotificationEntry) = onEntryInflated(entry) override fun onEntryRemoved( entry: NotificationEntry, visibility: NotificationVisibility?, removedByUser: Boolean, reason: Int ) = removeTrackedEntry(entry) }) init { if (featureFlags.isNewPipelineEnabled()) { notifCollection.addCollectionListener(notifCollectionListener) } else { notificationEntryManager.addNotificationEntryListener(entryManagerListener) } } private fun ConversationState.shouldIncrementUnread(newBuilder: Notification.Builder) = Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java +10 −1 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.statusbar.notification.ConversationNotificationManager; import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotifPipeline; Loading Loading @@ -98,6 +99,7 @@ public class PreparationCoordinator implements Coordinator { /** How long we can delay a group while waiting for all children to inflate */ private final long mMaxGroupInflationDelay; private final ConversationNotificationManager mConversationManager; @Inject public PreparationCoordinator( Loading @@ -106,7 +108,8 @@ public class PreparationCoordinator implements Coordinator { NotifInflationErrorManager errorManager, NotifViewBarn viewBarn, NotifUiAdjustmentProvider adjustmentProvider, IStatusBarService service) { IStatusBarService service, ConversationNotificationManager conversationManager) { this( logger, notifInflater, Loading @@ -114,6 +117,7 @@ public class PreparationCoordinator implements Coordinator { viewBarn, adjustmentProvider, service, conversationManager, CHILD_BIND_CUTOFF, MAX_GROUP_INFLATION_DELAY); } Loading @@ -126,6 +130,7 @@ public class PreparationCoordinator implements Coordinator { NotifViewBarn viewBarn, NotifUiAdjustmentProvider adjustmentProvider, IStatusBarService service, ConversationNotificationManager conversationManager, int childBindCutoff, long maxGroupInflationDelay) { mLogger = logger; Loading @@ -136,6 +141,7 @@ public class PreparationCoordinator implements Coordinator { mStatusBarService = service; mChildBindCutoff = childBindCutoff; mMaxGroupInflationDelay = maxGroupInflationDelay; mConversationManager = conversationManager; } @Override Loading Loading @@ -363,6 +369,9 @@ public class PreparationCoordinator implements Coordinator { mInflatingNotifs.remove(entry); mViewBarn.registerViewForEntry(entry, controller); mInflationStates.put(entry, STATE_INFLATED); // NOTE: under the new pipeline there's no way to register for an inflation callback, // so this one method is called by the PreparationCoordinator directly. mConversationManager.onEntryViewBound(entry); mNotifInflatingFilter.invalidateList(); } Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java +10 −0 Original line number Diff line number Diff line Loading @@ -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.RankingBuilder; import com.android.systemui.statusbar.notification.ConversationNotificationManager; import com.android.systemui.statusbar.notification.SectionClassifier; import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder; Loading Loading @@ -92,6 +93,7 @@ public class PreparationCoordinatorTest extends SysuiTestCase { @Mock private NotifSection mNotifSection; @Mock private NotifPipeline mNotifPipeline; @Mock private IStatusBarService mService; @Mock private ConversationNotificationManager mConvoManager; @Spy private FakeNotifInflater mNotifInflater = new FakeNotifInflater(); private final SectionClassifier mSectionClassifier = new SectionClassifier(); private final NotifUiAdjustmentProvider mAdjustmentProvider = Loading Loading @@ -119,6 +121,7 @@ public class PreparationCoordinatorTest extends SysuiTestCase { mock(NotifViewBarn.class), mAdjustmentProvider, mService, mConvoManager, TEST_CHILD_BIND_CUTOFF, TEST_MAX_GROUP_DELAY); Loading Loading @@ -404,6 +407,13 @@ public class PreparationCoordinatorTest extends SysuiTestCase { assertFalse(mUninflatedFilter.shouldFilterOut(child1, 401)); } @Test public void testCallConversationManagerBindWhenInflated() { mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry)); mNotifInflater.getInflateCallback(mEntry).onInflationFinished(mEntry, null); verify(mConvoManager, times(1)).onEntryViewBound(eq(mEntry)); } @Test public void testPartiallyInflatedGroupsAreReleasedAfterTimeout() { // GIVEN a newly-posted group with a summary and two children Loading