From 81410323bc8da9b93172a253cf67d3e68c35c29f Mon Sep 17 00:00:00 2001 From: Yanting Yang Date: Wed, 23 Jan 2019 22:15:51 +0800 Subject: [PATCH] Sort notification channel in NotificationChannelSlice According request to sort the notification channel by average weekly sent count in descending. Bug: 119831690 Test: visual, robotests Change-Id: I96786b077a37dcbc53606f8d98998e01e15b674d --- .../slices/NotificationChannelSlice.java | 74 +++++++++++++++---- .../slices/NotificationChannelSliceTest.java | 50 +++++++++++++ 2 files changed, 111 insertions(+), 13 deletions(-) diff --git a/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java b/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java index ca5bbec2aef..016aa3261cc 100644 --- a/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java +++ b/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java @@ -57,6 +57,7 @@ import com.android.settings.core.SubSettingLauncher; import com.android.settings.notification.AppNotificationSettings; import com.android.settings.notification.ChannelNotificationSettings; import com.android.settings.notification.NotificationBackend; +import com.android.settings.notification.NotificationBackend.NotificationsSentState; import com.android.settings.slices.CustomSliceRegistry; import com.android.settings.slices.CustomSliceable; import com.android.settings.slices.SliceBroadcastReceiver; @@ -66,7 +67,6 @@ import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.applications.ApplicationsState; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.concurrent.TimeUnit; @@ -103,21 +103,32 @@ public class NotificationChannelSlice implements CustomSliceable { private static final String CHANNEL_ID = "channel_id"; /** - * TODO(b/119831690): Change to notification count sorting. - * This is the default sorting from NotificationSettingsBase, will be replaced with notification - * count sorting mechanism. + * Sort notification channel with weekly average sent count by descending. + * + * Note: + * When the sent count of notification channels is the same, follow the sorting mechanism from + * {@link com.android.settings.notification.NotificationSettingsBase#mChannelComparator}. + * Since slice view only shows displayable notification channels, so those deleted ones are + * excluded from the comparison here. */ - private static final Comparator mChannelComparator = + private static final Comparator CHANNEL_STATE_COMPARATOR = (left, right) -> { - if (TextUtils.equals(left.getId(), NotificationChannel.DEFAULT_CHANNEL_ID)) { - // Uncategorized/miscellaneous legacy channel goes last + final NotificationsSentState leftState = left.getNotificationsSentState(); + final NotificationsSentState rightState = right.getNotificationsSentState(); + if (rightState.avgSentWeekly != leftState.avgSentWeekly) { + return rightState.avgSentWeekly - leftState.avgSentWeekly; + } + + final NotificationChannel leftChannel = left.getNotificationChannel(); + final NotificationChannel rightChannel = right.getNotificationChannel(); + if (TextUtils.equals(leftChannel.getId(), NotificationChannel.DEFAULT_CHANNEL_ID)) { return 1; - } else if (TextUtils.equals(right.getId(), + } else if (TextUtils.equals(rightChannel.getId(), NotificationChannel.DEFAULT_CHANNEL_ID)) { return -1; } - return left.getId().compareTo(right.getId()); + return leftChannel.getId().compareTo(rightChannel.getId()); }; private final Context mContext; @@ -380,9 +391,19 @@ public class NotificationChannelSlice implements CustomSliceable { channel -> isChannelEnabled(group, channel, appRow))) .collect(Collectors.toList()); - // TODO(b/119831690): Sort the channels by notification count. - Collections.sort(channels, mChannelComparator); - return channels; + // Pack the notification channel with notification sent state for sorting. + final List channelStates = new ArrayList<>(); + for (NotificationChannel channel : channels) { + NotificationsSentState sentState = appRow.sentByChannel.get(channel.getId()); + if (sentState == null) { + sentState = new NotificationsSentState(); + } + channelStates.add(new NotificationChannelState(sentState, channel)); + } + + // Sort the notification channels with notification sent count by descending. + return channelStates.stream().sorted(CHANNEL_STATE_COMPARATOR).map( + state -> state.getNotificationChannel()).collect(Collectors.toList()); } private PackageInfo getMaxSentNotificationsPackage(List packageInfoList) { @@ -471,4 +492,31 @@ public class NotificationChannelSlice implements CustomSliceable { return false; } -} \ No newline at end of file + + /** + * This class is used to sort notification channels according to notification sent count and + * notification id in {@link NotificationChannelSlice#CHANNEL_STATE_COMPARATOR}. + * + * Include {@link NotificationsSentState#avgSentWeekly} and {@link NotificationChannel#getId()} + * to get the number of notifications being sent and notification id. + */ + private static class NotificationChannelState { + + final private NotificationsSentState mNotificationsSentState; + final private NotificationChannel mNotificationChannel; + + public NotificationChannelState(NotificationsSentState notificationsSentState, + NotificationChannel notificationChannel) { + mNotificationsSentState = notificationsSentState; + mNotificationChannel = notificationChannel; + } + + public NotificationChannel getNotificationChannel() { + return mNotificationChannel; + } + + public NotificationsSentState getNotificationsSentState() { + return mNotificationsSentState; + } + } +} diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSliceTest.java index f46570212a5..7ec131675ca 100644 --- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSliceTest.java +++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSliceTest.java @@ -39,6 +39,7 @@ import android.util.ArrayMap; import androidx.core.graphics.drawable.IconCompat; import androidx.slice.Slice; +import androidx.slice.SliceItem; import androidx.slice.SliceMetadata; import androidx.slice.SliceProvider; import androidx.slice.core.SliceQuery; @@ -124,6 +125,34 @@ public class NotificationChannelSliceTest { mContext.getString(R.string.manage_app_notification, APP_LABEL)); } + @Test + @Config(shadows = ShadowRestrictedLockUtilsInternal.class) + public void getSlice_hasSuggestedApp_shouldSortByNotificationSentCount() { + addMockPackageToPackageManager(true /* isRecentlyInstalled */, + ApplicationInfo.FLAG_INSTALLED); + mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */); + + final Slice slice = mNotificationChannelSlice.getSlice(); + + // Get all RowBuilders from Slice. + final List rowItems = SliceQuery.findAll(slice, FORMAT_SLICE, HINT_LIST_ITEM, + null /* nonHints */); + + // Ensure the total size of rows is equal to the notification channel count with header. + assertThat(rowItems).isNotNull(); + assertThat(rowItems.size()).isEqualTo(CHANNEL_COUNT + 1); + + // Remove the header of slice. + rowItems.remove(0); + + // Test the rows of slice are sorted with notification sent count by descending. + for (int i = 0; i < rowItems.size(); i++) { + // Assert the summary text is the same as expectation. + assertThat(getSummaryFromSliceItem(rowItems.get(i))).isEqualTo( + mContext.getString(R.string.notifications_sent_weekly, CHANNEL_COUNT - i)); + } + } + @Test public void getSlice_noRecentlyInstalledApp_shouldHaveNoSuggestedAppTitle() { addMockPackageToPackageManager(false /* isRecentlyInstalled */, @@ -269,10 +298,31 @@ public class NotificationChannelSliceTest { final Map states = new ArrayMap<>(); for (int i = 0; i < channelCount; i++) { final NotificationsSentState state = new NotificationsSentState(); + // Set the avgSentWeekly for each channel: channel0 is 1, channel1: 2, channel2: 3. + state.avgSentWeekly = i + 1; state.sentCount = sentCount; states.put(CHANNEL_NAME_PREFIX + i, state); } return states; } + + private CharSequence getSummaryFromSliceItem(SliceItem rowItem) { + if (rowItem == null) { + return null; + } + + final Slice rowSlice = rowItem.getSlice(); + if (rowSlice == null) { + return null; + } + + final List rowSliceItems = rowSlice.getItems(); + if (rowSliceItems == null || rowSliceItems.size() < 2) { + return null; + } + + // Index 0: title; Index 1: summary. + return rowSliceItems.get(1).getText(); + } } \ No newline at end of file