Home | History | Annotate | Download | only in app
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package androidx.core.app;
     18 
     19 import static androidx.core.app.NotificationCompat.DEFAULT_ALL;
     20 import static androidx.core.app.NotificationCompat.DEFAULT_LIGHTS;
     21 import static androidx.core.app.NotificationCompat.DEFAULT_SOUND;
     22 import static androidx.core.app.NotificationCompat.DEFAULT_VIBRATE;
     23 import static androidx.core.app.NotificationCompat.GROUP_ALERT_ALL;
     24 import static androidx.core.app.NotificationCompat.GROUP_ALERT_CHILDREN;
     25 import static androidx.core.app.NotificationCompat.GROUP_ALERT_SUMMARY;
     26 
     27 import static org.junit.Assert.assertEquals;
     28 import static org.junit.Assert.assertFalse;
     29 import static org.junit.Assert.assertNotNull;
     30 import static org.junit.Assert.assertNull;
     31 import static org.junit.Assert.assertSame;
     32 import static org.junit.Assert.assertTrue;
     33 import static org.junit.Assert.fail;
     34 
     35 import android.app.Notification;
     36 import android.content.Context;
     37 import android.graphics.Color;
     38 import android.media.AudioAttributes;
     39 import android.media.AudioManager;
     40 import android.net.Uri;
     41 import android.os.Build;
     42 import android.os.Bundle;
     43 import android.support.test.filters.SdkSuppress;
     44 import android.support.test.filters.SmallTest;
     45 import android.support.test.runner.AndroidJUnit4;
     46 import android.support.v4.BaseInstrumentationTestCase;
     47 
     48 import androidx.core.app.NotificationCompat.MessagingStyle.Message;
     49 
     50 import org.junit.Before;
     51 import org.junit.Test;
     52 import org.junit.runner.RunWith;
     53 
     54 import java.util.ArrayList;
     55 import java.util.List;
     56 
     57 
     58 @RunWith(AndroidJUnit4.class)
     59 @SmallTest
     60 public class NotificationCompatTest extends BaseInstrumentationTestCase<TestActivity> {
     61     private static final String TEXT_RESULT_KEY = "text";
     62     private static final String DATA_RESULT_KEY = "data";
     63     private static final String EXTRA_COLORIZED = "android.colorized";
     64 
     65     Context mContext;
     66 
     67     public NotificationCompatTest() {
     68         super(TestActivity.class);
     69     }
     70 
     71     @Before
     72     public void setup() {
     73         mContext = mActivityTestRule.getActivity();
     74     }
     75 
     76     @Test
     77     public void testBadgeIcon() throws Throwable {
     78         int badgeIcon = NotificationCompat.BADGE_ICON_SMALL;
     79         Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
     80                 .setBadgeIconType(badgeIcon)
     81                 .build();
     82         if (Build.VERSION.SDK_INT >= 26) {
     83             assertEquals(badgeIcon, NotificationCompat.getBadgeIconType(n));
     84         } else {
     85             assertEquals(NotificationCompat.BADGE_ICON_NONE,
     86                     NotificationCompat.getBadgeIconType(n));
     87         }
     88     }
     89 
     90     @Test
     91     public void testTimeout() throws Throwable {
     92         long timeout = 23552;
     93         Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
     94                 .setTimeoutAfter(timeout)
     95                 .build();
     96         if (Build.VERSION.SDK_INT >= 26) {
     97             assertEquals(timeout, NotificationCompat.getTimeoutAfter(n));
     98         } else {
     99             assertEquals(0, NotificationCompat.getTimeoutAfter(n));
    100         }
    101     }
    102 
    103     @Test
    104     public void testShortcutId() throws Throwable {
    105         String shortcutId = "fgdfg";
    106         Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
    107                 .setShortcutId(shortcutId)
    108                 .build();
    109         if (Build.VERSION.SDK_INT >= 26) {
    110             assertEquals(shortcutId, NotificationCompat.getShortcutId(n));
    111         } else {
    112             assertEquals(null, NotificationCompat.getShortcutId(n));
    113         }
    114     }
    115 
    116     @Test
    117     public void testNotificationChannel() throws Throwable {
    118         String channelId = "new ID";
    119         Notification n  = new NotificationCompat.Builder(mActivityTestRule.getActivity())
    120                 .setChannelId(channelId)
    121                 .build();
    122         if (Build.VERSION.SDK_INT >= 26) {
    123             assertEquals(channelId, NotificationCompat.getChannelId(n));
    124         } else {
    125             assertNull(NotificationCompat.getChannelId(n));
    126         }
    127     }
    128 
    129     @Test
    130     public void testNotificationChannel_assignedFromBuilder() throws Throwable {
    131         String channelId = "new ID";
    132         Notification n  = new NotificationCompat.Builder(mActivityTestRule.getActivity(), channelId)
    133                 .build();
    134         if (Build.VERSION.SDK_INT >= 26) {
    135             assertEquals(channelId, NotificationCompat.getChannelId(n));
    136         } else {
    137             assertNull(NotificationCompat.getChannelId(n));
    138         }
    139     }
    140 
    141     @Test
    142     public void testNotificationActionBuilder_assignsColorized() throws Throwable {
    143         Notification n = newNotificationBuilder().setColorized(true).build();
    144         if (Build.VERSION.SDK_INT >= 26) {
    145             Bundle extras = NotificationCompat.getExtras(n);
    146             assertTrue(Boolean.TRUE.equals(extras.get(EXTRA_COLORIZED)));
    147         }
    148     }
    149 
    150     @Test
    151     public void testNotificationActionBuilder_unassignesColorized() throws Throwable {
    152         Notification n = newNotificationBuilder().setColorized(false).build();
    153         if (Build.VERSION.SDK_INT >= 26) {
    154             Bundle extras = NotificationCompat.getExtras(n);
    155             assertTrue(Boolean.FALSE.equals(extras.get(EXTRA_COLORIZED)));
    156         }
    157     }
    158 
    159     @Test
    160     public void testNotificationActionBuilder_doesntAssignColorized() throws Throwable {
    161         Notification n = newNotificationBuilder().build();
    162         if (Build.VERSION.SDK_INT >= 26) {
    163             Bundle extras = NotificationCompat.getExtras(n);
    164             assertFalse(extras.containsKey(EXTRA_COLORIZED));
    165         }
    166     }
    167 
    168     @Test
    169     public void testNotificationActionBuilder_copiesRemoteInputs() throws Throwable {
    170         NotificationCompat.Action a = newActionBuilder()
    171                 .addRemoteInput(new RemoteInput("a", "b", null, false, null, null)).build();
    172 
    173         NotificationCompat.Action aCopy = new NotificationCompat.Action.Builder(a).build();
    174 
    175         assertSame(a.getRemoteInputs()[0], aCopy.getRemoteInputs()[0]);
    176     }
    177 
    178     @Test
    179     public void testNotificationActionBuilder_copiesAllowGeneratedReplies() throws Throwable {
    180         NotificationCompat.Action a = newActionBuilder()
    181                 .setAllowGeneratedReplies(true).build();
    182 
    183         NotificationCompat.Action aCopy = new NotificationCompat.Action.Builder(a).build();
    184 
    185         assertEquals(a.getAllowGeneratedReplies(), aCopy.getAllowGeneratedReplies());
    186     }
    187 
    188     @SdkSuppress(minSdkVersion = 24)
    189     @Test
    190     public void testFrameworkNotificationActionBuilder_setAllowGeneratedRepliesTrue()
    191             throws Throwable {
    192         Notification notif = new Notification.Builder(mContext)
    193                 .addAction(new Notification.Action.Builder(0, "title", null)
    194                         .setAllowGeneratedReplies(true).build()).build();
    195         NotificationCompat.Action action = NotificationCompat.getAction(notif, 0);
    196         assertTrue(action.getAllowGeneratedReplies());
    197     }
    198 
    199     @Test
    200     public void testNotificationActionBuilder_defaultAllowGeneratedRepliesTrue() throws Throwable {
    201         NotificationCompat.Action a = newActionBuilder().build();
    202 
    203         assertTrue(a.getAllowGeneratedReplies());
    204     }
    205 
    206     @Test
    207     public void testNotificationActionBuilder_defaultShowsUserInterfaceTrue() {
    208         NotificationCompat.Action action = newActionBuilder().build();
    209 
    210         assertTrue(action.getShowsUserInterface());
    211     }
    212 
    213     @Test
    214     public void testNotificationAction_defaultAllowGeneratedRepliesTrue() throws Throwable {
    215         NotificationCompat.Action a = new NotificationCompat.Action(0, null, null);
    216 
    217         assertTrue(a.getAllowGeneratedReplies());
    218     }
    219 
    220     @Test
    221     public void testNotificationAction_defaultShowsUserInterfaceTrue() {
    222         NotificationCompat.Action action = new NotificationCompat.Action(0, null, null);
    223 
    224         assertTrue(action.getShowsUserInterface());
    225     }
    226 
    227     @Test
    228     public void testNotificationActionBuilder_setAllowGeneratedRepliesFalse() throws Throwable {
    229         NotificationCompat.Action a = newActionBuilder()
    230                 .setAllowGeneratedReplies(false).build();
    231 
    232         assertFalse(a.getAllowGeneratedReplies());
    233     }
    234 
    235     @Test
    236     public void testNotificationAction_setShowsUserInterfaceFalse() {
    237         NotificationCompat.Action action = newActionBuilder()
    238                 .setShowsUserInterface(false).build();
    239 
    240         assertFalse(action.getShowsUserInterface());
    241     }
    242 
    243     @SdkSuppress(minSdkVersion = 20)
    244     @Test
    245     public void testGetActionCompatFromAction_showsUserInterface() {
    246         NotificationCompat.Action action = newActionBuilder()
    247                 .setShowsUserInterface(false).build();
    248         Notification notification = newNotificationBuilder().addAction(action).build();
    249         NotificationCompat.Action result =
    250                 NotificationCompat.getActionCompatFromAction(notification.actions[0]);
    251 
    252         assertFalse(result.getExtras().getBoolean(
    253                 NotificationCompat.Action.EXTRA_SHOWS_USER_INTERFACE, true));
    254         assertFalse(result.getShowsUserInterface());
    255     }
    256 
    257     @SdkSuppress(minSdkVersion = 17)
    258     @Test
    259     public void testNotificationWearableExtenderAction_setAllowGeneratedRepliesTrue()
    260             throws Throwable {
    261         NotificationCompat.Action a = newActionBuilder()
    262                 .setAllowGeneratedReplies(true).build();
    263         NotificationCompat.WearableExtender extender = new NotificationCompat.WearableExtender()
    264                 .addAction(a);
    265         Notification notification = newNotificationBuilder().extend(extender).build();
    266         assertTrue(new NotificationCompat.WearableExtender(notification).getActions().get(0)
    267                 .getAllowGeneratedReplies());
    268     }
    269 
    270     @SdkSuppress(minSdkVersion = 17)
    271     @Test
    272     public void testNotificationWearableExtenderAction_setAllowGeneratedRepliesFalse()
    273             throws Throwable {
    274         NotificationCompat.Action a = newActionBuilder()
    275                 .setAllowGeneratedReplies(false).build();
    276         NotificationCompat.WearableExtender extender = new NotificationCompat.WearableExtender()
    277                 .addAction(a);
    278         Notification notification = newNotificationBuilder().extend(extender).build();
    279         assertFalse(new NotificationCompat.WearableExtender(notification).getActions().get(0)
    280                 .getAllowGeneratedReplies());
    281     }
    282 
    283 
    284     @SdkSuppress(maxSdkVersion = 16)
    285     @SmallTest
    286     @Test
    287     public void testNotificationWearableExtenderAction_noActions()
    288             throws Throwable {
    289         NotificationCompat.Action a = newActionBuilder()
    290                 .setAllowGeneratedReplies(true).build();
    291         NotificationCompat.WearableExtender extender = new NotificationCompat.WearableExtender()
    292                 .addAction(a);
    293         Notification notification = newNotificationBuilder().extend(extender).build();
    294         assertTrue(new NotificationCompat.WearableExtender(notification).getActions().size() == 0);
    295     }
    296 
    297     @Test
    298     public void testNotificationActionBuilder_setDataOnlyRemoteInput() throws Throwable {
    299         NotificationCompat.Action a = newActionBuilder()
    300                 .addRemoteInput(newDataOnlyRemoteInput()).build();
    301         RemoteInput[] textInputs = a.getRemoteInputs();
    302         assertTrue(textInputs == null || textInputs.length == 0);
    303         verifyRemoteInputArrayHasSingleResult(a.getDataOnlyRemoteInputs(), DATA_RESULT_KEY);
    304     }
    305 
    306     @Test
    307     public void testNotificationActionBuilder_setTextAndDataOnlyRemoteInput() throws Throwable {
    308         NotificationCompat.Action a = newActionBuilder()
    309                 .addRemoteInput(newDataOnlyRemoteInput())
    310                 .addRemoteInput(newTextRemoteInput())
    311                 .build();
    312 
    313         verifyRemoteInputArrayHasSingleResult(a.getRemoteInputs(), TEXT_RESULT_KEY);
    314         verifyRemoteInputArrayHasSingleResult(a.getDataOnlyRemoteInputs(), DATA_RESULT_KEY);
    315     }
    316 
    317     @Test
    318     public void testMessage_setAndGetExtras() throws Throwable {
    319         String extraKey = "extra_key";
    320         CharSequence extraValue = "extra_value";
    321         Message m =
    322                 new Message("text", 0 /*timestamp */, "sender");
    323         m.getExtras().putCharSequence(extraKey, extraValue);
    324         assertEquals(extraValue, m.getExtras().getCharSequence(extraKey));
    325 
    326         ArrayList<Message> messages = new ArrayList<>(1);
    327         messages.add(m);
    328         Bundle[] bundleArray =
    329                 Message.getBundleArrayForMessages(messages);
    330         assertEquals(1, bundleArray.length);
    331         Message fromBundle =
    332                 Message.getMessageFromBundle(bundleArray[0]);
    333         assertEquals(extraValue, fromBundle.getExtras().getCharSequence(extraKey));
    334     }
    335 
    336     @Test
    337     public void testGetGroupAlertBehavior() throws Throwable {
    338         Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
    339                 .setGroupAlertBehavior(GROUP_ALERT_CHILDREN)
    340                 .build();
    341         if (Build.VERSION.SDK_INT >= 26) {
    342             assertEquals(GROUP_ALERT_CHILDREN, NotificationCompat.getGroupAlertBehavior(n));
    343         } else {
    344             assertEquals(GROUP_ALERT_ALL, NotificationCompat.getGroupAlertBehavior(n));
    345         }
    346     }
    347 
    348     @Test
    349     public void testGroupAlertBehavior_mutesGroupNotifications() throws Throwable {
    350         // valid between api 20, when groups were added, and api 25, the last to use sound
    351         // and vibration from the notification itself
    352 
    353         Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
    354                 .setGroupAlertBehavior(GROUP_ALERT_CHILDREN)
    355                 .setVibrate(new long[] {235})
    356                 .setSound(Uri.EMPTY)
    357                 .setDefaults(DEFAULT_ALL)
    358                 .setGroup("grouped")
    359                 .setGroupSummary(true)
    360                 .build();
    361 
    362         Notification n2 = new NotificationCompat.Builder(mActivityTestRule.getActivity())
    363                 .setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
    364                 .setVibrate(new long[] {235})
    365                 .setSound(Uri.EMPTY)
    366                 .setDefaults(DEFAULT_ALL)
    367                 .setGroup("grouped")
    368                 .setGroupSummary(false)
    369                 .build();
    370 
    371         if (Build.VERSION.SDK_INT >= 20 && !(Build.VERSION.SDK_INT >= 26)) {
    372             assertNull(n.sound);
    373             assertNull(n.vibrate);
    374             assertTrue((n.defaults & DEFAULT_LIGHTS) != 0);
    375             assertTrue((n.defaults & DEFAULT_SOUND) == 0);
    376             assertTrue((n.defaults & DEFAULT_VIBRATE) == 0);
    377 
    378             assertNull(n2.sound);
    379             assertNull(n2.vibrate);
    380             assertTrue((n2.defaults & DEFAULT_LIGHTS) != 0);
    381             assertTrue((n2.defaults & DEFAULT_SOUND) == 0);
    382             assertTrue((n2.defaults & DEFAULT_VIBRATE) == 0);
    383         } else if (Build.VERSION.SDK_INT < 20) {
    384             assertNotNull(n.sound);
    385             assertNotNull(n.vibrate);
    386             assertTrue((n.defaults & DEFAULT_LIGHTS) != 0);
    387             assertTrue((n.defaults & DEFAULT_SOUND) != 0);
    388             assertTrue((n.defaults & DEFAULT_VIBRATE) != 0);
    389 
    390             assertNotNull(n2.sound);
    391             assertNotNull(n2.vibrate);
    392             assertTrue((n2.defaults & DEFAULT_LIGHTS) != 0);
    393             assertTrue((n2.defaults & DEFAULT_SOUND) != 0);
    394             assertTrue((n2.defaults & DEFAULT_VIBRATE) != 0);
    395         }
    396     }
    397 
    398     @Test
    399     public void testGroupAlertBehavior_doesNotMuteIncorrectGroupNotifications() throws Throwable {
    400         Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
    401                 .setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
    402                 .setVibrate(new long[] {235})
    403                 .setSound(Uri.EMPTY)
    404                 .setDefaults(DEFAULT_ALL)
    405                 .setGroup("grouped")
    406                 .setGroupSummary(true)
    407                 .build();
    408 
    409         Notification n2 = new NotificationCompat.Builder(mActivityTestRule.getActivity())
    410                 .setGroupAlertBehavior(GROUP_ALERT_CHILDREN)
    411                 .setVibrate(new long[] {235})
    412                 .setSound(Uri.EMPTY)
    413                 .setDefaults(DEFAULT_ALL)
    414                 .setGroup("grouped")
    415                 .setGroupSummary(false)
    416                 .build();
    417 
    418         Notification n3 = new NotificationCompat.Builder(mActivityTestRule.getActivity())
    419                 .setVibrate(new long[] {235})
    420                 .setSound(Uri.EMPTY)
    421                 .setDefaults(DEFAULT_ALL)
    422                 .setGroup("grouped")
    423                 .setGroupSummary(false)
    424                 .build();
    425 
    426         if (Build.VERSION.SDK_INT >= 20 && !(Build.VERSION.SDK_INT >= 26)) {
    427             assertNotNull(n.sound);
    428             assertNotNull(n.vibrate);
    429             assertTrue((n.defaults & DEFAULT_LIGHTS) != 0);
    430             assertTrue((n.defaults & DEFAULT_SOUND) != 0);
    431             assertTrue((n.defaults & DEFAULT_VIBRATE) != 0);
    432 
    433             assertNotNull(n2.sound);
    434             assertNotNull(n2.vibrate);
    435             assertTrue((n2.defaults & DEFAULT_LIGHTS) != 0);
    436             assertTrue((n2.defaults & DEFAULT_SOUND) != 0);
    437             assertTrue((n2.defaults & DEFAULT_VIBRATE) != 0);
    438 
    439             assertNotNull(n3.sound);
    440             assertNotNull(n3.vibrate);
    441             assertTrue((n3.defaults & DEFAULT_LIGHTS) != 0);
    442             assertTrue((n3.defaults & DEFAULT_SOUND) != 0);
    443             assertTrue((n3.defaults & DEFAULT_VIBRATE) != 0);
    444         }
    445     }
    446 
    447     @Test
    448     public void testGroupAlertBehavior_doesNotMuteNonGroupNotifications() throws Throwable {
    449         Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
    450                 .setGroupAlertBehavior(GROUP_ALERT_CHILDREN)
    451                 .setVibrate(new long[] {235})
    452                 .setSound(Uri.EMPTY)
    453                 .setDefaults(DEFAULT_ALL)
    454                 .setGroup(null)
    455                 .setGroupSummary(false)
    456                 .build();
    457         if (!(Build.VERSION.SDK_INT >= 26)) {
    458             assertNotNull(n.sound);
    459             assertNotNull(n.vibrate);
    460             assertTrue((n.defaults & DEFAULT_LIGHTS) != 0);
    461             assertTrue((n.defaults & DEFAULT_SOUND) != 0);
    462             assertTrue((n.defaults & DEFAULT_VIBRATE) != 0);
    463         }
    464     }
    465 
    466     @Test
    467     @SdkSuppress(minSdkVersion = 21)
    468     public void testHasAudioAttributesFrom21() throws Throwable {
    469         Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
    470                 .setSound(Uri.EMPTY)
    471                 .build();
    472         assertNotNull(n.audioAttributes);
    473         assertEquals(-1, n.audioStreamType);
    474         assertEquals(Uri.EMPTY, n.sound);
    475 
    476         n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
    477                 .setSound(Uri.EMPTY, AudioManager.STREAM_RING)
    478                 .build();
    479         assertNotNull(n.audioAttributes);
    480         assertEquals(AudioAttributes.CONTENT_TYPE_SONIFICATION,
    481                 n.audioAttributes.getContentType());
    482         assertEquals(-1, n.audioStreamType);
    483         assertEquals(Uri.EMPTY, n.sound);
    484     }
    485 
    486     @Test
    487     @SdkSuppress(maxSdkVersion = 20)
    488     public void testHasStreamTypePre21() throws Throwable {
    489         Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
    490                 .setSound(Uri.EMPTY, 34)
    491                 .build();
    492         assertEquals(34, n.audioStreamType);
    493         assertEquals(Uri.EMPTY, n.sound);
    494     }
    495 
    496     @SdkSuppress(minSdkVersion = 26)
    497     @Test
    498     public void testClearAlertingFieldsIfUsingChannels() throws Throwable {
    499         long[] vibration = new long[]{100};
    500 
    501         // stripped if using channels
    502         Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity(), "test")
    503                 .setSound(Uri.EMPTY)
    504                 .setDefaults(Notification.DEFAULT_ALL)
    505                 .setVibrate(vibration)
    506                 .setLights(Color.BLUE, 100, 100)
    507                 .build();
    508         assertNull(n.sound);
    509         assertEquals(0, n.defaults);
    510         assertNull(n.vibrate);
    511         assertEquals(0, n.ledARGB);
    512         assertEquals(0, n.ledOnMS);
    513         assertEquals(0, n.ledOffMS);
    514 
    515         // left intact if not using channels
    516         n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
    517                 .setSound(Uri.EMPTY)
    518                 .setDefaults(Notification.DEFAULT_ALL)
    519                 .setVibrate(vibration)
    520                 .setLights(Color.BLUE, 100, 100)
    521                 .build();
    522         assertEquals(Uri.EMPTY, n.sound);
    523         assertNotNull(n.audioAttributes);
    524         assertEquals(Notification.DEFAULT_ALL, n.defaults);
    525         assertEquals(vibration, n.vibrate);
    526         assertEquals(Color.BLUE, n.ledARGB);
    527         assertEquals(100, n.ledOnMS);
    528         assertEquals(100, n.ledOffMS);
    529     }
    530 
    531     @Test
    532     public void testMessagingStyle_nullPerson() {
    533         NotificationCompat.MessagingStyle messagingStyle =
    534                 new NotificationCompat.MessagingStyle("self name");
    535         messagingStyle.addMessage("text", 200, (Person) null);
    536 
    537         Notification notification = new NotificationCompat.Builder(mContext, "test id")
    538                 .setSmallIcon(1)
    539                 .setContentTitle("test title")
    540                 .setStyle(messagingStyle)
    541                 .build();
    542 
    543         List<Message> result = NotificationCompat.MessagingStyle
    544                 .extractMessagingStyleFromNotification(notification)
    545                 .getMessages();
    546 
    547         assertEquals(1, result.size());
    548         assertEquals("text", result.get(0).getText());
    549         assertEquals(200, result.get(0).getTimestamp());
    550         assertNull(result.get(0).getPerson());
    551         assertNull(result.get(0).getSender());
    552     }
    553 
    554     @Test
    555     public void testMessagingStyle_message() {
    556         NotificationCompat.MessagingStyle messagingStyle =
    557                 new NotificationCompat.MessagingStyle("self name");
    558         Person person = new Person.Builder().setName("test name").setKey("key").build();
    559         Person person2 = new Person.Builder()
    560                 .setName("test name 2").setKey("key 2").setImportant(true).build();
    561         messagingStyle.addMessage("text", 200, person);
    562         messagingStyle.addMessage("text2", 300, person2);
    563 
    564         Notification notification = new NotificationCompat.Builder(mContext, "test id")
    565                 .setSmallIcon(1)
    566                 .setContentTitle("test title")
    567                 .setStyle(messagingStyle)
    568                 .build();
    569 
    570         List<Message> result = NotificationCompat.MessagingStyle
    571                 .extractMessagingStyleFromNotification(notification)
    572                 .getMessages();
    573 
    574         assertEquals(2, result.size());
    575         assertEquals("text", result.get(0).getText());
    576         assertEquals(200, result.get(0).getTimestamp());
    577         assertEquals("test name", result.get(0).getPerson().getName());
    578         assertEquals("key", result.get(0).getPerson().getKey());
    579         assertEquals("text2", result.get(1).getText());
    580         assertEquals(300, result.get(1).getTimestamp());
    581         assertEquals("test name 2", result.get(1).getPerson().getName());
    582         assertEquals("key 2", result.get(1).getPerson().getKey());
    583         assertTrue(result.get(1).getPerson().isImportant());
    584     }
    585 
    586     @Test
    587     public void testMessagingStyle_requiresNonEmptyUserName() {
    588         try {
    589             new NotificationCompat.MessagingStyle(new Person.Builder().build());
    590             fail("Expected IllegalArgumentException about a non-empty user name.");
    591         } catch (IllegalArgumentException e) {
    592             // Expected
    593         }
    594     }
    595 
    596     @Test
    597     public void testMessagingStyle_isGroupConversation() {
    598         mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.P;
    599         NotificationCompat.MessagingStyle messagingStyle =
    600                 new NotificationCompat.MessagingStyle("self name")
    601                         .setGroupConversation(true)
    602                         .setConversationTitle("test conversation title");
    603         Notification notification = new NotificationCompat.Builder(mContext, "test id")
    604                 .setSmallIcon(1)
    605                 .setContentTitle("test title")
    606                 .setStyle(messagingStyle)
    607                 .build();
    608 
    609         NotificationCompat.MessagingStyle result =
    610                 NotificationCompat.MessagingStyle
    611                         .extractMessagingStyleFromNotification(notification);
    612 
    613         assertTrue(result.isGroupConversation());
    614     }
    615 
    616     @Test
    617     public void testMessagingStyle_isGroupConversation_noConversationTitle() {
    618         mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.P;
    619         NotificationCompat.MessagingStyle messagingStyle =
    620                 new NotificationCompat.MessagingStyle("self name")
    621                         .setGroupConversation(true)
    622                         .setConversationTitle(null);
    623         Notification notification = new NotificationCompat.Builder(mContext, "test id")
    624                 .setSmallIcon(1)
    625                 .setContentTitle("test title")
    626                 .setStyle(messagingStyle)
    627                 .build();
    628 
    629         NotificationCompat.MessagingStyle result =
    630                 NotificationCompat.MessagingStyle
    631                         .extractMessagingStyleFromNotification(notification);
    632 
    633         assertTrue(result.isGroupConversation());
    634     }
    635 
    636     @Test
    637     public void testMessagingStyle_isGroupConversation_withConversationTitle_legacy() {
    638         // In legacy (version < P), isGroupConversation is controlled by conversationTitle.
    639         mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.O;
    640         NotificationCompat.MessagingStyle messagingStyle =
    641                 new NotificationCompat.MessagingStyle("self name")
    642                         .setConversationTitle("test conversation title");
    643         Notification notification = new NotificationCompat.Builder(mContext, "test id")
    644                 .setSmallIcon(1)
    645                 .setContentTitle("test title")
    646                 .setStyle(messagingStyle)
    647                 .build();
    648 
    649         NotificationCompat.MessagingStyle result =
    650                 NotificationCompat.MessagingStyle
    651                         .extractMessagingStyleFromNotification(notification);
    652 
    653         assertTrue(result.isGroupConversation());
    654     }
    655 
    656     @Test
    657     public void testMessagingStyle_isGroupConversation_withoutConversationTitle_legacy() {
    658         // In legacy (version < P), isGroupConversation is controlled by conversationTitle.
    659         mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.O;
    660         NotificationCompat.MessagingStyle messagingStyle =
    661                 new NotificationCompat.MessagingStyle("self name")
    662                         .setConversationTitle(null);
    663         Notification notification = new NotificationCompat.Builder(mContext, "test id")
    664                 .setSmallIcon(1)
    665                 .setContentTitle("test title")
    666                 .setStyle(messagingStyle)
    667                 .build();
    668 
    669         NotificationCompat.MessagingStyle result =
    670                 NotificationCompat.MessagingStyle
    671                         .extractMessagingStyleFromNotification(notification);
    672 
    673         assertFalse(result.isGroupConversation());
    674     }
    675 
    676     @Test
    677     public void testMessagingStyle_isGroupConversation_withConversationTitle_legacyWithOverride() {
    678         // #setGroupConversation should always take precedence over legacy behavior, so a non-null
    679         // title shouldn't affect #isGroupConversation.
    680         mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.O;
    681         NotificationCompat.MessagingStyle messagingStyle =
    682                 new NotificationCompat.MessagingStyle("self name")
    683                         .setGroupConversation(false)
    684                         .setConversationTitle("test conversation title");
    685         Notification notification = new NotificationCompat.Builder(mContext, "test id")
    686                 .setSmallIcon(1)
    687                 .setContentTitle("test title")
    688                 .setStyle(messagingStyle)
    689                 .build();
    690 
    691         NotificationCompat.MessagingStyle result =
    692                 NotificationCompat.MessagingStyle
    693                         .extractMessagingStyleFromNotification(notification);
    694 
    695         assertFalse(result.isGroupConversation());
    696     }
    697 
    698     @Test
    699     public void testMessagingStyle_isGroupConversation_withoutTitle_legacyWithOverride() {
    700         // #setGroupConversation should always take precedence over legacy behavior, so a null
    701         // title shouldn't affect #isGroupConversation.
    702         mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.O;
    703         NotificationCompat.MessagingStyle messagingStyle =
    704                 new NotificationCompat.MessagingStyle("self name")
    705                         .setGroupConversation(true)
    706                         .setConversationTitle(null);
    707         Notification notification = new NotificationCompat.Builder(mContext, "test id")
    708                 .setSmallIcon(1)
    709                 .setContentTitle("test title")
    710                 .setStyle(messagingStyle)
    711                 .build();
    712 
    713         NotificationCompat.MessagingStyle result =
    714                 NotificationCompat.MessagingStyle
    715                         .extractMessagingStyleFromNotification(notification);
    716 
    717         assertTrue(result.isGroupConversation());
    718     }
    719 
    720     @SdkSuppress(minSdkVersion = 28)
    721     @Test
    722     public void testMessagingStyle_applyNoTitleAndNotGroup() {
    723         NotificationCompat.MessagingStyle messagingStyle =
    724                 new NotificationCompat.MessagingStyle("self name")
    725                         .setGroupConversation(false)
    726                         .addMessage(
    727                                 new Message(
    728                                         "body",
    729                                         1,
    730                                         new Person.Builder().setName("example name").build()))
    731                         .addMessage(new Message("body 2", 2, (Person) null));
    732 
    733         Notification resultNotification = new NotificationCompat.Builder(mContext, "test id")
    734                 .setStyle(messagingStyle)
    735                 .build();
    736         NotificationCompat.MessagingStyle resultCompatMessagingStyle =
    737                 NotificationCompat.MessagingStyle
    738                         .extractMessagingStyleFromNotification(resultNotification);
    739 
    740         // SDK >= 28 applies no title when none is provided to MessagingStyle.
    741         assertNull(resultCompatMessagingStyle.getConversationTitle());
    742         assertFalse(resultCompatMessagingStyle.isGroupConversation());
    743     }
    744 
    745     @SdkSuppress(minSdkVersion = 24, maxSdkVersion = 27)
    746     @Test
    747     public void testMessagingStyle_applyNoTitleAndNotGroup_legacy() {
    748         NotificationCompat.MessagingStyle messagingStyle =
    749                 new NotificationCompat.MessagingStyle("self name")
    750                         .setGroupConversation(false)
    751                         .addMessage(
    752                                 new Message(
    753                                         "body",
    754                                         1,
    755                                         new Person.Builder().setName("example name").build()))
    756                         .addMessage(new Message("body 2", 2, (Person) null));
    757 
    758         Notification resultNotification = new NotificationCompat.Builder(mContext, "test id")
    759                 .setStyle(messagingStyle)
    760                 .build();
    761         NotificationCompat.MessagingStyle resultCompatMessagingStyle =
    762                 NotificationCompat.MessagingStyle
    763                         .extractMessagingStyleFromNotification(resultNotification);
    764 
    765         // SDK [24, 27] applies first incoming message sender name as Notification content title.
    766         assertEquals("example name", NotificationCompat.getContentTitle(resultNotification));
    767         assertNull(resultCompatMessagingStyle.getConversationTitle());
    768         assertFalse(resultCompatMessagingStyle.isGroupConversation());
    769     }
    770 
    771     @SdkSuppress(minSdkVersion = 28)
    772     @Test
    773     public void testMessagingStyle_applyConversationTitleAndNotGroup() {
    774         NotificationCompat.MessagingStyle messagingStyle =
    775                 new NotificationCompat.MessagingStyle("self name")
    776                         .setGroupConversation(false)
    777                         .setConversationTitle("test title");
    778 
    779         Notification resultNotification = new NotificationCompat.Builder(mContext, "test id")
    780                 .setStyle(messagingStyle)
    781                 .build();
    782         NotificationCompat.MessagingStyle resultMessagingStyle =
    783                 NotificationCompat.MessagingStyle
    784                         .extractMessagingStyleFromNotification(resultNotification);
    785 
    786         // SDK >= 28 applies provided title to MessagingStyle.
    787         assertEquals("test title", resultMessagingStyle.getConversationTitle());
    788         assertFalse(resultMessagingStyle.isGroupConversation());
    789     }
    790 
    791     @SdkSuppress(minSdkVersion = 19, maxSdkVersion = 27)
    792     @Test
    793     public void testMessagingStyle_applyConversationTitleAndNotGroup_legacy() {
    794         NotificationCompat.MessagingStyle messagingStyle =
    795                 new NotificationCompat.MessagingStyle("self name")
    796                         .setGroupConversation(false)
    797                         .setConversationTitle("test title");
    798 
    799         Notification resultNotification = new NotificationCompat.Builder(mContext, "test id")
    800                 .setStyle(messagingStyle)
    801                 .build();
    802         NotificationCompat.MessagingStyle resultMessagingStyle =
    803                 NotificationCompat.MessagingStyle
    804                         .extractMessagingStyleFromNotification(resultNotification);
    805 
    806         // SDK <= 27 applies MessagingStyle title as Notification content title.
    807         assertEquals("test title", NotificationCompat.getContentTitle(resultNotification));
    808         assertEquals("test title", resultMessagingStyle.getConversationTitle());
    809         assertFalse(resultMessagingStyle.isGroupConversation());
    810     }
    811 
    812     @Test
    813     public void testMessagingStyle_restoreFromCompatExtras() {
    814         NotificationCompat.MessagingStyle messagingStyle =
    815                 new NotificationCompat.MessagingStyle(
    816                         new Person.Builder().setName("test name").build())
    817                         .setGroupConversation(true);
    818         Bundle bundle = new Bundle();
    819         messagingStyle.addCompatExtras(bundle);
    820 
    821         NotificationCompat.MessagingStyle resultMessagingStyle =
    822                 new NotificationCompat.MessagingStyle(new Person.Builder().setName("temp").build());
    823         resultMessagingStyle.restoreFromCompatExtras(bundle);
    824 
    825         assertTrue(resultMessagingStyle.isGroupConversation());
    826         assertEquals("test name", resultMessagingStyle.getUser().getName());
    827     }
    828 
    829     @Test
    830     public void testMessagingStyleMessage_bundle_legacySender() {
    831         Bundle legacyBundle = new Bundle();
    832         legacyBundle.putCharSequence(Message.KEY_TEXT, "message");
    833         legacyBundle.putLong(Message.KEY_TIMESTAMP, 100);
    834         legacyBundle.putCharSequence(Message.KEY_SENDER, "sender");
    835 
    836         Message result = Message.getMessageFromBundle(legacyBundle);
    837         assertEquals("sender", result.getPerson().getName());
    838     }
    839 
    840     @Test
    841     public void action_builder_hasDefault() {
    842         NotificationCompat.Action action =
    843                 new NotificationCompat.Action.Builder(0, "Test Title", null).build();
    844         assertEquals(NotificationCompat.Action.SEMANTIC_ACTION_NONE, action.getSemanticAction());
    845     }
    846 
    847     @Test
    848     public void action_builder_setSemanticAction() {
    849         NotificationCompat.Action action =
    850                 new NotificationCompat.Action.Builder(0, "Test Title", null)
    851                         .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY)
    852                         .build();
    853         assertEquals(NotificationCompat.Action.SEMANTIC_ACTION_REPLY, action.getSemanticAction());
    854     }
    855 
    856     @Test
    857     @SdkSuppress(minSdkVersion = 20)
    858     public void action_semanticAction_toAndFromNotification() {
    859         NotificationCompat.Action action =
    860                 new NotificationCompat.Action.Builder(0, "Test Title", null)
    861                         .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY)
    862                         .build();
    863         Notification notification = newNotificationBuilder().addAction(action).build();
    864         NotificationCompat.Action result = NotificationCompat.getAction(notification, 0);
    865 
    866         assertEquals(NotificationCompat.Action.SEMANTIC_ACTION_REPLY, result.getSemanticAction());
    867     }
    868 
    869     private static final NotificationCompat.Action TEST_INVISIBLE_ACTION =
    870             new NotificationCompat.Action.Builder(0, "Test Title", null)
    871                     .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_MUTE)
    872                     .setShowsUserInterface(false)
    873                     .build();
    874 
    875     @Test
    876     @SdkSuppress(minSdkVersion = 21)
    877     public void getInvisibleActions() {
    878         Notification notification =
    879                 newNotificationBuilder().addInvisibleAction(TEST_INVISIBLE_ACTION).build();
    880         verifyInvisibleActionExists(notification);
    881     }
    882 
    883     @Test
    884     @SdkSuppress(minSdkVersion = 21)
    885     public void getInvisibleActions_withCarExtender() {
    886         NotificationCompat.CarExtender carExtender = new NotificationCompat.CarExtender();
    887         Notification notification = newNotificationBuilder()
    888                 .addInvisibleAction(TEST_INVISIBLE_ACTION)
    889                 .extend(carExtender)
    890                 .build();
    891         verifyInvisibleActionExists(notification);
    892     }
    893 
    894     @Test
    895     @SdkSuppress(minSdkVersion = 19)
    896     public void getContentTitle() {
    897         Notification notification = new NotificationCompat.Builder(mContext, "test channel")
    898                 .setContentTitle("example title")
    899                 .build();
    900 
    901         assertEquals("example title", NotificationCompat.getContentTitle(notification));
    902     }
    903 
    904     private static void verifyInvisibleActionExists(Notification notification) {
    905         List<NotificationCompat.Action> result =
    906                 NotificationCompat.getInvisibleActions(notification);
    907         assertTrue("Expecting 1 result, got " + result.size(), result.size() == 1);
    908         NotificationCompat.Action resultAction = result.get(0);
    909         assertEquals(resultAction.getIcon(), TEST_INVISIBLE_ACTION.getIcon());
    910         assertEquals(resultAction.getTitle(), TEST_INVISIBLE_ACTION.getTitle());
    911         assertEquals(
    912                 resultAction.getShowsUserInterface(),
    913                 TEST_INVISIBLE_ACTION.getShowsUserInterface());
    914         assertEquals(resultAction.getSemanticAction(), TEST_INVISIBLE_ACTION.getSemanticAction());
    915     }
    916 
    917     private static RemoteInput newDataOnlyRemoteInput() {
    918         return new RemoteInput.Builder(DATA_RESULT_KEY)
    919             .setAllowFreeFormInput(false)
    920             .setAllowDataType("mimeType", true)
    921             .build();
    922     }
    923 
    924     private static RemoteInput newTextRemoteInput() {
    925         return new RemoteInput.Builder(TEXT_RESULT_KEY).build();  // allowFreeForm defaults to true
    926     }
    927 
    928     private static void verifyRemoteInputArrayHasSingleResult(
    929             RemoteInput[] remoteInputs, String expectedResultKey) {
    930         assertTrue(remoteInputs != null && remoteInputs.length == 1);
    931         assertEquals(expectedResultKey, remoteInputs[0].getResultKey());
    932     }
    933 
    934     private static NotificationCompat.Action.Builder newActionBuilder() {
    935         return new NotificationCompat.Action.Builder(0, "title", null);
    936     }
    937 
    938     private NotificationCompat.Builder newNotificationBuilder() {
    939         return new NotificationCompat.Builder(mContext)
    940                 .setSmallIcon(0)
    941                 .setContentTitle("title")
    942                 .setContentText("text");
    943     }
    944 }
    945