blob: 546bce81a2600617734343488a18ac833541cfa6 [file] [log] [blame]
Ned Burns9eb06332019-04-23 16:02:12 -04001/*
2 * Copyright (C) 2019 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.statusbar.notification.stack;
18
19import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
20
Evan Laird25f02752019-08-14 19:25:06 -040021import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
Steve Elliott49671e02020-05-12 13:51:28 -040022import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_FOREGROUND_SERVICE;
Steve Elliott35956b42020-02-25 17:12:09 -050023import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP;
24import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE;
Evan Laird25f02752019-08-14 19:25:06 -040025import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
26
Steve Elliott49671e02020-05-12 13:51:28 -040027import static com.google.common.truth.Truth.assertThat;
28
Ned Burns9eb06332019-04-23 16:02:12 -040029import static org.mockito.ArgumentMatchers.any;
30import static org.mockito.ArgumentMatchers.anyInt;
31import static org.mockito.ArgumentMatchers.eq;
32import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
33import static org.mockito.Mockito.clearInvocations;
Steve Elliott49671e02020-05-12 13:51:28 -040034import static org.mockito.Mockito.doAnswer;
Ned Burns9eb06332019-04-23 16:02:12 -040035import static org.mockito.Mockito.mock;
36import static org.mockito.Mockito.never;
37import static org.mockito.Mockito.verify;
38import static org.mockito.Mockito.when;
39
40import android.testing.AndroidTestingRunner;
41import android.testing.TestableLooper;
42import android.util.AttributeSet;
Ned Burns2c74c2a2019-06-13 19:06:47 -040043import android.view.LayoutInflater;
Ned Burns9eb06332019-04-23 16:02:12 -040044import android.view.View;
45import android.view.ViewGroup;
46
47import androidx.test.filters.SmallTest;
48
49import com.android.systemui.ActivityStarterDelegate;
50import com.android.systemui.SysuiTestCase;
Selim Cinekb52642b2020-04-17 14:30:29 -070051import com.android.systemui.media.KeyguardMediaController;
Ned Burns7eeccdd2019-05-15 14:50:11 -040052import com.android.systemui.plugins.statusbar.StatusBarStateController;
53import com.android.systemui.statusbar.StatusBarState;
Dave Mankoff56fe9e42020-01-08 15:42:06 -050054import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
Steve Elliottb0940382020-02-20 14:24:02 -050055import com.android.systemui.statusbar.notification.people.PeopleHubViewAdapter;
Dave Mankoff56fe9e42020-01-08 15:42:06 -050056import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController;
Ned Burns9eb06332019-04-23 16:02:12 -040057import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Dave Mankoff56fe9e42020-01-08 15:42:06 -050058import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
Ned Burns2c74c2a2019-06-13 19:06:47 -040059import com.android.systemui.statusbar.policy.ConfigurationController;
Ned Burns9eb06332019-04-23 16:02:12 -040060
61import org.junit.Before;
62import org.junit.Rule;
63import org.junit.Test;
64import org.junit.runner.RunWith;
65import org.mockito.Mock;
66import org.mockito.junit.MockitoJUnit;
67import org.mockito.junit.MockitoRule;
68
Steve Elliott49671e02020-05-12 13:51:28 -040069import java.util.ArrayList;
70import java.util.List;
71
Ned Burns9eb06332019-04-23 16:02:12 -040072@SmallTest
73@RunWith(AndroidTestingRunner.class)
Dave Mankoff56fe9e42020-01-08 15:42:06 -050074@TestableLooper.RunWithLooper(setAsMainLooper = true)
Ned Burns9eb06332019-04-23 16:02:12 -040075public class NotificationSectionsManagerTest extends SysuiTestCase {
76
77 @Rule public final MockitoRule mockitoRule = MockitoJUnit.rule();
78
79 @Mock private NotificationStackScrollLayout mNssl;
80 @Mock private ActivityStarterDelegate mActivityStarterDelegate;
Ned Burns7eeccdd2019-05-15 14:50:11 -040081 @Mock private StatusBarStateController mStatusBarStateController;
Ned Burns2c74c2a2019-06-13 19:06:47 -040082 @Mock private ConfigurationController mConfigurationController;
Steve Elliottb0940382020-02-20 14:24:02 -050083 @Mock private PeopleHubViewAdapter mPeopleHubAdapter;
Selim Cinekb52642b2020-04-17 14:30:29 -070084 @Mock private KeyguardMediaController mKeyguardMediaController;
Dave Mankoff56fe9e42020-01-08 15:42:06 -050085 @Mock private NotificationSectionsFeatureManager mSectionsFeatureManager;
86 @Mock private NotificationRowComponent mNotificationRowComponent;
87 @Mock private ActivatableNotificationViewController mActivatableNotificationViewController;
Steve Elliott1ba1b7c2020-05-05 14:16:32 -040088 @Mock private NotificationSectionsLogger mLogger;
Ned Burns9eb06332019-04-23 16:02:12 -040089
90 private NotificationSectionsManager mSectionsManager;
91
92 @Before
93 public void setUp() {
Steve Elliott49671e02020-05-12 13:51:28 -040094 when(mSectionsFeatureManager.getNumberOfBuckets()).thenAnswer(
95 invocation -> {
96 int count = 2;
97 if (mSectionsFeatureManager.isFilteringEnabled()) {
98 count = 5;
99 }
100 if (mSectionsFeatureManager.isMediaControlsEnabled()) {
101 if (!mSectionsFeatureManager.isFilteringEnabled()) {
102 count = 5;
103 } else {
104 count += 1;
105 }
106 }
107 return count;
108 });
109 when(mNotificationRowComponent.getActivatableNotificationViewController())
110 .thenReturn(mActivatableNotificationViewController);
Ned Burns7eeccdd2019-05-15 14:50:11 -0400111 mSectionsManager =
112 new NotificationSectionsManager(
Ned Burns7eeccdd2019-05-15 14:50:11 -0400113 mActivityStarterDelegate,
114 mStatusBarStateController,
Ned Burns2c74c2a2019-06-13 19:06:47 -0400115 mConfigurationController,
Steve Elliott58adc212019-10-15 11:07:54 -0400116 mPeopleHubAdapter,
Selim Cinekb52642b2020-04-17 14:30:29 -0700117 mKeyguardMediaController,
Steve Elliott1ba1b7c2020-05-05 14:16:32 -0400118 mSectionsFeatureManager,
119 mLogger
Steve Elliottb0940382020-02-20 14:24:02 -0500120 );
Ned Burns9eb06332019-04-23 16:02:12 -0400121 // Required in order for the header inflation to work properly
122 when(mNssl.generateLayoutParams(any(AttributeSet.class)))
123 .thenReturn(new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
Dave Mankoff56fe9e42020-01-08 15:42:06 -0500124 mSectionsManager.initialize(mNssl, LayoutInflater.from(mContext));
Ned Burns9eb06332019-04-23 16:02:12 -0400125 when(mNssl.indexOfChild(any(View.class))).thenReturn(-1);
Ned Burns7eeccdd2019-05-15 14:50:11 -0400126 when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
Steve Elliott49671e02020-05-12 13:51:28 -0400127
Ned Burns9eb06332019-04-23 16:02:12 -0400128 }
129
Ned Burns2c74c2a2019-06-13 19:06:47 -0400130 @Test(expected = IllegalStateException.class)
131 public void testDuplicateInitializeThrows() {
Dave Mankoff56fe9e42020-01-08 15:42:06 -0500132 mSectionsManager.initialize(mNssl, LayoutInflater.from(mContext));
Ned Burns2c74c2a2019-06-13 19:06:47 -0400133 }
134
Ned Burns9eb06332019-04-23 16:02:12 -0400135 @Test
136 public void testInsertHeader() {
137 // GIVEN a stack with HI and LO rows but no section headers
Steve Elliott35956b42020-02-25 17:12:09 -0500138 setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE);
Ned Burns9eb06332019-04-23 16:02:12 -0400139
140 // WHEN we update the section headers
141 mSectionsManager.updateSectionBoundaries();
142
143 // THEN a LO section header is added
144 verify(mNssl).addView(mSectionsManager.getGentleHeaderView(), 3);
145 }
146
147 @Test
148 public void testRemoveHeader() {
149 // GIVEN a stack that originally had a header between the HI and LO sections
Steve Elliott35956b42020-02-25 17:12:09 -0500150 setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE);
Ned Burns9eb06332019-04-23 16:02:12 -0400151 mSectionsManager.updateSectionBoundaries();
152
153 // WHEN the last LO row is replaced with a HI row
Steve Elliott35956b42020-02-25 17:12:09 -0500154 setStackState(
155 ChildType.ALERTING,
156 ChildType.ALERTING,
157 ChildType.GENTLE_HEADER,
158 ChildType.ALERTING);
Ned Burns9eb06332019-04-23 16:02:12 -0400159 clearInvocations(mNssl);
160 mSectionsManager.updateSectionBoundaries();
161
162 // THEN the LO section header is removed
163 verify(mNssl).removeView(mSectionsManager.getGentleHeaderView());
164 }
165
166 @Test
167 public void testDoNothingIfHeaderAlreadyRemoved() {
168 // GIVEN a stack with only HI rows
Steve Elliott35956b42020-02-25 17:12:09 -0500169 setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING);
Ned Burns9eb06332019-04-23 16:02:12 -0400170
171 // WHEN we update the sections headers
172 mSectionsManager.updateSectionBoundaries();
173
174 // THEN we don't add any section headers
175 verify(mNssl, never()).addView(eq(mSectionsManager.getGentleHeaderView()), anyInt());
176 }
177
178 @Test
179 public void testMoveHeaderForward() {
180 // GIVEN a stack that originally had a header between the HI and LO sections
181 setStackState(
Steve Elliott35956b42020-02-25 17:12:09 -0500182 ChildType.ALERTING,
183 ChildType.ALERTING,
184 ChildType.ALERTING,
185 ChildType.GENTLE);
Ned Burns9eb06332019-04-23 16:02:12 -0400186 mSectionsManager.updateSectionBoundaries();
187
188 // WHEN the LO section moves forward
189 setStackState(
Steve Elliott35956b42020-02-25 17:12:09 -0500190 ChildType.ALERTING,
191 ChildType.ALERTING,
192 ChildType.GENTLE,
193 ChildType.GENTLE_HEADER,
194 ChildType.GENTLE);
Ned Burns9eb06332019-04-23 16:02:12 -0400195 mSectionsManager.updateSectionBoundaries();
196
197 // THEN the LO section header is also moved forward
198 verify(mNssl).changeViewPosition(mSectionsManager.getGentleHeaderView(), 2);
199 }
200
201 @Test
202 public void testMoveHeaderBackward() {
203 // GIVEN a stack that originally had a header between the HI and LO sections
204 setStackState(
Steve Elliott35956b42020-02-25 17:12:09 -0500205 ChildType.ALERTING,
206 ChildType.GENTLE,
207 ChildType.GENTLE,
208 ChildType.GENTLE);
Ned Burns9eb06332019-04-23 16:02:12 -0400209 mSectionsManager.updateSectionBoundaries();
210
211 // WHEN the LO section moves backward
212 setStackState(
Steve Elliott35956b42020-02-25 17:12:09 -0500213 ChildType.ALERTING,
214 ChildType.GENTLE_HEADER,
215 ChildType.ALERTING,
216 ChildType.ALERTING,
217 ChildType.GENTLE);
Ned Burns9eb06332019-04-23 16:02:12 -0400218 mSectionsManager.updateSectionBoundaries();
219
220 // THEN the LO section header is also moved backward (with appropriate index shifting)
221 verify(mNssl).changeViewPosition(mSectionsManager.getGentleHeaderView(), 3);
222 }
223
224 @Test
225 public void testHeaderRemovedFromTransientParent() {
226 // GIVEN a stack where the header is animating away
227 setStackState(
Steve Elliott35956b42020-02-25 17:12:09 -0500228 ChildType.ALERTING,
229 ChildType.GENTLE,
230 ChildType.GENTLE,
231 ChildType.GENTLE);
Ned Burns9eb06332019-04-23 16:02:12 -0400232 mSectionsManager.updateSectionBoundaries();
233 setStackState(
Steve Elliott35956b42020-02-25 17:12:09 -0500234 ChildType.ALERTING,
235 ChildType.GENTLE_HEADER);
Ned Burns9eb06332019-04-23 16:02:12 -0400236 mSectionsManager.updateSectionBoundaries();
237 clearInvocations(mNssl);
238
239 ViewGroup transientParent = mock(ViewGroup.class);
240 mSectionsManager.getGentleHeaderView().setTransientContainer(transientParent);
241
242 // WHEN the LO section reappears
243 setStackState(
Steve Elliott35956b42020-02-25 17:12:09 -0500244 ChildType.ALERTING,
245 ChildType.GENTLE);
Ned Burns9eb06332019-04-23 16:02:12 -0400246 mSectionsManager.updateSectionBoundaries();
247
248 // THEN the header is first removed from the transient parent before being added to the
249 // NSSL.
250 verify(transientParent).removeTransientView(mSectionsManager.getGentleHeaderView());
251 verify(mNssl).addView(mSectionsManager.getGentleHeaderView(), 1);
252 }
253
Ned Burns7eeccdd2019-05-15 14:50:11 -0400254 @Test
255 public void testHeaderNotShownOnLockscreen() {
256 // GIVEN a stack of HI and LO notifs on the lockscreen
257 when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
Steve Elliott35956b42020-02-25 17:12:09 -0500258 setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE);
Ned Burns7eeccdd2019-05-15 14:50:11 -0400259
260 // WHEN we update the section headers
261 mSectionsManager.updateSectionBoundaries();
262
263 // Then the section header is not added
264 verify(mNssl, never()).addView(eq(mSectionsManager.getGentleHeaderView()), anyInt());
265 }
266
267 @Test
268 public void testHeaderShownWhenEnterLockscreen() {
269 // GIVEN a stack of HI and LO notifs on the lockscreen
270 when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
Steve Elliott35956b42020-02-25 17:12:09 -0500271 setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE);
Ned Burns7eeccdd2019-05-15 14:50:11 -0400272 mSectionsManager.updateSectionBoundaries();
273
274 // WHEN we unlock
275 when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
276 mSectionsManager.updateSectionBoundaries();
277
278 // Then the section header is added
279 verify(mNssl).addView(mSectionsManager.getGentleHeaderView(), 3);
280 }
281
282 @Test
283 public void testHeaderHiddenWhenEnterLockscreen() {
284 // GIVEN a stack of HI and LO notifs on the shade
Steve Elliott35956b42020-02-25 17:12:09 -0500285 setStackState(ChildType.ALERTING, ChildType.GENTLE_HEADER, ChildType.GENTLE);
Ned Burns7eeccdd2019-05-15 14:50:11 -0400286
287 // WHEN we go back to the keyguard
288 when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
289 mSectionsManager.updateSectionBoundaries();
290
291 // Then the section header is removed
Steve Elliott35956b42020-02-25 17:12:09 -0500292 verify(mNssl).removeView(mSectionsManager.getGentleHeaderView());
Ned Burns7eeccdd2019-05-15 14:50:11 -0400293 }
294
Steve Elliott35956b42020-02-25 17:12:09 -0500295 @Test
296 public void testPeopleFiltering_addHeadersFromShowingOnlyGentle() {
297 enablePeopleFiltering();
298
299 setStackState(
300 ChildType.GENTLE_HEADER,
301 ChildType.PERSON,
302 ChildType.ALERTING,
303 ChildType.GENTLE);
304 mSectionsManager.updateSectionBoundaries();
305
306 verify(mNssl).changeViewPosition(mSectionsManager.getGentleHeaderView(), 2);
307 verify(mNssl).addView(mSectionsManager.getAlertingHeaderView(), 1);
308 verify(mNssl).addView(mSectionsManager.getPeopleHeaderView(), 0);
309 }
310
311 @Test
312 public void testPeopleFiltering_addAllHeaders() {
313 enablePeopleFiltering();
314
315 setStackState(
316 ChildType.PERSON,
317 ChildType.ALERTING,
318 ChildType.GENTLE);
319 mSectionsManager.updateSectionBoundaries();
320
321 verify(mNssl).addView(mSectionsManager.getGentleHeaderView(), 2);
322 verify(mNssl).addView(mSectionsManager.getAlertingHeaderView(), 1);
323 verify(mNssl).addView(mSectionsManager.getPeopleHeaderView(), 0);
324 }
325
326 @Test
327 public void testPeopleFiltering_moveAllHeaders() {
328 enablePeopleFiltering();
329
330 setStackState(
331 ChildType.PEOPLE_HEADER,
332 ChildType.ALERTING_HEADER,
333 ChildType.GENTLE_HEADER,
334 ChildType.PERSON,
335 ChildType.ALERTING,
336 ChildType.GENTLE);
337 mSectionsManager.updateSectionBoundaries();
338
339 verify(mNssl).changeViewPosition(mSectionsManager.getGentleHeaderView(), 4);
340 verify(mNssl).changeViewPosition(mSectionsManager.getAlertingHeaderView(), 2);
341 verify(mNssl).changeViewPosition(mSectionsManager.getPeopleHeaderView(), 0);
342 }
343
Steve Elliott6de51a72020-03-05 11:00:47 -0500344 @Test
345 public void testPeopleFiltering_keepPeopleHeaderWhenSectionEmpty() {
346 mSectionsManager.setPeopleHubVisible(true);
347 enablePeopleFiltering();
348
349 setStackState(
350 ChildType.PEOPLE_HEADER,
351 ChildType.ALERTING_HEADER,
352 ChildType.ALERTING,
353 ChildType.GENTLE_HEADER,
354 ChildType.GENTLE
355 );
356 mSectionsManager.updateSectionBoundaries();
357
358 verify(mNssl, never()).removeView(mSectionsManager.getPeopleHeaderView());
359 verify(mNssl).changeViewPosition(mSectionsManager.getPeopleHeaderView(), 0);
360 }
361
Robert Snoebergerb6464ea2020-03-20 11:56:22 -0400362 @Test
Steve Elliott49671e02020-05-12 13:51:28 -0400363 public void testPeopleFiltering_HunWhilePeopleVisible() {
364 enablePeopleFiltering();
365
366 setupMockStack(
367 ChildType.PEOPLE_HEADER,
368 ChildType.HEADS_UP,
369 ChildType.PERSON,
370 ChildType.ALERTING_HEADER,
371 ChildType.GENTLE_HEADER,
372 ChildType.GENTLE
373 );
374 mSectionsManager.updateSectionBoundaries();
375
376 verifyMockStack(
377 ChildType.INCOMING_HEADER,
378 ChildType.HEADS_UP,
379 ChildType.PEOPLE_HEADER,
380 ChildType.PERSON,
381 ChildType.GENTLE_HEADER,
382 ChildType.GENTLE
383 );
384 }
385
386 @Test
387 public void testPeopleFiltering_Fsn() {
388 enablePeopleFiltering();
389
390 setupMockStack(
391 ChildType.INCOMING_HEADER,
392 ChildType.HEADS_UP,
393 ChildType.PEOPLE_HEADER,
394 ChildType.FSN,
395 ChildType.PERSON,
396 ChildType.ALERTING,
397 ChildType.GENTLE
398 );
399 mSectionsManager.updateSectionBoundaries();
400
401 verifyMockStack(
402 ChildType.INCOMING_HEADER,
403 ChildType.HEADS_UP,
404 ChildType.FSN,
405 ChildType.PEOPLE_HEADER,
406 ChildType.PERSON,
407 ChildType.ALERTING_HEADER,
408 ChildType.ALERTING,
409 ChildType.GENTLE_HEADER,
410 ChildType.GENTLE
411 );
412 }
413
414 @Test
Robert Snoebergerb6464ea2020-03-20 11:56:22 -0400415 public void testMediaControls_AddWhenEnterKeyguard() {
416 enableMediaControls();
417
418 // GIVEN a stack that doesn't include media controls
419 setStackState(ChildType.ALERTING, ChildType.GENTLE_HEADER, ChildType.GENTLE);
420
421 // WHEN we go back to the keyguard
422 when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
423 mSectionsManager.updateSectionBoundaries();
424
425 // Then the media controls are added
426 verify(mNssl).addView(mSectionsManager.getMediaControlsView(), 0);
427 }
428
429 @Test
430 public void testMediaControls_AddWhenEnterKeyguardWithHeadsUp() {
431 enableMediaControls();
432
433 // GIVEN a stack that doesn't include media controls but includes HEADS_UP
Steve Elliott49671e02020-05-12 13:51:28 -0400434 setupMockStack(ChildType.HEADS_UP, ChildType.ALERTING, ChildType.GENTLE_HEADER,
Robert Snoebergerb6464ea2020-03-20 11:56:22 -0400435 ChildType.GENTLE);
436
437 // WHEN we go back to the keyguard
438 when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
439 mSectionsManager.updateSectionBoundaries();
440
Steve Elliott49671e02020-05-12 13:51:28 -0400441 verifyMockStack(ChildType.HEADS_UP, ChildType.MEDIA_CONTROLS, ChildType.ALERTING,
442 ChildType.GENTLE);
Robert Snoebergerb6464ea2020-03-20 11:56:22 -0400443 }
444
Steve Elliott35956b42020-02-25 17:12:09 -0500445 private void enablePeopleFiltering() {
446 when(mSectionsFeatureManager.isFilteringEnabled()).thenReturn(true);
Steve Elliott35956b42020-02-25 17:12:09 -0500447 }
448
Robert Snoebergerb6464ea2020-03-20 11:56:22 -0400449 private void enableMediaControls() {
450 when(mSectionsFeatureManager.isMediaControlsEnabled()).thenReturn(true);
Robert Snoebergerb6464ea2020-03-20 11:56:22 -0400451 }
452
Steve Elliott35956b42020-02-25 17:12:09 -0500453 private enum ChildType {
Steve Elliott49671e02020-05-12 13:51:28 -0400454 INCOMING_HEADER, MEDIA_CONTROLS, PEOPLE_HEADER, ALERTING_HEADER, GENTLE_HEADER, HEADS_UP,
455 FSN, PERSON, ALERTING, GENTLE, OTHER
Steve Elliott35956b42020-02-25 17:12:09 -0500456 }
Ned Burns9eb06332019-04-23 16:02:12 -0400457
458 private void setStackState(ChildType... children) {
459 when(mNssl.getChildCount()).thenReturn(children.length);
460 for (int i = 0; i < children.length; i++) {
461 View child;
462 switch (children[i]) {
Steve Elliott49671e02020-05-12 13:51:28 -0400463 case INCOMING_HEADER:
464 child = mSectionsManager.getIncomingHeaderView();
465 break;
Robert Snoebergerb6464ea2020-03-20 11:56:22 -0400466 case MEDIA_CONTROLS:
467 child = mSectionsManager.getMediaControlsView();
468 break;
Steve Elliott35956b42020-02-25 17:12:09 -0500469 case PEOPLE_HEADER:
470 child = mSectionsManager.getPeopleHeaderView();
471 break;
472 case ALERTING_HEADER:
473 child = mSectionsManager.getAlertingHeaderView();
474 break;
475 case GENTLE_HEADER:
Ned Burns9eb06332019-04-23 16:02:12 -0400476 child = mSectionsManager.getGentleHeaderView();
477 break;
Steve Elliott35956b42020-02-25 17:12:09 -0500478 case HEADS_UP:
479 child = mockNotification(BUCKET_HEADS_UP);
480 break;
Steve Elliott49671e02020-05-12 13:51:28 -0400481 case FSN:
482 child = mockNotification(BUCKET_FOREGROUND_SERVICE);
483 break;
Steve Elliott35956b42020-02-25 17:12:09 -0500484 case PERSON:
485 child = mockNotification(BUCKET_PEOPLE);
486 break;
487 case ALERTING:
488 child = mockNotification(BUCKET_ALERTING);
489 break;
490 case GENTLE:
491 child = mockNotification(BUCKET_SILENT);
492 break;
493 case OTHER:
494 child = mock(View.class);
495 when(child.getVisibility()).thenReturn(View.VISIBLE);
496 when(child.getParent()).thenReturn(mNssl);
Ned Burns9eb06332019-04-23 16:02:12 -0400497 break;
498 default:
499 throw new RuntimeException("Unknown ChildType: " + children[i]);
500 }
501 when(mNssl.getChildAt(i)).thenReturn(child);
502 when(mNssl.indexOfChild(child)).thenReturn(i);
503 }
504 }
Steve Elliott35956b42020-02-25 17:12:09 -0500505
506 private View mockNotification(int bucket) {
507 ExpandableNotificationRow notifRow = mock(ExpandableNotificationRow.class,
508 RETURNS_DEEP_STUBS);
509 when(notifRow.getVisibility()).thenReturn(View.VISIBLE);
510 when(notifRow.getEntry().getBucket()).thenReturn(bucket);
511 when(notifRow.getParent()).thenReturn(mNssl);
512 return notifRow;
513 }
Steve Elliott49671e02020-05-12 13:51:28 -0400514
515 private void verifyMockStack(ChildType... expected) {
516 final List<ChildType> actual = new ArrayList<>();
517 int childCount = mNssl.getChildCount();
518 for (int i = 0; i < childCount; i++) {
519 View child = mNssl.getChildAt(i);
520 if (child == mSectionsManager.getIncomingHeaderView()) {
521 actual.add(ChildType.INCOMING_HEADER);
522 continue;
523 }
524 if (child == mSectionsManager.getMediaControlsView()) {
525 actual.add(ChildType.MEDIA_CONTROLS);
526 continue;
527 }
528 if (child == mSectionsManager.getPeopleHeaderView()) {
529 actual.add(ChildType.PEOPLE_HEADER);
530 continue;
531 }
532 if (child == mSectionsManager.getAlertingHeaderView()) {
533 actual.add(ChildType.ALERTING_HEADER);
534 continue;
535 }
536 if (child == mSectionsManager.getGentleHeaderView()) {
537 actual.add(ChildType.GENTLE_HEADER);
538 continue;
539 }
540 if (child instanceof ExpandableNotificationRow) {
541 switch (((ExpandableNotificationRow) child).getEntry().getBucket()) {
542 case BUCKET_HEADS_UP:
543 actual.add(ChildType.HEADS_UP);
544 break;
545 case BUCKET_FOREGROUND_SERVICE:
546 actual.add(ChildType.FSN);
547 break;
548 case BUCKET_PEOPLE:
549 actual.add(ChildType.PERSON);
550 break;
551 case BUCKET_ALERTING:
552 actual.add(ChildType.ALERTING);
553 break;
554 case BUCKET_SILENT:
555 actual.add(ChildType.GENTLE);
556 break;
557 default:
558 actual.add(ChildType.OTHER);
559 break;
560 }
561 continue;
562 }
563 actual.add(ChildType.OTHER);
564 }
565 assertThat(actual).containsExactly((Object[]) expected).inOrder();
566 }
567
568 private void setupMockStack(ChildType... childTypes) {
569 final List<View> children = new ArrayList<>();
570 when(mNssl.getChildCount()).thenAnswer(invocation -> children.size());
571 when(mNssl.getChildAt(anyInt()))
572 .thenAnswer(invocation -> children.get(invocation.getArgument(0)));
573 when(mNssl.indexOfChild(any()))
574 .thenAnswer(invocation -> children.indexOf(invocation.getArgument(0)));
575 doAnswer(invocation -> {
576 View child = invocation.getArgument(0);
577 int index = invocation.getArgument(1);
578 children.add(index, child);
579 return null;
580 }).when(mNssl).addView(any(), anyInt());
581 doAnswer(invocation -> {
582 View child = invocation.getArgument(0);
583 children.remove(child);
584 return null;
585 }).when(mNssl).removeView(any());
586 doAnswer(invocation -> {
587 View child = invocation.getArgument(0);
588 int newIndex = invocation.getArgument(1);
589 children.remove(child);
590 children.add(newIndex, child);
591 return null;
592 }).when(mNssl).changeViewPosition(any(), anyInt());
593 for (ChildType childType : childTypes) {
594 View child;
595 switch (childType) {
596 case INCOMING_HEADER:
597 child = mSectionsManager.getIncomingHeaderView();
598 break;
599 case MEDIA_CONTROLS:
600 child = mSectionsManager.getMediaControlsView();
601 break;
602 case PEOPLE_HEADER:
603 child = mSectionsManager.getPeopleHeaderView();
604 break;
605 case ALERTING_HEADER:
606 child = mSectionsManager.getAlertingHeaderView();
607 break;
608 case GENTLE_HEADER:
609 child = mSectionsManager.getGentleHeaderView();
610 break;
611 case HEADS_UP:
612 child = mockNotification(BUCKET_HEADS_UP);
613 break;
614 case FSN:
615 child = mockNotification(BUCKET_FOREGROUND_SERVICE);
616 break;
617 case PERSON:
618 child = mockNotification(BUCKET_PEOPLE);
619 break;
620 case ALERTING:
621 child = mockNotification(BUCKET_ALERTING);
622 break;
623 case GENTLE:
624 child = mockNotification(BUCKET_SILENT);
625 break;
626 case OTHER:
627 child = mock(View.class);
628 when(child.getVisibility()).thenReturn(View.VISIBLE);
629 when(child.getParent()).thenReturn(mNssl);
630 break;
631 default:
632 throw new RuntimeException("Unknown ChildType: " + childType);
633 }
634 children.add(child);
635 }
636 }
Ned Burns9eb06332019-04-23 16:02:12 -0400637}