Home | History | Annotate | Download | only in shadows
      1 package org.robolectric.shadows;
      2 
      3 import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL;
      4 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
      5 import static com.google.common.truth.Truth.assertThat;
      6 import static org.junit.Assert.assertEquals;
      7 import static org.junit.Assert.assertNull;
      8 import static org.junit.Assert.fail;
      9 import static org.robolectric.Shadows.shadowOf;
     10 
     11 import android.app.AutomaticZenRule;
     12 import android.app.Notification;
     13 import android.app.NotificationChannel;
     14 import android.app.NotificationChannelGroup;
     15 import android.app.NotificationManager;
     16 import android.app.NotificationManager.Policy;
     17 import android.content.ComponentName;
     18 import android.content.Context;
     19 import android.net.Uri;
     20 import android.os.Build;
     21 import android.service.notification.StatusBarNotification;
     22 import androidx.test.core.app.ApplicationProvider;
     23 import androidx.test.ext.junit.runners.AndroidJUnit4;
     24 import com.google.common.collect.ImmutableList;
     25 import java.util.ArrayList;
     26 import java.util.List;
     27 import org.junit.Before;
     28 import org.junit.Test;
     29 import org.junit.runner.RunWith;
     30 import org.robolectric.annotation.Config;
     31 
     32 @RunWith(AndroidJUnit4.class)
     33 public class ShadowNotificationManagerTest {
     34   private NotificationManager notificationManager;
     35   private Notification notification1 = new Notification();
     36   private Notification notification2 = new Notification();
     37 
     38   @Before public void setUp() {
     39     notificationManager =
     40         (NotificationManager)
     41             ApplicationProvider.getApplicationContext()
     42                 .getSystemService(Context.NOTIFICATION_SERVICE);
     43   }
     44 
     45   @Test
     46   @Config(minSdk = Build.VERSION_CODES.M)
     47   public void getCurrentInterruptionFilter() {
     48     // Sensible default
     49     assertThat(notificationManager.getCurrentInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_ALL);
     50 
     51     notificationManager.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY);
     52     assertThat(notificationManager.getCurrentInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_PRIORITY);
     53   }
     54 
     55   @Test
     56   @Config(minSdk = Build.VERSION_CODES.M)
     57   public void getNotificationPolicy() {
     58     assertThat(notificationManager.getNotificationPolicy()).isNull();
     59 
     60     final Policy policy = new Policy(0, 0, 0);
     61     notificationManager.setNotificationPolicy(policy);
     62     assertThat(notificationManager.getNotificationPolicy()).isEqualTo(policy);
     63   }
     64 
     65   @Test
     66   @Config(minSdk = Build.VERSION_CODES.O)
     67   public void createNotificationChannel() {
     68     notificationManager.createNotificationChannel(new NotificationChannel("id", "name", 1));
     69 
     70     assertThat(shadowOf(notificationManager).getNotificationChannels()).hasSize(1);
     71     NotificationChannel channel = (NotificationChannel)shadowOf(notificationManager)
     72         .getNotificationChannel("id");
     73     assertThat(channel.getName()).isEqualTo("name");
     74     assertThat(channel.getImportance()).isEqualTo(1);
     75   }
     76 
     77   @Test
     78   @Config(minSdk = Build.VERSION_CODES.O)
     79   public void createNotificationChannelGroup() {
     80     notificationManager.createNotificationChannelGroup(new NotificationChannelGroup("id", "name"));
     81 
     82     assertThat(shadowOf(notificationManager).getNotificationChannelGroups()).hasSize(1);
     83     NotificationChannelGroup group = (NotificationChannelGroup)shadowOf(notificationManager)
     84         .getNotificationChannelGroup("id");
     85     assertThat(group.getName()).isEqualTo("name");
     86   }
     87 
     88   @Test
     89   @Config(minSdk = Build.VERSION_CODES.O)
     90   public void createNotificationChannels() {
     91     NotificationChannel channel1 = new NotificationChannel("id", "name", 1);
     92     NotificationChannel channel2 = new NotificationChannel("id2", "name2", 1);
     93 
     94     notificationManager.createNotificationChannels(ImmutableList.of(channel1, channel2));
     95 
     96     assertThat(shadowOf(notificationManager).getNotificationChannels()).hasSize(2);
     97     NotificationChannel channel =
     98         (NotificationChannel) shadowOf(notificationManager).getNotificationChannel("id");
     99     assertThat(channel.getName()).isEqualTo("name");
    100     assertThat(channel.getImportance()).isEqualTo(1);
    101     channel = (NotificationChannel) shadowOf(notificationManager).getNotificationChannel("id2");
    102     assertThat(channel.getName()).isEqualTo("name2");
    103     assertThat(channel.getImportance()).isEqualTo(1);
    104   }
    105 
    106   @Test
    107   @Config(minSdk = Build.VERSION_CODES.O)
    108   public void deleteNotificationChannel() {
    109     final String channelId = "channelId";
    110     assertThat(shadowOf(notificationManager).isChannelDeleted(channelId)).isFalse();
    111     notificationManager.createNotificationChannel(new NotificationChannel(channelId, "name", 1));
    112     assertThat(shadowOf(notificationManager).isChannelDeleted(channelId)).isFalse();
    113     notificationManager.deleteNotificationChannel(channelId);
    114     assertThat(shadowOf(notificationManager).isChannelDeleted(channelId)).isTrue();
    115     assertThat(notificationManager.getNotificationChannel(channelId)).isNull();
    116     // Per documentation, recreating a deleted channel should have the same settings as the old
    117     // deleted channel.
    118     notificationManager.createNotificationChannel(
    119         new NotificationChannel(channelId, "otherName", 2));
    120     assertThat(shadowOf(notificationManager).isChannelDeleted(channelId)).isFalse();
    121     NotificationChannel channel = notificationManager.getNotificationChannel(channelId);
    122     assertThat(channel.getName()).isEqualTo("name");
    123     assertThat(channel.getImportance()).isEqualTo(1);
    124   }
    125 
    126   @Test
    127   @Config(minSdk = Build.VERSION_CODES.O)
    128   public void deleteNotificationChannelGroup() {
    129     final String channelId = "channelId";
    130     final String channelGroupId = "channelGroupId";
    131     notificationManager.createNotificationChannelGroup(
    132         new NotificationChannelGroup(channelGroupId, "groupName"));
    133     NotificationChannel channel = new NotificationChannel(channelId, "channelName", 1);
    134     channel.setGroup(channelGroupId);
    135     notificationManager.createNotificationChannel(channel);
    136     assertThat(shadowOf(notificationManager).isChannelDeleted(channelId)).isFalse();
    137     notificationManager.deleteNotificationChannelGroup(channelGroupId);
    138     assertThat(shadowOf(notificationManager).getNotificationChannelGroup(channelGroupId)).isNull();
    139     // Per documentation, deleting a channel group also deletes all associated channels.
    140     assertThat(shadowOf(notificationManager).isChannelDeleted(channelId)).isTrue();
    141   }
    142 
    143   @Test
    144   @Config(minSdk = Build.VERSION_CODES.N)
    145   public void areNotificationsEnabled() {
    146     shadowOf(notificationManager).setNotificationsEnabled(true);
    147     assertThat(notificationManager.areNotificationsEnabled()).isTrue();
    148     shadowOf(notificationManager).setNotificationsEnabled(false);
    149     assertThat(notificationManager.areNotificationsEnabled()).isFalse();
    150   }
    151 
    152   @Test
    153   @Config(minSdk = Build.VERSION_CODES.M)
    154   public void isNotificationPolicyAccessGranted() {
    155     shadowOf(notificationManager).setNotificationPolicyAccessGranted(true);
    156     assertThat(notificationManager.isNotificationPolicyAccessGranted()).isTrue();
    157     shadowOf(notificationManager).setNotificationPolicyAccessGranted(false);
    158     assertThat(notificationManager.isNotificationPolicyAccessGranted()).isFalse();
    159   }
    160 
    161   @Test
    162   @Config(minSdk = Build.VERSION_CODES.N)
    163   public void
    164       setNotificationPolicyAccessGranted_temporarilyDenyAccess_shouldClearAutomaticZenRules() {
    165     shadowOf(notificationManager).setNotificationPolicyAccessGranted(true);
    166     AutomaticZenRule rule =
    167         new AutomaticZenRule(
    168             "name",
    169             new ComponentName("pkg", "cls"),
    170             Uri.parse("condition://id"),
    171             NotificationManager.INTERRUPTION_FILTER_PRIORITY,
    172             /* enabled= */ true);
    173     String id = notificationManager.addAutomaticZenRule(rule);
    174 
    175     shadowOf(notificationManager).setNotificationPolicyAccessGranted(false);
    176     shadowOf(notificationManager).setNotificationPolicyAccessGranted(true);
    177 
    178     assertThat(notificationManager.getAutomaticZenRule(id)).isNull();
    179     assertThat(notificationManager.getAutomaticZenRules()).isEmpty();
    180   }
    181 
    182   @Test
    183   @Config(minSdk = Build.VERSION_CODES.N)
    184   public void getAutomaticZenRule_notificationAccessDenied_shouldThrowSecurityException() {
    185     try {
    186       notificationManager.getAutomaticZenRule("some_id");
    187       fail("Should have thrown SecurityException");
    188     } catch (SecurityException expected) {
    189     }
    190   }
    191 
    192   @Test
    193   @Config(minSdk = Build.VERSION_CODES.N)
    194   public void getAutomaticZenRule_nonexistentId_shouldReturnNull() {
    195     shadowOf(notificationManager).setNotificationPolicyAccessGranted(true);
    196     AutomaticZenRule rule =
    197         new AutomaticZenRule(
    198             "name",
    199             new ComponentName("pkg", "cls"),
    200             Uri.parse("condition://id"),
    201             NotificationManager.INTERRUPTION_FILTER_PRIORITY,
    202             /* enabled= */ true);
    203     String id = notificationManager.addAutomaticZenRule(rule);
    204 
    205     String nonexistentId = "id_different_from_" + id;
    206     assertThat(notificationManager.getAutomaticZenRule(nonexistentId)).isNull();
    207   }
    208 
    209   @Test
    210   @Config(minSdk = Build.VERSION_CODES.N)
    211   public void getAutomaticZenRules_notificationAccessDenied_shouldThrowSecurityException() {
    212     try {
    213       notificationManager.getAutomaticZenRules();
    214       fail("Should have thrown SecurityException");
    215     } catch (SecurityException expected) {
    216     }
    217   }
    218 
    219   @Test
    220   @Config(minSdk = Build.VERSION_CODES.N)
    221   public void getAutomaticZenRules_noRulesAdded_shouldReturnEmptyMap() {
    222     shadowOf(notificationManager).setNotificationPolicyAccessGranted(true);
    223     assertThat(notificationManager.getAutomaticZenRules()).isEmpty();
    224   }
    225 
    226   @Test
    227   @Config(minSdk = Build.VERSION_CODES.N)
    228   public void addAutomaticZenRule_notificationAccessDenied_shouldThrowSecurityException() {
    229     AutomaticZenRule rule =
    230         new AutomaticZenRule(
    231             "name",
    232             new ComponentName("pkg", "cls"),
    233             Uri.parse("condition://id"),
    234             NotificationManager.INTERRUPTION_FILTER_PRIORITY,
    235             /* enabled= */ true);
    236     try {
    237       notificationManager.addAutomaticZenRule(rule);
    238       fail("Should have thrown SecurityException");
    239     } catch (SecurityException expected) {
    240     }
    241   }
    242 
    243   @Test
    244   @Config(minSdk = Build.VERSION_CODES.N)
    245   public void addAutomaticZenRule_oneRule_shouldAddRuleAndReturnId() {
    246     shadowOf(notificationManager).setNotificationPolicyAccessGranted(true);
    247 
    248     AutomaticZenRule rule =
    249         new AutomaticZenRule(
    250             "name",
    251             new ComponentName("pkg", "cls"),
    252             Uri.parse("condition://id"),
    253             NotificationManager.INTERRUPTION_FILTER_PRIORITY,
    254             /* enabled= */ true);
    255     String id = notificationManager.addAutomaticZenRule(rule);
    256 
    257     assertThat(id).isNotEmpty();
    258     assertThat(notificationManager.getAutomaticZenRule(id)).isEqualTo(rule);
    259     assertThat(notificationManager.getAutomaticZenRules()).containsExactly(id, rule);
    260   }
    261 
    262   @Test
    263   @Config(minSdk = Build.VERSION_CODES.N)
    264   public void addAutomaticZenRule_twoRules_shouldAddBothRulesAndReturnDifferentIds() {
    265     shadowOf(notificationManager).setNotificationPolicyAccessGranted(true);
    266 
    267     AutomaticZenRule rule1 =
    268         new AutomaticZenRule(
    269             "name1",
    270             new ComponentName("pkg1", "cls1"),
    271             Uri.parse("condition://id1"),
    272             NotificationManager.INTERRUPTION_FILTER_PRIORITY,
    273             /* enabled= */ true);
    274     AutomaticZenRule rule2 =
    275         new AutomaticZenRule(
    276             "name2",
    277             new ComponentName("pkg2", "cls2"),
    278             Uri.parse("condition://id2"),
    279             NotificationManager.INTERRUPTION_FILTER_ALARMS,
    280             /* enabled= */ false);
    281     String id1 = notificationManager.addAutomaticZenRule(rule1);
    282     String id2 = notificationManager.addAutomaticZenRule(rule2);
    283 
    284     assertThat(id2).isNotEqualTo(id1);
    285     assertThat(notificationManager.getAutomaticZenRule(id1)).isEqualTo(rule1);
    286     assertThat(notificationManager.getAutomaticZenRule(id2)).isEqualTo(rule2);
    287     assertThat(notificationManager.getAutomaticZenRules()).containsExactly(id1, rule1, id2, rule2);
    288   }
    289 
    290   @Test
    291   @Config(minSdk = Build.VERSION_CODES.N)
    292   public void updateAutomaticZenRule_notificationAccessDenied_shouldThrowSecurityException() {
    293     AutomaticZenRule rule =
    294         new AutomaticZenRule(
    295             "name",
    296             new ComponentName("pkg", "cls"),
    297             Uri.parse("condition://id"),
    298             NotificationManager.INTERRUPTION_FILTER_PRIORITY,
    299             /* enabled= */ true);
    300     try {
    301       notificationManager.updateAutomaticZenRule("some_id", rule);
    302       fail("Should have thrown SecurityException");
    303     } catch (SecurityException expected) {
    304     }
    305   }
    306 
    307   @Test
    308   @Config(minSdk = Build.VERSION_CODES.N)
    309   public void updateAutomaticZenRule_nonexistentId_shouldThrowSecurityException() {
    310     shadowOf(notificationManager).setNotificationPolicyAccessGranted(true);
    311     AutomaticZenRule rule =
    312         new AutomaticZenRule(
    313             "name",
    314             new ComponentName("pkg", "cls"),
    315             Uri.parse("condition://id"),
    316             NotificationManager.INTERRUPTION_FILTER_PRIORITY,
    317             /* enabled= */ true);
    318     String id = notificationManager.addAutomaticZenRule(rule);
    319 
    320     String nonexistentId = "id_different_from_" + id;
    321     AutomaticZenRule updatedRule =
    322         new AutomaticZenRule(
    323             "updated_name",
    324             new ComponentName("updated_pkg", "updated_cls"),
    325             Uri.parse("condition://updated_id"),
    326             NotificationManager.INTERRUPTION_FILTER_ALL,
    327             /* enabled= */ false);
    328     try {
    329       assertThat(notificationManager.updateAutomaticZenRule(nonexistentId, updatedRule));
    330       fail("Should have thrown SecurityException");
    331     } catch (SecurityException expected) {
    332     }
    333 
    334     assertThat(notificationManager.getAutomaticZenRule(id)).isEqualTo(rule);
    335     assertThat(notificationManager.getAutomaticZenRule(nonexistentId)).isNull();
    336     assertThat(notificationManager.getAutomaticZenRules()).containsExactly(id, rule);
    337   }
    338 
    339   @Test
    340   @Config(minSdk = Build.VERSION_CODES.N)
    341   public void updateAutomaticZenRule_existingId_shouldUpdateRuleAndReturnTrue() {
    342     shadowOf(notificationManager).setNotificationPolicyAccessGranted(true);
    343     AutomaticZenRule rule1 =
    344         new AutomaticZenRule(
    345             "name1",
    346             new ComponentName("pkg1", "cls1"),
    347             Uri.parse("condition://id1"),
    348             NotificationManager.INTERRUPTION_FILTER_PRIORITY,
    349             /* enabled= */ true);
    350     AutomaticZenRule rule2 =
    351         new AutomaticZenRule(
    352             "name2",
    353             new ComponentName("pkg2", "cls2"),
    354             Uri.parse("condition://id2"),
    355             NotificationManager.INTERRUPTION_FILTER_ALARMS,
    356             /* enabled= */ false);
    357     String id1 = notificationManager.addAutomaticZenRule(rule1);
    358     String id2 = notificationManager.addAutomaticZenRule(rule2);
    359 
    360     AutomaticZenRule updatedRule =
    361         new AutomaticZenRule(
    362             "updated_name",
    363             new ComponentName("updated_pkg", "updated_cls"),
    364             Uri.parse("condition://updated_id"),
    365             NotificationManager.INTERRUPTION_FILTER_ALL,
    366             /* enabled= */ false);
    367     assertThat(notificationManager.updateAutomaticZenRule(id2, updatedRule)).isTrue();
    368 
    369     assertThat(notificationManager.getAutomaticZenRule(id1)).isEqualTo(rule1);
    370     assertThat(notificationManager.getAutomaticZenRule(id2)).isEqualTo(updatedRule);
    371     assertThat(notificationManager.getAutomaticZenRules())
    372         .containsExactly(id1, rule1, id2, updatedRule);
    373   }
    374 
    375   @Test
    376   @Config(minSdk = Build.VERSION_CODES.N)
    377   public void removeAutomaticZenRule_notificationAccessDenied_shouldThrowSecurityException() {
    378     try {
    379       notificationManager.removeAutomaticZenRule("some_id");
    380       fail("Should have thrown SecurityException");
    381     } catch (SecurityException expected) {
    382     }
    383   }
    384 
    385   @Test
    386   @Config(minSdk = Build.VERSION_CODES.N)
    387   public void removeAutomaticZenRule_nonexistentId_shouldAndReturnFalse() {
    388     shadowOf(notificationManager).setNotificationPolicyAccessGranted(true);
    389     AutomaticZenRule rule =
    390         new AutomaticZenRule(
    391             "name",
    392             new ComponentName("pkg", "cls"),
    393             Uri.parse("condition://id"),
    394             NotificationManager.INTERRUPTION_FILTER_PRIORITY,
    395             /* enabled= */ true);
    396     String id = notificationManager.addAutomaticZenRule(rule);
    397 
    398     String nonexistentId = "id_different_from_" + id;
    399     assertThat(notificationManager.removeAutomaticZenRule(nonexistentId)).isFalse();
    400     // The rules stored in NotificationManager should remain unchanged.
    401     assertThat(notificationManager.getAutomaticZenRules()).containsExactly(id, rule);
    402   }
    403 
    404   @Test
    405   @Config(minSdk = Build.VERSION_CODES.N)
    406   public void removeAutomaticZenRule_existingId_shouldRemoveRuleAndReturnTrue() {
    407     shadowOf(notificationManager).setNotificationPolicyAccessGranted(true);
    408     AutomaticZenRule rule1 =
    409         new AutomaticZenRule(
    410             "name1",
    411             new ComponentName("pkg1", "cls1"),
    412             Uri.parse("condition://id1"),
    413             NotificationManager.INTERRUPTION_FILTER_PRIORITY,
    414             /* enabled= */ true);
    415     AutomaticZenRule rule2 =
    416         new AutomaticZenRule(
    417             "name2",
    418             new ComponentName("pkg2", "cls2"),
    419             Uri.parse("condition://id2"),
    420             NotificationManager.INTERRUPTION_FILTER_ALARMS,
    421             /* enabled= */ false);
    422     String id1 = notificationManager.addAutomaticZenRule(rule1);
    423     String id2 = notificationManager.addAutomaticZenRule(rule2);
    424 
    425     assertThat(notificationManager.removeAutomaticZenRule(id1)).isTrue();
    426 
    427     assertThat(notificationManager.getAutomaticZenRule(id1)).isNull();
    428     assertThat(notificationManager.getAutomaticZenRule(id2)).isEqualTo(rule2);
    429     assertThat(notificationManager.getAutomaticZenRules()).containsExactly(id2, rule2);
    430   }
    431 
    432   @Test
    433   public void testNotify() throws Exception {
    434     notificationManager.notify(1, notification1);
    435     assertEquals(1, shadowOf(notificationManager).size());
    436     assertEquals(notification1, shadowOf(notificationManager).getNotification(null, 1));
    437 
    438     notificationManager.notify(31, notification2);
    439     assertEquals(2, shadowOf(notificationManager).size());
    440     assertEquals(notification2, shadowOf(notificationManager).getNotification(null, 31));
    441   }
    442 
    443   @Test
    444   public void testNotifyReplaces() throws Exception {
    445     notificationManager.notify(1, notification1);
    446 
    447     notificationManager.notify(1, notification2);
    448     assertEquals(1, shadowOf(notificationManager).size());
    449     assertEquals(notification2, shadowOf(notificationManager).getNotification(null, 1));
    450   }
    451 
    452   @Test
    453   public void testNotifyWithTag() throws Exception {
    454     notificationManager.notify("a tag", 1, notification1);
    455     assertEquals(1, shadowOf(notificationManager).size());
    456     assertEquals(notification1, shadowOf(notificationManager).getNotification("a tag", 1));
    457   }
    458 
    459   @Test
    460   public void notifyWithTag_shouldReturnNullForNullTag() throws Exception {
    461     notificationManager.notify("a tag", 1, notification1);
    462     assertEquals(1, shadowOf(notificationManager).size());
    463     assertNull(shadowOf(notificationManager).getNotification(null, 1));
    464   }
    465 
    466   @Test
    467   public void notifyWithTag_shouldReturnNullForUnknownTag() throws Exception {
    468     notificationManager.notify("a tag", 1, notification1);
    469     assertEquals(1, shadowOf(notificationManager).size());
    470     assertNull(shadowOf(notificationManager).getNotification("unknown tag", 1));
    471   }
    472 
    473   @Test
    474   public void testCancel() throws Exception {
    475     notificationManager.notify(1, notification1);
    476     notificationManager.cancel(1);
    477 
    478     assertEquals(0, shadowOf(notificationManager).size());
    479     assertNull(shadowOf(notificationManager).getNotification(null, 1));
    480   }
    481 
    482   @Test
    483   public void testCancelWithTag() throws Exception {
    484     notificationManager.notify("a tag", 1, notification1);
    485     notificationManager.cancel("a tag", 1);
    486 
    487     assertEquals(0, shadowOf(notificationManager).size());
    488     assertNull(shadowOf(notificationManager).getNotification(null, 1));
    489     assertNull(shadowOf(notificationManager).getNotification("a tag", 1));
    490   }
    491 
    492   @Test
    493   public void testCancelAll() throws Exception {
    494     notificationManager.notify(1, notification1);
    495     notificationManager.notify(31, notification2);
    496     notificationManager.cancelAll();
    497 
    498     assertEquals(0, shadowOf(notificationManager).size());
    499     assertNull(shadowOf(notificationManager).getNotification(null, 1));
    500     assertNull(shadowOf(notificationManager).getNotification(null, 31));
    501   }
    502 
    503   @Test
    504   @Config(minSdk = Build.VERSION_CODES.M)
    505   public void testGetActiveNotifications() throws Exception {
    506     notificationManager.notify(1, notification1);
    507     notificationManager.notify(31, notification2);
    508 
    509     StatusBarNotification[] statusBarNotifications =
    510         shadowOf(notificationManager).getActiveNotifications();
    511 
    512     assertThat(asNotificationList(statusBarNotifications))
    513         .containsExactly(notification1, notification2);
    514   }
    515 
    516   private static List<Notification> asNotificationList(
    517       StatusBarNotification[] statusBarNotifications) {
    518     List<Notification> notificationList = new ArrayList<>(statusBarNotifications.length);
    519     for (StatusBarNotification statusBarNotification : statusBarNotifications) {
    520       notificationList.add(statusBarNotification.getNotification());
    521     }
    522     return notificationList;
    523   }
    524 }
    525