diff --git a/api/current.txt b/api/current.txt index 264437255e43a..b61475db32d46 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5548,12 +5548,14 @@ package android.app { method public void createNotificationChannelGroups(java.util.List); method public void createNotificationChannels(java.util.List); method public void deleteNotificationChannel(java.lang.String); + method public void deleteNotificationChannelGroup(java.lang.String); method public android.service.notification.StatusBarNotification[] getActiveNotifications(); method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String); method public java.util.Map getAutomaticZenRules(); method public final int getCurrentInterruptionFilter(); method public int getImportance(); method public android.app.NotificationChannel getNotificationChannel(java.lang.String); + method public java.util.List getNotificationChannelGroups(); method public java.util.List getNotificationChannels(); method public android.app.NotificationManager.Policy getNotificationPolicy(); method public boolean isNotificationPolicyAccessGranted(); diff --git a/api/system-current.txt b/api/system-current.txt index eb5ebd779b605..ddfc1ccd8908d 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5751,12 +5751,14 @@ package android.app { method public void createNotificationChannelGroups(java.util.List); method public void createNotificationChannels(java.util.List); method public void deleteNotificationChannel(java.lang.String); + method public void deleteNotificationChannelGroup(java.lang.String); method public android.service.notification.StatusBarNotification[] getActiveNotifications(); method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String); method public java.util.Map getAutomaticZenRules(); method public final int getCurrentInterruptionFilter(); method public int getImportance(); method public android.app.NotificationChannel getNotificationChannel(java.lang.String); + method public java.util.List getNotificationChannelGroups(); method public java.util.List getNotificationChannels(); method public android.app.NotificationManager.Policy getNotificationPolicy(); method public boolean isNotificationPolicyAccessGranted(); diff --git a/api/test-current.txt b/api/test-current.txt index 3b02916c84ca4..fe67696735411 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -5558,6 +5558,7 @@ package android.app { method public void createNotificationChannelGroups(java.util.List); method public void createNotificationChannels(java.util.List); method public void deleteNotificationChannel(java.lang.String); + method public void deleteNotificationChannelGroup(java.lang.String); method public android.service.notification.StatusBarNotification[] getActiveNotifications(); method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String); method public java.util.Map getAutomaticZenRules(); @@ -5565,6 +5566,7 @@ package android.app { method public android.content.ComponentName getEffectsSuppressor(); method public int getImportance(); method public android.app.NotificationChannel getNotificationChannel(java.lang.String); + method public java.util.List getNotificationChannelGroups(); method public java.util.List getNotificationChannels(); method public android.app.NotificationManager.Policy getNotificationPolicy(); method public boolean isNotificationPolicyAccessGranted(); diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 896f56c9f4d9f..5ea24804e0fd2 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -67,6 +67,8 @@ interface INotificationManager ParceledListSlice getNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted); int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted); int getDeletedChannelCount(String pkg, int uid); + void deleteNotificationChannelGroup(String pkg, String channelGroupId); + ParceledListSlice getNotificationChannelGroups(String pkg); // TODO: Remove this when callers have been migrated to the equivalent // INotificationListener method. diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 2a78b6b7b143c..0379970762abc 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -497,6 +497,30 @@ public class NotificationManager } } + /** + * Returns all notification channel groups belonging to the calling app. + */ + public List getNotificationChannelGroups() { + INotificationManager service = getService(); + try { + return service.getNotificationChannelGroups(mContext.getPackageName()).getList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Deletes the given notification channel group. + */ + public void deleteNotificationChannelGroup(String groupId) { + INotificationManager service = getService(); + try { + service.deleteNotificationChannelGroup(mContext.getPackageName(), groupId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * @hide */ diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 7285a4c0e9c7d..82809469d89cc 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -159,6 +159,8 @@ import com.android.server.notification.ManagedServices.UserProfiles; import libcore.io.IoUtils; +import com.google.android.collect.Lists; + import org.json.JSONException; import org.json.JSONObject; import org.xmlpull.v1.XmlPullParser; @@ -1658,8 +1660,7 @@ public class NotificationManagerService extends SystemService { public NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId, boolean includeDeleted) { checkCallerIsSystem(); - return mRankingHelper.getNotificationChannel - (pkg, uid, channelId, includeDeleted); + return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted); } @Override @@ -1674,6 +1675,27 @@ public class NotificationManagerService extends SystemService { savePolicyFile(); } + @Override + public ParceledListSlice getNotificationChannelGroups( + String pkg) { + checkCallerIsSystemOrSameApp(pkg); + return new ParceledListSlice<>(new ArrayList( + mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid()))); + } + + @Override + public void deleteNotificationChannelGroup(String pkg, String channelGroupId) { + checkCallerIsSystemOrSameApp(pkg); + + List deletedChannelIds = mRankingHelper.deleteNotificationChannelGroup( + pkg, Binder.getCallingUid(), channelGroupId); + for (int i = 0; i < deletedChannelIds.size(); i++) { + cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannelIds.get(i), 0, 0, true, + UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null); + } + savePolicyFile(); + } + @Override public void updateNotificationChannelForPackage(String pkg, int uid, NotificationChannel channel) { diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index e239164d65689..02f92fedb85d9 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -15,8 +15,6 @@ */ package com.android.server.notification; -import static android.app.NotificationManager.IMPORTANCE_NONE; - import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; @@ -654,8 +652,6 @@ public class RankingHelper implements RankingConfig { @Override public void deleteNotificationChannel(String pkg, int uid, String channelId) { - Preconditions.checkNotNull(pkg); - Preconditions.checkNotNull(channelId); Record r = getRecord(pkg, uid); if (r == null) { return; @@ -667,6 +663,7 @@ public class RankingHelper implements RankingConfig { LogMaker lm = getChannelLog(channel, pkg); lm.setType(MetricsProto.MetricsEvent.TYPE_CLOSE); MetricsLogger.action(lm); + updateConfig(); } @Override @@ -679,6 +676,7 @@ public class RankingHelper implements RankingConfig { return; } r.channels.remove(channelId); + updateConfig(); } @Override @@ -695,6 +693,7 @@ public class RankingHelper implements RankingConfig { r.channels.remove(key); } } + updateConfig(); } public NotificationChannelGroup getNotificationChannelGroup(String groupId, String pkg, @@ -719,12 +718,15 @@ public class RankingHelper implements RankingConfig { final NotificationChannel nc = r.channels.valueAt(i); if (includeDeleted || !nc.isDeleted()) { if (nc.getGroup() != null) { - NotificationChannelGroup ncg = groups.get(nc.getGroup()); - if (ncg == null ) { - ncg = r.groups.get(nc.getGroup()).clone(); - groups.put(nc.getGroup(), ncg); + if (r.groups.get(nc.getGroup()) != null) { + NotificationChannelGroup ncg = groups.get(nc.getGroup()); + if (ncg == null) { + ncg = r.groups.get(nc.getGroup()).clone(); + groups.put(nc.getGroup(), ncg); + + } + ncg.addChannel(nc); } - ncg.addChannel(nc); } else { nonGrouped.addChannel(nc); } @@ -736,8 +738,29 @@ public class RankingHelper implements RankingConfig { return new ParceledListSlice<>(new ArrayList<>(groups.values())); } + public List deleteNotificationChannelGroup(String pkg, int uid, + String groupId) { + List deletedChannelIds = new ArrayList<>(); + Record r = getRecord(pkg, uid); + if (r == null || TextUtils.isEmpty(groupId)) { + return deletedChannelIds; + } + + r.groups.remove(groupId); + + int N = r.channels.size(); + for (int i = 0; i < N; i++) { + final NotificationChannel nc = r.channels.valueAt(i); + if (groupId.equals(nc.getGroup())) { + nc.setDeleted(true); + deletedChannelIds.add(nc.getId()); + } + } + updateConfig(); + return deletedChannelIds; + } + @Override - @VisibleForTesting public Collection getNotificationChannelGroups(String pkg, int uid) { Record r = getRecord(pkg, uid); diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java index b538453dc93d9..27b9a880c4ace 100644 --- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java +++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java @@ -853,6 +853,43 @@ public class RankingHelperTest { assertEquals(1, mHelper.getNotificationChannels(pkg, uid, true).getList().size()); } + @Test + public void testDeleteGroup() throws Exception { + NotificationChannelGroup notDeleted = new NotificationChannelGroup("not", "deleted"); + NotificationChannelGroup deleted = new NotificationChannelGroup("totally", "deleted"); + NotificationChannel nonGroupedNonDeletedChannel = + new NotificationChannel("no group", "so not deleted", IMPORTANCE_HIGH); + NotificationChannel groupedButNotDeleted = + new NotificationChannel("not deleted", "belongs to notDeleted", IMPORTANCE_DEFAULT); + groupedButNotDeleted.setGroup("not"); + NotificationChannel groupedAndDeleted = + new NotificationChannel("deleted", "belongs to deleted", IMPORTANCE_DEFAULT); + groupedAndDeleted.setGroup("totally"); + + mHelper.createNotificationChannelGroup(pkg, uid, notDeleted, true); + mHelper.createNotificationChannelGroup(pkg, uid, deleted, true); + mHelper.createNotificationChannel(pkg, uid, nonGroupedNonDeletedChannel, true); + mHelper.createNotificationChannel(pkg, uid, groupedAndDeleted, true); + mHelper.createNotificationChannel(pkg, uid, groupedButNotDeleted, true); + + mHelper.deleteNotificationChannelGroup(pkg, uid, deleted.getId()); + + assertNull(mHelper.getNotificationChannelGroup(deleted.getId(), pkg, uid)); + assertNotNull(mHelper.getNotificationChannelGroup(notDeleted.getId(), pkg, uid)); + + assertNull(mHelper.getNotificationChannel(pkg, uid, groupedAndDeleted.getId(), false)); + compareChannels(groupedAndDeleted, + mHelper.getNotificationChannel(pkg, uid, groupedAndDeleted.getId(), true)); + + compareChannels(groupedButNotDeleted, + mHelper.getNotificationChannel(pkg, uid, groupedButNotDeleted.getId(), false)); + compareChannels(nonGroupedNonDeletedChannel, mHelper.getNotificationChannel( + pkg, uid, nonGroupedNonDeletedChannel.getId(), false)); + + // notDeleted + assertEquals(1, mHelper.getNotificationChannelGroups(pkg, uid).size()); + } + @Test public void testOnPackageChanged_packageRemoval() throws Exception { // Deleted @@ -889,7 +926,7 @@ public class RankingHelperTest { mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{pkg}, new int[]{uid}); - assertEquals(0, mHelper.getNotificationChannelGroups(pkg, uid, true).getList().size()); + assertEquals(0, mHelper.getNotificationChannelGroups(pkg, uid).size()); } @Test