Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java +4 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.collection.coalescer; import androidx.annotation.Nullable; import java.util.ArrayList; import java.util.List; Loading @@ -35,6 +37,8 @@ public class EventBatch { */ final List<CoalescedEvent> mMembers = new ArrayList<>(); @Nullable Runnable mCancelShortTimeout; EventBatch(long createdTimestamp, String groupKey) { mCreatedTimestamp = createdTimestamp; this.mGroupKey = groupKey; Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java +54 −25 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.collection.coalescer; import static com.android.systemui.statusbar.notification.logging.NotifEvent.BATCH_MAX_TIMEOUT; import static com.android.systemui.statusbar.notification.logging.NotifEvent.COALESCED_EVENT; import static com.android.systemui.statusbar.notification.logging.NotifEvent.EARLY_BATCH_EMIT; import static com.android.systemui.statusbar.notification.logging.NotifEvent.EMIT_EVENT_BATCH; Loading Loading @@ -71,7 +72,8 @@ public class GroupCoalescer implements Dumpable { private final DelayableExecutor mMainExecutor; private final SystemClock mClock; private final NotifLog mLog; private final long mGroupLingerDuration; private final long mMinGroupLingerDuration; private final long mMaxGroupLingerDuration; private BatchableNotificationHandler mHandler; Loading @@ -82,22 +84,28 @@ public class GroupCoalescer implements Dumpable { public GroupCoalescer( @Main DelayableExecutor mainExecutor, SystemClock clock, NotifLog log) { this(mainExecutor, clock, log, GROUP_LINGER_DURATION); this(mainExecutor, clock, log, MIN_GROUP_LINGER_DURATION, MAX_GROUP_LINGER_DURATION); } /** * @param groupLingerDuration How long, in ms, that notifications that are members of a group * are delayed within the GroupCoalescer before being posted * @param minGroupLingerDuration How long, in ms, to wait for another notification from the same * group to arrive before emitting all pending events for that * group. Each subsequent arrival of a group member resets the * timer for that group. * @param maxGroupLingerDuration The maximum time, in ms, that a group can linger in the * coalescer before it's force-emitted. */ GroupCoalescer( @Main DelayableExecutor mainExecutor, SystemClock clock, NotifLog log, long groupLingerDuration) { long minGroupLingerDuration, long maxGroupLingerDuration) { mMainExecutor = mainExecutor; mClock = clock; mLog = log; mGroupLingerDuration = groupLingerDuration; mMinGroupLingerDuration = minGroupLingerDuration; mMaxGroupLingerDuration = maxGroupLingerDuration; } /** Loading @@ -115,7 +123,7 @@ public class GroupCoalescer implements Dumpable { private final NotificationHandler mListener = new NotificationHandler() { @Override public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) { maybeEmitBatch(sbn.getKey()); maybeEmitBatch(sbn); applyRanking(rankingMap); final boolean shouldCoalesce = handleNotificationPosted(sbn, rankingMap); Loading @@ -130,7 +138,7 @@ public class GroupCoalescer implements Dumpable { @Override public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) { maybeEmitBatch(sbn.getKey()); maybeEmitBatch(sbn); applyRanking(rankingMap); mHandler.onNotificationRemoved(sbn, rankingMap); } Loading @@ -140,7 +148,7 @@ public class GroupCoalescer implements Dumpable { StatusBarNotification sbn, RankingMap rankingMap, int reason) { maybeEmitBatch(sbn.getKey()); maybeEmitBatch(sbn); applyRanking(rankingMap); mHandler.onNotificationRemoved(sbn, rankingMap, reason); } Loading @@ -152,13 +160,20 @@ public class GroupCoalescer implements Dumpable { } }; private void maybeEmitBatch(String memberKey) { CoalescedEvent event = mCoalescedEvents.get(memberKey); private void maybeEmitBatch(StatusBarNotification sbn) { final CoalescedEvent event = mCoalescedEvents.get(sbn.getKey()); final EventBatch batch = mBatches.get(sbn.getGroupKey()); if (event != null) { mLog.log(EARLY_BATCH_EMIT, String.format("Modification of %s triggered early emit of batched group %s", memberKey, requireNonNull(event.getBatch()).mGroupKey)); sbn.getKey(), requireNonNull(event.getBatch()).mGroupKey)); emitBatch(requireNonNull(event.getBatch())); } else if (batch != null && mClock.uptimeMillis() - batch.mCreatedTimestamp >= mMaxGroupLingerDuration) { mLog.log(BATCH_MAX_TIMEOUT, String.format("Modification of %s triggered timeout emit of batched group %s", sbn.getKey(), batch.mGroupKey)); emitBatch(batch); } } Loading @@ -175,7 +190,8 @@ public class GroupCoalescer implements Dumpable { } if (sbn.isGroup()) { EventBatch batch = startBatchingGroup(sbn.getGroupKey()); final EventBatch batch = getOrBuildBatch(sbn.getGroupKey()); CoalescedEvent event = new CoalescedEvent( sbn.getKey(), Loading @@ -183,10 +199,10 @@ public class GroupCoalescer implements Dumpable { sbn, requireRanking(rankingMap, sbn.getKey()), batch); mCoalescedEvents.put(event.getKey(), event); batch.mMembers.add(event); mCoalescedEvents.put(event.getKey(), event); resetShortTimeout(batch); return true; } else { Loading @@ -194,27 +210,39 @@ public class GroupCoalescer implements Dumpable { } } private EventBatch startBatchingGroup(final String groupKey) { private EventBatch getOrBuildBatch(final String groupKey) { EventBatch batch = mBatches.get(groupKey); if (batch == null) { final EventBatch newBatch = new EventBatch(mClock.uptimeMillis(), groupKey); mBatches.put(groupKey, newBatch); mMainExecutor.executeDelayed(() -> emitBatch(newBatch), mGroupLingerDuration); batch = newBatch; batch = new EventBatch(mClock.uptimeMillis(), groupKey); mBatches.put(groupKey, batch); } return batch; } private void resetShortTimeout(EventBatch batch) { if (batch.mCancelShortTimeout != null) { batch.mCancelShortTimeout.run(); } batch.mCancelShortTimeout = mMainExecutor.executeDelayed( () -> { batch.mCancelShortTimeout = null; emitBatch(batch); }, mMinGroupLingerDuration); } private void emitBatch(EventBatch batch) { if (batch != mBatches.get(batch.mGroupKey)) { // If we emit a batch early, we don't want to emit it a second time when its timeout // expires. return; throw new IllegalStateException("Cannot emit out-of-date batch " + batch.mGroupKey); } if (batch.mMembers.isEmpty()) { throw new IllegalStateException("Batch " + batch.mGroupKey + " cannot be empty"); } if (batch.mCancelShortTimeout != null) { batch.mCancelShortTimeout.run(); batch.mCancelShortTimeout = null; } mBatches.remove(batch.mGroupKey); Loading Loading @@ -299,5 +327,6 @@ public class GroupCoalescer implements Dumpable { void onNotificationBatchPosted(List<CoalescedEvent> events); } private static final int GROUP_LINGER_DURATION = 500; private static final int MIN_GROUP_LINGER_DURATION = 50; private static final int MAX_GROUP_LINGER_DURATION = 500; } packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java +3 −1 Original line number Diff line number Diff line Loading @@ -156,7 +156,8 @@ public class NotifEvent extends RichEvent { // GroupCoalescer labels: "CoalescedEvent", "EarlyBatchEmit", "EmitEventBatch" "EmitEventBatch", "BatchMaxTimeout" }; private static final int TOTAL_EVENT_LABELS = EVENT_LABELS.length; Loading Loading @@ -206,5 +207,6 @@ public class NotifEvent extends RichEvent { public static final int COALESCED_EVENT = COALESCER_EVENT_START_INDEX; public static final int EARLY_BATCH_EMIT = COALESCER_EVENT_START_INDEX + 1; public static final int EMIT_EVENT_BATCH = COALESCER_EVENT_START_INDEX + 2; public static final int BATCH_MAX_TIMEOUT = COALESCER_EVENT_START_INDEX + 3; private static final int TOTAL_COALESCER_EVENT_TYPES = 3; } packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java +61 −7 Original line number Diff line number Diff line Loading @@ -80,7 +80,8 @@ public class GroupCoalescerTest extends SysuiTestCase { mExecutor, mClock, mLog, LINGER_DURATION); MIN_LINGER_DURATION, MAX_LINGER_DURATION); mCoalescer.setNotificationHandler(mListener); mCoalescer.attach(mListenerService); Loading @@ -96,7 +97,7 @@ public class GroupCoalescerTest extends SysuiTestCase { new NotificationEntryBuilder() .setId(0) .setPkg(TEST_PACKAGE_A)); mClock.advanceTime(LINGER_DURATION); mClock.advanceTime(MIN_LINGER_DURATION); // THEN the event is passed through to the handler verify(mListener).onNotificationPosted(notif1.sbn, notif1.rankingMap); Loading Loading @@ -144,12 +145,16 @@ public class GroupCoalescerTest extends SysuiTestCase { .setId(1) .setGroup(mContext, GROUP_1)); mClock.advanceTime(2); NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(2) .setGroup(mContext, GROUP_1) .setGroupSummary(mContext, true)); mClock.advanceTime(3); NotifEvent notif3 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(3) Loading @@ -161,7 +166,7 @@ public class GroupCoalescerTest extends SysuiTestCase { verify(mListener, never()).onNotificationBatchPosted(anyList()); // WHEN enough time passes mClock.advanceTime(LINGER_DURATION); mClock.advanceTime(MIN_LINGER_DURATION); // THEN the coalesced notifs are applied. The summary is sorted to the front. verify(mListener).onNotificationBatchPosted(Arrays.asList( Loading Loading @@ -212,7 +217,7 @@ public class GroupCoalescerTest extends SysuiTestCase { // WHEN the time runs out on the remainder of the group clearInvocations(mListener); mClock.advanceTime(LINGER_DURATION); mClock.advanceTime(MIN_LINGER_DURATION); // THEN no lingering batch is applied verify(mListener, never()).onNotificationBatchPosted(anyList()); Loading @@ -225,11 +230,13 @@ public class GroupCoalescerTest extends SysuiTestCase { .setPkg(TEST_PACKAGE_A) .setId(1) .setGroup(mContext, GROUP_1)); mClock.advanceTime(2); NotifEvent notif2a = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(2) .setContentTitle(mContext, "Version 1") .setGroup(mContext, GROUP_1)); mClock.advanceTime(4); // WHEN one of them gets updated NotifEvent notif2b = mNoMan.postNotif(new NotificationEntryBuilder() Loading @@ -248,7 +255,7 @@ public class GroupCoalescerTest extends SysuiTestCase { any(RankingMap.class)); // THEN second, the update is emitted mClock.advanceTime(LINGER_DURATION); mClock.advanceTime(MIN_LINGER_DURATION); verify(mListener).onNotificationBatchPosted(Collections.singletonList( new CoalescedEvent(notif2b.key, 0, notif2b.sbn, notif2b.ranking, null) )); Loading Loading @@ -308,14 +315,61 @@ public class GroupCoalescerTest extends SysuiTestCase { .setId(17)); // THEN they have the new rankings when they are eventually emitted mClock.advanceTime(LINGER_DURATION); mClock.advanceTime(MIN_LINGER_DURATION); verify(mListener).onNotificationBatchPosted(Arrays.asList( new CoalescedEvent(notif1.key, 0, notif1.sbn, ranking1b, null), new CoalescedEvent(notif2.key, 1, notif2.sbn, ranking2b, null) )); } private static final long LINGER_DURATION = 4700; @Test public void testMaxLingerDuration() { // GIVEN five coalesced notifications that have collectively taken 20ms to arrive, 2ms // longer than the max linger duration NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(1) .setGroup(mContext, GROUP_1)); mClock.advanceTime(4); NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(2) .setGroup(mContext, GROUP_1)); mClock.advanceTime(4); NotifEvent notif3 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(3) .setGroup(mContext, GROUP_1)); mClock.advanceTime(4); NotifEvent notif4 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(4) .setGroup(mContext, GROUP_1)); mClock.advanceTime(4); NotifEvent notif5 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(5) .setGroup(mContext, GROUP_1)); mClock.advanceTime(4); // WHEN a sixth notification arrives NotifEvent notif6 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(6) .setGroup(mContext, GROUP_1)); // THEN the first five notifications are emitted in a batch verify(mListener).onNotificationBatchPosted(Arrays.asList( new CoalescedEvent(notif1.key, 0, notif1.sbn, notif1.ranking, null), new CoalescedEvent(notif2.key, 1, notif2.sbn, notif2.ranking, null), new CoalescedEvent(notif3.key, 2, notif3.sbn, notif3.ranking, null), new CoalescedEvent(notif4.key, 3, notif4.sbn, notif4.ranking, null), new CoalescedEvent(notif5.key, 4, notif5.sbn, notif5.ranking, null) )); } private static final long MIN_LINGER_DURATION = 5; private static final long MAX_LINGER_DURATION = 18; private static final String TEST_PACKAGE_A = "com.test.package_a"; private static final String TEST_PACKAGE_B = "com.test.package_b"; Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java +4 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.collection.coalescer; import androidx.annotation.Nullable; import java.util.ArrayList; import java.util.List; Loading @@ -35,6 +37,8 @@ public class EventBatch { */ final List<CoalescedEvent> mMembers = new ArrayList<>(); @Nullable Runnable mCancelShortTimeout; EventBatch(long createdTimestamp, String groupKey) { mCreatedTimestamp = createdTimestamp; this.mGroupKey = groupKey; Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java +54 −25 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.collection.coalescer; import static com.android.systemui.statusbar.notification.logging.NotifEvent.BATCH_MAX_TIMEOUT; import static com.android.systemui.statusbar.notification.logging.NotifEvent.COALESCED_EVENT; import static com.android.systemui.statusbar.notification.logging.NotifEvent.EARLY_BATCH_EMIT; import static com.android.systemui.statusbar.notification.logging.NotifEvent.EMIT_EVENT_BATCH; Loading Loading @@ -71,7 +72,8 @@ public class GroupCoalescer implements Dumpable { private final DelayableExecutor mMainExecutor; private final SystemClock mClock; private final NotifLog mLog; private final long mGroupLingerDuration; private final long mMinGroupLingerDuration; private final long mMaxGroupLingerDuration; private BatchableNotificationHandler mHandler; Loading @@ -82,22 +84,28 @@ public class GroupCoalescer implements Dumpable { public GroupCoalescer( @Main DelayableExecutor mainExecutor, SystemClock clock, NotifLog log) { this(mainExecutor, clock, log, GROUP_LINGER_DURATION); this(mainExecutor, clock, log, MIN_GROUP_LINGER_DURATION, MAX_GROUP_LINGER_DURATION); } /** * @param groupLingerDuration How long, in ms, that notifications that are members of a group * are delayed within the GroupCoalescer before being posted * @param minGroupLingerDuration How long, in ms, to wait for another notification from the same * group to arrive before emitting all pending events for that * group. Each subsequent arrival of a group member resets the * timer for that group. * @param maxGroupLingerDuration The maximum time, in ms, that a group can linger in the * coalescer before it's force-emitted. */ GroupCoalescer( @Main DelayableExecutor mainExecutor, SystemClock clock, NotifLog log, long groupLingerDuration) { long minGroupLingerDuration, long maxGroupLingerDuration) { mMainExecutor = mainExecutor; mClock = clock; mLog = log; mGroupLingerDuration = groupLingerDuration; mMinGroupLingerDuration = minGroupLingerDuration; mMaxGroupLingerDuration = maxGroupLingerDuration; } /** Loading @@ -115,7 +123,7 @@ public class GroupCoalescer implements Dumpable { private final NotificationHandler mListener = new NotificationHandler() { @Override public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) { maybeEmitBatch(sbn.getKey()); maybeEmitBatch(sbn); applyRanking(rankingMap); final boolean shouldCoalesce = handleNotificationPosted(sbn, rankingMap); Loading @@ -130,7 +138,7 @@ public class GroupCoalescer implements Dumpable { @Override public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) { maybeEmitBatch(sbn.getKey()); maybeEmitBatch(sbn); applyRanking(rankingMap); mHandler.onNotificationRemoved(sbn, rankingMap); } Loading @@ -140,7 +148,7 @@ public class GroupCoalescer implements Dumpable { StatusBarNotification sbn, RankingMap rankingMap, int reason) { maybeEmitBatch(sbn.getKey()); maybeEmitBatch(sbn); applyRanking(rankingMap); mHandler.onNotificationRemoved(sbn, rankingMap, reason); } Loading @@ -152,13 +160,20 @@ public class GroupCoalescer implements Dumpable { } }; private void maybeEmitBatch(String memberKey) { CoalescedEvent event = mCoalescedEvents.get(memberKey); private void maybeEmitBatch(StatusBarNotification sbn) { final CoalescedEvent event = mCoalescedEvents.get(sbn.getKey()); final EventBatch batch = mBatches.get(sbn.getGroupKey()); if (event != null) { mLog.log(EARLY_BATCH_EMIT, String.format("Modification of %s triggered early emit of batched group %s", memberKey, requireNonNull(event.getBatch()).mGroupKey)); sbn.getKey(), requireNonNull(event.getBatch()).mGroupKey)); emitBatch(requireNonNull(event.getBatch())); } else if (batch != null && mClock.uptimeMillis() - batch.mCreatedTimestamp >= mMaxGroupLingerDuration) { mLog.log(BATCH_MAX_TIMEOUT, String.format("Modification of %s triggered timeout emit of batched group %s", sbn.getKey(), batch.mGroupKey)); emitBatch(batch); } } Loading @@ -175,7 +190,8 @@ public class GroupCoalescer implements Dumpable { } if (sbn.isGroup()) { EventBatch batch = startBatchingGroup(sbn.getGroupKey()); final EventBatch batch = getOrBuildBatch(sbn.getGroupKey()); CoalescedEvent event = new CoalescedEvent( sbn.getKey(), Loading @@ -183,10 +199,10 @@ public class GroupCoalescer implements Dumpable { sbn, requireRanking(rankingMap, sbn.getKey()), batch); mCoalescedEvents.put(event.getKey(), event); batch.mMembers.add(event); mCoalescedEvents.put(event.getKey(), event); resetShortTimeout(batch); return true; } else { Loading @@ -194,27 +210,39 @@ public class GroupCoalescer implements Dumpable { } } private EventBatch startBatchingGroup(final String groupKey) { private EventBatch getOrBuildBatch(final String groupKey) { EventBatch batch = mBatches.get(groupKey); if (batch == null) { final EventBatch newBatch = new EventBatch(mClock.uptimeMillis(), groupKey); mBatches.put(groupKey, newBatch); mMainExecutor.executeDelayed(() -> emitBatch(newBatch), mGroupLingerDuration); batch = newBatch; batch = new EventBatch(mClock.uptimeMillis(), groupKey); mBatches.put(groupKey, batch); } return batch; } private void resetShortTimeout(EventBatch batch) { if (batch.mCancelShortTimeout != null) { batch.mCancelShortTimeout.run(); } batch.mCancelShortTimeout = mMainExecutor.executeDelayed( () -> { batch.mCancelShortTimeout = null; emitBatch(batch); }, mMinGroupLingerDuration); } private void emitBatch(EventBatch batch) { if (batch != mBatches.get(batch.mGroupKey)) { // If we emit a batch early, we don't want to emit it a second time when its timeout // expires. return; throw new IllegalStateException("Cannot emit out-of-date batch " + batch.mGroupKey); } if (batch.mMembers.isEmpty()) { throw new IllegalStateException("Batch " + batch.mGroupKey + " cannot be empty"); } if (batch.mCancelShortTimeout != null) { batch.mCancelShortTimeout.run(); batch.mCancelShortTimeout = null; } mBatches.remove(batch.mGroupKey); Loading Loading @@ -299,5 +327,6 @@ public class GroupCoalescer implements Dumpable { void onNotificationBatchPosted(List<CoalescedEvent> events); } private static final int GROUP_LINGER_DURATION = 500; private static final int MIN_GROUP_LINGER_DURATION = 50; private static final int MAX_GROUP_LINGER_DURATION = 500; }
packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java +3 −1 Original line number Diff line number Diff line Loading @@ -156,7 +156,8 @@ public class NotifEvent extends RichEvent { // GroupCoalescer labels: "CoalescedEvent", "EarlyBatchEmit", "EmitEventBatch" "EmitEventBatch", "BatchMaxTimeout" }; private static final int TOTAL_EVENT_LABELS = EVENT_LABELS.length; Loading Loading @@ -206,5 +207,6 @@ public class NotifEvent extends RichEvent { public static final int COALESCED_EVENT = COALESCER_EVENT_START_INDEX; public static final int EARLY_BATCH_EMIT = COALESCER_EVENT_START_INDEX + 1; public static final int EMIT_EVENT_BATCH = COALESCER_EVENT_START_INDEX + 2; public static final int BATCH_MAX_TIMEOUT = COALESCER_EVENT_START_INDEX + 3; private static final int TOTAL_COALESCER_EVENT_TYPES = 3; }
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java +61 −7 Original line number Diff line number Diff line Loading @@ -80,7 +80,8 @@ public class GroupCoalescerTest extends SysuiTestCase { mExecutor, mClock, mLog, LINGER_DURATION); MIN_LINGER_DURATION, MAX_LINGER_DURATION); mCoalescer.setNotificationHandler(mListener); mCoalescer.attach(mListenerService); Loading @@ -96,7 +97,7 @@ public class GroupCoalescerTest extends SysuiTestCase { new NotificationEntryBuilder() .setId(0) .setPkg(TEST_PACKAGE_A)); mClock.advanceTime(LINGER_DURATION); mClock.advanceTime(MIN_LINGER_DURATION); // THEN the event is passed through to the handler verify(mListener).onNotificationPosted(notif1.sbn, notif1.rankingMap); Loading Loading @@ -144,12 +145,16 @@ public class GroupCoalescerTest extends SysuiTestCase { .setId(1) .setGroup(mContext, GROUP_1)); mClock.advanceTime(2); NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(2) .setGroup(mContext, GROUP_1) .setGroupSummary(mContext, true)); mClock.advanceTime(3); NotifEvent notif3 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(3) Loading @@ -161,7 +166,7 @@ public class GroupCoalescerTest extends SysuiTestCase { verify(mListener, never()).onNotificationBatchPosted(anyList()); // WHEN enough time passes mClock.advanceTime(LINGER_DURATION); mClock.advanceTime(MIN_LINGER_DURATION); // THEN the coalesced notifs are applied. The summary is sorted to the front. verify(mListener).onNotificationBatchPosted(Arrays.asList( Loading Loading @@ -212,7 +217,7 @@ public class GroupCoalescerTest extends SysuiTestCase { // WHEN the time runs out on the remainder of the group clearInvocations(mListener); mClock.advanceTime(LINGER_DURATION); mClock.advanceTime(MIN_LINGER_DURATION); // THEN no lingering batch is applied verify(mListener, never()).onNotificationBatchPosted(anyList()); Loading @@ -225,11 +230,13 @@ public class GroupCoalescerTest extends SysuiTestCase { .setPkg(TEST_PACKAGE_A) .setId(1) .setGroup(mContext, GROUP_1)); mClock.advanceTime(2); NotifEvent notif2a = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(2) .setContentTitle(mContext, "Version 1") .setGroup(mContext, GROUP_1)); mClock.advanceTime(4); // WHEN one of them gets updated NotifEvent notif2b = mNoMan.postNotif(new NotificationEntryBuilder() Loading @@ -248,7 +255,7 @@ public class GroupCoalescerTest extends SysuiTestCase { any(RankingMap.class)); // THEN second, the update is emitted mClock.advanceTime(LINGER_DURATION); mClock.advanceTime(MIN_LINGER_DURATION); verify(mListener).onNotificationBatchPosted(Collections.singletonList( new CoalescedEvent(notif2b.key, 0, notif2b.sbn, notif2b.ranking, null) )); Loading Loading @@ -308,14 +315,61 @@ public class GroupCoalescerTest extends SysuiTestCase { .setId(17)); // THEN they have the new rankings when they are eventually emitted mClock.advanceTime(LINGER_DURATION); mClock.advanceTime(MIN_LINGER_DURATION); verify(mListener).onNotificationBatchPosted(Arrays.asList( new CoalescedEvent(notif1.key, 0, notif1.sbn, ranking1b, null), new CoalescedEvent(notif2.key, 1, notif2.sbn, ranking2b, null) )); } private static final long LINGER_DURATION = 4700; @Test public void testMaxLingerDuration() { // GIVEN five coalesced notifications that have collectively taken 20ms to arrive, 2ms // longer than the max linger duration NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(1) .setGroup(mContext, GROUP_1)); mClock.advanceTime(4); NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(2) .setGroup(mContext, GROUP_1)); mClock.advanceTime(4); NotifEvent notif3 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(3) .setGroup(mContext, GROUP_1)); mClock.advanceTime(4); NotifEvent notif4 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(4) .setGroup(mContext, GROUP_1)); mClock.advanceTime(4); NotifEvent notif5 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(5) .setGroup(mContext, GROUP_1)); mClock.advanceTime(4); // WHEN a sixth notification arrives NotifEvent notif6 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(6) .setGroup(mContext, GROUP_1)); // THEN the first five notifications are emitted in a batch verify(mListener).onNotificationBatchPosted(Arrays.asList( new CoalescedEvent(notif1.key, 0, notif1.sbn, notif1.ranking, null), new CoalescedEvent(notif2.key, 1, notif2.sbn, notif2.ranking, null), new CoalescedEvent(notif3.key, 2, notif3.sbn, notif3.ranking, null), new CoalescedEvent(notif4.key, 3, notif4.sbn, notif4.ranking, null), new CoalescedEvent(notif5.key, 4, notif5.sbn, notif5.ranking, null) )); } private static final long MIN_LINGER_DURATION = 5; private static final long MAX_LINGER_DURATION = 18; private static final String TEST_PACKAGE_A = "com.test.package_a"; private static final String TEST_PACKAGE_B = "com.test.package_b"; Loading