Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8c268afa authored by Valentin Iftime's avatar Valentin Iftime
Browse files

Update autogroup summary on child flag updates

 Update the autogroup summary if a child notification is posted with updated flags.

Flag: EXEMPT bugfix

Test: atest GroupHelperTest
Test: atest NotificationManagerServiceTest

Bug: 428516725

Change-Id: I12e385651ed0de929c44910af408b6bfe07f41f6
parent f810fca3
Loading
Loading
Loading
Loading
+37 −4
Original line number Diff line number Diff line
@@ -604,11 +604,14 @@ public class GroupHelper {
            maybeUngroupOnSectionChanged(record, prevSectionKey);
        }

        synchronized (mAggregatedNotifications) {
            // This notification is already aggregated
            if (record.getGroupKey().equals(fullAggregateGroupKey.toString())) {
                // Update summary if flags updated
                maybeUpdateSummaryAttributes(record, fullAggregateGroupKey, sectioner);
                return false;
            }
        synchronized (mAggregatedNotifications) {

            ArrayMap<String, NotificationAttributes> ungrouped =
                mUngroupedAbuseNotifications.getOrDefault(fullAggregateGroupKey, new ArrayMap<>());
            ungrouped.put(record.getKey(), new NotificationAttributes(
@@ -659,6 +662,36 @@ public class GroupHelper {
        return sbnToBeAutogrouped;
    }

    @GuardedBy("mAggregatedNotifications")
    private void maybeUpdateSummaryAttributes(NotificationRecord childRecord,
            FullyQualifiedGroupKey fullAggregateGroupKey,
            NotificationSectioner sectioner) {
        final ArrayMap<String, NotificationAttributes> aggregatedNotificationsAttrs =
                mAggregatedNotifications.getOrDefault(fullAggregateGroupKey, new ArrayMap<>());
        NotificationAttributes oldAttrs = aggregatedNotificationsAttrs.get(childRecord.getKey());
        if (oldAttrs != null) {
            NotificationAttributes newAttr = new NotificationAttributes(
                    childRecord.getFlags(),
                    childRecord.getNotification().getSmallIcon(),
                    childRecord.getNotification().color,
                    childRecord.getNotification().visibility,
                    childRecord.getNotification().getGroupAlertBehavior(),
                    childRecord.getChannel().getId());
            if (!oldAttrs.equals(newAttr)) {
                aggregatedNotificationsAttrs.put(childRecord.getKey(), newAttr);
                mAggregatedNotifications.put(fullAggregateGroupKey, aggregatedNotificationsAttrs);

                if (DEBUG) {
                    Slog.i(TAG, "maybeUpdateSummaryAttributes: " + childRecord);
                }

                // Update aggregate summary
                updateAggregateAppGroup(fullAggregateGroupKey, childRecord.getKey(), true,
                        sectioner.mSummaryId);
            }
        }
    }

    /**
     * A notification was added that was previously part of a valid section and needs to trigger
     * GH state cleanup.
+156 −0
Original line number Diff line number Diff line
@@ -824,6 +824,162 @@ public class GroupHelperTest extends UiServiceTestCase {
            any());
    }

    @Test
    @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
    public void testAutoGrouped_updateOngoingChild_updatesSummary() {
        final String pkg = "package";
        final String expectedGroupKey = GroupHelper.getFullAggregateGroupKey(pkg,
                AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());

        // Post AUTOGROUP_AT_COUNT ongoing notifications
        ArrayList<NotificationRecord> notifications = new ArrayList<>();
        for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
            NotificationRecord r = getNotificationRecord(pkg, i, String.valueOf(i),
                    UserHandle.SYSTEM);
            notifications.add(r);
        }

        for (NotificationRecord r: notifications) {
            mGroupHelper.onNotificationPosted(r, false);
            r.setOverrideGroupKey(expectedGroupKey);
        }

        // Update one notification to ONGOING_EVENT
        Mockito.reset(mCallback);
        final NotificationRecord updatedNotification = notifications.get(0);
        updatedNotification.getNotification().flags |= FLAG_ONGOING_EVENT;
        mGroupHelper.onNotificationPosted(updatedNotification, true);

        // Check that summary has FLAG_ONGOING_EVENT
        verify(mCallback).updateAutogroupSummary(anyInt(), anyString(), anyString(),
                eq(getNotificationAttributes(BASE_FLAGS | FLAG_ONGOING_EVENT)));
    }

    @Test
    @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
    public void testAutoGrouped_noFlagsUpdate_doesNotUpdateSummary() {
        final String pkg = "package";
        final String expectedGroupKey = GroupHelper.getFullAggregateGroupKey(pkg,
                AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());

        // Post AUTOGROUP_AT_COUNT ongoing notifications
        ArrayList<NotificationRecord> notifications = new ArrayList<>();
        for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
            NotificationRecord r = getNotificationRecord(pkg, i, String.valueOf(i),
                    UserHandle.SYSTEM);
            notifications.add(r);
        }

        for (NotificationRecord r: notifications) {
            mGroupHelper.onNotificationPosted(r, false);
            r.setOverrideGroupKey(expectedGroupKey);
        }

        // Update one notification without updating its flags
        Mockito.reset(mCallback);
        final NotificationRecord updatedNotification = notifications.get(0);
        mGroupHelper.onNotificationPosted(updatedNotification, true);

        // Check that nothing was updated
        verify(mCallback, never()).removeAutoGroup(anyString());
        verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
        verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
                any());
    }

    @Test
    @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
    public void testAddAggregateSummary_summaryNoChildren_updateFlags_updatesSummary() {
        final String pkg = "package";
        final String expectedGroupKey = GroupHelper.getFullAggregateGroupKey(pkg,
                AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());
        final List<NotificationRecord> notificationList = new ArrayList<>();
        final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
        // Post group summaries without children => force autogroup
        for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
            NotificationRecord r = getNotificationRecord(pkg, i, String.valueOf(i),
                    UserHandle.SYSTEM, "testGrp " + i, true);
            notificationList.add(r);
            mGroupHelper.onNotificationPostedWithDelay(r, notificationList, summaryByGroup);
        }
        // Check that notifications were autogrouped
        verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
                eq(expectedGroupKey), anyInt(), eq(getNotificationAttributes(BASE_FLAGS)));
        verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(),
                eq(expectedGroupKey), eq(true));
        verify(mCallback, never()).removeAutoGroup(anyString());
        verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
        verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
                any());

        // Update notifications group key to aggregate group
        for (NotificationRecord r: notificationList) {
            r.setOverrideGroupKey(expectedGroupKey);
        }

        // Update to FLAG_ONGOING_EVENT
        Mockito.reset(mCallback);
        final NotificationRecord updatedNotification = notificationList.get(0);
        updatedNotification.getNotification().flags |= FLAG_ONGOING_EVENT;
        mGroupHelper.onNotificationPosted(updatedNotification, true);

        verify(mCallback, times(1)).removeAutoGroup(updatedNotification.getKey());
        updatedNotification.setOverrideGroupKey(null);

        mGroupHelper.onNotificationPostedWithDelay(updatedNotification, notificationList,
                summaryByGroup);

        // Check that summary has FLAG_ONGOING_EVENT
        verify(mCallback).updateAutogroupSummary(anyInt(), anyString(), anyString(),
                eq(getNotificationAttributes(BASE_FLAGS | FLAG_ONGOING_EVENT)));
    }

    @Test
    @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
    public void testAddAggregateSummary_childrenNoSummary_updateFlags_updatesSummary() {
        final String pkg = "package";
        final String expectedGroupKey = GroupHelper.getFullAggregateGroupKey(pkg,
                AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());
        final List<NotificationRecord> notificationList = new ArrayList<>();
        final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
        // Post group notifications without summaries => force autogroup
        for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
            NotificationRecord r = getNotificationRecord(pkg, i, String.valueOf(i),
                    UserHandle.SYSTEM, "testGrp " + i, false);
            notificationList.add(r);
            mGroupHelper.onNotificationPostedWithDelay(r, notificationList, summaryByGroup);
        }
        verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
                eq(expectedGroupKey), anyInt(), eq(getNotificationAttributes(BASE_FLAGS)));
        verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(),
                eq(expectedGroupKey), eq(true));
        verify(mCallback, never()).removeAutoGroup(anyString());
        verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
        verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
                any());

        // Update notification group
        for (NotificationRecord r: notificationList) {
            r.setOverrideGroupKey(expectedGroupKey);
        }

        // Update to FLAG_ONGOING_EVENT
        Mockito.reset(mCallback);
        final NotificationRecord updatedNotification = notificationList.get(0);
        updatedNotification.getNotification().flags |= FLAG_ONGOING_EVENT;
        mGroupHelper.onNotificationPosted(updatedNotification, true);

        verify(mCallback, times(1)).removeAutoGroup(updatedNotification.getKey());
        updatedNotification.setOverrideGroupKey(null);

        mGroupHelper.onNotificationPostedWithDelay(updatedNotification, notificationList,
                summaryByGroup);

        // Check that summary has FLAG_ONGOING_EVENT
        verify(mCallback).updateAutogroupSummary(anyInt(), anyString(), anyString(),
                eq(getNotificationAttributes(BASE_FLAGS | FLAG_ONGOING_EVENT)));
    }

    @Test
    @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING})
    public void testDropToZeroRemoveGroup() {
+102 −0
Original line number Diff line number Diff line
@@ -2696,6 +2696,108 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertThat(summary.getChannel().getId()).isEqualTo(newChannelId);
    }
    @Test
    @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
    public void testAggregatedSummary_updateUngroupedChildFlags_updatesSummary() throws Exception {
        // Add 2 ungrouped notifications
        NotificationRecord nr0 = generateNotificationRecord(mTestNotificationChannel, 0, mUserId);
        mService.addEnqueuedNotification(nr0);
        NotificationManagerService.PostNotificationRunnable runnable =
                mService.new PostNotificationRunnable(nr0.getKey(), nr0.getSbn().getPackageName(),
                    nr0.getUid(), mPostNotificationTrackerFactory.newTracker(null));
        runnable.run();
        waitForIdle();
        moveTimeForwardAndWaitForIdle(DELAY_FORCE_REGROUP_TIME);
        NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 1, mUserId);
        mService.addEnqueuedNotification(nr1);
        runnable = mService.new PostNotificationRunnable(nr1.getKey(),
                nr1.getSbn().getPackageName(), nr1.getUid(),
                mPostNotificationTrackerFactory.newTracker(null));
        runnable.run();
        waitForIdle();
        moveTimeForwardAndWaitForIdle(DELAY_FORCE_REGROUP_TIME);
        // Check that the aggregate group summary was created
        nr0.applyAdjustments();
        nr1.applyAdjustments();
        final String fullAggregateGroupKey = nr0.getGroupKey();
        NotificationRecord aggregateSummary = mService.mSummaryByGroupKey.get(
                fullAggregateGroupKey);
        assertThat(aggregateSummary).isNotNull();
        assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(fullAggregateGroupKey);
        assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo(
                nr0.getChannel().getId());
        assertThat(aggregateSummary.getSbn().isOngoing()).isFalse();
        // Update first child's flags
        final NotificationRecord updatedNotification = generateNotificationRecord(
                mTestNotificationChannel, 0, mUserId);
        updatedNotification.getNotification().flags |= FLAG_ONGOING_EVENT;
        mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr0.getSbn().getTag(),
                nr0.getSbn().getId(), updatedNotification.getNotification(),
                nr0.getSbn().getUserId());
        waitForIdle();
        moveTimeForwardAndWaitForIdle(DELAY_FORCE_REGROUP_TIME);
        // Check that summary has FLAG_ONGOING_EVENT
        assertThat(aggregateSummary.getSbn().isOngoing()).isTrue();
    }
    @Test
    @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
    public void testAggregatedSummary_updateForceGroupedChildFlags_updatesSummary()
            throws Exception {
        // Add 2 summary notifications without children
        final String originalGroupName = "originalGroup";
        final NotificationRecord nr0 =
                generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true);
        mService.addEnqueuedNotification(nr0);
        NotificationManagerService.PostNotificationRunnable runnable =
                mService.new PostNotificationRunnable(nr0.getKey(), nr0.getSbn().getPackageName(),
                    nr0.getUid(), mPostNotificationTrackerFactory.newTracker(null));
        runnable.run();
        waitForIdle();
        moveTimeForwardAndWaitForIdle(DELAY_FORCE_REGROUP_TIME);
        final NotificationRecord nr1 =
                generateNotificationRecord(mTestNotificationChannel, 1, originalGroupName, true);
        mService.addEnqueuedNotification(nr1);
        runnable = mService.new PostNotificationRunnable(nr1.getKey(),
                nr1.getSbn().getPackageName(), nr1.getUid(),
                    mPostNotificationTrackerFactory.newTracker(null));
        runnable.run();
        waitForIdle();
        moveTimeForwardAndWaitForIdle(DELAY_FORCE_REGROUP_TIME);
        // Check that the aggregate group summary was created
        nr0.applyAdjustments();
        nr1.applyAdjustments();
        final String fullAggregateGroupKey = nr0.getGroupKey();
        NotificationRecord aggregateSummary = mService.mSummaryByGroupKey.get(
                fullAggregateGroupKey);
        assertThat(aggregateSummary).isNotNull();
        assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(fullAggregateGroupKey);
        assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo(
                nr0.getChannel().getId());
        assertThat(aggregateSummary.getSbn().isOngoing()).isFalse();
        assertThat(nr0.getNotification().isGroupSummary()).isFalse();
        assertThat(nr1.getNotification().isGroupSummary()).isFalse();
        // Update first child's flags
        final NotificationRecord updatedNotification =
                generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true);
        updatedNotification.getNotification().flags |= FLAG_ONGOING_EVENT;
        mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr0.getSbn().getTag(),
                nr0.getSbn().getId(), updatedNotification.getNotification(),
                nr0.getSbn().getUserId());
        waitForIdle();
        moveTimeForwardAndWaitForIdle(DELAY_FORCE_REGROUP_TIME);
        // Check that summary has FLAG_ONGOING_EVENT
        assertThat(aggregateSummary.getSbn().isOngoing()).isTrue();
    }
    @Test
    @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
    public void testAddAggregateNotification_notifyPostedLocked() throws Exception {