Add groupAlertBehavior to notificationcompat

Pre O this will remove all sounds and vibrations from
relevant grouped notifications. In O+ it'll just set
the field on notification.

Test: NotificationCompatTest
Change-Id: Ida0a26d21f42876f399c3049324cd909d6180c5c
Fixes: 37478457
(cherry picked from commit 8c2ee58bb9538e43225d7553fd6479a68619a149)
diff --git a/api/26.0.0-SNAPSHOT.txt b/api/26.0.0-SNAPSHOT.txt
index b74a196..8b9ee5a 100644
--- a/api/26.0.0-SNAPSHOT.txt
+++ b/api/26.0.0-SNAPSHOT.txt
@@ -6208,6 +6208,7 @@
     method public static java.lang.String getChannelId(android.app.Notification);
     method public static android.os.Bundle getExtras(android.app.Notification);
     method public static java.lang.String getGroup(android.app.Notification);
+    method public static int getGroupAlertBehavior(android.app.Notification);
     method public static boolean getLocalOnly(android.app.Notification);
     method public static java.lang.String getShortcutId(android.app.Notification);
     method public static java.lang.String getSortKey(android.app.Notification);
@@ -6274,6 +6275,9 @@
     field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
     field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
     field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+    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 int PRIORITY_DEFAULT = 0; // 0x0
     field public static final int PRIORITY_HIGH = 1; // 0x1
     field public static final int PRIORITY_LOW = -1; // 0xffffffff
@@ -6382,6 +6386,7 @@
     method public android.support.v4.app.NotificationCompat.Builder setExtras(android.os.Bundle);
     method public android.support.v4.app.NotificationCompat.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
     method public android.support.v4.app.NotificationCompat.Builder setGroup(java.lang.String);
+    method public android.support.v4.app.NotificationCompat.Builder setGroupAlertBehavior(int);
     method public android.support.v4.app.NotificationCompat.Builder setGroupSummary(boolean);
     method public android.support.v4.app.NotificationCompat.Builder setLargeIcon(android.graphics.Bitmap);
     method public android.support.v4.app.NotificationCompat.Builder setLights(int, int, int);
diff --git a/compat/api20/android/support/v4/app/NotificationCompatApi20.java b/compat/api20/android/support/v4/app/NotificationCompatApi20.java
index 54250b6..f646b8f 100644
--- a/compat/api20/android/support/v4/app/NotificationCompatApi20.java
+++ b/compat/api20/android/support/v4/app/NotificationCompatApi20.java
@@ -16,6 +16,13 @@
 
 package android.support.v4.app;
 
+import static android.support.v4.app.NotificationCompat.DEFAULT_SOUND;
+import static android.support.v4.app.NotificationCompat.DEFAULT_VIBRATE;
+import static android.support.v4.app.NotificationCompat.FLAG_GROUP_SUMMARY;
+import static android.support.v4.app.NotificationCompat.GROUP_ALERT_ALL;
+import static android.support.v4.app.NotificationCompat.GROUP_ALERT_CHILDREN;
+import static android.support.v4.app.NotificationCompat.GROUP_ALERT_SUMMARY;
+
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.RemoteInput;
@@ -36,6 +43,7 @@
         private Bundle mExtras;
         private RemoteViews mContentView;
         private RemoteViews mBigContentView;
+        private int mGroupAlertBehavior;
 
         public Builder(Context context, Notification n,
                 CharSequence contentTitle, CharSequence contentText, CharSequence contentInfo,
@@ -44,7 +52,8 @@
                 int progressMax, int progress, boolean progressIndeterminate, boolean showWhen,
                 boolean useChronometer, int priority, CharSequence subText, boolean localOnly,
                 ArrayList<String> people, Bundle extras, String groupKey, boolean groupSummary,
-                String sortKey, RemoteViews contentView, RemoteViews bigContentView) {
+                String sortKey, RemoteViews contentView, RemoteViews bigContentView,
+                int groupAlertBehavior) {
             b = new Notification.Builder(context)
                 .setWhen(n.when)
                 .setShowWhen(showWhen)
@@ -85,6 +94,7 @@
             }
             mContentView = contentView;
             mBigContentView = bigContentView;
+            mGroupAlertBehavior = groupAlertBehavior;
         }
 
         @Override
@@ -107,8 +117,31 @@
             if (mBigContentView != null) {
                 notification.bigContentView = mBigContentView;
             }
+
+            if (mGroupAlertBehavior != GROUP_ALERT_ALL) {
+                // if is summary and only children should alert
+                if (notification.getGroup() != null
+                        && (notification.flags & FLAG_GROUP_SUMMARY) != 0
+                        && mGroupAlertBehavior == GROUP_ALERT_CHILDREN) {
+                    removeSoundAndVibration(notification);
+                }
+                // if is group child and only summary should alert
+                if (notification.getGroup() != null
+                        && (notification.flags & FLAG_GROUP_SUMMARY) == 0
+                        && mGroupAlertBehavior == GROUP_ALERT_SUMMARY) {
+                    removeSoundAndVibration(notification);
+                }
+            }
+
             return notification;
         }
+
+        private void removeSoundAndVibration(Notification notification) {
+            notification.sound = null;
+            notification.vibrate = null;
+            notification.defaults &= ~DEFAULT_SOUND;
+            notification.defaults &= ~DEFAULT_VIBRATE;
+        }
     }
 
     public static void addAction(Notification.Builder b, NotificationCompatBase.Action action) {
diff --git a/compat/api21/android/support/v4/app/NotificationCompatApi21.java b/compat/api21/android/support/v4/app/NotificationCompatApi21.java
index 8a273c7..44237f3 100644
--- a/compat/api21/android/support/v4/app/NotificationCompatApi21.java
+++ b/compat/api21/android/support/v4/app/NotificationCompatApi21.java
@@ -16,6 +16,13 @@
 
 package android.support.v4.app;
 
+import static android.support.v4.app.NotificationCompat.DEFAULT_SOUND;
+import static android.support.v4.app.NotificationCompat.DEFAULT_VIBRATE;
+import static android.support.v4.app.NotificationCompat.FLAG_GROUP_SUMMARY;
+import static android.support.v4.app.NotificationCompat.GROUP_ALERT_ALL;
+import static android.support.v4.app.NotificationCompat.GROUP_ALERT_CHILDREN;
+import static android.support.v4.app.NotificationCompat.GROUP_ALERT_SUMMARY;
+
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -61,6 +68,7 @@
         private RemoteViews mContentView;
         private RemoteViews mBigContentView;
         private RemoteViews mHeadsUpContentView;
+        private int mGroupAlertBehavior;
 
         public Builder(Context context, Notification n,
                 CharSequence contentTitle, CharSequence contentText, CharSequence contentInfo,
@@ -71,7 +79,7 @@
                 String category, ArrayList<String> people, Bundle extras, int color,
                 int visibility, Notification publicVersion, String groupKey, boolean groupSummary,
                 String sortKey, RemoteViews contentView, RemoteViews bigContentView,
-                RemoteViews headsUpContentView) {
+                RemoteViews headsUpContentView, int groupAlertBehavior) {
             b = new Notification.Builder(context)
                     .setWhen(n.when)
                     .setShowWhen(showWhen)
@@ -116,6 +124,7 @@
             mContentView = contentView;
             mBigContentView = bigContentView;
             mHeadsUpContentView = headsUpContentView;
+            mGroupAlertBehavior = groupAlertBehavior;
         }
 
         @Override
@@ -141,8 +150,30 @@
             if (mHeadsUpContentView != null) {
                 notification.headsUpContentView = mHeadsUpContentView;
             }
+
+            if (mGroupAlertBehavior != GROUP_ALERT_ALL) {
+                // if is summary and only children should alert
+                if (notification.getGroup() != null
+                        && (notification.flags & FLAG_GROUP_SUMMARY) != 0
+                        && mGroupAlertBehavior == GROUP_ALERT_CHILDREN) {
+                    removeSoundAndVibration(notification);
+                }
+                // if is group child and only summary should alert
+                if (notification.getGroup() != null
+                        && (notification.flags & FLAG_GROUP_SUMMARY) == 0
+                        && mGroupAlertBehavior == GROUP_ALERT_SUMMARY) {
+                    removeSoundAndVibration(notification);
+                }
+            }
             return notification;
         }
+
+        private void removeSoundAndVibration(Notification notification) {
+            notification.sound = null;
+            notification.vibrate = null;
+            notification.defaults &= ~DEFAULT_SOUND;
+            notification.defaults &= ~DEFAULT_VIBRATE;
+        }
     }
 
     static Bundle getBundleForUnreadConversation(NotificationCompatBase.UnreadConversation uc) {
diff --git a/compat/api24/android/support/v4/app/NotificationCompatApi24.java b/compat/api24/android/support/v4/app/NotificationCompatApi24.java
index 12faa8e..17e5cad 100644
--- a/compat/api24/android/support/v4/app/NotificationCompatApi24.java
+++ b/compat/api24/android/support/v4/app/NotificationCompatApi24.java
@@ -16,6 +16,13 @@
 
 package android.support.v4.app;
 
+import static android.support.v4.app.NotificationCompat.DEFAULT_SOUND;
+import static android.support.v4.app.NotificationCompat.DEFAULT_VIBRATE;
+import static android.support.v4.app.NotificationCompat.FLAG_GROUP_SUMMARY;
+import static android.support.v4.app.NotificationCompat.GROUP_ALERT_ALL;
+import static android.support.v4.app.NotificationCompat.GROUP_ALERT_CHILDREN;
+import static android.support.v4.app.NotificationCompat.GROUP_ALERT_SUMMARY;
+
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.RemoteInput;
@@ -32,24 +39,10 @@
 @RequiresApi(24)
 class NotificationCompatApi24 {
 
-    public static final String CATEGORY_CALL = Notification.CATEGORY_CALL;
-    public static final String CATEGORY_MESSAGE = Notification.CATEGORY_MESSAGE;
-    public static final String CATEGORY_EMAIL = Notification.CATEGORY_EMAIL;
-    public static final String CATEGORY_EVENT = Notification.CATEGORY_EVENT;
-    public static final String CATEGORY_PROMO = Notification.CATEGORY_PROMO;
-    public static final String CATEGORY_ALARM = Notification.CATEGORY_ALARM;
-    public static final String CATEGORY_PROGRESS = Notification.CATEGORY_PROGRESS;
-    public static final String CATEGORY_SOCIAL = Notification.CATEGORY_SOCIAL;
-    public static final String CATEGORY_ERROR = Notification.CATEGORY_ERROR;
-    public static final String CATEGORY_TRANSPORT = Notification.CATEGORY_TRANSPORT;
-    public static final String CATEGORY_SYSTEM = Notification.CATEGORY_SYSTEM;
-    public static final String CATEGORY_SERVICE = Notification.CATEGORY_SERVICE;
-    public static final String CATEGORY_RECOMMENDATION = Notification.CATEGORY_RECOMMENDATION;
-    public static final String CATEGORY_STATUS = Notification.CATEGORY_STATUS;
-
     public static class Builder implements NotificationBuilderWithBuilderAccessor,
             NotificationBuilderWithActions {
         private Notification.Builder b;
+        private int mGroupAlertBehavior;
 
         public Builder(Context context, Notification n,
                 CharSequence contentTitle, CharSequence contentText, CharSequence contentInfo,
@@ -60,7 +53,8 @@
                 String category, ArrayList<String> people, Bundle extras, int color,
                 int visibility, Notification publicVersion, String groupKey, boolean groupSummary,
                 String sortKey, CharSequence[] remoteInputHistory, RemoteViews contentView,
-                RemoteViews bigContentView, RemoteViews headsUpContentView) {
+                RemoteViews bigContentView, RemoteViews headsUpContentView,
+                int groupAlertBehavior) {
             b = new Notification.Builder(context)
                     .setWhen(n.when)
                     .setShowWhen(showWhen)
@@ -109,6 +103,8 @@
             for (String person: people) {
                 b.addPerson(person);
             }
+
+            mGroupAlertBehavior = groupAlertBehavior;
         }
 
         @Override
@@ -123,7 +119,31 @@
 
         @Override
         public Notification build() {
-            return b.build();
+            Notification notification =  b.build();
+
+            if (mGroupAlertBehavior != GROUP_ALERT_ALL) {
+                // if is summary and only children should alert
+                if (notification.getGroup() != null
+                        && (notification.flags & FLAG_GROUP_SUMMARY) != 0
+                        && mGroupAlertBehavior == GROUP_ALERT_CHILDREN) {
+                    removeSoundAndVibration(notification);
+                }
+                // if is group child and only summary should alert
+                if (notification.getGroup() != null
+                        && (notification.flags & FLAG_GROUP_SUMMARY) == 0
+                        && mGroupAlertBehavior == GROUP_ALERT_SUMMARY) {
+                    removeSoundAndVibration(notification);
+                }
+            }
+
+            return notification;
+        }
+
+        private void removeSoundAndVibration(Notification notification) {
+            notification.sound = null;
+            notification.vibrate = null;
+            notification.defaults &= ~DEFAULT_SOUND;
+            notification.defaults &= ~DEFAULT_VIBRATE;
         }
     }
 
diff --git a/compat/api26/android/support/v4/app/NotificationCompatApi26.java b/compat/api26/android/support/v4/app/NotificationCompatApi26.java
index 2db7183..ad696a8 100644
--- a/compat/api26/android/support/v4/app/NotificationCompatApi26.java
+++ b/compat/api26/android/support/v4/app/NotificationCompatApi26.java
@@ -44,7 +44,7 @@
                 String sortKey, CharSequence[] remoteInputHistory, RemoteViews contentView,
                 RemoteViews bigContentView, RemoteViews headsUpContentView,
                 String channelId, int badgeIcon, String shortcutId, long timeoutMs,
-                boolean colorized, boolean colorizedSet) {
+                boolean colorized, boolean colorizedSet, int groupAlertBehavior) {
             mB = new Notification.Builder(context, channelId)
                     .setWhen(n.when)
                     .setShowWhen(showWhen)
@@ -84,7 +84,8 @@
                     .setChannelId(channelId)
                     .setBadgeIconType(badgeIcon)
                     .setShortcutId(shortcutId)
-                    .setTimeoutAfter(timeoutMs);
+                    .setTimeoutAfter(timeoutMs)
+                    .setGroupAlertBehavior(groupAlertBehavior);
             if (colorizedSet) {
                 mB.setColorized(colorized);
             }
diff --git a/compat/java/android/support/v4/app/NotificationCompat.java b/compat/java/android/support/v4/app/NotificationCompat.java
index 14477b1..ec46c55 100644
--- a/compat/java/android/support/v4/app/NotificationCompat.java
+++ b/compat/java/android/support/v4/app/NotificationCompat.java
@@ -548,6 +548,36 @@
      */
     public static final int BADGE_ICON_LARGE = Notification.BADGE_ICON_LARGE;
 
+    /**
+     * Constant for {@link Builder#setGroupAlertBehavior(int)}, meaning that all notifications in a
+     * group with sound or vibration ought to make sound or vibrate (respectively), so this
+     * notification will not be muted when it is in a group.
+     */
+    public static final int GROUP_ALERT_ALL = 0;
+
+    /**
+     * Constant for {@link Builder#setGroupAlertBehavior(int)}, meaning that all children
+     * notification in a group should be silenced (no sound or vibration) even if they would
+     * otherwise make sound or vibrate. Use this constant to mute this notification if this
+     * notification is a group child.
+     *
+     * <p> For example, you might want to use this constant if you post a number of children
+     * notifications at once (say, after a periodic sync), and only need to notify the user
+     * audibly once.
+     */
+    public static final int GROUP_ALERT_SUMMARY = 1;
+
+    /**
+     * Constant for {@link Builder#setGroupAlertBehavior(int)}, meaning that the summary
+     * notification in a group should be silenced (no sound or vibration) even if they would
+     * otherwise make sound or vibrate. Use this constant
+     * to mute this notification if this notification is a group summary.
+     *
+     * <p>For example, you might want to use this constant if only the children notifications
+     * in your group have content and the summary is only used to visually group notifications.
+     */
+    public static final int GROUP_ALERT_CHILDREN = 2;
+
     static final NotificationCompatImpl IMPL;
 
     interface NotificationCompatImpl {
@@ -735,7 +765,8 @@
                     b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
                     b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen,
                     b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mPeople, b.mExtras,
-                    b.mGroupKey, b.mGroupSummary, b.mSortKey, b.mContentView, b.mBigContentView);
+                    b.mGroupKey, b.mGroupSummary, b.mSortKey, b.mContentView, b.mBigContentView,
+                    b.mGroupAlertBehavior);
             addActionsToBuilder(builder, b.mActions);
             addStyleToBuilderJellybean(builder, b.mStyle);
             Notification notification = extender.build(b, builder);
@@ -776,7 +807,7 @@
                     b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mCategory,
                     b.mPeople, b.mExtras, b.mColor, b.mVisibility, b.mPublicVersion,
                     b.mGroupKey, b.mGroupSummary, b.mSortKey, b.mContentView, b.mBigContentView,
-                    b.mHeadsUpContentView);
+                    b.mHeadsUpContentView, b.mGroupAlertBehavior);
             addActionsToBuilder(builder, b.mActions);
             addStyleToBuilderJellybean(builder, b.mStyle);
             Notification notification = extender.build(b, builder);
@@ -812,7 +843,7 @@
                     b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mCategory,
                     b.mPeople, b.mExtras, b.mColor, b.mVisibility, b.mPublicVersion,
                     b.mGroupKey, b.mGroupSummary, b.mSortKey, b.mRemoteInputHistory, b.mContentView,
-                    b.mBigContentView, b.mHeadsUpContentView);
+                    b.mBigContentView, b.mHeadsUpContentView, b.mGroupAlertBehavior);
             addActionsToBuilder(builder, b.mActions);
             addStyleToBuilderApi24(builder, b.mStyle);
             Notification notification = extender.build(b, builder);
@@ -836,7 +867,8 @@
                     b.mPeople, b.mExtras, b.mColor, b.mVisibility, b.mPublicVersion,
                     b.mGroupKey, b.mGroupSummary, b.mSortKey, b.mRemoteInputHistory, b.mContentView,
                     b.mBigContentView, b.mHeadsUpContentView, b.mChannelId, b.mBadgeIcon,
-                    b.mShortcutId, b.mTimeout, b.mColorized, b.mColorizedSet);
+                    b.mShortcutId, b.mTimeout, b.mColorized, b.mColorizedSet,
+                    b.mGroupAlertBehavior);
             addActionsToBuilder(builder, b.mActions);
             addStyleToBuilderApi24(builder, b.mStyle);
             Notification notification = extender.build(b, builder);
@@ -1023,6 +1055,7 @@
         int mBadgeIcon = BADGE_ICON_NONE;
         String mShortcutId;
         long mTimeout;
+        private int mGroupAlertBehavior = GROUP_ALERT_ALL;
 
         /** @hide */
         @RestrictTo(LIBRARY_GROUP)
@@ -1799,6 +1832,19 @@
         }
 
         /**
+         * Sets the group alert behavior for this notification. Use this method to mute this
+         * notification if alerts for this notification's group should be handled by a different
+         * notification. This is only applicable for notifications that belong to a
+         * {@link #setGroup(String) group}.
+         *
+         * <p> The default value is {@link #GROUP_ALERT_ALL}.</p>
+         */
+        public Builder setGroupAlertBehavior(int groupAlertBehavior) {
+            mGroupAlertBehavior = groupAlertBehavior;
+            return this;
+        }
+
+        /**
          * Apply an extender to this notification builder. Extenders may be used to add
          * metadata or change options on this builder.
          */
@@ -4419,4 +4465,17 @@
             return null;
         }
     }
+
+    /**
+     * Returns which type of notifications in a group are responsible for audibly alerting the
+     * user. See {@link #GROUP_ALERT_ALL}, {@link #GROUP_ALERT_CHILDREN},
+     * {@link #GROUP_ALERT_SUMMARY}.
+     */
+    public static int getGroupAlertBehavior(Notification notification) {
+        if (BuildCompat.isAtLeastO()) {
+            return notification.getGroupAlertBehavior();
+        } else {
+            return GROUP_ALERT_ALL;
+        }
+    }
 }
diff --git a/compat/tests/java/android/support/v4/app/NotificationCompatTest.java b/compat/tests/java/android/support/v4/app/NotificationCompatTest.java
index 2d42b19..7e1ea30 100644
--- a/compat/tests/java/android/support/v4/app/NotificationCompatTest.java
+++ b/compat/tests/java/android/support/v4/app/NotificationCompatTest.java
@@ -16,8 +16,17 @@
 
 package android.support.v4.app;
 
+import static android.support.v4.app.NotificationCompat.DEFAULT_ALL;
+import static android.support.v4.app.NotificationCompat.DEFAULT_LIGHTS;
+import static android.support.v4.app.NotificationCompat.DEFAULT_SOUND;
+import static android.support.v4.app.NotificationCompat.DEFAULT_VIBRATE;
+import static android.support.v4.app.NotificationCompat.GROUP_ALERT_ALL;
+import static android.support.v4.app.NotificationCompat.GROUP_ALERT_CHILDREN;
+import static android.support.v4.app.NotificationCompat.GROUP_ALERT_SUMMARY;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
@@ -25,6 +34,8 @@
 import android.annotation.TargetApi;
 import android.app.Notification;
 import android.content.Context;
+import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.SmallTest;
@@ -272,6 +283,136 @@
         assertEquals(extraValue, fromBundle.getExtras().getCharSequence(extraKey));
     }
 
+    @Test
+    public void testGetGroupAlertBehavior() throws Throwable {
+        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setGroupAlertBehavior(GROUP_ALERT_CHILDREN)
+                .build();
+        if (BuildCompat.isAtLeastO()) {
+            assertEquals(GROUP_ALERT_CHILDREN, NotificationCompat.getGroupAlertBehavior(n));
+        } else {
+            assertEquals(GROUP_ALERT_ALL, NotificationCompat.getGroupAlertBehavior(n));
+        }
+    }
+
+    @Test
+    public void testGroupAlertBehavior_mutesGroupNotifications() throws Throwable {
+        // valid between api 20, when groups were added, and api 25, the last to use sound
+        // and vibration from the notification itself
+
+        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setGroupAlertBehavior(GROUP_ALERT_CHILDREN)
+                .setVibrate(new long[] {235})
+                .setSound(Uri.EMPTY)
+                .setDefaults(DEFAULT_ALL)
+                .setGroup("grouped")
+                .setGroupSummary(true)
+                .build();
+
+        Notification n2 = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
+                .setVibrate(new long[] {235})
+                .setSound(Uri.EMPTY)
+                .setDefaults(DEFAULT_ALL)
+                .setGroup("grouped")
+                .setGroupSummary(false)
+                .build();
+
+        if (Build.VERSION.SDK_INT >= 20 && !BuildCompat.isAtLeastO()) {
+            assertNull(n.sound);
+            assertNull(n.vibrate);
+            assertTrue((n.defaults & DEFAULT_LIGHTS) != 0);
+            assertTrue((n.defaults & DEFAULT_SOUND) == 0);
+            assertTrue((n.defaults & DEFAULT_VIBRATE) == 0);
+
+            assertNull(n2.sound);
+            assertNull(n2.vibrate);
+            assertTrue((n2.defaults & DEFAULT_LIGHTS) != 0);
+            assertTrue((n2.defaults & DEFAULT_SOUND) == 0);
+            assertTrue((n2.defaults & DEFAULT_VIBRATE) == 0);
+        } else if (Build.VERSION.SDK_INT < 20) {
+            assertNotNull(n.sound);
+            assertNotNull(n.vibrate);
+            assertTrue((n.defaults & DEFAULT_LIGHTS) != 0);
+            assertTrue((n.defaults & DEFAULT_SOUND) != 0);
+            assertTrue((n.defaults & DEFAULT_VIBRATE) != 0);
+
+            assertNotNull(n2.sound);
+            assertNotNull(n2.vibrate);
+            assertTrue((n2.defaults & DEFAULT_LIGHTS) != 0);
+            assertTrue((n2.defaults & DEFAULT_SOUND) != 0);
+            assertTrue((n2.defaults & DEFAULT_VIBRATE) != 0);
+        }
+    }
+
+    @Test
+    public void testGroupAlertBehavior_doesNotMuteIncorrectGroupNotifications() throws Throwable {
+        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
+                .setVibrate(new long[] {235})
+                .setSound(Uri.EMPTY)
+                .setDefaults(DEFAULT_ALL)
+                .setGroup("grouped")
+                .setGroupSummary(true)
+                .build();
+
+        Notification n2 = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setGroupAlertBehavior(GROUP_ALERT_CHILDREN)
+                .setVibrate(new long[] {235})
+                .setSound(Uri.EMPTY)
+                .setDefaults(DEFAULT_ALL)
+                .setGroup("grouped")
+                .setGroupSummary(false)
+                .build();
+
+        Notification n3 = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setVibrate(new long[] {235})
+                .setSound(Uri.EMPTY)
+                .setDefaults(DEFAULT_ALL)
+                .setGroup("grouped")
+                .setGroupSummary(false)
+                .build();
+
+        if (Build.VERSION.SDK_INT >= 20 && !BuildCompat.isAtLeastO()) {
+            assertNotNull(n.sound);
+            assertNotNull(n.vibrate);
+            assertTrue((n.defaults & DEFAULT_LIGHTS) != 0);
+            assertTrue((n.defaults & DEFAULT_SOUND) != 0);
+            assertTrue((n.defaults & DEFAULT_VIBRATE) != 0);
+
+            assertNotNull(n2.sound);
+            assertNotNull(n2.vibrate);
+            assertTrue((n2.defaults & DEFAULT_LIGHTS) != 0);
+            assertTrue((n2.defaults & DEFAULT_SOUND) != 0);
+            assertTrue((n2.defaults & DEFAULT_VIBRATE) != 0);
+
+            assertNotNull(n3.sound);
+            assertNotNull(n3.vibrate);
+            assertTrue((n3.defaults & DEFAULT_LIGHTS) != 0);
+            assertTrue((n3.defaults & DEFAULT_SOUND) != 0);
+            assertTrue((n3.defaults & DEFAULT_VIBRATE) != 0);
+        }
+    }
+
+    @Test
+    public void testGroupAlertBehavior_doesNotMuteNonGroupNotifications() throws Throwable {
+        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setGroupAlertBehavior(GROUP_ALERT_CHILDREN)
+                .setVibrate(new long[] {235})
+                .setSound(Uri.EMPTY)
+                .setDefaults(DEFAULT_ALL)
+                .setGroup(null)
+                .setGroupSummary(false)
+                .build();
+        if (!BuildCompat.isAtLeastO()) {
+            assertNotNull(n.sound);
+            assertNotNull(n.vibrate);
+            assertTrue((n.defaults & DEFAULT_LIGHTS) != 0);
+            assertTrue((n.defaults & DEFAULT_SOUND) != 0);
+            assertTrue((n.defaults & DEFAULT_VIBRATE) != 0);
+        }
+    }
+
     private static RemoteInput newDataOnlyRemoteInput() {
         return new RemoteInput.Builder(DATA_RESULT_KEY)
             .setAllowFreeFormInput(false)