Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2018 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 android.app.notification.legacy.cts;
     18 
     19 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
     20 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
     21 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
     22 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
     23 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
     24 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
     25 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
     26 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
     27 
     28 import static junit.framework.Assert.assertEquals;
     29 
     30 import android.app.ActivityManager;
     31 import android.app.Instrumentation;
     32 import android.app.Notification;
     33 import android.app.NotificationChannel;
     34 import android.app.NotificationManager;
     35 import android.app.PendingIntent;
     36 import android.app.UiAutomation;
     37 import android.content.ComponentName;
     38 import android.content.Context;
     39 import android.content.Intent;
     40 import android.os.ParcelFileDescriptor;
     41 import android.provider.Telephony.Threads;
     42 import android.service.notification.NotificationListenerService;
     43 import android.support.test.InstrumentationRegistry;
     44 import android.support.test.runner.AndroidJUnit4;
     45 import android.util.Log;
     46 
     47 import junit.framework.Assert;
     48 
     49 import org.junit.Before;
     50 import org.junit.Test;
     51 import org.junit.runner.RunWith;
     52 
     53 import java.io.FileInputStream;
     54 import java.io.IOException;
     55 import java.io.InputStream;
     56 
     57 /**
     58  * Home for tests that need to verify behavior for apps that target old sdk versions.
     59  */
     60 @RunWith(AndroidJUnit4.class)
     61 public class LegacyNotificationManagerTest {
     62     final String TAG = "LegacyNoManTest";
     63 
     64     final String NOTIFICATION_CHANNEL_ID = "LegacyNotificationManagerTest";
     65     private NotificationManager mNotificationManager;
     66     private ActivityManager mActivityManager;
     67     private Context mContext;
     68     private MockNotificationListener mListener;
     69 
     70     @Before
     71     public void setUp() throws Exception {
     72         mContext = InstrumentationRegistry.getContext();
     73         toggleListenerAccess(MockNotificationListener.getId(),
     74                 InstrumentationRegistry.getInstrumentation(), false);
     75         mNotificationManager = (NotificationManager) mContext.getSystemService(
     76                 Context.NOTIFICATION_SERVICE);
     77         mNotificationManager.createNotificationChannel(new NotificationChannel(
     78                 NOTIFICATION_CHANNEL_ID, "name", NotificationManager.IMPORTANCE_DEFAULT));
     79         mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
     80     }
     81 
     82     @Test
     83     public void testPrePCannotToggleAlarmsAndMediaTest() throws Exception {
     84         if (mActivityManager.isLowRamDevice()) {
     85             return;
     86         }
     87         toggleNotificationPolicyAccess(mContext.getPackageName(),
     88                 InstrumentationRegistry.getInstrumentation(), true);
     89 
     90         // Pre-P cannot toggle alarms and media
     91         NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
     92         int alarmBit = origPolicy.priorityCategories & NotificationManager.Policy
     93                 .PRIORITY_CATEGORY_ALARMS;
     94         int mediaBit = origPolicy.priorityCategories & NotificationManager.Policy
     95                 .PRIORITY_CATEGORY_MEDIA;
     96         int systemBit = origPolicy.priorityCategories & NotificationManager.Policy
     97                 .PRIORITY_CATEGORY_SYSTEM;
     98 
     99         // attempt to toggle off alarms, media, system:
    100         mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0));
    101         NotificationManager.Policy policy = mNotificationManager.getNotificationPolicy();
    102         assertEquals(alarmBit, policy.priorityCategories
    103                 & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS);
    104         assertEquals(mediaBit, policy.priorityCategories
    105                 & NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA);
    106         assertEquals(systemBit, policy.priorityCategories
    107                 & NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM);
    108 
    109         // attempt to toggle on alarms, media, system:
    110         mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
    111                 NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS
    112                         | NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA, 0, 0));
    113         policy = mNotificationManager.getNotificationPolicy();
    114         assertEquals(alarmBit, policy.priorityCategories
    115                 & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS);
    116         assertEquals(mediaBit, policy.priorityCategories
    117                 & NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA);
    118         assertEquals(systemBit, policy.priorityCategories
    119                 & NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM);
    120 
    121         toggleNotificationPolicyAccess(mContext.getPackageName(),
    122                 InstrumentationRegistry.getInstrumentation(), false);
    123     }
    124 
    125     @Test
    126     public void testSetNotificationPolicy_preP_setOldFields() throws Exception {
    127         if (mActivityManager.isLowRamDevice()) {
    128             return;
    129         }
    130         toggleNotificationPolicyAccess(mContext.getPackageName(),
    131                 InstrumentationRegistry.getInstrumentation(), true);
    132 
    133         NotificationManager.Policy userPolicy = mNotificationManager.getNotificationPolicy();
    134 
    135         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
    136                 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF);
    137         mNotificationManager.setNotificationPolicy(appPolicy);
    138 
    139         int expected = userPolicy.suppressedVisualEffects
    140                 | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF
    141                 | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_LIGHTS
    142                 | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
    143 
    144         assertEquals(expected,
    145                 mNotificationManager.getNotificationPolicy().suppressedVisualEffects);
    146     }
    147 
    148     @Test
    149     public void testSetNotificationPolicy_preP_setNewFields() throws Exception {
    150         if (mActivityManager.isLowRamDevice()) {
    151             return;
    152         }
    153         toggleNotificationPolicyAccess(mContext.getPackageName(),
    154                 InstrumentationRegistry.getInstrumentation(), true);
    155 
    156         NotificationManager.Policy userPolicy = mNotificationManager.getNotificationPolicy();
    157 
    158         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
    159                 SUPPRESSED_EFFECT_NOTIFICATION_LIST);
    160         mNotificationManager.setNotificationPolicy(appPolicy);
    161 
    162         int expected = userPolicy.suppressedVisualEffects;
    163         expected &= ~ SUPPRESSED_EFFECT_SCREEN_OFF & ~ SUPPRESSED_EFFECT_SCREEN_ON;
    164         assertEquals(expected,
    165                 mNotificationManager.getNotificationPolicy().suppressedVisualEffects);
    166 
    167         toggleNotificationPolicyAccess(mContext.getPackageName(),
    168                 InstrumentationRegistry.getInstrumentation(), false);
    169     }
    170 
    171     @Test
    172     public void testSuspendPackage() throws Exception {
    173         toggleListenerAccess(MockNotificationListener.getId(),
    174                 InstrumentationRegistry.getInstrumentation(), true);
    175         Thread.sleep(500); // wait for listener to be allowed
    176 
    177         mListener = MockNotificationListener.getInstance();
    178         Assert.assertNotNull(mListener);
    179 
    180         sendNotification(1, R.drawable.icon_black);
    181         Thread.sleep(500); // wait for notification listener to receive notification
    182         assertEquals(1, mListener.mPosted.size());
    183         mListener.resetData();
    184 
    185         // suspend package, listener receives onRemoved
    186         suspendPackage(mContext.getPackageName(), InstrumentationRegistry.getInstrumentation(),
    187                 true);
    188         Thread.sleep(500); // wait for notification listener to get response
    189         assertEquals(1, mListener.mRemoved.size());
    190 
    191         // unsuspend package, listener receives onPosted
    192         suspendPackage(mContext.getPackageName(), InstrumentationRegistry.getInstrumentation(),
    193                 false);
    194         Thread.sleep(500); // wait for notification listener to get response
    195         assertEquals(1, mListener.mPosted.size());
    196 
    197         toggleListenerAccess(MockNotificationListener.getId(),
    198                 InstrumentationRegistry.getInstrumentation(), false);
    199 
    200         mListener.resetData();
    201     }
    202 
    203     @Test
    204     public void testSetNotificationPolicy_preP_setOldNewFields() throws Exception {
    205         if (mActivityManager.isLowRamDevice()) {
    206             return;
    207         }
    208         toggleNotificationPolicyAccess(mContext.getPackageName(),
    209                 InstrumentationRegistry.getInstrumentation(), true);
    210 
    211         NotificationManager.Policy userPolicy = mNotificationManager.getNotificationPolicy();
    212 
    213         NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0,
    214                 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR);
    215         mNotificationManager.setNotificationPolicy(appPolicy);
    216 
    217         int expected = userPolicy.suppressedVisualEffects
    218                 | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK;
    219         expected &= ~ SUPPRESSED_EFFECT_SCREEN_OFF;
    220         assertEquals(expected,
    221                 mNotificationManager.getNotificationPolicy().suppressedVisualEffects);
    222 
    223         toggleNotificationPolicyAccess(mContext.getPackageName(),
    224                 InstrumentationRegistry.getInstrumentation(), false);
    225     }
    226 
    227     private void sendNotification(final int id, final int icon) throws Exception {
    228         sendNotification(id, null, icon);
    229     }
    230 
    231     private void sendNotification(final int id, String groupKey, final int icon) throws Exception {
    232         final Intent intent = new Intent(Intent.ACTION_MAIN, Threads.CONTENT_URI);
    233 
    234         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP
    235                 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    236         intent.setAction(Intent.ACTION_MAIN);
    237 
    238         final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
    239         final Notification notification =
    240                 new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
    241                         .setSmallIcon(icon)
    242                         .setWhen(System.currentTimeMillis())
    243                         .setContentTitle("notify#" + id)
    244                         .setContentText("This is #" + id + "notification  ")
    245                         .setContentIntent(pendingIntent)
    246                         .setGroup(groupKey)
    247                         .build();
    248         mNotificationManager.notify(id, notification);
    249     }
    250 
    251     private void toggleNotificationPolicyAccess(String packageName,
    252             Instrumentation instrumentation, boolean on) throws IOException {
    253 
    254         String command = " cmd notification " + (on ? "allow_dnd " : "disallow_dnd ") + packageName;
    255 
    256         runCommand(command, instrumentation);
    257 
    258         NotificationManager nm = mContext.getSystemService(NotificationManager.class);
    259         Assert.assertEquals("Notification Policy Access Grant is " +
    260                         nm.isNotificationPolicyAccessGranted() + " not " + on, on,
    261                 nm.isNotificationPolicyAccessGranted());
    262     }
    263 
    264     private void suspendPackage(String packageName,
    265             Instrumentation instrumentation, boolean suspend) throws IOException {
    266         String command = " cmd notification " + (suspend ? "suspend_package "
    267                 : "unsuspend_package ") + packageName;
    268 
    269         runCommand(command, instrumentation);
    270     }
    271 
    272     private void toggleListenerAccess(String componentName, Instrumentation instrumentation,
    273             boolean on) throws IOException {
    274 
    275         String command = " cmd notification " + (on ? "allow_listener " : "disallow_listener ")
    276                 + componentName;
    277 
    278         runCommand(command, instrumentation);
    279 
    280         final NotificationManager nm = mContext.getSystemService(NotificationManager.class);
    281         final ComponentName listenerComponent = MockNotificationListener.getComponentName();
    282         Assert.assertTrue(listenerComponent + " has not been granted access",
    283                 nm.isNotificationListenerAccessGranted(listenerComponent) == on);
    284     }
    285 
    286     private void runCommand(String command, Instrumentation instrumentation) throws IOException {
    287         UiAutomation uiAutomation = instrumentation.getUiAutomation();
    288         // Execute command
    289         try (ParcelFileDescriptor fd = uiAutomation.executeShellCommand(command)) {
    290             Assert.assertNotNull("Failed to execute shell command: " + command, fd);
    291             // Wait for the command to finish by reading until EOF
    292             try (InputStream in = new FileInputStream(fd.getFileDescriptor())) {
    293                 byte[] buffer = new byte[4096];
    294                 while (in.read(buffer) > 0) {}
    295             } catch (IOException e) {
    296                 throw new IOException("Could not read stdout of command:" + command, e);
    297             }
    298         } finally {
    299             uiAutomation.destroy();
    300         }
    301     }
    302 }
    303