1 /*
2  * Copyright (C) 2020 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 package com.android.server.notification;
17 
18 import static android.Manifest.permission.RECEIVE_SENSITIVE_NOTIFICATIONS;
19 import static android.content.pm.PackageManager.MATCH_ANY_USER;
20 import static android.permission.PermissionManager.PERMISSION_GRANTED;
21 import static android.service.notification.Flags.FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS;
22 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
23 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
24 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
25 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
26 
27 import static com.android.server.notification.NotificationManagerService.NotificationListeners.TAG_REQUESTED_LISTENERS;
28 
29 import static com.google.common.truth.Truth.assertThat;
30 
31 import static junit.framework.Assert.assertFalse;
32 import static junit.framework.Assert.assertTrue;
33 
34 import static org.junit.Assert.fail;
35 import static org.mockito.ArgumentMatchers.any;
36 import static org.mockito.ArgumentMatchers.anyInt;
37 import static org.mockito.ArgumentMatchers.anyString;
38 import static org.mockito.ArgumentMatchers.eq;
39 import static org.mockito.ArgumentMatchers.intThat;
40 import static org.mockito.ArgumentMatchers.nullable;
41 import static org.mockito.Mockito.atLeast;
42 import static org.mockito.Mockito.doAnswer;
43 import static org.mockito.Mockito.doNothing;
44 import static org.mockito.Mockito.doReturn;
45 import static org.mockito.Mockito.mock;
46 import static org.mockito.Mockito.never;
47 import static org.mockito.Mockito.reset;
48 import static org.mockito.Mockito.spy;
49 import static org.mockito.Mockito.times;
50 import static org.mockito.Mockito.verify;
51 import static org.mockito.Mockito.when;
52 
53 import android.annotation.SuppressLint;
54 import android.app.INotificationManager;
55 import android.app.Notification;
56 import android.app.NotificationChannel;
57 import android.app.NotificationChannelGroup;
58 import android.app.NotificationManager;
59 import android.companion.AssociationInfo;
60 import android.companion.ICompanionDeviceManager;
61 import android.content.ComponentName;
62 import android.content.pm.IPackageManager;
63 import android.content.pm.PackageManager;
64 import android.content.pm.ServiceInfo;
65 import android.content.pm.VersionedPackage;
66 import android.content.res.Resources;
67 import android.os.Bundle;
68 import android.os.Parcel;
69 import android.os.RemoteException;
70 import android.os.UserHandle;
71 import android.platform.test.flag.junit.SetFlagsRule;
72 import android.service.notification.INotificationListener;
73 import android.service.notification.IStatusBarNotificationHolder;
74 import android.service.notification.NotificationListenerFilter;
75 import android.service.notification.NotificationListenerService;
76 import android.service.notification.NotificationRankingUpdate;
77 import android.service.notification.NotificationStats;
78 import android.service.notification.StatusBarNotification;
79 import android.testing.TestableContext;
80 import android.util.ArraySet;
81 import android.util.Pair;
82 import android.util.Xml;
83 
84 import com.android.modules.utils.TypedXmlPullParser;
85 import com.android.modules.utils.TypedXmlSerializer;
86 import com.android.server.UiServiceTestCase;
87 import com.android.server.pm.pkg.PackageStateInternal;
88 
89 import com.google.common.collect.ImmutableList;
90 
91 import org.junit.Before;
92 import org.junit.Rule;
93 import org.junit.Test;
94 import org.mockito.ArgumentCaptor;
95 import org.mockito.ArgumentMatcher;
96 import org.mockito.Mock;
97 import org.mockito.MockitoAnnotations;
98 import org.mockito.internal.util.reflection.FieldSetter;
99 
100 import java.io.BufferedInputStream;
101 import java.io.BufferedOutputStream;
102 import java.io.ByteArrayInputStream;
103 import java.io.ByteArrayOutputStream;
104 import java.util.ArrayList;
105 import java.util.Arrays;
106 import java.util.List;
107 import java.util.concurrent.CountDownLatch;
108 
109 @SuppressLint("GuardedBy")
110 public class NotificationListenersTest extends UiServiceTestCase {
111 
112     @Rule
113     public SetFlagsRule mSetFlagsRule = new SetFlagsRule();
114 
115     @Mock
116     private PackageManager mPm;
117     @Mock
118     private IPackageManager miPm;
119     @Mock
120     private Resources mResources;
121 
122     // mNm is going to be a spy, so it must use doReturn.when, not when.thenReturn, as
123     // when.thenReturn will result in the real method being called
124     NotificationManagerService mNm;
125     @Mock
126     private INotificationManager mINm;
127     private TestableContext mContext = spy(getContext());
128 
129     NotificationManagerService.NotificationListeners mListeners;
130 
131     private int mUid1 = 98989;
132     private ComponentName mCn1 = new ComponentName("pkg", "pkg.cmp");
133     private ComponentName mCn2 = new ComponentName("pkg2", "pkg2.cmp2");
134     private ComponentName mUninstalledComponent = new ComponentName("pkg3",
135             "pkg3.NotificationListenerService");
136 
137     @Before
setUp()138     public void setUp() throws Exception {
139         mNm = spy(new NotificationManagerService(mContext));
140         MockitoAnnotations.initMocks(this);
141         getContext().setMockPackageManager(mPm);
142         doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
143 
144         doReturn(true).when(mNm).isInteractionVisibleToListener(any(), anyInt());
145 
146         mListeners = spy(mNm.new NotificationListeners(
147                 mContext, new Object(), mock(ManagedServices.UserProfiles.class), miPm));
148         when(mNm.getBinderService()).thenReturn(mINm);
149         mNm.mPackageManager = mock(IPackageManager.class);
150         PackageStateInternal psi = mock(PackageStateInternal.class);
151         mNm.mPackageManagerInternal = mPmi;
152         when(psi.getAppId()).thenReturn(mUid1);
153         when(mNm.mPackageManagerInternal.getPackageStateInternal(any())).thenReturn(psi);
154         mNm.mCompanionManager = mock(ICompanionDeviceManager.class);
155         when(mNm.mCompanionManager.getAllAssociationsForUser(anyInt()))
156                 .thenReturn(new ArrayList<>());
157         mNm.mHandler = mock(NotificationManagerService.WorkerHandler.class);
158         mNm.mAssistants = mock(NotificationManagerService.NotificationAssistants.class);
159         FieldSetter.setField(mNm,
160                 NotificationManagerService.class.getDeclaredField("mListeners"),
161                 mListeners);
162         doReturn(android.service.notification.NotificationListenerService.TRIM_FULL)
163                 .when(mListeners).getOnNotificationPostedTrim(any());
164     }
165 
166     @Test
testReadExtraTag()167     public void testReadExtraTag() throws Exception {
168         String xml = "<" + TAG_REQUESTED_LISTENERS + ">"
169                 + "<listener component=\"" + mCn1.flattenToString() + "\" user=\"0\">"
170                 + "<allowed types=\"7\" />"
171                 + "</listener>"
172                 + "<listener component=\"" + mCn2.flattenToString() + "\" user=\"10\">"
173                 + "<allowed types=\"4\" />"
174                 + "<disallowed pkg=\"pkg1\" uid=\"243\"/>"
175                 + "</listener>"
176                 + "</" + TAG_REQUESTED_LISTENERS + ">";
177 
178         TypedXmlPullParser parser = Xml.newFastPullParser();
179         parser.setInput(new BufferedInputStream(
180                 new ByteArrayInputStream(xml.getBytes())), null);
181         parser.nextTag();
182         mListeners.readExtraTag(TAG_REQUESTED_LISTENERS, parser);
183 
184         validateListenersFromXml();
185     }
186 
187     @Test
loadDefaultsFromConfig_forHeadlessSystemUser_loadUninstalled()188     public void loadDefaultsFromConfig_forHeadlessSystemUser_loadUninstalled() throws Exception {
189         // setup with headless system user mode
190         mListeners = spy(mNm.new NotificationListeners(
191                 mContext, new Object(), mock(ManagedServices.UserProfiles.class), miPm,
192                 /* isHeadlessSystemUserMode= */ true));
193         mockDefaultListenerConfigForUninstalledComponent(mUninstalledComponent);
194 
195         mListeners.loadDefaultsFromConfig();
196 
197         assertThat(mListeners.getDefaultComponents()).contains(mUninstalledComponent);
198     }
199 
200     @Test
loadDefaultsFromConfig_forNonHeadlessSystemUser_ignoreUninstalled()201     public void loadDefaultsFromConfig_forNonHeadlessSystemUser_ignoreUninstalled()
202             throws Exception {
203         // setup without headless system user mode
204         mListeners = spy(mNm.new NotificationListeners(
205                 mContext, new Object(), mock(ManagedServices.UserProfiles.class), miPm,
206                 /* isHeadlessSystemUserMode= */ false));
207         mockDefaultListenerConfigForUninstalledComponent(mUninstalledComponent);
208 
209         mListeners.loadDefaultsFromConfig();
210 
211         assertThat(mListeners.getDefaultComponents()).doesNotContain(mUninstalledComponent);
212     }
213 
mockDefaultListenerConfigForUninstalledComponent(ComponentName componentName)214     private void mockDefaultListenerConfigForUninstalledComponent(ComponentName componentName) {
215         ArraySet<ComponentName> components = new ArraySet<>(Arrays.asList(componentName));
216         when(mResources
217                 .getString(
218                         com.android.internal.R.string.config_defaultListenerAccessPackages))
219                 .thenReturn(componentName.getPackageName());
220         when(mContext.getResources()).thenReturn(mResources);
221         doReturn(components).when(mListeners).queryPackageForServices(
222                 eq(componentName.getPackageName()),
223                 intThat(hasIntBitFlag(MATCH_ANY_USER)),
224                 anyInt());
225     }
226 
hasIntBitFlag(int flag)227     public static ArgumentMatcher<Integer> hasIntBitFlag(int flag) {
228         return arg -> arg != null && ((arg & flag) == flag);
229     }
230 
231     @Test
testWriteExtraTag()232     public void testWriteExtraTag() throws Exception {
233         NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>());
234         VersionedPackage a1 = new VersionedPackage("pkg1", 243);
235         NotificationListenerFilter nlf2 =
236                 new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[]{a1}));
237         mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf);
238         mListeners.setNotificationListenerFilter(Pair.create(mCn2, 10), nlf2);
239 
240         TypedXmlSerializer serializer = Xml.newFastSerializer();
241         ByteArrayOutputStream baos = new ByteArrayOutputStream();
242         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
243         serializer.startDocument(null, true);
244         mListeners.writeExtraXmlTags(serializer);
245         serializer.endDocument();
246         serializer.flush();
247 
248         TypedXmlPullParser parser = Xml.newFastPullParser();
249         parser.setInput(new BufferedInputStream(
250                 new ByteArrayInputStream(baos.toByteArray())), null);
251         parser.nextTag();
252         mListeners.readExtraTag("req_listeners", parser);
253 
254         validateListenersFromXml();
255     }
256 
validateListenersFromXml()257     private void validateListenersFromXml() {
258         assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn1, 0)).getTypes())
259                 .isEqualTo(7);
260         assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn1, 0))
261                 .getDisallowedPackages())
262                 .isEmpty();
263 
264         assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 10)).getTypes())
265                 .isEqualTo(4);
266         VersionedPackage a1 = new VersionedPackage("pkg1", 243);
267         assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 10))
268                 .getDisallowedPackages())
269                 .contains(a1);
270     }
271 
272     @Test
testOnUserRemoved()273     public void testOnUserRemoved() {
274         NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>());
275         VersionedPackage a1 = new VersionedPackage("pkg1", 243);
276         NotificationListenerFilter nlf2 =
277                 new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1}));
278         mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf);
279         mListeners.setNotificationListenerFilter(Pair.create(mCn2, 10), nlf2);
280 
281         mListeners.onUserRemoved(0);
282 
283         assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn1, 0))).isNull();
284         assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 10)).getTypes())
285                 .isEqualTo(4);
286     }
287 
288     @Test
testEnsureFilters_newServiceNoMetadata()289     public void testEnsureFilters_newServiceNoMetadata() {
290         ServiceInfo si = new ServiceInfo();
291         si.packageName = "new2";
292         si.name = "comp2";
293 
294         mListeners.ensureFilters(si, 0);
295 
296         assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 0))).isNull();
297     }
298 
299     @Test
testEnsureFilters_preExisting()300     public void testEnsureFilters_preExisting() {
301         // one exists already, say from xml
302         VersionedPackage a1 = new VersionedPackage("pkg1", 243);
303         NotificationListenerFilter nlf =
304                 new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1}));
305         mListeners.setNotificationListenerFilter(Pair.create(mCn2, 0), nlf);
306         ServiceInfo siOld = new ServiceInfo();
307         siOld.packageName = mCn2.getPackageName();
308         siOld.name = mCn2.getClassName();
309 
310         mListeners.ensureFilters(siOld, 0);
311 
312         assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 0))).isEqualTo(nlf);
313     }
314 
315     @Test
testEnsureFilters_newServiceWithMetadata()316     public void testEnsureFilters_newServiceWithMetadata() {
317         ServiceInfo si = new ServiceInfo();
318         si.packageName = "new";
319         si.name = "comp";
320         si.metaData = new Bundle();
321         si.metaData.putString(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, "1|2");
322 
323         mListeners.ensureFilters(si, 0);
324 
325         assertThat(mListeners.getNotificationListenerFilter(
326                 Pair.create(si.getComponentName(), 0)).getTypes())
327                 .isEqualTo(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ALERTING);
328     }
329 
330     @Test
testEnsureFilters_newServiceWithMetadata_namesNotNumbers()331     public void testEnsureFilters_newServiceWithMetadata_namesNotNumbers() {
332         ServiceInfo si = new ServiceInfo();
333         si.packageName = "new";
334         si.name = "comp";
335         si.metaData = new Bundle();
336         si.metaData.putString(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES,
337                 "conversations|ALERTING");
338 
339         mListeners.ensureFilters(si, 0);
340 
341         assertThat(mListeners.getNotificationListenerFilter(
342                 Pair.create(si.getComponentName(), 0)).getTypes())
343                 .isEqualTo(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ALERTING);
344     }
345 
346     @Test
testEnsureFilters_newServiceWithMetadata_onlyOneListed()347     public void testEnsureFilters_newServiceWithMetadata_onlyOneListed() {
348         ServiceInfo si = new ServiceInfo();
349         si.packageName = "new";
350         si.name = "comp";
351         si.metaData = new Bundle();
352         si.metaData.putInt(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, 2);
353 
354         mListeners.ensureFilters(si, 0);
355 
356         assertThat(mListeners.getNotificationListenerFilter(
357                 Pair.create(si.getComponentName(), 0)).getTypes())
358                 .isEqualTo(FLAG_FILTER_TYPE_ALERTING);
359     }
360 
361     @Test
testEnsureFilters_newServiceWithMetadata_disabledTypes()362     public void testEnsureFilters_newServiceWithMetadata_disabledTypes() {
363         ServiceInfo si = new ServiceInfo();
364         si.packageName = "new";
365         si.name = "comp";
366         si.metaData = new Bundle();
367         si.metaData.putString(NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES, "1|2");
368 
369         mListeners.ensureFilters(si, 0);
370 
371         assertThat(mListeners.getNotificationListenerFilter(
372                 Pair.create(si.getComponentName(), 0)).getTypes())
373                 .isEqualTo(FLAG_FILTER_TYPE_SILENT | FLAG_FILTER_TYPE_ONGOING);
374     }
375 
376     @Test
testEnsureFilters_newServiceWithMetadata_disabledTypes_mixedText()377     public void testEnsureFilters_newServiceWithMetadata_disabledTypes_mixedText() {
378         ServiceInfo si = new ServiceInfo();
379         si.packageName = "new";
380         si.name = "comp";
381         si.metaData = new Bundle();
382         si.metaData.putString(NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES,
383                 "1|alerting");
384 
385         mListeners.ensureFilters(si, 0);
386 
387         assertThat(mListeners.getNotificationListenerFilter(
388                 Pair.create(si.getComponentName(), 0)).getTypes())
389                 .isEqualTo(FLAG_FILTER_TYPE_SILENT | FLAG_FILTER_TYPE_ONGOING);
390     }
391 
392     @Test
testEnsureFilters_newServiceWithMetadata_metaDataDisagrees()393     public void testEnsureFilters_newServiceWithMetadata_metaDataDisagrees() {
394         ServiceInfo si = new ServiceInfo();
395         si.packageName = "new";
396         si.name = "comp";
397         si.metaData = new Bundle();
398         si.metaData.putString(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, "1|2");
399         si.metaData.putInt(NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES, 1);
400 
401         mListeners.ensureFilters(si, 0);
402 
403         assertThat(mListeners.getNotificationListenerFilter(
404                 Pair.create(si.getComponentName(), 0)).getTypes())
405                 .isEqualTo(FLAG_FILTER_TYPE_ALERTING);
406     }
407 
408     @Test
testEnsureFilters_newServiceWithEmptyMetadata()409     public void testEnsureFilters_newServiceWithEmptyMetadata() {
410         ServiceInfo si = new ServiceInfo();
411         si.packageName = "new";
412         si.name = "comp";
413         si.metaData = new Bundle();
414         si.metaData.putString(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, "");
415 
416         mListeners.ensureFilters(si, 0);
417 
418         assertThat(mListeners.getNotificationListenerFilter(
419                 Pair.create(si.getComponentName(), 0)).getTypes())
420                 .isEqualTo(0);
421     }
422 
423     @Test
testOnPackageChanged()424     public void testOnPackageChanged() {
425         NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>());
426         VersionedPackage a1 = new VersionedPackage("pkg1", 243);
427         NotificationListenerFilter nlf2 =
428                 new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1}));
429         mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf);
430         mListeners.setNotificationListenerFilter(Pair.create(mCn2, 10), nlf2);
431 
432         String[] pkgs = new String[] {mCn1.getPackageName()};
433         int[] uids = new int[] {1};
434         mListeners.onPackagesChanged(false, pkgs, uids);
435 
436         // not removing; no change
437         assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn1, 0)).getTypes())
438                 .isEqualTo(7);
439         assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 10)).getTypes())
440                 .isEqualTo(4);
441     }
442 
443     @Test
testOnPackageChanged_removing()444     public void testOnPackageChanged_removing() {
445         NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>());
446         VersionedPackage a1 = new VersionedPackage("pkg1", 243);
447         NotificationListenerFilter nlf2 =
448                 new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1}));
449         mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf);
450         mListeners.setNotificationListenerFilter(Pair.create(mCn2, 0), nlf2);
451 
452         String[] pkgs = new String[] {mCn1.getPackageName()};
453         int[] uids = new int[] {1};
454         mListeners.onPackagesChanged(true, pkgs, uids);
455 
456         // only mCn1 removed
457         assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn1, 0))).isNull();
458         assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 0)).getTypes())
459                 .isEqualTo(4);
460     }
461 
462     @Test
testOnPackageChanged_removingPackage_removeFromDisallowed()463     public void testOnPackageChanged_removingPackage_removeFromDisallowed() {
464         NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>());
465         VersionedPackage a1 = new VersionedPackage("pkg1", 243);
466         NotificationListenerFilter nlf2 =
467                 new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1}));
468         mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf);
469         mListeners.setNotificationListenerFilter(Pair.create(mCn2, 0), nlf2);
470 
471         String[] pkgs = new String[] {"pkg1"};
472         int[] uids = new int[] {243};
473         mListeners.onPackagesChanged(true, pkgs, uids);
474 
475         assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn1, 0))
476                 .getDisallowedPackages()).isEmpty();
477         assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 0))
478                 .getDisallowedPackages()).isEmpty();
479     }
480 
481     @Test
testOnPackageChanged_notRemovingPackage_staysInDisallowed()482     public void testOnPackageChanged_notRemovingPackage_staysInDisallowed() {
483         NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>());
484         VersionedPackage a1 = new VersionedPackage("pkg1", 243);
485         NotificationListenerFilter nlf2 =
486                 new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1}));
487         mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf);
488         mListeners.setNotificationListenerFilter(Pair.create(mCn2, 0), nlf2);
489 
490         String[] pkgs = new String[] {"pkg1"};
491         int[] uids = new int[] {243};
492         mListeners.onPackagesChanged(false, pkgs, uids);
493 
494         assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 0))
495                 .getDisallowedPackages()).contains(a1);
496     }
497 
498     @Test
testHasAllowedListener()499     public void testHasAllowedListener() {
500         final int uid1 = 1, uid2 = 2;
501         // enable mCn1 but not mCn2 for uid1
502         mListeners.addApprovedList(mCn1.flattenToString(), uid1, true);
503 
504         // verify that:
505         // the package for mCn1 has an allowed listener for uid1 and not uid2
506         assertTrue(mListeners.hasAllowedListener(mCn1.getPackageName(), uid1));
507         assertFalse(mListeners.hasAllowedListener(mCn1.getPackageName(), uid2));
508 
509         // and that mCn2 has no allowed listeners for either user id
510         assertFalse(mListeners.hasAllowedListener(mCn2.getPackageName(), uid1));
511         assertFalse(mListeners.hasAllowedListener(mCn2.getPackageName(), uid2));
512     }
513 
514     @Test
testBroadcastUsers()515     public void testBroadcastUsers() {
516         int userId = 0;
517         mListeners.setPackageOrComponentEnabled(mCn1.flattenToString(), userId, true, false, true);
518 
519         verify(mContext).sendBroadcastAsUser(
520                 any(), eq(UserHandle.of(userId)), nullable(String.class));
521     }
522 
523     @Test
testNotifyPostedLockedInLockdownMode()524     public void testNotifyPostedLockedInLockdownMode() {
525         NotificationRecord r0 = mock(NotificationRecord.class);
526         NotificationRecord old0 = mock(NotificationRecord.class);
527         UserHandle uh0 = mock(UserHandle.class);
528 
529         NotificationRecord r1 = mock(NotificationRecord.class);
530         NotificationRecord old1 = mock(NotificationRecord.class);
531         UserHandle uh1 = mock(UserHandle.class);
532 
533         // Neither user0 and user1 is in the lockdown mode
534         when(r0.getUser()).thenReturn(uh0);
535         when(uh0.getIdentifier()).thenReturn(0);
536         doReturn(false).when(mNm).isInLockDownMode(0);
537 
538         when(r1.getUser()).thenReturn(uh1);
539         when(uh1.getIdentifier()).thenReturn(1);
540         doReturn(false).when(mNm).isInLockDownMode(1);
541 
542         mListeners.notifyPostedLocked(r0, old0, true);
543         mListeners.notifyPostedLocked(r0, old0, false);
544         verify(r0, atLeast(2)).getSbn();
545 
546         mListeners.notifyPostedLocked(r1, old1, true);
547         mListeners.notifyPostedLocked(r1, old1, false);
548         verify(r1, atLeast(2)).getSbn();
549 
550         // Reset
551         reset(r0);
552         reset(old0);
553         reset(r1);
554         reset(old1);
555 
556         // Only user 0 is in the lockdown mode
557         when(r0.getUser()).thenReturn(uh0);
558         when(uh0.getIdentifier()).thenReturn(0);
559         when(mNm.isInLockDownMode(0)).thenReturn(true);
560 
561         when(r1.getUser()).thenReturn(uh1);
562         when(uh1.getIdentifier()).thenReturn(1);
563         when(mNm.isInLockDownMode(1)).thenReturn(false);
564 
565         mListeners.notifyPostedLocked(r0, old0, true);
566         mListeners.notifyPostedLocked(r0, old0, false);
567         verify(r0, never()).getSbn();
568 
569         mListeners.notifyPostedLocked(r1, old1, true);
570         mListeners.notifyPostedLocked(r1, old1, false);
571         verify(r1, atLeast(2)).getSbn();
572     }
573 
574     @Test
testNotifyRemovedLockedInLockdownMode()575     public void testNotifyRemovedLockedInLockdownMode() throws NoSuchFieldException {
576         NotificationRecord r0 = mock(NotificationRecord.class);
577         NotificationStats rs0 = mock(NotificationStats.class);
578         UserHandle uh0 = mock(UserHandle.class);
579 
580         NotificationRecord r1 = mock(NotificationRecord.class);
581         NotificationStats rs1 = mock(NotificationStats.class);
582         UserHandle uh1 = mock(UserHandle.class);
583 
584         StatusBarNotification sbn = mock(StatusBarNotification.class);
585         FieldSetter.setField(mNm,
586                 NotificationManagerService.class.getDeclaredField("mHandler"),
587                 mock(NotificationManagerService.WorkerHandler.class));
588 
589         // Neither user0 and user1 is in the lockdown mode
590         when(r0.getUser()).thenReturn(uh0);
591         when(uh0.getIdentifier()).thenReturn(0);
592         doReturn(false).when(mNm).isInLockDownMode(0);
593         when(r0.getSbn()).thenReturn(sbn);
594 
595         when(r1.getUser()).thenReturn(uh1);
596         when(uh1.getIdentifier()).thenReturn(1);
597         doReturn(false).when(mNm).isInLockDownMode(1);
598         when(r1.getSbn()).thenReturn(sbn);
599 
600         mListeners.notifyRemovedLocked(r0, 0, rs0);
601         mListeners.notifyRemovedLocked(r0, 0, rs0);
602         verify(r0, atLeast(2)).getSbn();
603 
604         mListeners.notifyRemovedLocked(r1, 0, rs1);
605         mListeners.notifyRemovedLocked(r1, 0, rs1);
606         verify(r1, atLeast(2)).getSbn();
607 
608         // Reset
609         reset(r0);
610         reset(rs0);
611         reset(r1);
612         reset(rs1);
613 
614         // Only user 0 is in the lockdown mode
615         when(r0.getUser()).thenReturn(uh0);
616         when(uh0.getIdentifier()).thenReturn(0);
617         when(mNm.isInLockDownMode(0)).thenReturn(true);
618         when(r0.getSbn()).thenReturn(sbn);
619 
620         when(r1.getUser()).thenReturn(uh1);
621         when(uh1.getIdentifier()).thenReturn(1);
622         when(mNm.isInLockDownMode(1)).thenReturn(false);
623         when(r1.getSbn()).thenReturn(sbn);
624 
625         mListeners.notifyRemovedLocked(r0, 0, rs0);
626         mListeners.notifyRemovedLocked(r0, 0, rs0);
627         verify(r0, never()).getSbn();
628 
629         mListeners.notifyRemovedLocked(r1, 0, rs1);
630         mListeners.notifyRemovedLocked(r1, 0, rs1);
631         verify(r1, atLeast(2)).getSbn();
632     }
633 
634     @Test
testImplicitGrant()635     public void testImplicitGrant() {
636         String pkg = "pkg";
637         int uid = 9;
638         NotificationChannel channel = new NotificationChannel("id", "name",
639                 NotificationManager.IMPORTANCE_HIGH);
640         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
641                 .setContentTitle("foo")
642                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
643                 .setTimeoutAfter(1);
644 
645         StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0,
646                 nb.build(), UserHandle.getUserHandleForUid(uid), null, 0);
647         NotificationRecord r = new NotificationRecord(mContext, sbn, channel);
648 
649         ManagedServices.ManagedServiceInfo info = mListeners.new ManagedServiceInfo(
650                 null, new ComponentName("a", "a"), sbn.getUserId(), false, null, 33, 33);
651         List<ManagedServices.ManagedServiceInfo> services = ImmutableList.of(info);
652         when(mListeners.getServices()).thenReturn(services);
653 
654         doReturn(true).when(mNm).isVisibleToListener(any(), anyInt(), any());
655         doReturn(mock(NotificationRankingUpdate.class)).when(mNm).makeRankingUpdateLocked(info);
656         doReturn(false).when(mNm).isInLockDownMode(anyInt());
657         doNothing().when(mNm).updateUriPermissions(any(), any(), any(), anyInt());
658 
659         mListeners.notifyPostedLocked(r, null);
660 
661         verify(mPmi).grantImplicitAccess(sbn.getUserId(), null, UserHandle.getAppId(33),
662                 sbn.getUid(), false, false);
663     }
664 
665     @Test
testUpdateGroup_notifyTwoListeners()666     public void testUpdateGroup_notifyTwoListeners() throws Exception {
667         final NotificationChannelGroup updated = new NotificationChannelGroup("id", "name");
668         updated.setChannels(ImmutableList.of(
669                 new NotificationChannel("a", "a", 1), new NotificationChannel("b", "b", 2)));
670         updated.setBlocked(true);
671 
672         ManagedServices.ManagedServiceInfo i1 = getParcelingListener(updated);
673         ManagedServices.ManagedServiceInfo i2= getParcelingListener(updated);
674         when(mListeners.getServices()).thenReturn(ImmutableList.of(i1, i2));
675         NotificationChannelGroup existing = new NotificationChannelGroup("id", "name");
676 
677         mListeners.notifyNotificationChannelGroupChanged("pkg", UserHandle.of(0), updated, 0);
678         Thread.sleep(500);
679 
680         verify(((INotificationListener) i1.getService()), times(1))
681                 .onNotificationChannelGroupModification(anyString(), any(), any(), anyInt());
682     }
683 
684     @Test
testNotificationListenerFilter_threadSafety()685     public void testNotificationListenerFilter_threadSafety() throws Exception {
686         testThreadSafety(() -> {
687             mListeners.setNotificationListenerFilter(
688                     new Pair<>(new ComponentName("pkg1", "cls1"), 0),
689                     new NotificationListenerFilter());
690             mListeners.setNotificationListenerFilter(
691                     new Pair<>(new ComponentName("pkg2", "cls2"), 10),
692                     new NotificationListenerFilter());
693             mListeners.setNotificationListenerFilter(
694                     new Pair<>(new ComponentName("pkg3", "cls3"), 11),
695                     new NotificationListenerFilter());
696 
697             mListeners.onUserRemoved(10);
698             mListeners.onPackagesChanged(true, new String[]{"pkg1", "pkg2"}, new int[]{0, 0});
699         }, 20, 50);
700     }
701 
702     @Test
testListenerTrusted_withPermission()703     public void testListenerTrusted_withPermission() throws RemoteException {
704         mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
705         when(mNm.mPackageManager.checkUidPermission(RECEIVE_SENSITIVE_NOTIFICATIONS, mUid1))
706                 .thenReturn(PERMISSION_GRANTED);
707         ManagedServices.ManagedServiceInfo info = getMockServiceInfo();
708         mListeners.onServiceAdded(info);
709         assertTrue(mListeners.isUidTrusted(mUid1));
710     }
711 
712     @Test
testListenerTrusted_withSystemSignature()713     public void testListenerTrusted_withSystemSignature() {
714         mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
715         when(mNm.mPackageManagerInternal.isPlatformSigned(mCn1.getPackageName())).thenReturn(true);
716         ManagedServices.ManagedServiceInfo info = getMockServiceInfo();
717         mListeners.onServiceAdded(info);
718         assertTrue(mListeners.isUidTrusted(mUid1));
719     }
720 
721     @Test
testListenerTrusted_withCdmAssociation()722     public void testListenerTrusted_withCdmAssociation() throws Exception {
723         mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
724         mNm.mCompanionManager = mock(ICompanionDeviceManager.class);
725         AssociationInfo assocInfo = mock(AssociationInfo.class);
726         when(assocInfo.isRevoked()).thenReturn(false);
727         when(assocInfo.getPackageName()).thenReturn(mCn1.getPackageName());
728         when(assocInfo.getUserId()).thenReturn(UserHandle.getUserId(mUid1));
729         ArrayList<AssociationInfo> infos = new ArrayList<>();
730         infos.add(assocInfo);
731         when(mNm.mCompanionManager.getAllAssociationsForUser(anyInt())).thenReturn(infos);
732         ManagedServices.ManagedServiceInfo info = getMockServiceInfo();
733         mListeners.onServiceAdded(info);
734         assertTrue(mListeners.isUidTrusted(mUid1));
735     }
736 
737     @Test
testListenerTrusted_ifFlagDisabled()738     public void testListenerTrusted_ifFlagDisabled() {
739         mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
740         ManagedServices.ManagedServiceInfo info = getMockServiceInfo();
741         mListeners.onServiceAdded(info);
742         assertTrue(mListeners.isUidTrusted(mUid1));
743     }
744 
745     @Test
testRedaction_whenPosted()746     public void testRedaction_whenPosted() {
747         mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
748         ArrayList<ManagedServices.ManagedServiceInfo> infos = new ArrayList<>();
749         infos.add(getMockServiceInfo());
750         doReturn(infos).when(mListeners).getServices();
751         doReturn(mock(StatusBarNotification.class))
752                 .when(mListeners).redactStatusBarNotification(any());
753         doReturn(false).when(mNm).isInLockDownMode(anyInt());
754         doReturn(true).when(mNm).isVisibleToListener(any(), anyInt(), any());
755         NotificationRecord r = mock(NotificationRecord.class);
756         when(r.getUser()).thenReturn(UserHandle.of(0));
757         StatusBarNotification sbn = getSbn(0);
758         NotificationRecord old = mock(NotificationRecord.class);
759         when(old.getUser()).thenReturn(UserHandle.of(0));
760         StatusBarNotification oldSbn = getSbn(1);
761         when(r.getSbn()).thenReturn(sbn);
762         when(r.hasSensitiveContent()).thenReturn(true);
763         when(old.getSbn()).thenReturn(oldSbn);
764         when(old.hasSensitiveContent()).thenReturn(true);
765 
766         mListeners.notifyPostedLocked(r, old);
767         verify(mListeners, atLeast(1)).redactStatusBarNotification(eq(sbn));
768         verify(mListeners, never()).redactStatusBarNotification(eq(oldSbn));
769     }
770 
771     @Test
testRedaction_whenPosted_oldRemoved()772     public void testRedaction_whenPosted_oldRemoved() {
773         mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
774         ArrayList<ManagedServices.ManagedServiceInfo> infos = new ArrayList<>();
775         infos.add(getMockServiceInfo());
776         doReturn(infos).when(mListeners).getServices();
777         doReturn(mock(StatusBarNotification.class))
778                 .when(mListeners).redactStatusBarNotification(any());
779         doReturn(false).when(mNm).isInLockDownMode(anyInt());
780         doReturn(true).when(mNm).isVisibleToListener(any(), anyInt(), any());
781         NotificationRecord r = mock(NotificationRecord.class);
782         when(r.getUser()).thenReturn(UserHandle.of(0));
783         StatusBarNotification sbn = getSbn(0);
784         NotificationRecord old = mock(NotificationRecord.class);
785         when(old.getUser()).thenReturn(UserHandle.of(0));
786         StatusBarNotification oldSbn = getSbn(1);
787         when(r.getSbn()).thenReturn(sbn);
788         when(r.hasSensitiveContent()).thenReturn(true);
789         when(old.getSbn()).thenReturn(oldSbn);
790         when(old.hasSensitiveContent()).thenReturn(true);
791 
792         doReturn(true).when(mNm).isVisibleToListener(eq(oldSbn), anyInt(), any());
793         doReturn(false).when(mNm).isVisibleToListener(eq(sbn), anyInt(), any());
794         mListeners.notifyPostedLocked(r, old);
795         // When the old sbn is removed, the old should be redacted
796         verify(mListeners, atLeast(1)).redactStatusBarNotification(eq(oldSbn));
797     }
798 
799     @Test
testRedaction_whenRemoved()800     public void testRedaction_whenRemoved() {
801         mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
802         doReturn(mock(StatusBarNotification.class))
803                 .when(mListeners).redactStatusBarNotification(any());
804         ArrayList<ManagedServices.ManagedServiceInfo> infos = new ArrayList<>();
805         infos.add(getMockServiceInfo());
806         doReturn(infos).when(mListeners).getServices();
807         doReturn(false).when(mNm).isInLockDownMode(anyInt());
808         doReturn(true).when(mNm).isVisibleToListener(any(), anyInt(), any());
809         NotificationRecord r = mock(NotificationRecord.class);
810         when(r.getUser()).thenReturn(UserHandle.of(0));
811         StatusBarNotification sbn = getSbn(0);
812         when(r.getSbn()).thenReturn(sbn);
813         when(r.hasSensitiveContent()).thenReturn(true);
814         mNm.mAssistants = mock(NotificationManagerService.NotificationAssistants.class);
815 
816         mListeners.notifyRemovedLocked(r, 0, mock(NotificationStats.class));
817         verify(mListeners, atLeast(1)).redactStatusBarNotification(any());
818     }
819 
820     @Test
testRedaction_noneIfFlagDisabled()821     public void testRedaction_noneIfFlagDisabled() {
822         mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
823         ArrayList<ManagedServices.ManagedServiceInfo> infos = new ArrayList<>();
824         infos.add(getMockServiceInfo());
825         doReturn(infos).when(mListeners).getServices();
826         doReturn(false).when(mNm).isInLockDownMode(anyInt());
827         doReturn(true).when(mNm).isVisibleToListener(any(), anyInt(), any());
828         NotificationRecord r = mock(NotificationRecord.class);
829         when(r.getUser()).thenReturn(UserHandle.of(0));
830         StatusBarNotification sbn = getSbn(0);
831         when(r.getSbn()).thenReturn(sbn);
832         when(r.hasSensitiveContent()).thenReturn(true);
833         mListeners.notifyRemovedLocked(r, 0, mock(NotificationStats.class));
834         verify(mListeners, never()).redactStatusBarNotification(eq(sbn));
835     }
836 
837     @Test
testListenerPost_UpdateLifetimeExtended()838     public void testListenerPost_UpdateLifetimeExtended() throws Exception {
839         mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);
840 
841         // Create original notification, with FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY.
842         String pkg = "pkg";
843         int uid = 9;
844         UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
845         NotificationChannel channel = new NotificationChannel("id", "name",
846                 NotificationManager.IMPORTANCE_HIGH);
847         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
848                 .setContentTitle("foo")
849                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
850                 .setFlag(Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, true);
851         StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0,
852                 nb.build(), userHandle, null, 0);
853         NotificationRecord old = new NotificationRecord(mContext, sbn, channel);
854 
855         // Creates updated notification (without FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY)
856         Notification.Builder nb2 = new Notification.Builder(mContext, channel.getId())
857                 .setContentTitle("new title")
858                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
859                 .setFlag(Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, false);
860         StatusBarNotification sbn2 = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0,
861                 nb2.build(), userHandle, null, 0);
862         NotificationRecord toPost = new NotificationRecord(mContext, sbn2, channel);
863 
864         // Create system ui-like service.
865         ManagedServices.ManagedServiceInfo info = mListeners.new ManagedServiceInfo(
866                 null, new ComponentName("a", "a"), sbn2.getUserId(), false, null, 33, 33);
867         info.isSystemUi = true;
868         INotificationListener l1 = mock(INotificationListener.class);
869         info.service = l1;
870         List<ManagedServices.ManagedServiceInfo> services = ImmutableList.of(info);
871         when(mListeners.getServices()).thenReturn(services);
872 
873         FieldSetter.setField(mNm,
874                 NotificationManagerService.class.getDeclaredField("mHandler"),
875                 mock(NotificationManagerService.WorkerHandler.class));
876         doReturn(true).when(mNm).isVisibleToListener(any(), anyInt(), any());
877         doReturn(mock(NotificationRankingUpdate.class)).when(mNm).makeRankingUpdateLocked(info);
878         doReturn(false).when(mNm).isInLockDownMode(anyInt());
879         doNothing().when(mNm).updateUriPermissions(any(), any(), any(), anyInt());
880         doReturn(sbn2).when(mListeners).redactStatusBarNotification(sbn2);
881         doReturn(sbn2).when(mListeners).redactStatusBarNotification(any());
882 
883         // The notification change is posted to the service listener.
884         mListeners.notifyPostedLocked(toPost, old);
885 
886         // Verify that the post occcurs with the updated notification value.
887         ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
888         verify(mNm.mHandler, times(1)).post(runnableCaptor.capture());
889         runnableCaptor.getValue().run();
890         ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor =
891                 ArgumentCaptor.forClass(IStatusBarNotificationHolder.class);
892         verify(l1, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
893         StatusBarNotification sbnResult = sbnCaptor.getValue().get();
894         assertThat(sbnResult.getNotification()
895                 .extras.getCharSequence(Notification.EXTRA_TITLE).toString())
896                 .isEqualTo("new title");
897     }
898 
899     /**
900      * Helper method to test the thread safety of some operations.
901      *
902      * <p>Runs the supplied {@code operationToTest}, {@code nRunsPerThread} times,
903      * concurrently using {@code nThreads} threads, and waits for all of them to finish.
904      */
testThreadSafety(Runnable operationToTest, int nThreads, int nRunsPerThread)905     private static void testThreadSafety(Runnable operationToTest, int nThreads,
906             int nRunsPerThread) throws InterruptedException {
907         final CountDownLatch startLatch = new CountDownLatch(1);
908         final CountDownLatch doneLatch = new CountDownLatch(nThreads);
909 
910         for (int i = 0; i < nThreads; i++) {
911             Runnable threadRunnable = () -> {
912                 try {
913                     startLatch.await();
914                     for (int j = 0; j < nRunsPerThread; j++) {
915                         operationToTest.run();
916                     }
917                 } catch (InterruptedException e) {
918                     e.printStackTrace();
919                 } finally {
920                     doneLatch.countDown();
921                 }
922             };
923             new Thread(threadRunnable, "Test Thread #" + i).start();
924         }
925 
926         // Ready set go
927         startLatch.countDown();
928 
929         // Wait for all test threads to be done.
930         doneLatch.await();
931     }
932 
getParcelingListener( final NotificationChannelGroup toParcel)933     private ManagedServices.ManagedServiceInfo getParcelingListener(
934             final NotificationChannelGroup toParcel)
935             throws RemoteException {
936         ManagedServices.ManagedServiceInfo i1 = getMockServiceInfo();
937         INotificationListener l1 = (INotificationListener) i1.getService();
938         doAnswer(invocationOnMock -> {
939             try {
940                 toParcel.writeToParcel(Parcel.obtain(), 0);
941             } catch (Exception e) {
942                 fail("Failed to parcel group to listener");
943                 return e;
944 
945             }
946             return null;
947         }).when(l1).onNotificationChannelGroupModification(anyString(), any(), any(), anyInt());
948         return i1;
949     }
950 
getMockServiceInfo()951     private ManagedServices.ManagedServiceInfo getMockServiceInfo() {
952         ManagedServices.ManagedServiceInfo i1 = mock(ManagedServices.ManagedServiceInfo.class);
953         when(i1.isSystem()).thenReturn(true);
954         INotificationListener l1 = mock(INotificationListener.class);
955         when(i1.enabledAndUserMatches(anyInt())).thenReturn(true);
956         when(i1.getService()).thenReturn(l1);
957         i1.service = l1;
958         i1.uid = mUid1;
959         i1.component = mCn1;
960         return i1;
961     }
962 
getSbn(int id)963     private StatusBarNotification getSbn(int id) {
964         return new StatusBarNotification("pkg1", "pkg1", id, "", mUid1, 0,
965                 mock(Notification.class), UserHandle.of(0), "", 0);
966 
967     }
968 }
969