Merge "Sort notification channel in NotificationChannelSlice"
diff --git a/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java b/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java
index ca5bbec..016aa32 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.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.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 @@
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<NotificationChannel> mChannelComparator =
+ private static final Comparator<NotificationChannelState> 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 @@
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<NotificationChannelState> 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<PackageInfo> packageInfoList) {
@@ -471,4 +492,31 @@
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 f465702..7ec1316 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 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;
@@ -125,6 +126,34 @@
}
@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<SliceItem> 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 */,
ApplicationInfo.FLAG_INSTALLED);
@@ -269,10 +298,31 @@
final Map<String, NotificationBackend.NotificationsSentState> 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<SliceItem> 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