1 /*
2  * Copyright (C) 2022 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.permission.cts;
18 
19 import static android.permission.cts.PermissionUtils.clearAppState;
20 import static android.permission.cts.PermissionUtils.install;
21 import static android.permission.cts.PermissionUtils.uninstallApp;
22 import static android.permission.cts.TestUtils.ensure;
23 import static android.permission.cts.TestUtils.eventually;
24 
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertNull;
27 
28 import android.app.ActivityOptions;
29 import android.app.PendingIntent;
30 import android.os.Build;
31 import android.platform.test.annotations.AppModeFull;
32 import android.platform.test.rule.ScreenRecordRule;
33 import android.service.notification.StatusBarNotification;
34 
35 import androidx.test.filters.FlakyTest;
36 import androidx.test.filters.SdkSuppress;
37 import androidx.test.runner.AndroidJUnit4;
38 
39 import com.android.modules.utils.build.SdkLevel;
40 
41 import org.junit.After;
42 import org.junit.Before;
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 
46 /**
47  * Tests the {@code NotificationListenerCheck} in permission controller.
48  */
49 @RunWith(AndroidJUnit4.class)
50 @AppModeFull(reason = "Cannot set system settings as instant app. Also we never show a notification"
51         + " listener check notification for instant apps.")
52 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
53 @ScreenRecordRule.ScreenRecord
54 @FlakyTest
55 public class NotificationListenerCheckTest extends BaseNotificationListenerCheckTest {
56 
57     public final ScreenRecordRule mScreenRecordRule = new ScreenRecordRule(false, false);
58 
59     @Before
setup()60     public void setup() throws Throwable {
61         // Skip tests if safety center not allowed
62         assumeDeviceSupportsSafetyCenter();
63 
64         wakeUpAndDismissKeyguard();
65         resetPermissionControllerBeforeEachTest();
66 
67         // Cts NLS is required to verify sent Notifications, however, we don't want it to show up in
68         // testing
69         triggerAndDismissCtsNotificationListenerNotification();
70 
71         clearNotifications();
72 
73         // Install and allow the app with NLS for testing
74         install(TEST_APP_NOTIFICATION_LISTENER_APK);
75         allowTestAppNotificationListenerService();
76     }
77 
78     @After
tearDown()79     public void tearDown() throws Throwable {
80         // Disallow and uninstall the app with NLS for testing
81         disallowTestAppNotificationListenerService();
82         uninstallApp(TEST_APP_PKG);
83 
84         clearNotifications();
85     }
86 
87     @Test
noNotificationIfFeatureDisabled()88     public void noNotificationIfFeatureDisabled() throws Throwable {
89         setNotificationListenerCheckEnabled(false);
90 
91         runNotificationListenerCheck();
92 
93         ensure(() -> assertNull("Expected no notifications", getNotification(false)),
94                 ENSURE_NOTIFICATION_NOT_SHOWN_EXPECTED_TIMEOUT_MILLIS);
95     }
96 
97     @Test
noNotificationIfSafetyCenterDisabled()98     public void noNotificationIfSafetyCenterDisabled() throws Throwable {
99         SafetyCenterUtils.setSafetyCenterEnabled(false);
100 
101         runNotificationListenerCheck();
102 
103         ensure(() -> assertNull("Expected no notifications", getNotification(false)),
104                 ENSURE_NOTIFICATION_NOT_SHOWN_EXPECTED_TIMEOUT_MILLIS);
105     }
106 
107     @Test
notificationIsShown()108     public void notificationIsShown() throws Throwable {
109         runNotificationListenerCheck();
110 
111         eventually(() -> assertNotNull("Expected notification, none found", getNotification(false)),
112                 UNEXPECTED_TIMEOUT_MILLIS);
113     }
114 
115     @Test
notificationIsShownOnlyOnce()116     public void notificationIsShownOnlyOnce() throws Throwable {
117         runNotificationListenerCheck();
118         eventually(() -> assertNotNull(getNotification(true)), UNEXPECTED_TIMEOUT_MILLIS);
119 
120         runNotificationListenerCheck();
121         ensure(() -> assertNull("Expected no notifications", getNotification(false)),
122                 ENSURE_NOTIFICATION_NOT_SHOWN_EXPECTED_TIMEOUT_MILLIS);
123     }
124 
125     @Test
notificationIsShownAgainAfterClear()126     public void notificationIsShownAgainAfterClear() throws Throwable {
127         runNotificationListenerCheck();
128         eventually(() -> assertNotNull(getNotification(true)), UNEXPECTED_TIMEOUT_MILLIS);
129 
130         clearAppState(TEST_APP_PKG);
131         // Wait until package is cleared and permission controller has cleared the state
132         Thread.sleep(2000);
133 
134         allowTestAppNotificationListenerService();
135         runNotificationListenerCheck();
136 
137         eventually(() -> assertNotNull(getNotification(true)), UNEXPECTED_TIMEOUT_MILLIS);
138     }
139 
140     @Test
notificationIsShownAgainAfterUninstallAndReinstall()141     public void notificationIsShownAgainAfterUninstallAndReinstall() throws Throwable {
142         runNotificationListenerCheck();
143 
144         eventually(() -> assertNotNull(getNotification(true)), UNEXPECTED_TIMEOUT_MILLIS);
145 
146         uninstallApp(TEST_APP_PKG);
147 
148         // Wait until package permission controller has cleared the state
149         Thread.sleep(2000);
150 
151         install(TEST_APP_NOTIFICATION_LISTENER_APK);
152 
153         allowTestAppNotificationListenerService();
154         runNotificationListenerCheck();
155 
156         eventually(() -> assertNotNull(getNotification(true)), UNEXPECTED_TIMEOUT_MILLIS);
157     }
158 
159     @Test
notificationIsShownAgainAfterDisableAndReenableAppNotificationListener()160     public void notificationIsShownAgainAfterDisableAndReenableAppNotificationListener()
161             throws Throwable {
162         runNotificationListenerCheck();
163 
164         eventually(() -> assertNotNull(getNotification(true)), UNEXPECTED_TIMEOUT_MILLIS);
165 
166         // Disallow NLS, and run NLS check job. This  should clear NLS off notified list
167         disallowTestAppNotificationListenerService();
168         runNotificationListenerCheck();
169 
170         // Re-allow NLS, and run NLS check job. This work now that it's cleared NLS off notified
171         // list
172         allowTestAppNotificationListenerService();
173         runNotificationListenerCheck();
174 
175         eventually(() -> assertNotNull(getNotification(true)), UNEXPECTED_TIMEOUT_MILLIS);
176     }
177 
178     @Test
removeNotificationOnUninstall()179     public void removeNotificationOnUninstall() throws Throwable {
180         runNotificationListenerCheck();
181 
182         eventually(() -> assertNotNull(getNotification(false)), UNEXPECTED_TIMEOUT_MILLIS);
183 
184         uninstallApp(TEST_APP_PKG);
185 
186         // Wait until package permission controller has cleared the state
187         Thread.sleep(2000);
188 
189         eventually(() -> assertNull(getNotification(false)), UNEXPECTED_TIMEOUT_MILLIS);
190     }
191 
192     @Test
notificationIsNotShownAfterDisableAppNotificationListener()193     public void notificationIsNotShownAfterDisableAppNotificationListener() throws Throwable {
194         disallowTestAppNotificationListenerService();
195 
196         runNotificationListenerCheck();
197 
198         // We don't expect a notification, but try to trigger one anyway
199         ensure(() -> assertNull("Expected no notifications", getNotification(false)),
200                 ENSURE_NOTIFICATION_NOT_SHOWN_EXPECTED_TIMEOUT_MILLIS);
201     }
202 
203     @Test
notificationOnClick_opensSafetyCenter()204     public void notificationOnClick_opensSafetyCenter() throws Throwable {
205         runNotificationListenerCheck();
206 
207         StatusBarNotification currentNotification = eventually(
208                 () -> {
209                     StatusBarNotification notification = getNotification(false);
210                     assertNotNull(notification);
211                     return notification;
212                 }, UNEXPECTED_TIMEOUT_MILLIS);
213 
214         // Verify content intent
215         PendingIntent contentIntent = currentNotification.getNotification().contentIntent;
216         if (SdkLevel.isAtLeastU()) {
217             contentIntent.send(null, 0, null, null, null, null,
218                     ActivityOptions.makeBasic().setPendingIntentBackgroundActivityStartMode(
219                             ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED).toBundle());
220         } else {
221             contentIntent.send();
222         }
223 
224         SafetyCenterUtils.assertSafetyCenterStarted();
225     }
226 }
227