summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/notification/NotificationChannelGroupsHelper.java186
-rw-r--r--core/tests/coretests/src/com/android/internal/notification/NotificationChannelGroupsHelperTest.java268
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java15
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java58
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java37
5 files changed, 491 insertions, 73 deletions
diff --git a/core/java/com/android/internal/notification/NotificationChannelGroupsHelper.java b/core/java/com/android/internal/notification/NotificationChannelGroupsHelper.java
new file mode 100644
index 000000000000..2bfb19f10807
--- /dev/null
+++ b/core/java/com/android/internal/notification/NotificationChannelGroupsHelper.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.notification;
+
+import static android.app.NotificationChannel.SYSTEM_RESERVED_IDS;
+import static android.app.NotificationManager.IMPORTANCE_NONE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.INotificationManager;
+import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
+import android.service.notification.Flags;
+import android.util.ArrayMap;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * NotificationChannelGroupHelper contains helper methods for associating channels with the groups
+ * they belong to, matching by ID.
+ */
+public class NotificationChannelGroupsHelper {
+ /**
+ * Set of parameters passed into
+ * {@link NotificationChannelGroupsHelper#getGroupsWithChannels(Collection, Map, Params)}.
+ *
+ * @param includeDeleted Whether to include deleted channels.
+ * @param includeNonGrouped Whether to include channels that are not associated with a group.
+ * @param includeEmpty Whether to include groups containing no channels.
+ * @param includeAllBlockedWithFilter Whether to include channels that are blocked from
+ * sending notifications along with channels specified by
+ * the filter. This setting only takes effect when
+ * channelFilter is not {@code null}, and if true will
+ * include all blocked channels in the output (regardless
+ * of whether they are included in the filter).
+ * @param channelFilter If non-null, a specific set of channels to include. If a channel
+ * matching this filter is blocked, it will still be included even
+ * if includeAllBlockedWithFilter=false.
+ */
+ public record Params(
+ boolean includeDeleted,
+ boolean includeNonGrouped,
+ boolean includeEmpty,
+ boolean includeAllBlockedWithFilter,
+ Set<String> channelFilter
+ ) {
+ /**
+ * Default set of parameters used to specify the behavior of
+ * {@link INotificationManager#getNotificationChannelGroups(String)}. This will include
+ * output for all groups, including those without channels, but not any ungrouped channels.
+ */
+ public static Params forAllGroups() {
+ return new Params(
+ /* includeDeleted= */ false,
+ /* includeNonGrouped= */ false,
+ /* includeEmpty= */ true,
+ /* includeAllBlockedWithFilter= */ true,
+ /* channelFilter= */ null);
+ }
+
+ /**
+ * Parameters to get groups for all channels, including those not associated with any groups
+ * and optionally including deleted channels as well. Channels not associated with a group
+ * are returned inside a group with id {@code null}.
+ *
+ * @param includeDeleted Whether to include deleted channels.
+ */
+ public static Params forAllChannels(boolean includeDeleted) {
+ return new Params(
+ includeDeleted,
+ /* includeNonGrouped= */ true,
+ /* includeEmpty= */ false,
+ /* includeAllBlockedWithFilter= */ true,
+ /* channelFilter= */ null);
+ }
+
+ /**
+ * Parameters to collect groups only for channels specified by the channel filter, as well
+ * as any blocked channels (independent of whether they exist in the filter).
+ * @param channelFilter Specific set of channels to return.
+ */
+ public static Params onlySpecifiedOrBlockedChannels(Set<String> channelFilter) {
+ return new Params(
+ /* includeDeleted= */ false,
+ /* includeNonGrouped= */ true,
+ /* includeEmpty= */ false,
+ /* includeAllBlockedWithFilter= */ true,
+ channelFilter);
+ }
+ }
+
+ /**
+ * Retrieve the {@link NotificationChannelGroup} object specified by the given groupId, if it
+ * exists, with the list of channels filled in from the provided available channels.
+ *
+ * @param groupId The ID of the group to return.
+ * @param allChannels A list of all channels associated with the package.
+ * @param allGroups A map of group ID -> NotificationChannelGroup objects.
+ */
+ public static @Nullable NotificationChannelGroup getGroupWithChannels(@NonNull String groupId,
+ @NonNull Collection<NotificationChannel> allChannels,
+ @NonNull Map<String, NotificationChannelGroup> allGroups,
+ boolean includeDeleted) {
+ NotificationChannelGroup group = null;
+ if (allGroups.containsKey(groupId)) {
+ group = allGroups.get(groupId).clone();
+ group.setChannels(new ArrayList<>());
+ for (NotificationChannel nc : allChannels) {
+ if (includeDeleted || !nc.isDeleted()) {
+ if (groupId.equals(nc.getGroup())) {
+ group.addChannel(nc);
+ }
+ }
+ }
+ }
+ return group;
+ }
+
+ /**
+ * Returns a list of groups with their associated channels filled in.
+ *
+ * @param allChannels All available channels that may be associated with these groups.
+ * @param allGroups Map of group ID -> {@link NotificationChannelGroup} objects.
+ * @param params Params indicating which channels and which groups to include.
+ */
+ public static @NonNull List<NotificationChannelGroup> getGroupsWithChannels(
+ @NonNull Collection<NotificationChannel> allChannels,
+ @NonNull Map<String, NotificationChannelGroup> allGroups,
+ Params params) {
+ Map<String, NotificationChannelGroup> outputGroups = new ArrayMap<>();
+ NotificationChannelGroup nonGrouped = new NotificationChannelGroup(null, null);
+ for (NotificationChannel nc : allChannels) {
+ boolean includeChannel = (params.includeDeleted || !nc.isDeleted())
+ && (params.channelFilter == null
+ || (params.includeAllBlockedWithFilter
+ && nc.getImportance() == IMPORTANCE_NONE)
+ || params.channelFilter.contains(nc.getId()))
+ && (!Flags.notificationClassification()
+ || !SYSTEM_RESERVED_IDS.contains(nc.getId()));
+ if (includeChannel) {
+ if (nc.getGroup() != null) {
+ if (allGroups.get(nc.getGroup()) != null) {
+ NotificationChannelGroup ncg = outputGroups.get(nc.getGroup());
+ if (ncg == null) {
+ ncg = allGroups.get(nc.getGroup()).clone();
+ ncg.setChannels(new ArrayList<>());
+ outputGroups.put(nc.getGroup(), ncg);
+ }
+ ncg.addChannel(nc);
+ }
+ } else {
+ nonGrouped.addChannel(nc);
+ }
+ }
+ }
+ if (params.includeNonGrouped && nonGrouped.getChannels().size() > 0) {
+ outputGroups.put(null, nonGrouped);
+ }
+ if (params.includeEmpty) {
+ for (NotificationChannelGroup group : allGroups.values()) {
+ if (!outputGroups.containsKey(group.getId())) {
+ outputGroups.put(group.getId(), group);
+ }
+ }
+ }
+ return new ArrayList<>(outputGroups.values());
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/notification/NotificationChannelGroupsHelperTest.java b/core/tests/coretests/src/com/android/internal/notification/NotificationChannelGroupsHelperTest.java
new file mode 100644
index 000000000000..26e96ea79e4b
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/notification/NotificationChannelGroupsHelperTest.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.notification;
+
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_NONE;
+
+import static com.android.internal.notification.NotificationChannelGroupsHelper.getGroupWithChannels;
+import static com.android.internal.notification.NotificationChannelGroupsHelper.getGroupsWithChannels;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.notification.NotificationChannelGroupsHelper.Params;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+public class NotificationChannelGroupsHelperTest {
+ private Collection<NotificationChannel> mChannels;
+ private Map<String, NotificationChannelGroup> mGroups;
+
+ @Before
+ public void setUp() {
+ // Test data setup.
+ // Channels and their corresponding groups:
+ // * "regular": a channel that is not deleted or blocked. In group A.
+ // * "blocked": blocked channel. In group A.
+ // * "deleted": deleted channel. In group A.
+ // * "adrift": regular channel. No group.
+ // * "gone": deleted channel. No group.
+ // * "alternate": regular channel. In group B.
+ // * "another blocked": blocked channel. In group B.
+ // * "another deleted": deleted channel. In group C.
+ // * Additionally, there is an empty group D.
+ mChannels = List.of(makeChannel("regular", "a", false, false),
+ makeChannel("blocked", "a", true, false),
+ makeChannel("deleted", "a", false, true),
+ makeChannel("adrift", null, false, false),
+ makeChannel("gone", null, false, true),
+ makeChannel("alternate", "b", false, false),
+ makeChannel("anotherBlocked", "b", true, false),
+ makeChannel("anotherDeleted", "c", false, true));
+
+ mGroups = Map.of("a", new NotificationChannelGroup("a", "a"),
+ "b", new NotificationChannelGroup("b", "b"),
+ "c", new NotificationChannelGroup("c", "c"),
+ "d", new NotificationChannelGroup("d", "d"));
+ }
+
+ @Test
+ public void testGetGroup_noDeleted() {
+ NotificationChannelGroup res = getGroupWithChannels("a", mChannels, mGroups, false);
+ assertThat(res).isNotNull();
+ assertThat(res.getChannels()).hasSize(2); // "regular" & "blocked"
+ assertThat(res.getChannels()).containsExactlyElementsIn(List.of(
+ makeChannel("regular", "a", false, false),
+ makeChannel("blocked", "a", true, false)));
+ }
+
+ @Test
+ public void testGetGroup_includeDeleted() {
+ NotificationChannelGroup res = getGroupWithChannels("c", mChannels, mGroups, true);
+ assertThat(res).isNotNull();
+ assertThat(res.getChannels()).hasSize(1);
+ assertThat(res.getChannels().getFirst()).isEqualTo(
+ makeChannel("anotherDeleted", "c", false, true));
+ }
+
+ @Test
+ public void testGetGroup_empty() {
+ NotificationChannelGroup res = getGroupWithChannels("d", mChannels, mGroups, true);
+ assertThat(res).isNotNull();
+ assertThat(res.getChannels()).isEmpty();
+ }
+
+ @Test
+ public void testGetGroup_emptyBecauseNoChannelMatch() {
+ NotificationChannelGroup res = getGroupWithChannels("c", mChannels, mGroups, false);
+ assertThat(res).isNotNull();
+ assertThat(res.getChannels()).isEmpty();
+ }
+
+ @Test
+ public void testGetGroup_nonexistent() {
+ NotificationChannelGroup res = getGroupWithChannels("e", mChannels, mGroups, true);
+ assertThat(res).isNull();
+ }
+
+ @Test
+ public void testGetGroups_paramsForAllGroups() {
+ // deleted=false, nongrouped=false, empty=true, blocked=true, no channel filter
+ List<NotificationChannelGroup> res = getGroupsWithChannels(mChannels, mGroups,
+ Params.forAllGroups());
+
+ NotificationChannelGroup expectedA = new NotificationChannelGroup("a", "a");
+ expectedA.setChannels(List.of(
+ makeChannel("regular", "a", false, false),
+ makeChannel("blocked", "a", true, false)));
+
+ NotificationChannelGroup expectedB = new NotificationChannelGroup("b", "b");
+ expectedB.setChannels(List.of(
+ makeChannel("alternate", "b", false, false),
+ makeChannel("anotherBlocked", "b", true, false)));
+
+ NotificationChannelGroup expectedC = new NotificationChannelGroup("c", "c");
+ expectedC.setChannels(new ArrayList<>()); // empty, no deleted
+
+ NotificationChannelGroup expectedD = new NotificationChannelGroup("d", "d");
+ expectedD.setChannels(new ArrayList<>()); // empty
+
+ assertThat(res).containsExactly(expectedA, expectedB, expectedC, expectedD);
+ }
+
+ @Test
+ public void testGetGroups_paramsForAllChannels_noDeleted() {
+ // Excluding deleted channels to means group C is not included because it's "empty"
+ List<NotificationChannelGroup> res = getGroupsWithChannels(mChannels, mGroups,
+ Params.forAllChannels(false));
+
+ NotificationChannelGroup expectedA = new NotificationChannelGroup("a", "a");
+ expectedA.setChannels(List.of(
+ makeChannel("regular", "a", false, false),
+ makeChannel("blocked", "a", true, false)));
+
+ NotificationChannelGroup expectedB = new NotificationChannelGroup("b", "b");
+ expectedB.setChannels(List.of(
+ makeChannel("alternate", "b", false, false),
+ makeChannel("anotherBlocked", "b", true, false)));
+
+ NotificationChannelGroup expectedUngrouped = new NotificationChannelGroup(null, null);
+ expectedUngrouped.setChannels(List.of(
+ makeChannel("adrift", null, false, false),
+ makeChannel("gone", null, false, true)));
+
+ assertThat(res).containsExactly(expectedA, expectedB, expectedUngrouped);
+ }
+
+ @Test
+ public void testGetGroups_paramsForAllChannels_withDeleted() {
+ // This will get everything!
+ List<NotificationChannelGroup> res = getGroupsWithChannels(mChannels, mGroups,
+ Params.forAllChannels(true));
+
+ NotificationChannelGroup expectedA = new NotificationChannelGroup("a", "a");
+ expectedA.setChannels(List.of(
+ makeChannel("regular", "a", false, false),
+ makeChannel("blocked", "a", true, false),
+ makeChannel("deleted", "a", false, true)));
+
+ NotificationChannelGroup expectedB = new NotificationChannelGroup("b", "b");
+ expectedB.setChannels(List.of(
+ makeChannel("alternate", "b", false, false),
+ makeChannel("anotherBlocked", "b", true, false)));
+
+ NotificationChannelGroup expectedC = new NotificationChannelGroup("c", "c");
+ expectedC.setChannels(List.of(makeChannel("anotherDeleted", "c", false, true)));
+
+ // no D, because D is empty
+
+ NotificationChannelGroup expectedUngrouped = new NotificationChannelGroup(null, null);
+ expectedUngrouped.setChannels(List.of(makeChannel("adrift", null, false, false)));
+
+ assertThat(res).containsExactly(expectedA, expectedB, expectedC, expectedUngrouped);
+ }
+
+ @Test
+ public void testGetGroups_onlySpecifiedOrBlocked() {
+ Set<String> filter = Set.of("regular", "blocked", "adrift", "anotherDeleted");
+
+ // also not including deleted channels to check intersection of those params
+ List<NotificationChannelGroup> res = getGroupsWithChannels(mChannels, mGroups,
+ Params.onlySpecifiedOrBlockedChannels(filter));
+
+ NotificationChannelGroup expectedA = new NotificationChannelGroup("a", "a");
+ expectedA.setChannels(List.of(
+ makeChannel("regular", "a", false, false),
+ makeChannel("blocked", "a", true, false)));
+
+ // While nothing matches the filter from group B, includeBlocked=true means all blocked
+ // channels are included even if they are not in the filter.
+ NotificationChannelGroup expectedB = new NotificationChannelGroup("b", "b");
+ expectedB.setChannels(List.of(makeChannel("anotherBlocked", "b", true, false)));
+
+ NotificationChannelGroup expectedC = new NotificationChannelGroup("c", "c");
+ expectedC.setChannels(new ArrayList<>()); // deleted channel not included
+
+ NotificationChannelGroup expectedD = new NotificationChannelGroup("d", "d");
+ expectedD.setChannels(new ArrayList<>()); // empty
+
+ NotificationChannelGroup expectedUngrouped = new NotificationChannelGroup(null, null);
+ expectedUngrouped.setChannels(List.of(makeChannel("adrift", null, false, false)));
+
+ assertThat(res).containsExactly(expectedA, expectedB, expectedC, expectedD,
+ expectedUngrouped);
+ }
+
+
+ @Test
+ public void testGetGroups_noBlockedWithFilter() {
+ Set<String> filter = Set.of("regular", "blocked", "adrift");
+
+ // The includeBlocked setting only takes effect if there is a channel filter.
+ List<NotificationChannelGroup> res = getGroupsWithChannels(mChannels, mGroups,
+ new Params(true, true, true, false, filter));
+
+ // Even though includeBlocked=false, "blocked" is included because it's explicitly specified
+ // by the channel filter.
+ NotificationChannelGroup expectedA = new NotificationChannelGroup("a", "a");
+ expectedA.setChannels(List.of(
+ makeChannel("regular", "a", false, false),
+ makeChannel("blocked", "a", true, false)));
+
+ NotificationChannelGroup expectedB = new NotificationChannelGroup("b", "b");
+ expectedB.setChannels(new ArrayList<>()); // no matches; blocked channel not in filter
+
+ NotificationChannelGroup expectedC = new NotificationChannelGroup("c", "c");
+ expectedC.setChannels(new ArrayList<>()); // no matches
+
+ NotificationChannelGroup expectedD = new NotificationChannelGroup("d", "d");
+ expectedD.setChannels(new ArrayList<>()); // empty
+
+ NotificationChannelGroup expectedUngrouped = new NotificationChannelGroup(null, null);
+ expectedUngrouped.setChannels(List.of(makeChannel("adrift", null, false, false)));
+
+ assertThat(res).containsExactly(expectedA, expectedB, expectedC, expectedD,
+ expectedUngrouped);
+ }
+
+ private NotificationChannel makeChannel(String id, String groupId, boolean blocked,
+ boolean deleted) {
+ NotificationChannel c = new NotificationChannel(id, id,
+ blocked ? IMPORTANCE_NONE : IMPORTANCE_DEFAULT);
+ if (deleted) {
+ c.setDeleted(true);
+ }
+ if (groupId != null) {
+ c.setGroup(groupId);
+ }
+ return c;
+ }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index a16b122771ef..aaa1de0ff1bf 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -346,6 +346,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.messages.nano.SystemMessageProto;
+import com.android.internal.notification.NotificationChannelGroupsHelper;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.SomeArgs;
@@ -5005,8 +5006,8 @@ public class NotificationManagerService extends SystemService {
public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
String pkg) {
checkCallerIsSystemOrSameApp(pkg);
- return mPreferencesHelper.getNotificationChannelGroups(
- pkg, Binder.getCallingUid(), false, false, true, true, null);
+ return mPreferencesHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid(),
+ NotificationChannelGroupsHelper.Params.forAllGroups());
}
@Override
@@ -5126,8 +5127,9 @@ public class NotificationManagerService extends SystemService {
public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
String pkg, int uid, boolean includeDeleted) {
enforceSystemOrSystemUI("getNotificationChannelGroupsForPackage");
- return mPreferencesHelper.getNotificationChannelGroups(
- pkg, uid, includeDeleted, true, false, true, null);
+ return mPreferencesHelper.getNotificationChannelGroups(pkg, uid,
+ new NotificationChannelGroupsHelper.Params(includeDeleted, true, false, true,
+ null));
}
@Override
@@ -5155,8 +5157,9 @@ public class NotificationManagerService extends SystemService {
}
}
- return mPreferencesHelper.getNotificationChannelGroups(
- pkg, uid, false, true, false, true, recentlySentChannels);
+ return mPreferencesHelper.getNotificationChannelGroups(pkg, uid,
+ NotificationChannelGroupsHelper.Params.onlySpecifiedOrBlockedChannels(
+ recentlySentChannels));
}
@Override
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 7d45cd9752b8..33c94a7e63da 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -92,6 +92,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.notification.NotificationChannelGroupsHelper;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
@@ -1678,18 +1679,8 @@ public class PreferencesHelper implements RankingConfig {
if (r == null || groupId == null || !r.groups.containsKey(groupId)) {
return null;
}
- NotificationChannelGroup group = r.groups.get(groupId).clone();
- group.setChannels(new ArrayList<>());
- int N = r.channels.size();
- for (int i = 0; i < N; i++) {
- final NotificationChannel nc = r.channels.valueAt(i);
- if (includeDeleted || !nc.isDeleted()) {
- if (groupId.equals(nc.getGroup())) {
- group.addChannel(nc);
- }
- }
- }
- return group;
+ return NotificationChannelGroupsHelper.getGroupWithChannels(groupId,
+ r.channels.values(), r.groups, includeDeleted);
}
}
@@ -1706,51 +1697,16 @@ public class PreferencesHelper implements RankingConfig {
}
public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
- int uid, boolean includeDeleted, boolean includeNonGrouped, boolean includeEmpty,
- boolean includeBlocked, Set<String> activeChannelFilter) {
+ int uid, NotificationChannelGroupsHelper.Params params) {
Objects.requireNonNull(pkg);
- Map<String, NotificationChannelGroup> groups = new ArrayMap<>();
synchronized (mLock) {
PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
if (r == null) {
return ParceledListSlice.emptyList();
}
- NotificationChannelGroup nonGrouped = new NotificationChannelGroup(null, null);
- int N = r.channels.size();
- for (int i = 0; i < N; i++) {
- final NotificationChannel nc = r.channels.valueAt(i);
- boolean includeChannel = (includeDeleted || !nc.isDeleted())
- && (activeChannelFilter == null
- || (includeBlocked && nc.getImportance() == IMPORTANCE_NONE)
- || activeChannelFilter.contains(nc.getId()))
- && !SYSTEM_RESERVED_IDS.contains(nc.getId());
- if (includeChannel) {
- if (nc.getGroup() != null) {
- if (r.groups.get(nc.getGroup()) != null) {
- NotificationChannelGroup ncg = groups.get(nc.getGroup());
- if (ncg == null) {
- ncg = r.groups.get(nc.getGroup()).clone();
- ncg.setChannels(new ArrayList<>());
- groups.put(nc.getGroup(), ncg);
- }
- ncg.addChannel(nc);
- }
- } else {
- nonGrouped.addChannel(nc);
- }
- }
- }
- if (includeNonGrouped && nonGrouped.getChannels().size() > 0) {
- groups.put(null, nonGrouped);
- }
- if (includeEmpty) {
- for (NotificationChannelGroup group : r.groups.values()) {
- if (!groups.containsKey(group.getId())) {
- groups.put(group.getId(), group);
- }
- }
- }
- return new ParceledListSlice<>(new ArrayList<>(groups.values()));
+ return new ParceledListSlice<>(
+ NotificationChannelGroupsHelper.getGroupsWithChannels(r.channels.values(),
+ r.groups, params));
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 832ca51ae580..31f9a1cffe7c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -158,6 +158,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
import com.android.internal.config.sysui.TestableFlagResolver;
+import com.android.internal.notification.NotificationChannelGroupsHelper;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.os.AtomsProto;
@@ -690,7 +691,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
List<NotificationChannelGroup> actualGroups = mXmlHelper.getNotificationChannelGroups(
- PKG_N_MR1, UID_N_MR1, false, true, false, true, null).getList();
+ PKG_N_MR1, UID_N_MR1,
+ NotificationChannelGroupsHelper.Params.forAllChannels(false)).getList();
boolean foundNcg = false;
for (NotificationChannelGroup actual : actualGroups) {
if (ncg.getId().equals(actual.getId())) {
@@ -774,7 +776,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), false));
List<NotificationChannelGroup> actualGroups = mXmlHelper.getNotificationChannelGroups(
- PKG_N_MR1, UID_N_MR1, false, true, false, true, null).getList();
+ PKG_N_MR1, UID_N_MR1,
+ NotificationChannelGroupsHelper.Params.forAllChannels(false)).getList();
boolean foundNcg = false;
for (NotificationChannelGroup actual : actualGroups) {
if (ncg.getId().equals(actual.getId())) {
@@ -3426,8 +3429,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.onPackagesChanged(true, USER_SYSTEM, new String[]{PKG_N_MR1}, new int[]{
UID_N_MR1});
- assertEquals(0, mHelper.getNotificationChannelGroups(
- PKG_N_MR1, UID_N_MR1, true, true, false, true, null).getList().size());
+ assertEquals(0, mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1,
+ NotificationChannelGroupsHelper.Params.forAllChannels(true)).getList().size());
}
@Test
@@ -3566,8 +3569,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false,
UID_N_MR1, false);
- List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(
- PKG_N_MR1, UID_N_MR1, true, true, false, true, null).getList();
+ List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(PKG_N_MR1,
+ UID_N_MR1, NotificationChannelGroupsHelper.Params.forAllChannels(true)).getList();
assertEquals(3, actual.size());
for (NotificationChannelGroup group : actual) {
if (group.getId() == null) {
@@ -3601,15 +3604,15 @@ public class PreferencesHelperTest extends UiServiceTestCase {
channel1.setGroup(ncg.getId());
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
UID_N_MR1, false);
- mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true, false, true, null)
- .getList();
+ mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1,
+ NotificationChannelGroupsHelper.Params.forAllChannels(true)).getList();
channel1.setImportance(IMPORTANCE_LOW);
mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true,
UID_N_MR1, false);
- List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(
- PKG_N_MR1, UID_N_MR1, true, true, false, true, null).getList();
+ List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(PKG_N_MR1,
+ UID_N_MR1, NotificationChannelGroupsHelper.Params.forAllChannels(true)).getList();
assertEquals(2, actual.size());
for (NotificationChannelGroup group : actual) {
@@ -3634,8 +3637,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
UID_N_MR1, false);
- List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(
- PKG_N_MR1, UID_N_MR1, false, false, true, true, null).getList();
+ List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(PKG_N_MR1,
+ UID_N_MR1, NotificationChannelGroupsHelper.Params.forAllGroups()).getList();
assertEquals(2, actual.size());
for (NotificationChannelGroup group : actual) {
@@ -6440,8 +6443,9 @@ public class PreferencesHelperTest extends UiServiceTestCase {
Set<String> filter = ImmutableSet.of("id3");
- NotificationChannelGroup actual = mHelper.getNotificationChannelGroups(
- PKG_N_MR1, UID_N_MR1, false, true, false, true, filter).getList().get(0);
+ NotificationChannelGroup actual = mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1,
+ NotificationChannelGroupsHelper.Params.onlySpecifiedOrBlockedChannels(
+ filter)).getList().get(0);
assertEquals(2, actual.getChannels().size());
assertEquals(1, actual.getChannels().stream().filter(c -> c.getId().equals("id3")).count());
assertEquals(1, actual.getChannels().stream().filter(c -> c.getId().equals("id2")).count());
@@ -6468,8 +6472,9 @@ public class PreferencesHelperTest extends UiServiceTestCase {
Set<String> filter = ImmutableSet.of("id3");
- NotificationChannelGroup actual = mHelper.getNotificationChannelGroups(
- PKG_N_MR1, UID_N_MR1, false, true, false, false, filter).getList().get(0);
+ NotificationChannelGroup actual = mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1,
+ new NotificationChannelGroupsHelper.Params(false, true, false, false,
+ filter)).getList().get(0);
assertEquals(1, actual.getChannels().size());
assertEquals(1, actual.getChannels().stream().filter(c -> c.getId().equals("id3")).count());
assertEquals(0, actual.getChannels().stream().filter(c -> c.getId().equals("id2")).count());