Loading src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java +61 −13 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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<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; Loading Loading @@ -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<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) { Loading Loading @@ -471,4 +492,31 @@ public class NotificationChannelSlice implements CustomSliceable { return false; } /** * 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; } } } tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSliceTest.java +50 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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<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 */, Loading Loading @@ -269,10 +298,31 @@ public class NotificationChannelSliceTest { 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 Loading
src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java +61 −13 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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<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; Loading Loading @@ -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<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) { Loading Loading @@ -471,4 +492,31 @@ public class NotificationChannelSlice implements CustomSliceable { return false; } /** * 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; } } }
tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSliceTest.java +50 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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<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 */, Loading Loading @@ -269,10 +298,31 @@ public class NotificationChannelSliceTest { 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