blob: 768bd138fd64c18ea095120a60d006e9237448be [file] [log] [blame]
Dan Sandlerf5aafb92017-05-28 12:18:53 -04001/*
2 * Copyright (C) 2017 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
17package com.android.systemui;
18
Julia Reynoldsfc640012018-02-21 12:25:27 -050019import static junit.framework.Assert.assertEquals;
20import static junit.framework.Assert.assertNull;
21
22import static org.junit.Assert.assertFalse;
23import static org.junit.Assert.assertTrue;
Beverly201cdd52019-10-18 14:30:46 -040024import static org.mockito.ArgumentMatchers.anyString;
Julia Reynoldsfc640012018-02-21 12:25:27 -050025import static org.mockito.Mockito.mock;
Beverly201cdd52019-10-18 14:30:46 -040026import static org.mockito.Mockito.never;
27import static org.mockito.Mockito.times;
Gus Prevaseb4e2e12018-12-28 14:57:59 -050028import static org.mockito.Mockito.verify;
Julia Reynoldsfc640012018-02-21 12:25:27 -050029import static org.mockito.Mockito.when;
30
Dan Sandlerf5aafb92017-05-28 12:18:53 -040031import android.annotation.UserIdInt;
Beverly201cdd52019-10-18 14:30:46 -040032import android.app.AppOpsManager;
Dan Sandlerf5aafb92017-05-28 12:18:53 -040033import android.app.Notification;
34import android.app.NotificationManager;
35import android.os.Bundle;
36import android.os.UserHandle;
37import android.service.notification.StatusBarNotification;
Julia Reynoldsfc640012018-02-21 12:25:27 -050038import android.widget.RemoteViews;
39
Brett Chabot84151d92019-02-27 15:37:59 -080040import androidx.test.filters.SmallTest;
41import androidx.test.runner.AndroidJUnit4;
42
Dan Sandlerf5aafb92017-05-28 12:18:53 -040043import com.android.internal.messages.nano.SystemMessageProto;
Ned Burns60e94592019-09-06 14:47:25 -040044import com.android.systemui.statusbar.NotificationEntryBuilder;
Gus Prevaseb4e2e12018-12-28 14:57:59 -050045import com.android.systemui.statusbar.notification.NotificationEntryListener;
46import com.android.systemui.statusbar.notification.NotificationEntryManager;
Ned Burnsf81c4c42019-01-07 14:10:43 -050047import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Dan Sandlerf5aafb92017-05-28 12:18:53 -040048
Beverly201cdd52019-10-18 14:30:46 -040049import junit.framework.Assert;
50
Dan Sandlerf5aafb92017-05-28 12:18:53 -040051import org.junit.Before;
52import org.junit.Test;
53import org.junit.runner.RunWith;
Gus Prevaseb4e2e12018-12-28 14:57:59 -050054import org.mockito.ArgumentCaptor;
Dan Sandlerf5aafb92017-05-28 12:18:53 -040055
Dan Sandlerf5aafb92017-05-28 12:18:53 -040056@SmallTest
57@RunWith(AndroidJUnit4.class)
58public class ForegroundServiceControllerTest extends SysuiTestCase {
Gus Prevaseb4e2e12018-12-28 14:57:59 -050059 private ForegroundServiceController mFsc;
60 private ForegroundServiceNotificationListener mListener;
61 private NotificationEntryListener mEntryListener;
Beverly201cdd52019-10-18 14:30:46 -040062 private NotificationEntryManager mEntryManager;
Dan Sandlerf5aafb92017-05-28 12:18:53 -040063
64 @Before
65 public void setUp() throws Exception {
Beverly201cdd52019-10-18 14:30:46 -040066 mEntryManager = mock(NotificationEntryManager.class);
67 mFsc = new ForegroundServiceController(mEntryManager);
Gus Prevaseb4e2e12018-12-28 14:57:59 -050068 mListener = new ForegroundServiceNotificationListener(
Beverly201cdd52019-10-18 14:30:46 -040069 mContext, mFsc, mEntryManager);
Gus Prevaseb4e2e12018-12-28 14:57:59 -050070 ArgumentCaptor<NotificationEntryListener> entryListenerCaptor =
71 ArgumentCaptor.forClass(NotificationEntryListener.class);
Beverly201cdd52019-10-18 14:30:46 -040072 verify(mEntryManager).addNotificationEntryListener(
Gus Prevaseb4e2e12018-12-28 14:57:59 -050073 entryListenerCaptor.capture());
74 mEntryListener = entryListenerCaptor.getValue();
Julia Reynoldsfc640012018-02-21 12:25:27 -050075 }
76
77 @Test
Beverly201cdd52019-10-18 14:30:46 -040078 public void testAppOps_appOpChangedBeforeNotificationExists() {
79 // GIVEN app op exists, but notification doesn't exist in NEM yet
80 NotificationEntry entry = createFgEntry();
81 mFsc.onAppOpChanged(
82 AppOpsManager.OP_CAMERA,
83 entry.getSbn().getUid(),
84 entry.getSbn().getPackageName(),
85 true);
86 assertFalse(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA));
87
88 // WHEN the notification is added
89 mEntryListener.onPendingEntryAdded(entry);
90
91 // THEN the app op is added to the entry
92 Assert.assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA));
93 }
94
95 @Test
96 public void testAppOps_appOpAddedToForegroundNotif() {
97 // GIVEN a notification associated with a foreground service
98 NotificationEntry entry = addFgEntry();
99 when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(entry);
100
101 // WHEN we are notified of a new app op for this notification
102 mFsc.onAppOpChanged(
103 AppOpsManager.OP_CAMERA,
104 entry.getSbn().getUid(),
105 entry.getSbn().getPackageName(),
106 true);
107
108 // THEN the app op is added to the entry
109 Assert.assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA));
110
111 // THEN notification views are updated since the notification is visible
112 verify(mEntryManager, times(1)).updateNotifications(anyString());
113 }
114
115 @Test
116 public void testAppOpsAlreadyAdded() {
117 // GIVEN a foreground service associated notification that already has the correct app op
118 NotificationEntry entry = addFgEntry();
119 entry.mActiveAppOps.add(AppOpsManager.OP_CAMERA);
120 when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(entry);
121
122 // WHEN we are notified of the same app op for this notification
123 mFsc.onAppOpChanged(
124 AppOpsManager.OP_CAMERA,
125 entry.getSbn().getUid(),
126 entry.getSbn().getPackageName(),
127 true);
128
129 // THEN the app op still exists in the notification entry
130 Assert.assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA));
131
132 // THEN notification views aren't updated since nothing changed
133 verify(mEntryManager, never()).updateNotifications(anyString());
134 }
135
136 @Test
137 public void testAppOps_appOpNotAddedToUnrelatedNotif() {
138 // GIVEN no notification entries correspond to the newly updated appOp
139 NotificationEntry entry = addFgEntry();
140 when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(null);
141
142 // WHEN a new app op is detected
143 mFsc.onAppOpChanged(
144 AppOpsManager.OP_CAMERA,
145 entry.getSbn().getUid(),
146 entry.getSbn().getPackageName(),
147 true);
148
149 // THEN we won't see appOps on the entry
150 Assert.assertFalse(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA));
151
152 // THEN notification views aren't updated since nothing changed
153 verify(mEntryManager, never()).updateNotifications(anyString());
154 }
155
156 @Test
Julia Reynoldsfc640012018-02-21 12:25:27 -0500157 public void testAppOpsCRUD() {
158 // no crash on remove that doesn't exist
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500159 mFsc.onAppOpChanged(9, 1000, "pkg1", false);
160 assertNull(mFsc.getAppOps(0, "pkg1"));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500161
162 // multiuser & multipackage
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500163 mFsc.onAppOpChanged(8, 50, "pkg1", true);
164 mFsc.onAppOpChanged(1, 60, "pkg3", true);
165 mFsc.onAppOpChanged(7, 500000, "pkg2", true);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500166
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500167 assertEquals(1, mFsc.getAppOps(0, "pkg1").size());
168 assertTrue(mFsc.getAppOps(0, "pkg1").contains(8));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500169
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500170 assertEquals(1, mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
171 assertTrue(mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500172
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500173 assertEquals(1, mFsc.getAppOps(0, "pkg3").size());
174 assertTrue(mFsc.getAppOps(0, "pkg3").contains(1));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500175
176 // multiple ops for the same package
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500177 mFsc.onAppOpChanged(9, 50, "pkg1", true);
178 mFsc.onAppOpChanged(5, 50, "pkg1", true);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500179
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500180 assertEquals(3, mFsc.getAppOps(0, "pkg1").size());
181 assertTrue(mFsc.getAppOps(0, "pkg1").contains(8));
182 assertTrue(mFsc.getAppOps(0, "pkg1").contains(9));
183 assertTrue(mFsc.getAppOps(0, "pkg1").contains(5));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500184
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500185 assertEquals(1, mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
186 assertTrue(mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500187
188 // remove one of the multiples
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500189 mFsc.onAppOpChanged(9, 50, "pkg1", false);
190 assertEquals(2, mFsc.getAppOps(0, "pkg1").size());
191 assertTrue(mFsc.getAppOps(0, "pkg1").contains(8));
192 assertTrue(mFsc.getAppOps(0, "pkg1").contains(5));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500193
194 // remove last op
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500195 mFsc.onAppOpChanged(1, 60, "pkg3", false);
196 assertNull(mFsc.getAppOps(0, "pkg3"));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500197 }
198
199 @Test
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500200 public void testDisclosurePredicate() {
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400201 StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
202 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500203 StatusBarNotification sbn_user1_disclosure = makeMockSBN(USERID_ONE, "android",
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400204 SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES,
205 null, Notification.FLAG_NO_CLEAR);
206
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500207 assertTrue(mFsc.isDisclosureNotification(sbn_user1_disclosure));
208 assertFalse(mFsc.isDisclosureNotification(sbn_user1_app1));
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400209 }
210
211 @Test
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500212 public void testNeedsDisclosureAfterRemovingUnrelatedNotification() {
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400213 final String PKG1 = "com.example.app100";
214
215 StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
216 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
217 StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1);
218
219 // first add a normal notification
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500220 entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400221 // nothing required yet
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500222 assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400223 // now the app starts a fg service
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500224 entryAdded(makeMockDisclosure(USERID_ONE, new String[]{PKG1}),
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400225 NotificationManager.IMPORTANCE_DEFAULT);
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500226 assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400227 // add the fg notification
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500228 entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
229 assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE)); // app1 has got it covered
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400230 // remove the boring notification
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500231 entryRemoved(sbn_user1_app1);
232 assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE)); // app1 has STILL got it covered
233 entryRemoved(sbn_user1_app1_fg);
234 assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400235 }
236
237 @Test
238 public void testSimpleAddRemove() {
239 final String PKG1 = "com.example.app1";
240 final String PKG2 = "com.example.app2";
241
242 StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
243 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500244 entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400245
246 // no services are "running"
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500247 entryAdded(makeMockDisclosure(USERID_ONE, null),
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400248 NotificationManager.IMPORTANCE_DEFAULT);
249
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500250 assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
251 assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400252
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500253 entryUpdated(makeMockDisclosure(USERID_ONE, new String[]{PKG1}),
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400254 NotificationManager.IMPORTANCE_DEFAULT);
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500255 assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
256 assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400257
258 // switch to different package
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500259 entryUpdated(makeMockDisclosure(USERID_ONE, new String[]{PKG2}),
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400260 NotificationManager.IMPORTANCE_DEFAULT);
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500261 assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
262 assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400263
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500264 entryUpdated(makeMockDisclosure(USERID_TWO, new String[]{PKG1}),
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400265 NotificationManager.IMPORTANCE_DEFAULT);
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500266 assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
267 assertTrue(mFsc.isDisclosureNeededForUser(USERID_TWO)); // finally user2 needs one too
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400268
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500269 entryUpdated(makeMockDisclosure(USERID_ONE, new String[]{PKG2, PKG1}),
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400270 NotificationManager.IMPORTANCE_DEFAULT);
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500271 assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
272 assertTrue(mFsc.isDisclosureNeededForUser(USERID_TWO));
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400273
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500274 entryRemoved(makeMockDisclosure(USERID_ONE, null /*unused*/));
275 assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
276 assertTrue(mFsc.isDisclosureNeededForUser(USERID_TWO));
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400277
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500278 entryRemoved(makeMockDisclosure(USERID_TWO, null /*unused*/));
279 assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
280 assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400281 }
282
283 @Test
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500284 public void testDisclosureBasic() {
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400285 final String PKG1 = "com.example.app0";
286
287 StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
288 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
289 StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1);
290
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500291 entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT); // not fg
292 entryAdded(makeMockDisclosure(USERID_ONE, new String[]{PKG1}),
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400293 NotificationManager.IMPORTANCE_DEFAULT);
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500294 assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
295 entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
296 assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE)); // app1 has got it covered
297 assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400298
299 // let's take out the other notification and see what happens.
300
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500301 entryRemoved(sbn_user1_app1);
302 assertFalse(
303 mFsc.isDisclosureNeededForUser(USERID_ONE)); // still covered by sbn_user1_app1_fg
304 assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400305
306 // let's attempt to downgrade the notification from FLAG_FOREGROUND and see what we get
307 StatusBarNotification sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1);
308 sbn_user1_app1_fg_sneaky.getNotification().flags = 0;
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500309 entryUpdated(sbn_user1_app1_fg_sneaky,
310 NotificationManager.IMPORTANCE_DEFAULT);
311 assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
312 assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400313
314 // ok, ok, we'll put it back
315 sbn_user1_app1_fg_sneaky.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500316 entryUpdated(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
317 assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
318 assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400319
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500320 entryRemoved(sbn_user1_app1_fg_sneaky);
321 assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
322 assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400323
324 // now let's test an upgrade
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500325 entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
326 assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
327 assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400328 sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500329 entryUpdated(sbn_user1_app1,
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400330 NotificationManager.IMPORTANCE_DEFAULT); // this is now a fg notification
331
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500332 assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
333 assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400334
335 // remove it, make sure we're out of compliance again
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500336 entryRemoved(sbn_user1_app1); // was fg, should return true
337 entryRemoved(sbn_user1_app1);
338 assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
339 assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400340
Julia Reynoldsfc640012018-02-21 12:25:27 -0500341 // importance upgrade
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500342 entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
343 assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
344 assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500345 sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500346 entryUpdated(sbn_user1_app1_fg,
Julia Reynoldsfc640012018-02-21 12:25:27 -0500347 NotificationManager.IMPORTANCE_DEFAULT); // this is now a fg notification
348
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400349 // finally, let's turn off the service
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500350 entryAdded(makeMockDisclosure(USERID_ONE, null),
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400351 NotificationManager.IMPORTANCE_DEFAULT);
352
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500353 assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
354 assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400355 }
356
Julia Reynoldsfc640012018-02-21 12:25:27 -0500357 @Test
Julia Reynoldsaf78a792018-03-06 14:27:00 -0500358 public void testOverlayPredicate() {
359 StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
360 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
361 StatusBarNotification sbn_user1_overlay = makeMockSBN(USERID_ONE, "android",
362 0, "AlertWindowNotification", Notification.FLAG_NO_CLEAR);
363
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500364 assertTrue(mFsc.isSystemAlertNotification(sbn_user1_overlay));
365 assertFalse(mFsc.isSystemAlertNotification(sbn_user1_app1));
Julia Reynoldsaf78a792018-03-06 14:27:00 -0500366 }
367
368 @Test
Julia Reynoldsfc640012018-02-21 12:25:27 -0500369 public void testStdLayoutBasic() {
370 final String PKG1 = "com.example.app0";
371
372 StatusBarNotification sbn_user1_app1 = makeMockFgSBN(USERID_ONE, PKG1, 0, true);
373 sbn_user1_app1.getNotification().flags = 0;
374 StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1, 1, true);
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500375 entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN); // not fg
376 assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
377 entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
378 assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // app1 has got it covered
379 assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "otherpkg"));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500380 // let's take out the non-fg notification and see what happens.
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500381 entryRemoved(sbn_user1_app1);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500382 // still covered by sbn_user1_app1_fg
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500383 assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
384 assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "anyPkg"));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500385
386 // let's attempt to downgrade the notification from FLAG_FOREGROUND and see what we get
387 StatusBarNotification sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1, 1, true);
388 sbn_user1_app1_fg_sneaky.getNotification().flags = 0;
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500389 entryUpdated(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN);
390 assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
391 assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "anything"));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500392 // ok, ok, we'll put it back
393 sbn_user1_app1_fg_sneaky.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500394 entryUpdated(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
395 assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
396 assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "whatever"));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500397
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500398 entryRemoved(sbn_user1_app1_fg_sneaky);
399 assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
400 assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "a"));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500401
402 // let's try a custom layout
403 sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1, 1, false);
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500404 entryUpdated(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN);
405 assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
406 assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "anything"));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500407 // now let's test an upgrade (non fg to fg)
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500408 entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN);
409 assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
410 assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "b"));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500411 sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500412 entryUpdated(sbn_user1_app1,
Julia Reynoldsfc640012018-02-21 12:25:27 -0500413 NotificationManager.IMPORTANCE_MIN); // this is now a fg notification
414
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500415 assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1));
416 assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500417
418 // remove it, make sure we're out of compliance again
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500419 entryRemoved(sbn_user1_app1); // was fg, should return true
420 entryRemoved(sbn_user1_app1);
421 assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1));
422 assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500423 }
424
Beverly201cdd52019-10-18 14:30:46 -0400425 private StatusBarNotification makeMockSBN(int userId, String pkg, int id, String tag,
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400426 int flags) {
427 final Notification n = mock(Notification.class);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500428 n.extras = new Bundle();
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400429 n.flags = flags;
Beverly201cdd52019-10-18 14:30:46 -0400430 return makeMockSBN(userId, pkg, id, tag, n);
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400431 }
Julia Reynoldsfc640012018-02-21 12:25:27 -0500432
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400433 private StatusBarNotification makeMockSBN(int userid, String pkg, int id, String tag,
434 Notification n) {
435 final StatusBarNotification sbn = mock(StatusBarNotification.class);
436 when(sbn.getNotification()).thenReturn(n);
437 when(sbn.getId()).thenReturn(id);
438 when(sbn.getPackageName()).thenReturn(pkg);
Julia Reynoldsaf78a792018-03-06 14:27:00 -0500439 when(sbn.getTag()).thenReturn(tag);
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400440 when(sbn.getUserId()).thenReturn(userid);
441 when(sbn.getUser()).thenReturn(new UserHandle(userid));
442 when(sbn.getKey()).thenReturn("MOCK:"+userid+"|"+pkg+"|"+id+"|"+tag);
443 return sbn;
444 }
Julia Reynoldsfc640012018-02-21 12:25:27 -0500445
Beverly201cdd52019-10-18 14:30:46 -0400446 private StatusBarNotification makeMockFgSBN(int uid, String pkg, int id,
Julia Reynoldsfc640012018-02-21 12:25:27 -0500447 boolean usesStdLayout) {
448 StatusBarNotification sbn =
Beverly201cdd52019-10-18 14:30:46 -0400449 makeMockSBN(uid, pkg, id, "foo", Notification.FLAG_FOREGROUND_SERVICE);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500450 if (usesStdLayout) {
451 sbn.getNotification().contentView = null;
452 sbn.getNotification().headsUpContentView = null;
453 sbn.getNotification().bigContentView = null;
454 } else {
455 sbn.getNotification().contentView = mock(RemoteViews.class);
456 }
457 return sbn;
458 }
459
Beverly201cdd52019-10-18 14:30:46 -0400460 private StatusBarNotification makeMockFgSBN(int uid, String pkg) {
461 return makeMockSBN(uid, pkg, 1000, "foo", Notification.FLAG_FOREGROUND_SERVICE);
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400462 }
Julia Reynoldsfc640012018-02-21 12:25:27 -0500463
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500464 private StatusBarNotification makeMockDisclosure(int userid, String[] pkgs) {
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400465 final Notification n = mock(Notification.class);
466 n.flags = Notification.FLAG_ONGOING_EVENT;
467 final Bundle extras = new Bundle();
468 if (pkgs != null) extras.putStringArray(Notification.EXTRA_FOREGROUND_APPS, pkgs);
469 n.extras = extras;
Dan Sandler9830b5a2017-10-26 23:27:57 -0400470 n.when = System.currentTimeMillis() - 10000; // ten seconds ago
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400471 final StatusBarNotification sbn = makeMockSBN(userid, "android",
472 SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES,
473 null, n);
474 sbn.getNotification().extras = extras;
475 return sbn;
476 }
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500477
Beverly201cdd52019-10-18 14:30:46 -0400478 private NotificationEntry addFgEntry() {
479 NotificationEntry entry = createFgEntry();
480 mEntryListener.onPendingEntryAdded(entry);
481 return entry;
482 }
483
484 private NotificationEntry createFgEntry() {
485 return new NotificationEntryBuilder()
486 .setSbn(makeMockFgSBN(0, TEST_PACKAGE_NAME, 1000, true))
487 .setImportance(NotificationManager.IMPORTANCE_DEFAULT)
488 .build();
489 }
490
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500491 private void entryRemoved(StatusBarNotification notification) {
Ned Burns636c3792019-09-11 16:59:07 -0400492 mEntryListener.onEntryRemoved(
493 new NotificationEntryBuilder()
494 .setSbn(notification)
495 .build(),
496 null,
497 false);
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500498 }
499
500 private void entryAdded(StatusBarNotification notification, int importance) {
Ned Burns60e94592019-09-06 14:47:25 -0400501 NotificationEntry entry = new NotificationEntryBuilder()
502 .setSbn(notification)
503 .setImportance(importance)
504 .build();
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500505 mEntryListener.onPendingEntryAdded(entry);
506 }
507
508 private void entryUpdated(StatusBarNotification notification, int importance) {
Ned Burns60e94592019-09-06 14:47:25 -0400509 NotificationEntry entry = new NotificationEntryBuilder()
510 .setSbn(notification)
511 .setImportance(importance)
512 .build();
Beverly201cdd52019-10-18 14:30:46 -0400513 mEntryListener.onPreEntryUpdated(entry);
Gus Prevaseb4e2e12018-12-28 14:57:59 -0500514 }
Beverly201cdd52019-10-18 14:30:46 -0400515
516 @UserIdInt private static final int USERID_ONE = 10; // UserManagerService.MIN_USER_ID;
517 @UserIdInt private static final int USERID_TWO = USERID_ONE + 1;
518 private static final String TEST_PACKAGE_NAME = "test";
Dan Sandlerf5aafb92017-05-28 12:18:53 -0400519}