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