1 /*
2  * Copyright (C) 2016 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.app.Notification.FLAG_AUTO_CANCEL;
19 import static android.app.Notification.FLAG_BUBBLE;
20 import static android.app.Notification.FLAG_CAN_COLORIZE;
21 import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
22 import static android.app.Notification.FLAG_NO_CLEAR;
23 import static android.app.Notification.FLAG_ONGOING_EVENT;
24 
25 import static com.android.server.notification.GroupHelper.BASE_FLAGS;
26 
27 import static junit.framework.Assert.assertEquals;
28 
29 import static org.mockito.Matchers.anyInt;
30 import static org.mockito.Matchers.anyString;
31 import static org.mockito.Matchers.eq;
32 import static org.mockito.Mockito.never;
33 import static org.mockito.Mockito.times;
34 import static org.mockito.Mockito.verify;
35 import static org.mockito.Mockito.verifyZeroInteractions;
36 
37 import android.annotation.SuppressLint;
38 import android.app.Notification;
39 import android.os.UserHandle;
40 import android.service.notification.StatusBarNotification;
41 import android.test.suitebuilder.annotation.SmallTest;
42 import android.util.ArrayMap;
43 
44 import androidx.test.runner.AndroidJUnit4;
45 
46 import com.android.server.UiServiceTestCase;
47 
48 import org.junit.Before;
49 import org.junit.Test;
50 import org.junit.runner.RunWith;
51 import org.mockito.Mock;
52 import org.mockito.Mockito;
53 import org.mockito.MockitoAnnotations;
54 
55 import java.util.ArrayList;
56 import java.util.List;
57 
58 @SmallTest
59 @SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the class.
60 @RunWith(AndroidJUnit4.class)
61 public class GroupHelperTest extends UiServiceTestCase {
62     private @Mock GroupHelper.Callback mCallback;
63 
64     private final static int AUTOGROUP_AT_COUNT = 7;
65     private GroupHelper mGroupHelper;
66 
67     @Before
setUp()68     public void setUp() {
69         MockitoAnnotations.initMocks(this);
70 
71         mGroupHelper = new GroupHelper(AUTOGROUP_AT_COUNT, mCallback);
72     }
73 
getSbn(String pkg, int id, String tag, UserHandle user, String groupKey)74     private StatusBarNotification getSbn(String pkg, int id, String tag,
75             UserHandle user, String groupKey) {
76         Notification.Builder nb = new Notification.Builder(getContext(), "test_channel_id")
77                 .setContentTitle("A")
78                 .setWhen(1205);
79         if (groupKey != null) {
80             nb.setGroup(groupKey);
81         }
82         return new StatusBarNotification(pkg, pkg, id, tag, 0, 0, nb.build(), user, null,
83                 System.currentTimeMillis());
84     }
85 
getSbn(String pkg, int id, String tag, UserHandle user)86     private StatusBarNotification getSbn(String pkg, int id, String tag,
87             UserHandle user) {
88         return getSbn(pkg, id, tag, user, null);
89     }
90 
91     @Test
testGetAutogroupSummaryFlags_noChildren()92     public void testGetAutogroupSummaryFlags_noChildren() {
93         ArrayMap<String, Integer> children = new ArrayMap<>();
94 
95         assertEquals(BASE_FLAGS, mGroupHelper.getAutogroupSummaryFlags(children));
96     }
97 
98     @Test
testGetAutogroupSummaryFlags_oneOngoing()99     public void testGetAutogroupSummaryFlags_oneOngoing() {
100         ArrayMap<String, Integer> children = new ArrayMap<>();
101         children.put("a", 0);
102         children.put("b", FLAG_ONGOING_EVENT);
103         children.put("c", FLAG_BUBBLE);
104 
105         assertEquals(FLAG_ONGOING_EVENT | BASE_FLAGS,
106                 mGroupHelper.getAutogroupSummaryFlags(children));
107     }
108 
109     @Test
testGetAutogroupSummaryFlags_oneOngoingNoClear()110     public void testGetAutogroupSummaryFlags_oneOngoingNoClear() {
111         ArrayMap<String, Integer> children = new ArrayMap<>();
112         children.put("a", 0);
113         children.put("b", FLAG_ONGOING_EVENT|FLAG_NO_CLEAR);
114         children.put("c", FLAG_BUBBLE);
115 
116         assertEquals(FLAG_NO_CLEAR | FLAG_ONGOING_EVENT | BASE_FLAGS,
117                 mGroupHelper.getAutogroupSummaryFlags(children));
118     }
119 
120     @Test
testGetAutogroupSummaryFlags_oneOngoingBubble()121     public void testGetAutogroupSummaryFlags_oneOngoingBubble() {
122         ArrayMap<String, Integer> children = new ArrayMap<>();
123         children.put("a", 0);
124         children.put("b", FLAG_ONGOING_EVENT | FLAG_BUBBLE);
125         children.put("c", FLAG_BUBBLE);
126 
127         assertEquals(FLAG_ONGOING_EVENT | BASE_FLAGS,
128                 mGroupHelper.getAutogroupSummaryFlags(children));
129     }
130 
131     @Test
testGetAutogroupSummaryFlags_multipleOngoing()132     public void testGetAutogroupSummaryFlags_multipleOngoing() {
133         ArrayMap<String, Integer> children = new ArrayMap<>();
134         children.put("a", 0);
135         children.put("b", FLAG_ONGOING_EVENT);
136         children.put("c", FLAG_BUBBLE);
137         children.put("d", FLAG_ONGOING_EVENT);
138 
139         assertEquals(FLAG_ONGOING_EVENT | BASE_FLAGS,
140                 mGroupHelper.getAutogroupSummaryFlags(children));
141     }
142 
143     @Test
testGetAutogroupSummaryFlags_oneAutoCancel()144     public void testGetAutogroupSummaryFlags_oneAutoCancel() {
145         ArrayMap<String, Integer> children = new ArrayMap<>();
146         children.put("a", 0);
147         children.put("b", FLAG_AUTO_CANCEL);
148         children.put("c", FLAG_BUBBLE);
149 
150         assertEquals(BASE_FLAGS,
151                 mGroupHelper.getAutogroupSummaryFlags(children));
152     }
153 
154     @Test
testGetAutogroupSummaryFlags_allAutoCancel()155     public void testGetAutogroupSummaryFlags_allAutoCancel() {
156         ArrayMap<String, Integer> children = new ArrayMap<>();
157         children.put("a", FLAG_AUTO_CANCEL);
158         children.put("b", FLAG_AUTO_CANCEL | FLAG_CAN_COLORIZE);
159         children.put("c", FLAG_AUTO_CANCEL);
160         children.put("d", FLAG_AUTO_CANCEL | FLAG_FOREGROUND_SERVICE);
161 
162         assertEquals(FLAG_AUTO_CANCEL | BASE_FLAGS,
163                 mGroupHelper.getAutogroupSummaryFlags(children));
164     }
165 
166     @Test
testGetAutogroupSummaryFlags_allAutoCancelOneOngoing()167     public void testGetAutogroupSummaryFlags_allAutoCancelOneOngoing() {
168         ArrayMap<String, Integer> children = new ArrayMap<>();
169         children.put("a", FLAG_AUTO_CANCEL);
170         children.put("b", FLAG_AUTO_CANCEL | FLAG_CAN_COLORIZE);
171         children.put("c", FLAG_AUTO_CANCEL);
172         children.put("d", FLAG_AUTO_CANCEL | FLAG_FOREGROUND_SERVICE | FLAG_ONGOING_EVENT);
173 
174         assertEquals(FLAG_AUTO_CANCEL| FLAG_ONGOING_EVENT | BASE_FLAGS,
175                 mGroupHelper.getAutogroupSummaryFlags(children));
176     }
177 
178     @Test
testNoGroup_postingUnderLimit()179     public void testNoGroup_postingUnderLimit() {
180         final String pkg = "package";
181         for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) {
182             mGroupHelper.onNotificationPosted(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM),
183                     false);
184         }
185         verifyZeroInteractions(mCallback);
186     }
187 
188     @Test
testNoGroup_multiPackage()189     public void testNoGroup_multiPackage() {
190         final String pkg = "package";
191         final String pkg2 = "package2";
192         for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) {
193             mGroupHelper.onNotificationPosted(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM),
194                     false);
195         }
196         mGroupHelper.onNotificationPosted(
197                 getSbn(pkg2, AUTOGROUP_AT_COUNT, "four", UserHandle.SYSTEM), false);
198         verifyZeroInteractions(mCallback);
199     }
200 
201     @Test
testNoGroup_multiUser()202     public void testNoGroup_multiUser() {
203         final String pkg = "package";
204         for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) {
205             mGroupHelper.onNotificationPosted(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM),
206                     false);
207         }
208         mGroupHelper.onNotificationPosted(
209                 getSbn(pkg, AUTOGROUP_AT_COUNT, "four", UserHandle.of(7)), false);
210         verifyZeroInteractions(mCallback);
211     }
212 
213     @Test
testNoGroup_someAreGrouped()214     public void testNoGroup_someAreGrouped() {
215         final String pkg = "package";
216         for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) {
217             mGroupHelper.onNotificationPosted(
218                     getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM), false);
219         }
220         mGroupHelper.onNotificationPosted(
221                 getSbn(pkg, AUTOGROUP_AT_COUNT, "four", UserHandle.SYSTEM, "a"), false);
222         verifyZeroInteractions(mCallback);
223     }
224 
225     @Test
testAddSummary()226     public void testAddSummary() {
227         final String pkg = "package";
228         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
229             mGroupHelper.onNotificationPosted(
230                     getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM), false);
231         }
232         verify(mCallback, times(1)).addAutoGroupSummary(
233                 anyInt(), eq(pkg), anyString(), eq(BASE_FLAGS));
234         verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
235         verify(mCallback, never()).removeAutoGroup(anyString());
236         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
237         verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt());
238     }
239 
240     @Test
testAddSummary_oneChildOngoing_summaryOngoing()241     public void testAddSummary_oneChildOngoing_summaryOngoing() {
242         final String pkg = "package";
243         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
244             StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
245             if (i == 0) {
246                 sbn.getNotification().flags |= FLAG_ONGOING_EVENT;
247             }
248             mGroupHelper.onNotificationPosted(sbn, false);
249         }
250         verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
251                 eq(BASE_FLAGS | FLAG_ONGOING_EVENT));
252         verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
253         verify(mCallback, never()).removeAutoGroup(anyString());
254         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
255         verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt());
256     }
257 
258     @Test
testAddSummary_oneChildAutoCancel_summaryNotAutoCancel()259     public void testAddSummary_oneChildAutoCancel_summaryNotAutoCancel() {
260         final String pkg = "package";
261         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
262             StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
263             if (i == 0) {
264                 sbn.getNotification().flags |= FLAG_AUTO_CANCEL;
265             }
266             mGroupHelper.onNotificationPosted(sbn, false);
267         }
268         verify(mCallback, times(1)).addAutoGroupSummary(
269                 anyInt(), eq(pkg), anyString(), eq(BASE_FLAGS));
270         verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
271         verify(mCallback, never()).removeAutoGroup(anyString());
272         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
273         verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt());
274     }
275 
276     @Test
testAddSummary_allChildrenAutoCancel_summaryAutoCancel()277     public void testAddSummary_allChildrenAutoCancel_summaryAutoCancel() {
278         final String pkg = "package";
279         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
280             StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
281             sbn.getNotification().flags |= FLAG_AUTO_CANCEL;
282             mGroupHelper.onNotificationPosted(sbn, false);
283         }
284         verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
285                 eq(BASE_FLAGS | FLAG_AUTO_CANCEL));
286         verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
287         verify(mCallback, never()).removeAutoGroup(anyString());
288         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
289         verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt());
290     }
291 
292     @Test
testAddSummary_summaryAutoCancelNoClear()293     public void testAddSummary_summaryAutoCancelNoClear() {
294         final String pkg = "package";
295         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
296             StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
297             sbn.getNotification().flags |= FLAG_AUTO_CANCEL;
298             if (i == 0) {
299                 sbn.getNotification().flags |= FLAG_NO_CLEAR;
300             }
301             mGroupHelper.onNotificationPosted(sbn, false);
302         }
303         verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
304                 eq(BASE_FLAGS | FLAG_AUTO_CANCEL | FLAG_NO_CLEAR));
305         verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
306         verify(mCallback, never()).removeAutoGroup(anyString());
307         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
308         verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt());
309     }
310 
311     @Test
testAutoGrouped_allOngoing_updateChildNotOngoing()312     public void testAutoGrouped_allOngoing_updateChildNotOngoing() {
313         final String pkg = "package";
314 
315         // Post AUTOGROUP_AT_COUNT ongoing notifications
316         ArrayList<StatusBarNotification>  notifications = new ArrayList<>();
317         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
318             StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
319             sbn.getNotification().flags |= FLAG_ONGOING_EVENT;
320             notifications.add(sbn);
321         }
322 
323         for (StatusBarNotification sbn: notifications) {
324             mGroupHelper.onNotificationPosted(sbn, false);
325         }
326 
327         // One notification is no longer ongoing
328         notifications.get(0).getNotification().flags &= ~FLAG_ONGOING_EVENT;
329         mGroupHelper.onNotificationPosted(notifications.get(0), true);
330 
331         // Summary should keep FLAG_ONGOING_EVENT if any child has it
332         verify(mCallback).updateAutogroupSummary(
333                 anyInt(), anyString(), eq(BASE_FLAGS | FLAG_ONGOING_EVENT));
334     }
335 
336     @Test
testAutoGrouped_singleOngoing_removeOngoingChild()337     public void testAutoGrouped_singleOngoing_removeOngoingChild() {
338         final String pkg = "package";
339 
340         // Post AUTOGROUP_AT_COUNT ongoing notifications
341         ArrayList<StatusBarNotification>  notifications = new ArrayList<>();
342         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
343             StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
344             if (i == 0) {
345                 sbn.getNotification().flags |= FLAG_ONGOING_EVENT;
346             }
347             notifications.add(sbn);
348         }
349 
350         for (StatusBarNotification sbn: notifications) {
351             mGroupHelper.onNotificationPosted(sbn, false);
352         }
353 
354         // remove ongoing
355         mGroupHelper.onNotificationRemoved(notifications.get(0));
356 
357         // Summary is no longer ongoing
358         verify(mCallback).updateAutogroupSummary(anyInt(), anyString(), eq(BASE_FLAGS));
359     }
360 
361     @Test
testAutoGrouped_noOngoing_updateOngoingChild()362     public void testAutoGrouped_noOngoing_updateOngoingChild() {
363         final String pkg = "package";
364 
365         // Post AUTOGROUP_AT_COUNT ongoing notifications
366         ArrayList<StatusBarNotification>  notifications = new ArrayList<>();
367         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
368             StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
369             notifications.add(sbn);
370         }
371 
372         for (StatusBarNotification sbn: notifications) {
373             mGroupHelper.onNotificationPosted(sbn, false);
374         }
375 
376         // update to ongoing
377         notifications.get(0).getNotification().flags |= FLAG_ONGOING_EVENT;
378         mGroupHelper.onNotificationPosted(notifications.get(0), true);
379 
380         // Summary is now ongoing
381         verify(mCallback).updateAutogroupSummary(
382                 anyInt(), anyString(), eq(BASE_FLAGS | FLAG_ONGOING_EVENT));
383     }
384 
385     @Test
testAutoGrouped_noOngoing_addOngoingChild()386     public void testAutoGrouped_noOngoing_addOngoingChild() {
387         final String pkg = "package";
388 
389         // Post AUTOGROUP_AT_COUNT ongoing notifications
390         ArrayList<StatusBarNotification>  notifications = new ArrayList<>();
391         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
392             StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
393             notifications.add(sbn);
394         }
395 
396         for (StatusBarNotification sbn: notifications) {
397             mGroupHelper.onNotificationPosted(sbn, false);
398         }
399 
400         // add ongoing
401         StatusBarNotification sbn = getSbn(pkg, AUTOGROUP_AT_COUNT + 1, null, UserHandle.SYSTEM);
402         sbn.getNotification().flags |= FLAG_ONGOING_EVENT;
403         mGroupHelper.onNotificationPosted(sbn, true);
404 
405         // Summary is now ongoing
406         verify(mCallback).updateAutogroupSummary(
407                 anyInt(), anyString(), eq(BASE_FLAGS | FLAG_ONGOING_EVENT));
408     }
409 
410     @Test
testAutoGrouped_singleOngoing_appGroupOngoingChild()411     public void testAutoGrouped_singleOngoing_appGroupOngoingChild() {
412         final String pkg = "package";
413 
414         // Post AUTOGROUP_AT_COUNT ongoing notifications
415         ArrayList<StatusBarNotification>  notifications = new ArrayList<>();
416         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
417             StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
418             if (i == 0) {
419                 sbn.getNotification().flags |= FLAG_ONGOING_EVENT;
420             }
421             notifications.add(sbn);
422         }
423 
424         for (StatusBarNotification sbn: notifications) {
425             mGroupHelper.onNotificationPosted(sbn, false);
426         }
427 
428         // app group the ongoing child
429         StatusBarNotification sbn = getSbn(pkg, 0, "0", UserHandle.SYSTEM, "app group now");
430         mGroupHelper.onNotificationPosted(sbn, true);
431 
432         // Summary is no longer ongoing
433         verify(mCallback).updateAutogroupSummary(anyInt(), anyString(), eq(BASE_FLAGS));
434     }
435 
436     @Test
testAutoGrouped_singleOngoing_removeNonOngoingChild()437     public void testAutoGrouped_singleOngoing_removeNonOngoingChild() {
438         final String pkg = "package";
439 
440         // Post AUTOGROUP_AT_COUNT ongoing notifications
441         ArrayList<StatusBarNotification>  notifications = new ArrayList<>();
442         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
443             StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
444             if (i == 0) {
445                 sbn.getNotification().flags |= FLAG_ONGOING_EVENT;
446             }
447             notifications.add(sbn);
448         }
449 
450         for (StatusBarNotification sbn: notifications) {
451             mGroupHelper.onNotificationPosted(sbn, false);
452         }
453 
454         // remove ongoing
455         mGroupHelper.onNotificationRemoved(notifications.get(1));
456 
457         // Summary is still ongoing
458         verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt());
459     }
460 
461     @Test
testAutoGrouped_allAutoCancel_updateChildNotAutoCancel()462     public void testAutoGrouped_allAutoCancel_updateChildNotAutoCancel() {
463         final String pkg = "package";
464 
465         // Post AUTOGROUP_AT_COUNT ongoing notifications
466         ArrayList<StatusBarNotification>  notifications = new ArrayList<>();
467         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
468             StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
469             sbn.getNotification().flags |= FLAG_AUTO_CANCEL;
470             notifications.add(sbn);
471         }
472 
473         for (StatusBarNotification sbn: notifications) {
474             mGroupHelper.onNotificationPosted(sbn, false);
475         }
476 
477         // One notification is no longer autocancelable
478         notifications.get(0).getNotification().flags &= ~FLAG_AUTO_CANCEL;
479         mGroupHelper.onNotificationPosted(notifications.get(0), true);
480 
481         // Summary should no longer be autocancelable
482         verify(mCallback).updateAutogroupSummary(anyInt(), anyString(), eq(BASE_FLAGS));
483     }
484 
485     @Test
testAutoGrouped_almostAllAutoCancel_updateChildAutoCancel()486     public void testAutoGrouped_almostAllAutoCancel_updateChildAutoCancel() {
487         final String pkg = "package";
488 
489         // Post AUTOGROUP_AT_COUNT ongoing notifications
490         ArrayList<StatusBarNotification>  notifications = new ArrayList<>();
491         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
492             StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
493             if (i != 0) {
494                 sbn.getNotification().flags |= FLAG_AUTO_CANCEL;
495             }
496             notifications.add(sbn);
497         }
498 
499         for (StatusBarNotification sbn: notifications) {
500             mGroupHelper.onNotificationPosted(sbn, false);
501         }
502 
503         // Missing notification is now autocancelable
504         notifications.get(0).getNotification().flags |= FLAG_AUTO_CANCEL;
505         mGroupHelper.onNotificationPosted(notifications.get(0), true);
506 
507         // Summary should now autocancelable
508         verify(mCallback).updateAutogroupSummary(
509                 anyInt(), anyString(), eq(BASE_FLAGS | FLAG_AUTO_CANCEL));
510     }
511 
512     @Test
testAutoGrouped_allAutoCancel_updateChildAppGrouped()513     public void testAutoGrouped_allAutoCancel_updateChildAppGrouped() {
514         final String pkg = "package";
515 
516         // Post AUTOGROUP_AT_COUNT ongoing notifications
517         ArrayList<StatusBarNotification>  notifications = new ArrayList<>();
518         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
519             StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
520             sbn.getNotification().flags |= FLAG_AUTO_CANCEL;
521             notifications.add(sbn);
522         }
523 
524         for (StatusBarNotification sbn: notifications) {
525             mGroupHelper.onNotificationPosted(sbn, false);
526         }
527 
528         // One notification is now grouped by app
529         StatusBarNotification sbn = getSbn(pkg, 0, "0", UserHandle.SYSTEM, "app group now");
530         mGroupHelper.onNotificationPosted(sbn, true);
531 
532         // Summary should be still be autocancelable
533         verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt());
534     }
535 
536     @Test
testAutoGrouped_allAutoCancel_removeChild()537     public void testAutoGrouped_allAutoCancel_removeChild() {
538         final String pkg = "package";
539 
540         // Post AUTOGROUP_AT_COUNT ongoing notifications
541         ArrayList<StatusBarNotification>  notifications = new ArrayList<>();
542         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
543             StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
544             sbn.getNotification().flags |= FLAG_AUTO_CANCEL;
545             notifications.add(sbn);
546         }
547 
548         for (StatusBarNotification sbn: notifications) {
549             mGroupHelper.onNotificationPosted(sbn, false);
550         }
551 
552         mGroupHelper.onNotificationRemoved(notifications.get(0));
553 
554         // Summary should still be autocancelable
555         verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyInt());
556     }
557 
558     @Test
testDropToZeroRemoveGroup()559     public void testDropToZeroRemoveGroup() {
560         final String pkg = "package";
561         List<StatusBarNotification> posted = new ArrayList<>();
562         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
563             final StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
564             posted.add(sbn);
565             mGroupHelper.onNotificationPosted(sbn, false);
566         }
567         verify(mCallback, times(1)).addAutoGroupSummary(
568                 anyInt(), eq(pkg), anyString(), eq(BASE_FLAGS));
569         verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
570         verify(mCallback, never()).removeAutoGroup(anyString());
571         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
572         Mockito.reset(mCallback);
573 
574         for (int i = 0; i < AUTOGROUP_AT_COUNT - 1; i++) {
575             mGroupHelper.onNotificationRemoved(posted.remove(0));
576         }
577         verify(mCallback, never()).removeAutoGroup(anyString());
578         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
579         Mockito.reset(mCallback);
580 
581         mGroupHelper.onNotificationRemoved(posted.remove(0));
582         verify(mCallback, never()).removeAutoGroup(anyString());
583         verify(mCallback, times(1)).removeAutoGroupSummary(anyInt(), anyString());
584     }
585 
586     @Test
testAppStartsGrouping()587     public void testAppStartsGrouping() {
588         final String pkg = "package";
589         List<StatusBarNotification> posted = new ArrayList<>();
590         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
591             final StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
592             posted.add(sbn);
593             mGroupHelper.onNotificationPosted(sbn, false);
594         }
595         verify(mCallback, times(1)).addAutoGroupSummary(
596                 anyInt(), eq(pkg), anyString(), eq(BASE_FLAGS));
597         verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
598         verify(mCallback, never()).removeAutoGroup(anyString());
599         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
600         Mockito.reset(mCallback);
601 
602         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
603             final StatusBarNotification sbn =
604                     getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM, "app group");
605             sbn.setOverrideGroupKey("autogrouped");
606             mGroupHelper.onNotificationPosted(sbn, true);
607             verify(mCallback, times(1)).removeAutoGroup(sbn.getKey());
608             if (i < AUTOGROUP_AT_COUNT - 1) {
609                 verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
610             }
611         }
612         verify(mCallback, times(1)).removeAutoGroupSummary(anyInt(), anyString());
613     }
614 
615     @Test
testNewNotificationsAddedToAutogroup_ifOriginalNotificationsCanceled()616     public void testNewNotificationsAddedToAutogroup_ifOriginalNotificationsCanceled() {
617         final String pkg = "package";
618         List<StatusBarNotification> posted = new ArrayList<>();
619         for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
620             final StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM);
621             posted.add(sbn);
622             mGroupHelper.onNotificationPosted(sbn, false);
623         }
624         verify(mCallback, times(1)).addAutoGroupSummary(
625                 anyInt(), eq(pkg), anyString(), eq(BASE_FLAGS));
626         verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString());
627         verify(mCallback, never()).removeAutoGroup(anyString());
628         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
629         Mockito.reset(mCallback);
630 
631         for (int i = posted.size() - 2; i >= 0; i--) {
632             mGroupHelper.onNotificationRemoved(posted.remove(i));
633         }
634         verify(mCallback, never()).removeAutoGroup(anyString());
635         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
636         Mockito.reset(mCallback);
637 
638         // only one child remains
639         assertEquals(1, mGroupHelper.getNotGroupedByAppCount(UserHandle.USER_SYSTEM, pkg));
640 
641         // Add new notification; it should be autogrouped even though the total count is
642         // < AUTOGROUP_AT_COUNT
643         final StatusBarNotification sbn = getSbn(pkg, 5, String.valueOf(5), UserHandle.SYSTEM);
644         posted.add(sbn);
645         mGroupHelper.onNotificationPosted(sbn, true);
646         verify(mCallback, times(1)).addAutoGroup(sbn.getKey());
647         verify(mCallback, never()).removeAutoGroup(anyString());
648         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString());
649         verify(mCallback).updateAutogroupSummary(anyInt(), anyString(), eq(BASE_FLAGS));
650         verify(mCallback, never()).addAutoGroupSummary(
651                 anyInt(), anyString(), anyString(), anyInt());
652     }
653 }
654