Notify apps when channels/groups are blocked/unblocked
So that apps can disable/enable receivers/jobs/etc. that
would only need to run to post notifications to the blocked
channel(s).
Additionally let apps retrieve an individual group so they
can inspect blocked state.
Change-Id: I733b70c62cd0482d0cf9692ea9b00cf313ad7b81
Fixes: 36530302
Test: runtest systemui-notification, cts
diff --git a/api/current.txt b/api/current.txt
index c6d5430..02aba41 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5616,6 +5616,7 @@
method public final int getCurrentInterruptionFilter();
method public int getImportance();
method public android.app.NotificationChannel getNotificationChannel(java.lang.String);
+ method public android.app.NotificationChannelGroup getNotificationChannelGroup(java.lang.String);
method public java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups();
method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
method public android.app.NotificationManager.Policy getNotificationPolicy();
@@ -5628,8 +5629,12 @@
method public void setNotificationPolicy(android.app.NotificationManager.Policy);
method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
+ field public static final java.lang.String ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED";
+ field public static final java.lang.String ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED";
field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
+ field public static final java.lang.String EXTRA_BLOCKED_STATE = "android.app.extra.BLOCKED_STATE";
+ field public static final java.lang.String EXTRA_BLOCK_STATE_CHANGED_ID = "android.app.extra.BLOCK_STATE_CHANGED_ID";
field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
field public static final int IMPORTANCE_HIGH = 4; // 0x4
field public static final int IMPORTANCE_LOW = 2; // 0x2
diff --git a/api/system-current.txt b/api/system-current.txt
index 94e3786..a29d401 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5825,6 +5825,7 @@
method public final int getCurrentInterruptionFilter();
method public int getImportance();
method public android.app.NotificationChannel getNotificationChannel(java.lang.String);
+ method public android.app.NotificationChannelGroup getNotificationChannelGroup(java.lang.String);
method public java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups();
method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
method public android.app.NotificationManager.Policy getNotificationPolicy();
@@ -5837,8 +5838,12 @@
method public void setNotificationPolicy(android.app.NotificationManager.Policy);
method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
+ field public static final java.lang.String ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED";
+ field public static final java.lang.String ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED";
field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
+ field public static final java.lang.String EXTRA_BLOCKED_STATE = "android.app.extra.BLOCKED_STATE";
+ field public static final java.lang.String EXTRA_BLOCK_STATE_CHANGED_ID = "android.app.extra.BLOCK_STATE_CHANGED_ID";
field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
field public static final int IMPORTANCE_HIGH = 4; // 0x4
field public static final int IMPORTANCE_LOW = 2; // 0x2
@@ -48173,8 +48178,8 @@
}
public final class StatsManager {
- method public byte[] getData(java.lang.String);
method public boolean addConfiguration(java.lang.String, byte[], java.lang.String, java.lang.String);
+ method public byte[] getData(java.lang.String);
method public boolean removeConfiguration(java.lang.String);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index aebf380..f1419bd 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5647,6 +5647,7 @@
method public android.content.ComponentName getEffectsSuppressor();
method public int getImportance();
method public android.app.NotificationChannel getNotificationChannel(java.lang.String);
+ method public android.app.NotificationChannelGroup getNotificationChannelGroup(java.lang.String);
method public java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups();
method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
method public android.app.NotificationManager.Policy getNotificationPolicy();
@@ -5659,8 +5660,12 @@
method public void setNotificationPolicy(android.app.NotificationManager.Policy);
method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
+ field public static final java.lang.String ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED";
+ field public static final java.lang.String ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED";
field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
+ field public static final java.lang.String EXTRA_BLOCKED_STATE = "android.app.extra.BLOCKED_STATE";
+ field public static final java.lang.String EXTRA_BLOCK_STATE_CHANGED_ID = "android.app.extra.BLOCK_STATE_CHANGED_ID";
field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
field public static final int IMPORTANCE_HIGH = 4; // 0x4
field public static final int IMPORTANCE_LOW = 2; // 0x2
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 9e926bd..d1aacad 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -72,6 +72,7 @@
int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
int getDeletedChannelCount(String pkg, int uid);
void deleteNotificationChannelGroup(String pkg, String channelGroupId);
+ NotificationChannelGroup getNotificationChannelGroup(String pkg, String channelGroupId);
ParceledListSlice getNotificationChannelGroups(String pkg);
boolean onlyHasDefaultChannel(String pkg, int uid);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index f931589..659cf16 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -93,6 +93,58 @@
private static boolean localLOGV = false;
/**
+ * Intent that is broadcast when a {@link NotificationChannel} is blocked
+ * (when {@link NotificationChannel#getImportance()} is {@link #IMPORTANCE_NONE}) or unblocked
+ * (when {@link NotificationChannel#getImportance()} is anything other than
+ * {@link #IMPORTANCE_NONE}).
+ *
+ * This broadcast is only sent to the app that owns the channel that has changed.
+ *
+ * Input: nothing
+ * Output: {@link #EXTRA_BLOCK_STATE_CHANGED_ID}
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED =
+ "android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED";
+
+ /**
+ * Extra for {@link #ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED} or
+ * {@link #ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED} containing the id of the
+ * object which has a new blocked state.
+ *
+ * The value will be the {@link NotificationChannel#getId()} of the channel for
+ * {@link #ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED} and
+ * the {@link NotificationChannelGroup#getId()} of the group for
+ * {@link #ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED}.
+ */
+ public static final String EXTRA_BLOCK_STATE_CHANGED_ID =
+ "android.app.extra.BLOCK_STATE_CHANGED_ID";
+
+ /**
+ * Extra for {@link #ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED} or
+ * {@link #ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED} containing the new blocked
+ * state as a boolean.
+ *
+ * The value will be {@code true} if this channel or group is now blocked and {@code false} if
+ * this channel or group is now unblocked.
+ */
+ public static final String EXTRA_BLOCKED_STATE = "android.app.extra.BLOCKED_STATE";
+
+
+ /**
+ * Intent that is broadcast when a {@link NotificationChannelGroup} is
+ * {@link NotificationChannelGroup#isBlocked() blocked} or unblocked.
+ *
+ * This broadcast is only sent to the app that owns the channel group that has changed.
+ *
+ * Input: nothing
+ * Output: {@link #EXTRA_BLOCK_STATE_CHANGED_ID}
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED =
+ "android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED";
+
+ /**
* Intent that is broadcast when the state of {@link #getEffectsSuppressor()} changes.
* This broadcast is only sent to registered receivers.
*
@@ -504,6 +556,20 @@
}
/**
+ * Returns the notification channel group settings for a given channel group id.
+ *
+ * The channel group must belong to your package, or null will be returned.
+ */
+ public NotificationChannelGroup getNotificationChannelGroup(String channelGroupId) {
+ INotificationManager service = getService();
+ try {
+ return service.getNotificationChannelGroup(mContext.getPackageName(), channelGroupId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns all notification channel groups belonging to the calling app.
*/
public List<NotificationChannelGroup> getNotificationChannelGroups() {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 86103e4..ed5a7a9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -485,7 +485,6 @@
<protected-broadcast android:name="android.content.jobscheduler.JOB_DEADLINE_EXPIRED" />
<protected-broadcast android:name="android.intent.action.ACTION_UNSOL_RESPONSE_OEM_HOOK_RAW" />
<protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE_SUPL" />
- <protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" />
<protected-broadcast android:name="android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED" />
<protected-broadcast android:name="android.os.storage.action.VOLUME_STATE_CHANGED" />
<protected-broadcast android:name="android.os.storage.action.DISK_SCANNED" />
@@ -504,6 +503,8 @@
<protected-broadcast android:name="android.app.action.NOTIFICATION_POLICY_CHANGED" />
<protected-broadcast android:name="android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED" />
<protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" />
+ <protected-broadcast android:name="android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED" />
+ <protected-broadcast android:name="android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED" />
<protected-broadcast android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS" />
<protected-broadcast android:name="android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS" />
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6ba1d8d..08da568 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -16,15 +16,21 @@
package com.android.server.notification;
+import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
+import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.IMPORTANCE_NONE;
-import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_TELEVISION;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.UserHandle.USER_NULL;
import static android.service.notification.NotificationListenerService
+ .HINT_HOST_DISABLE_CALL_EFFECTS;
+import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
+import static android.service.notification.NotificationListenerService
+ .HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
+import static android.service.notification.NotificationListenerService
.NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
import static android.service.notification.NotificationListenerService
.NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
@@ -32,12 +38,13 @@
.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
-import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
+import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
import static android.service.notification.NotificationListenerService.REASON_CLICK;
import static android.service.notification.NotificationListenerService.REASON_ERROR;
-import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
+import static android.service.notification.NotificationListenerService
+ .REASON_GROUP_SUMMARY_CANCELED;
import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
@@ -48,14 +55,10 @@
import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
-import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
-import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
-import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.service.notification.NotificationListenerService.TRIM_FULL;
import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
-
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
@@ -68,17 +71,17 @@
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.AutomaticZenRule;
-import android.app.NotificationChannelGroup;
-import android.app.backup.BackupManager;
import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.ITransientNotification;
import android.app.Notification;
import android.app.NotificationChannel;
-import android.app.NotificationManager.Policy;
+import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
+import android.app.NotificationManager.Policy;
import android.app.PendingIntent;
import android.app.StatusBarManager;
+import android.app.backup.BackupManager;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.companion.ICompanionDeviceManager;
@@ -119,8 +122,8 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
-import android.os.Vibrator;
import android.os.VibrationEffect;
+import android.os.Vibrator;
import android.provider.Settings;
import android.service.notification.Adjustment;
import android.service.notification.Condition;
@@ -174,9 +177,9 @@
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
import com.android.server.notification.ManagedServices.ManagedServiceInfo;
+import com.android.server.notification.ManagedServices.UserProfiles;
import com.android.server.policy.PhoneWindowManager;
import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.notification.ManagedServices.UserProfiles;
import libcore.io.IoUtils;
@@ -196,7 +199,6 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
-import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -1520,7 +1522,11 @@
}
}
}
+ final NotificationChannel preUpdate =
+ mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
+
mRankingHelper.updateNotificationChannel(pkg, uid, channel, true);
+ maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
if (!fromListener) {
final NotificationChannel modifiedChannel =
@@ -1533,12 +1539,40 @@
savePolicyFile();
}
+ private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
+ NotificationChannel update) {
+ try {
+ if ((preUpdate.getImportance() == IMPORTANCE_NONE
+ && update.getImportance() != IMPORTANCE_NONE)
+ || (preUpdate.getImportance() != IMPORTANCE_NONE
+ && update.getImportance() == IMPORTANCE_NONE)) {
+ getContext().sendBroadcastAsUser(
+ new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
+ .putExtra(NotificationManager.EXTRA_BLOCK_STATE_CHANGED_ID,
+ update.getId())
+ .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
+ update.getImportance() == IMPORTANCE_NONE)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+ .setPackage(pkg),
+ UserHandle.of(UserHandle.getUserId(uid)), null);
+ }
+ } catch (SecurityException e) {
+ Slog.w(TAG, "Can't notify app about channel change", e);
+ }
+ }
+
private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
boolean fromApp, boolean fromListener) {
Preconditions.checkNotNull(group);
Preconditions.checkNotNull(pkg);
+
+ final NotificationChannelGroup preUpdate =
+ mRankingHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
mRankingHelper.createNotificationChannelGroup(pkg, uid, group,
fromApp);
+ if (!fromApp) {
+ maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
+ }
if (!fromListener) {
mListeners.notifyNotificationChannelGroupChanged(pkg,
UserHandle.of(UserHandle.getCallingUserId()), group,
@@ -1546,6 +1580,25 @@
}
}
+ private void maybeNotifyChannelGroupOwner(String pkg, int uid,
+ NotificationChannelGroup preUpdate, NotificationChannelGroup update) {
+ try {
+ if (preUpdate.isBlocked() != update.isBlocked()) {
+ getContext().sendBroadcastAsUser(
+ new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
+ .putExtra(NotificationManager.EXTRA_BLOCK_STATE_CHANGED_ID,
+ update.getId())
+ .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
+ update.isBlocked())
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+ .setPackage(pkg),
+ UserHandle.of(UserHandle.getUserId(uid)), null);
+ }
+ } catch (SecurityException e) {
+ Slog.w(TAG, "Can't notify app about group change", e);
+ }
+ }
+
private ArrayList<ComponentName> getSuppressors() {
ArrayList<ComponentName> names = new ArrayList<ComponentName>();
for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
@@ -1924,11 +1977,18 @@
}
@Override
+ public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) {
+ checkCallerIsSystemOrSameApp(pkg);
+ return mRankingHelper.getNotificationChannelGroupWithChannels(
+ pkg, Binder.getCallingUid(), groupId, false);
+ }
+
+ @Override
public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
String pkg) {
checkCallerIsSystemOrSameApp(pkg);
- return new ParceledListSlice<>(new ArrayList(
- mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid())));
+ return mRankingHelper.getNotificationChannelGroups(
+ pkg, Binder.getCallingUid(), false, false);
}
@Override
@@ -1998,7 +2058,7 @@
public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
String pkg, int uid, boolean includeDeleted) {
checkCallerIsSystem();
- return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted);
+ return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted, true);
}
@Override
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index b9c0d90..b1b0bf2 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -36,7 +36,7 @@
void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
boolean fromTargetApp);
ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
- int uid, boolean includeDeleted);
+ int uid, boolean includeDeleted, boolean includeNonGrouped);
void createNotificationChannel(String pkg, int uid, NotificationChannel channel,
boolean fromTargetApp);
void updateNotificationChannel(String pkg, int uid, NotificationChannel channel, boolean fromUser);
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index d566a45..c0dccb5 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -750,12 +750,15 @@
int uid) {
Preconditions.checkNotNull(pkg);
Record r = getRecord(pkg, uid);
+ if (r == null) {
+ return null;
+ }
return r.groups.get(groupId);
}
@Override
public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
- int uid, boolean includeDeleted) {
+ int uid, boolean includeDeleted, boolean includeNonGrouped) {
Preconditions.checkNotNull(pkg);
Map<String, NotificationChannelGroup> groups = new ArrayMap<>();
Record r = getRecord(pkg, uid);
@@ -783,7 +786,7 @@
}
}
}
- if (nonGrouped.getChannels().size() > 0) {
+ if (includeNonGrouped && nonGrouped.getChannels().size() > 0) {
groups.put(null, nonGrouped);
}
return new ParceledListSlice<>(new ArrayList<>(groups.values()));
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index c145e82..55ec133 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -16,8 +16,10 @@
package com.android.server.notification;
+import static android.app.NotificationManager.EXTRA_BLOCKED_STATE;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_MAX;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.content.pm.PackageManager.FEATURE_WATCH;
@@ -940,6 +942,120 @@
}
@Test
+ public void testUpdateChannelNotifyCreatorBlock() throws Exception {
+ mService.setRankingHelper(mRankingHelper);
+ when(mRankingHelper.getNotificationChannel(eq(PKG), anyInt(),
+ eq(mTestNotificationChannel.getId()), anyBoolean()))
+ .thenReturn(mTestNotificationChannel);
+
+ NotificationChannel updatedChannel =
+ new NotificationChannel(mTestNotificationChannel.getId(),
+ mTestNotificationChannel.getName(), IMPORTANCE_NONE);
+
+ mBinderService.updateNotificationChannelForPackage(PKG, 0, updatedChannel);
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
+
+ assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED,
+ captor.getValue().getAction());
+ assertEquals(PKG, captor.getValue().getPackage());
+ assertEquals(mTestNotificationChannel.getId(), captor.getValue().getStringExtra(
+ NotificationManager.EXTRA_BLOCK_STATE_CHANGED_ID));
+ assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
+ }
+
+ @Test
+ public void testUpdateChannelNotifyCreatorUnblock() throws Exception {
+ NotificationChannel existingChannel =
+ new NotificationChannel(mTestNotificationChannel.getId(),
+ mTestNotificationChannel.getName(), IMPORTANCE_NONE);
+ mService.setRankingHelper(mRankingHelper);
+ when(mRankingHelper.getNotificationChannel(eq(PKG), anyInt(),
+ eq(mTestNotificationChannel.getId()), anyBoolean()))
+ .thenReturn(existingChannel);
+
+ mBinderService.updateNotificationChannelForPackage(PKG, 0, mTestNotificationChannel);
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
+
+ assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED,
+ captor.getValue().getAction());
+ assertEquals(PKG, captor.getValue().getPackage());
+ assertEquals(mTestNotificationChannel.getId(), captor.getValue().getStringExtra(
+ NotificationManager.EXTRA_BLOCK_STATE_CHANGED_ID));
+ assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
+ }
+
+ @Test
+ public void testUpdateChannelNoNotifyCreatorOtherChanges() throws Exception {
+ NotificationChannel existingChannel =
+ new NotificationChannel(mTestNotificationChannel.getId(),
+ mTestNotificationChannel.getName(), IMPORTANCE_MAX);
+ mService.setRankingHelper(mRankingHelper);
+ when(mRankingHelper.getNotificationChannel(eq(PKG), anyInt(),
+ eq(mTestNotificationChannel.getId()), anyBoolean()))
+ .thenReturn(existingChannel);
+
+ mBinderService.updateNotificationChannelForPackage(PKG, 0, mTestNotificationChannel);
+ verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null));
+ }
+
+ @Test
+ public void testUpdateGroupNotifyCreatorBlock() throws Exception {
+ NotificationChannelGroup existing = new NotificationChannelGroup("id", "name");
+ mService.setRankingHelper(mRankingHelper);
+ when(mRankingHelper.getNotificationChannelGroup(eq(existing.getId()), eq(PKG), anyInt()))
+ .thenReturn(existing);
+
+ NotificationChannelGroup updated = new NotificationChannelGroup("id", "name");
+ updated.setBlocked(true);
+
+ mBinderService.updateNotificationChannelGroupForPackage(PKG, 0, updated);
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
+
+ assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED,
+ captor.getValue().getAction());
+ assertEquals(PKG, captor.getValue().getPackage());
+ assertEquals(existing.getId(), captor.getValue().getStringExtra(
+ NotificationManager.EXTRA_BLOCK_STATE_CHANGED_ID));
+ assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
+ }
+
+ @Test
+ public void testUpdateGroupNotifyCreatorUnblock() throws Exception {
+ NotificationChannelGroup existing = new NotificationChannelGroup("id", "name");
+ existing.setBlocked(true);
+ mService.setRankingHelper(mRankingHelper);
+ when(mRankingHelper.getNotificationChannelGroup(eq(existing.getId()), eq(PKG), anyInt()))
+ .thenReturn(existing);
+
+ mBinderService.updateNotificationChannelGroupForPackage(
+ PKG, 0, new NotificationChannelGroup("id", "name"));
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
+
+ assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED,
+ captor.getValue().getAction());
+ assertEquals(PKG, captor.getValue().getPackage());
+ assertEquals(existing.getId(), captor.getValue().getStringExtra(
+ NotificationManager.EXTRA_BLOCK_STATE_CHANGED_ID));
+ assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
+ }
+
+ @Test
+ public void testUpdateGroupNoNotifyCreatorOtherChanges() throws Exception {
+ NotificationChannelGroup existing = new NotificationChannelGroup("id", "name");
+ mService.setRankingHelper(mRankingHelper);
+ when(mRankingHelper.getNotificationChannelGroup(eq(existing.getId()), eq(PKG), anyInt()))
+ .thenReturn(existing);
+
+ mBinderService.updateNotificationChannelGroupForPackage(
+ PKG, 0, new NotificationChannelGroup("id", "new name"));
+ verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null));
+ }
+
+ @Test
public void testCreateChannelNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
@@ -1040,6 +1156,9 @@
List<String> associations = new ArrayList<>();
associations.add("a");
when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+ when(mRankingHelper.getNotificationChannel(eq(PKG), anyInt(),
+ eq(mTestNotificationChannel.getId()), anyBoolean()))
+ .thenReturn(mTestNotificationChannel);
mBinderService.updateNotificationChannelFromPrivilegedListener(
null, PKG, Process.myUserHandle(), mTestNotificationChannel);
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 3c02e23..2d03f11 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -372,7 +372,7 @@
mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
List<NotificationChannelGroup> actualGroups =
- mHelper.getNotificationChannelGroups(PKG, UID, false).getList();
+ mHelper.getNotificationChannelGroups(PKG, UID, false, true).getList();
boolean foundNcg = false;
for (NotificationChannelGroup actual : actualGroups) {
if (ncg.getId().equals(actual.getId())) {
@@ -442,7 +442,7 @@
mHelper.getNotificationChannel(PKG, UID, channel3.getId(), false));
List<NotificationChannelGroup> actualGroups =
- mHelper.getNotificationChannelGroups(PKG, UID, false).getList();
+ mHelper.getNotificationChannelGroups(PKG, UID, false, true).getList();
boolean foundNcg = false;
for (NotificationChannelGroup actual : actualGroups) {
if (ncg.getId().equals(actual.getId())) {
@@ -1281,7 +1281,8 @@
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, true, true).getList().size());
}
@Test
@@ -1370,7 +1371,7 @@
mHelper.createNotificationChannel(PKG, UID, channel3, true);
List<NotificationChannelGroup> actual =
- mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
+ mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList();
assertEquals(3, actual.size());
for (NotificationChannelGroup group : actual) {
if (group.getId() == null) {
@@ -1402,13 +1403,13 @@
new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
channel1.setGroup(ncg.getId());
mHelper.createNotificationChannel(PKG, UID, channel1, true);
- mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
+ mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList();
channel1.setImportance(IMPORTANCE_LOW);
mHelper.updateNotificationChannel(PKG, UID, channel1, true);
List<NotificationChannelGroup> actual =
- mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
+ mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList();
assertEquals(2, actual.size());
for (NotificationChannelGroup group : actual) {