Add method to silence a notification instance
Allows apps to selective silence notifications
even on noisy NotificationChannels.
Test: atest
Bug: 139067153
Change-Id: I22e5fcaa93f09558160e2fe24e97e5748dba4e31
diff --git a/core/core/api/1.3.0-alpha01.txt b/core/core/api/1.3.0-alpha01.txt
index b962a95..708b5da 100644
--- a/core/core/api/1.3.0-alpha01.txt
+++ b/core/core/api/1.3.0-alpha01.txt
@@ -264,6 +264,7 @@
field public static final int GROUP_ALERT_ALL = 0; // 0x0
field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
+ field public static final String GROUP_KEY_SILENT = "silent";
field public static final int PRIORITY_DEFAULT = 0; // 0x0
field public static final int PRIORITY_HIGH = 1; // 0x1
field public static final int PRIORITY_LOW = -1; // 0xffffffff
@@ -428,6 +429,7 @@
method public androidx.core.app.NotificationCompat.Builder! setLargeIcon(android.graphics.Bitmap!);
method public androidx.core.app.NotificationCompat.Builder! setLights(@ColorInt int, int, int);
method public androidx.core.app.NotificationCompat.Builder! setLocalOnly(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setNotificationSilent();
method public androidx.core.app.NotificationCompat.Builder! setNumber(int);
method public androidx.core.app.NotificationCompat.Builder! setOngoing(boolean);
method public androidx.core.app.NotificationCompat.Builder! setOnlyAlertOnce(boolean);
diff --git a/core/core/api/current.txt b/core/core/api/current.txt
index b962a95..708b5da 100644
--- a/core/core/api/current.txt
+++ b/core/core/api/current.txt
@@ -264,6 +264,7 @@
field public static final int GROUP_ALERT_ALL = 0; // 0x0
field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
+ field public static final String GROUP_KEY_SILENT = "silent";
field public static final int PRIORITY_DEFAULT = 0; // 0x0
field public static final int PRIORITY_HIGH = 1; // 0x1
field public static final int PRIORITY_LOW = -1; // 0xffffffff
@@ -428,6 +429,7 @@
method public androidx.core.app.NotificationCompat.Builder! setLargeIcon(android.graphics.Bitmap!);
method public androidx.core.app.NotificationCompat.Builder! setLights(@ColorInt int, int, int);
method public androidx.core.app.NotificationCompat.Builder! setLocalOnly(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setNotificationSilent();
method public androidx.core.app.NotificationCompat.Builder! setNumber(int);
method public androidx.core.app.NotificationCompat.Builder! setOngoing(boolean);
method public androidx.core.app.NotificationCompat.Builder! setOnlyAlertOnce(boolean);
diff --git a/core/core/api/public_plus_experimental_1.3.0-alpha01.txt b/core/core/api/public_plus_experimental_1.3.0-alpha01.txt
index b962a95..708b5da 100644
--- a/core/core/api/public_plus_experimental_1.3.0-alpha01.txt
+++ b/core/core/api/public_plus_experimental_1.3.0-alpha01.txt
@@ -264,6 +264,7 @@
field public static final int GROUP_ALERT_ALL = 0; // 0x0
field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
+ field public static final String GROUP_KEY_SILENT = "silent";
field public static final int PRIORITY_DEFAULT = 0; // 0x0
field public static final int PRIORITY_HIGH = 1; // 0x1
field public static final int PRIORITY_LOW = -1; // 0xffffffff
@@ -428,6 +429,7 @@
method public androidx.core.app.NotificationCompat.Builder! setLargeIcon(android.graphics.Bitmap!);
method public androidx.core.app.NotificationCompat.Builder! setLights(@ColorInt int, int, int);
method public androidx.core.app.NotificationCompat.Builder! setLocalOnly(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setNotificationSilent();
method public androidx.core.app.NotificationCompat.Builder! setNumber(int);
method public androidx.core.app.NotificationCompat.Builder! setOngoing(boolean);
method public androidx.core.app.NotificationCompat.Builder! setOnlyAlertOnce(boolean);
diff --git a/core/core/api/public_plus_experimental_current.txt b/core/core/api/public_plus_experimental_current.txt
index b962a95..708b5da 100644
--- a/core/core/api/public_plus_experimental_current.txt
+++ b/core/core/api/public_plus_experimental_current.txt
@@ -264,6 +264,7 @@
field public static final int GROUP_ALERT_ALL = 0; // 0x0
field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
+ field public static final String GROUP_KEY_SILENT = "silent";
field public static final int PRIORITY_DEFAULT = 0; // 0x0
field public static final int PRIORITY_HIGH = 1; // 0x1
field public static final int PRIORITY_LOW = -1; // 0xffffffff
@@ -428,6 +429,7 @@
method public androidx.core.app.NotificationCompat.Builder! setLargeIcon(android.graphics.Bitmap!);
method public androidx.core.app.NotificationCompat.Builder! setLights(@ColorInt int, int, int);
method public androidx.core.app.NotificationCompat.Builder! setLocalOnly(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setNotificationSilent();
method public androidx.core.app.NotificationCompat.Builder! setNumber(int);
method public androidx.core.app.NotificationCompat.Builder! setOngoing(boolean);
method public androidx.core.app.NotificationCompat.Builder! setOnlyAlertOnce(boolean);
diff --git a/core/core/api/restricted_1.3.0-alpha01.txt b/core/core/api/restricted_1.3.0-alpha01.txt
index 1121902..45949e9 100644
--- a/core/core/api/restricted_1.3.0-alpha01.txt
+++ b/core/core/api/restricted_1.3.0-alpha01.txt
@@ -309,6 +309,7 @@
field public static final int GROUP_ALERT_ALL = 0; // 0x0
field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
+ field public static final String GROUP_KEY_SILENT = "silent";
field public static final int PRIORITY_DEFAULT = 0; // 0x0
field public static final int PRIORITY_HIGH = 1; // 0x1
field public static final int PRIORITY_LOW = -1; // 0xffffffff
@@ -483,6 +484,7 @@
method public androidx.core.app.NotificationCompat.Builder! setLargeIcon(android.graphics.Bitmap!);
method public androidx.core.app.NotificationCompat.Builder! setLights(@ColorInt int, int, int);
method public androidx.core.app.NotificationCompat.Builder! setLocalOnly(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setNotificationSilent();
method public androidx.core.app.NotificationCompat.Builder! setNumber(int);
method public androidx.core.app.NotificationCompat.Builder! setOngoing(boolean);
method public androidx.core.app.NotificationCompat.Builder! setOnlyAlertOnce(boolean);
diff --git a/core/core/api/restricted_current.txt b/core/core/api/restricted_current.txt
index 1121902..45949e9 100644
--- a/core/core/api/restricted_current.txt
+++ b/core/core/api/restricted_current.txt
@@ -309,6 +309,7 @@
field public static final int GROUP_ALERT_ALL = 0; // 0x0
field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
+ field public static final String GROUP_KEY_SILENT = "silent";
field public static final int PRIORITY_DEFAULT = 0; // 0x0
field public static final int PRIORITY_HIGH = 1; // 0x1
field public static final int PRIORITY_LOW = -1; // 0xffffffff
@@ -483,6 +484,7 @@
method public androidx.core.app.NotificationCompat.Builder! setLargeIcon(android.graphics.Bitmap!);
method public androidx.core.app.NotificationCompat.Builder! setLights(@ColorInt int, int, int);
method public androidx.core.app.NotificationCompat.Builder! setLocalOnly(boolean);
+ method public androidx.core.app.NotificationCompat.Builder setNotificationSilent();
method public androidx.core.app.NotificationCompat.Builder! setNumber(int);
method public androidx.core.app.NotificationCompat.Builder! setOngoing(boolean);
method public androidx.core.app.NotificationCompat.Builder! setOnlyAlertOnce(boolean);
diff --git a/core/core/src/androidTest/java/androidx/core/app/NotificationCompatTest.java b/core/core/src/androidTest/java/androidx/core/app/NotificationCompatTest.java
index a79e27d..7107af0 100644
--- a/core/core/src/androidTest/java/androidx/core/app/NotificationCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/app/NotificationCompatTest.java
@@ -23,6 +23,7 @@
import static androidx.core.app.NotificationCompat.GROUP_ALERT_ALL;
import static androidx.core.app.NotificationCompat.GROUP_ALERT_CHILDREN;
import static androidx.core.app.NotificationCompat.GROUP_ALERT_SUMMARY;
+import static androidx.core.app.NotificationCompat.GROUP_KEY_SILENT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -449,6 +450,123 @@
}
@Test
+ public void testSetNotificationSilent() throws Throwable {
+
+ Notification nSummary = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+ .setVibrate(new long[] {235})
+ .setSound(Uri.EMPTY)
+ .setDefaults(DEFAULT_ALL)
+ .setGroupSummary(true)
+ .setTicker("summary")
+ .setNotificationSilent()
+ .build();
+
+ Notification nChild = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+ .setVibrate(new long[] {235})
+ .setSound(Uri.EMPTY)
+ .setDefaults(DEFAULT_ALL)
+ .setGroupSummary(false)
+ .setTicker("child")
+ .setNotificationSilent()
+ .build();
+
+ if (Build.VERSION.SDK_INT >= 20 && !(Build.VERSION.SDK_INT >= 26)) {
+ assertNull(nSummary.sound);
+ assertNull(nSummary.vibrate);
+ assertTrue((nSummary.defaults & DEFAULT_LIGHTS) != 0);
+ assertTrue((nSummary.defaults & DEFAULT_SOUND) == 0);
+ assertTrue((nSummary.defaults & DEFAULT_VIBRATE) == 0);
+
+ assertNull(nChild.sound);
+ assertNull(nChild.vibrate);
+ assertTrue((nChild.defaults & DEFAULT_LIGHTS) != 0);
+ assertTrue((nChild.defaults & DEFAULT_SOUND) == 0);
+ assertTrue((nChild.defaults & DEFAULT_VIBRATE) == 0);
+ }
+
+ if (Build.VERSION.SDK_INT >= 26) {
+ assertEquals(GROUP_ALERT_SUMMARY, nChild.getGroupAlertBehavior());
+ assertEquals(GROUP_ALERT_CHILDREN, nSummary.getGroupAlertBehavior());
+ assertEquals(GROUP_KEY_SILENT, nChild.getGroup());
+ assertEquals(GROUP_KEY_SILENT, nSummary.getGroup());
+ } else if (Build.VERSION.SDK_INT >= 20) {
+ assertNull(nChild.getGroup());
+ assertNull(nSummary.getGroup());
+ }
+ }
+
+ @Test
+ public void testSetNotificationSilent_doesNotOverrideGroup() throws Throwable {
+ final String groupKey = "grouped";
+
+ Notification nSummary = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+ .setVibrate(new long[] {235})
+ .setSound(Uri.EMPTY)
+ .setDefaults(DEFAULT_ALL)
+ .setGroupSummary(true)
+ .setGroup(groupKey)
+ .setTicker("summary")
+ .setNotificationSilent()
+ .build();
+
+ Notification nChild = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+ .setVibrate(new long[] {235})
+ .setSound(Uri.EMPTY)
+ .setDefaults(DEFAULT_ALL)
+ .setGroupSummary(false)
+ .setGroup(groupKey)
+ .setTicker("child")
+ .setNotificationSilent()
+ .build();
+
+ if (Build.VERSION.SDK_INT >= 26) {
+ assertEquals(GROUP_ALERT_SUMMARY, nChild.getGroupAlertBehavior());
+ assertEquals(GROUP_ALERT_CHILDREN, nSummary.getGroupAlertBehavior());
+ }
+ if (Build.VERSION.SDK_INT >= 20) {
+ assertEquals(groupKey, nChild.getGroup());
+ assertEquals(groupKey, nSummary.getGroup());
+ }
+ }
+
+ @Test
+ public void testSetNotificationSilent_notSilenced() throws Throwable {
+
+ Notification nSummary = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+ .setVibrate(new long[] {235})
+ .setSound(Uri.EMPTY)
+ .setDefaults(DEFAULT_ALL)
+ .setGroup("grouped")
+ .setGroupSummary(true)
+ .build();
+
+ Notification nChild = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+ .setVibrate(new long[] {235})
+ .setSound(Uri.EMPTY)
+ .setDefaults(DEFAULT_ALL)
+ .setGroup("grouped")
+ .setGroupSummary(false)
+ .build();
+
+ assertNotNull(nSummary.sound);
+ assertNotNull(nSummary.vibrate);
+ assertTrue((nSummary.defaults & DEFAULT_LIGHTS) != 0);
+ assertTrue((nSummary.defaults & DEFAULT_SOUND) != 0);
+ assertTrue((nSummary.defaults & DEFAULT_VIBRATE) != 0);
+
+ assertNotNull(nChild.sound);
+ assertNotNull(nChild.vibrate);
+ assertTrue((nChild.defaults & DEFAULT_LIGHTS) != 0);
+ assertTrue((nChild.defaults & DEFAULT_SOUND) != 0);
+ assertTrue((nChild.defaults & DEFAULT_VIBRATE) != 0);
+
+ if (Build.VERSION.SDK_INT >= 26) {
+ assertEquals(GROUP_ALERT_ALL, nChild.getGroupAlertBehavior());
+ assertEquals(GROUP_ALERT_ALL, nSummary.getGroupAlertBehavior());
+ }
+ }
+
+ @Test
public void testGroupAlertBehavior_doesNotMuteIncorrectGroupNotifications() throws Throwable {
Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
.setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
diff --git a/core/core/src/main/java/androidx/core/app/NotificationCompat.java b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
index 3df4449d..4364115 100644
--- a/core/core/src/main/java/androidx/core/app/NotificationCompat.java
+++ b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
@@ -660,6 +660,13 @@
public static final int GROUP_ALERT_CHILDREN = Notification.GROUP_ALERT_CHILDREN;
/**
+ * Constant for the {@link Builder#setGroup(String) group key} that's added to notifications
+ * that are not already grouped when {@link Builder#setNotificationSilent()} is used when
+ * {@link Build.VERSION#SDK_INT} is >= {@link Build.VERSION_CODES#O}.
+ */
+ public static final String GROUP_KEY_SILENT = "silent";
+
+ /**
* Builder class for {@link NotificationCompat} objects. Allows easier control over
* all the flags, as well as help constructing the typical notification layouts.
* <p>
@@ -744,6 +751,7 @@
boolean mAllowSystemGeneratedContextualActions;
BubbleMetadata mBubbleMetadata;
Notification mNotification = new Notification();
+ boolean mSilent;
/**
* @deprecated This field was not meant to be public.
@@ -864,6 +872,15 @@
}
/**
+ * Silences this instance of the notification, regardless of the sounds or vibrations set
+ * on the notification or notification channel.
+ */
+ public @NonNull Builder setNotificationSilent() {
+ mSilent = true;
+ return this;
+ }
+
+ /**
* Set the title (first row) of the notification, in a standard notification.
*/
public Builder setContentTitle(CharSequence title) {
diff --git a/core/core/src/main/java/androidx/core/app/NotificationCompatBuilder.java b/core/core/src/main/java/androidx/core/app/NotificationCompatBuilder.java
index aac35da..135eb21 100644
--- a/core/core/src/main/java/androidx/core/app/NotificationCompatBuilder.java
+++ b/core/core/src/main/java/androidx/core/app/NotificationCompatBuilder.java
@@ -96,7 +96,6 @@
mBuilder.setSubText(b.mSubText)
.setUsesChronometer(b.mUseChronometer)
.setPriority(b.mPriority);
-
for (NotificationCompat.Action action : b.mActions) {
addAction(action);
}
@@ -214,6 +213,21 @@
mBuilder.setBubbleMetadata(
NotificationCompat.BubbleMetadata.toPlatform(b.mBubbleMetadata));
}
+
+ if (b.mSilent) {
+ if (mBuilderCompat.mGroupSummary) {
+ mGroupAlertBehavior = GROUP_ALERT_CHILDREN;
+ } else {
+ mGroupAlertBehavior = GROUP_ALERT_SUMMARY;
+ }
+
+ if (Build.VERSION.SDK_INT >= 26) {
+ if (TextUtils.isEmpty(mBuilderCompat.mGroupKey)) {
+ mBuilder.setGroup(NotificationCompat.GROUP_KEY_SILENT);
+ }
+ mBuilder.setGroupAlertBehavior(mGroupAlertBehavior);
+ }
+ }
}
@Override