blob: d835082015290090b73d80acc4a04ddb4479a5b0 [file] [log] [blame]
Selim Cinek8a9308d2017-08-24 09:31:08 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
Jason Monke59dc402018-08-16 12:05:01 -04006 * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 *
Selim Cinek8a9308d2017-08-24 09:31:08 -07007 * Unless required by applicable law or agreed to in writing, software
8 * distributed under the License is distributed on an "AS IS" BASIS,
9 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 * See the License for the specific language governing permissions and
11 * limitations under the License
12 */
13
Rohan Shah20790b82018-07-02 17:21:04 -070014package com.android.systemui.statusbar.notification.stack;
Selim Cinek8a9308d2017-08-24 09:31:08 -070015
Gus Prevase2d6f042018-10-17 15:25:30 -040016import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL;
17
Jason Monke59dc402018-08-16 12:05:01 -040018import static junit.framework.Assert.assertEquals;
19import static junit.framework.Assert.assertNotNull;
Gus Prevas99ba4ba2018-10-01 16:40:23 -040020import static junit.framework.Assert.assertNull;
21
Jason Monk297c04e2018-08-23 17:16:59 -040022import static org.junit.Assert.assertFalse;
23import static org.junit.Assert.assertTrue;
Rohan Shah524cf7b2018-03-15 14:40:02 -070024import static org.mockito.ArgumentMatchers.any;
25import static org.mockito.ArgumentMatchers.anyBoolean;
Jason Monke59dc402018-08-16 12:05:01 -040026import static org.mockito.ArgumentMatchers.anyInt;
Will Brockmane718d582019-01-17 16:38:38 -050027import static org.mockito.ArgumentMatchers.argThat;
Selim Cinekd60ef9e2018-05-16 16:01:05 -070028import static org.mockito.ArgumentMatchers.eq;
Gus Prevase2d6f042018-10-17 15:25:30 -040029import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
Evan Lairdfec77662018-09-18 16:56:50 -040030import static org.mockito.Mockito.atLeastOnce;
Jason Monke59dc402018-08-16 12:05:01 -040031import static org.mockito.Mockito.clearInvocations;
Rohan Shah524cf7b2018-03-15 14:40:02 -070032import static org.mockito.Mockito.doNothing;
Selim Cinek8a9308d2017-08-24 09:31:08 -070033import static org.mockito.Mockito.mock;
Rohan Shah524cf7b2018-03-15 14:40:02 -070034import static org.mockito.Mockito.reset;
35import static org.mockito.Mockito.spy;
Julia Reynolds9cf17562018-03-14 09:49:35 -040036import static org.mockito.Mockito.verify;
Selim Cinek8a9308d2017-08-24 09:31:08 -070037import static org.mockito.Mockito.when;
38
Will Brockmane718d582019-01-17 16:38:38 -050039import android.metrics.LogMaker;
Gus Prevase2d6f042018-10-17 15:25:30 -040040import android.provider.Settings;
Selim Cinek8a9308d2017-08-24 09:31:08 -070041import android.support.test.annotation.UiThreadTest;
42import android.support.test.filters.SmallTest;
43import android.support.test.runner.AndroidJUnit4;
Gus Prevas99ba4ba2018-10-01 16:40:23 -040044import android.view.View;
Selim Cinek8a9308d2017-08-24 09:31:08 -070045
Will Brockmane718d582019-01-17 16:38:38 -050046import com.android.internal.logging.MetricsLogger;
47import com.android.internal.logging.nano.MetricsProto;
Jason Monk297c04e2018-08-23 17:16:59 -040048import com.android.systemui.Dependency;
Rohan Shah524cf7b2018-03-15 14:40:02 -070049import com.android.systemui.ExpandHelper;
Jason Monk297c04e2018-08-23 17:16:59 -040050import com.android.systemui.InitController;
Julia Reynolds9cf17562018-03-14 09:49:35 -040051import com.android.systemui.R;
Selim Cinek8a9308d2017-08-24 09:31:08 -070052import com.android.systemui.SysuiTestCase;
Will Brockmane718d582019-01-17 16:38:38 -050053import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
Beverly8fdb5332019-02-04 14:29:49 -050054import com.android.systemui.plugins.statusbar.StatusBarStateController;
Julia Reynolds9cf17562018-03-14 09:49:35 -040055import com.android.systemui.statusbar.EmptyShadeView;
Jason Monke59dc402018-08-16 12:05:01 -040056import com.android.systemui.statusbar.NotificationPresenter;
Jason Monk297c04e2018-08-23 17:16:59 -040057import com.android.systemui.statusbar.NotificationRemoteInputManager;
58import com.android.systemui.statusbar.NotificationShelf;
59import com.android.systemui.statusbar.RemoteInputController;
60import com.android.systemui.statusbar.StatusBarState;
Jason Monke59dc402018-08-16 12:05:01 -040061import com.android.systemui.statusbar.notification.NotificationEntryManager;
Ned Burnsf81c4c42019-01-07 14:10:43 -050062import com.android.systemui.statusbar.notification.collection.NotificationData;
63import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Jason Monke59dc402018-08-16 12:05:01 -040064import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Rohan Shah20790b82018-07-02 17:21:04 -070065import com.android.systemui.statusbar.notification.row.FooterView;
66import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
Rohan Shah524cf7b2018-03-15 14:40:02 -070067import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
68import com.android.systemui.statusbar.phone.NotificationGroupManager;
Selim Cinek8a9308d2017-08-24 09:31:08 -070069import com.android.systemui.statusbar.phone.ScrimController;
Jason Monk297c04e2018-08-23 17:16:59 -040070import com.android.systemui.statusbar.phone.ShadeController;
Selim Cinek8a9308d2017-08-24 09:31:08 -070071import com.android.systemui.statusbar.phone.StatusBar;
Jason Monke59dc402018-08-16 12:05:01 -040072import com.android.systemui.statusbar.phone.StatusBarTest.TestableNotificationEntryManager;
73
Gus Prevase2d6f042018-10-17 15:25:30 -040074import org.junit.After;
Selim Cinek8a9308d2017-08-24 09:31:08 -070075import org.junit.Assert;
76import org.junit.Before;
Rohan Shah524cf7b2018-03-15 14:40:02 -070077import org.junit.Rule;
Selim Cinek8a9308d2017-08-24 09:31:08 -070078import org.junit.Test;
79import org.junit.runner.RunWith;
Jason Monke59dc402018-08-16 12:05:01 -040080import org.mockito.ArgumentCaptor;
Will Brockmane718d582019-01-17 16:38:38 -050081import org.mockito.ArgumentMatcher;
Rohan Shah524cf7b2018-03-15 14:40:02 -070082import org.mockito.Mock;
83import org.mockito.junit.MockitoJUnit;
84import org.mockito.junit.MockitoRule;
Selim Cinek8a9308d2017-08-24 09:31:08 -070085
Jason Monk297c04e2018-08-23 17:16:59 -040086import java.util.ArrayList;
87
Rohan Shah524cf7b2018-03-15 14:40:02 -070088/**
89 * Tests for {@link NotificationStackScrollLayout}.
90 */
Selim Cinek8a9308d2017-08-24 09:31:08 -070091@SmallTest
92@RunWith(AndroidJUnit4.class)
93public class NotificationStackScrollLayoutTest extends SysuiTestCase {
94
Will Brockmane718d582019-01-17 16:38:38 -050095 private NotificationStackScrollLayout mStackScroller; // Normally test this
96 private NotificationStackScrollLayout mStackScrollerInternal; // See explanation below
Rohan Shah524cf7b2018-03-15 14:40:02 -070097
98 @Rule public MockitoRule mockito = MockitoJUnit.rule();
99 @Mock private StatusBar mBar;
Jason Monk1fd3fc32018-08-14 17:20:09 -0400100 @Mock private StatusBarStateController mBarState;
Rohan Shah524cf7b2018-03-15 14:40:02 -0700101 @Mock private HeadsUpManagerPhone mHeadsUpManager;
102 @Mock private NotificationBlockingHelperManager mBlockingHelperManager;
103 @Mock private NotificationGroupManager mGroupManager;
104 @Mock private ExpandHelper mExpandHelper;
105 @Mock private EmptyShadeView mEmptyShadeView;
Jason Monke59dc402018-08-16 12:05:01 -0400106 @Mock private NotificationData mNotificationData;
107 @Mock private NotificationRemoteInputManager mRemoteInputManager;
108 @Mock private RemoteInputController mRemoteInputController;
Will Brockmane718d582019-01-17 16:38:38 -0500109 @Mock private MetricsLogger mMetricsLogger;
Lucas Dupin00be88f2019-01-03 17:50:52 -0800110 @Mock private NotificationRoundnessManager mNotificationRoundnessManager;
Jason Monke59dc402018-08-16 12:05:01 -0400111 private TestableNotificationEntryManager mEntryManager;
Gus Prevase2d6f042018-10-17 15:25:30 -0400112 private int mOriginalInterruptionModelSetting;
Selim Cinek8a9308d2017-08-24 09:31:08 -0700113
Will Brockmane718d582019-01-17 16:38:38 -0500114
Selim Cinek8a9308d2017-08-24 09:31:08 -0700115 @Before
116 @UiThreadTest
117 public void setUp() throws Exception {
Rohan Shah524cf7b2018-03-15 14:40:02 -0700118 // Inject dependencies before initializing the layout
119 mDependency.injectTestDependency(
120 NotificationBlockingHelperManager.class,
121 mBlockingHelperManager);
Jason Monk1fd3fc32018-08-14 17:20:09 -0400122 mDependency.injectTestDependency(StatusBarStateController.class, mBarState);
Will Brockmane718d582019-01-17 16:38:38 -0500123 mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
Jason Monke59dc402018-08-16 12:05:01 -0400124 mDependency.injectTestDependency(NotificationRemoteInputManager.class,
125 mRemoteInputManager);
Jason Monk297c04e2018-08-23 17:16:59 -0400126 mDependency.injectMockDependency(ShadeController.class);
Jason Monke59dc402018-08-16 12:05:01 -0400127 when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
128
Gus Prevas92586462019-01-04 16:06:12 -0500129 mEntryManager = new TestableNotificationEntryManager(mContext);
Jason Monk297c04e2018-08-23 17:16:59 -0400130 mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
131 Dependency.get(InitController.class).executePostInitTasks();
Gus Prevas8621bd22018-12-20 15:04:25 -0500132 mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, mHeadsUpManager,
Kevina5ff1fa2018-08-21 16:35:48 -0700133 mNotificationData);
Rohan Shah524cf7b2018-03-15 14:40:02 -0700134
Jason Monk297c04e2018-08-23 17:16:59 -0400135
136 NotificationShelf notificationShelf = mock(NotificationShelf.class);
Will Brockmane718d582019-01-17 16:38:38 -0500137
138 // The actual class under test. You may need to work with this class directly when
139 // testing anonymous class members of mStackScroller, like mMenuEventListener,
140 // which refer to members of NotificationStackScrollLayout. The spy
141 // holds a copy of the CUT's instances of these classes, so they still refer to the CUT's
142 // member variables, not the spy's member variables.
143 mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null,
Lucas Dupin00be88f2019-01-03 17:50:52 -0800144 true /* allowLongPress */, mNotificationRoundnessManager);
Will Brockmane718d582019-01-17 16:38:38 -0500145 mStackScroller = spy(mStackScrollerInternal);
Rohan Shah524cf7b2018-03-15 14:40:02 -0700146 mStackScroller.setShelf(notificationShelf);
Selim Cinek8a9308d2017-08-24 09:31:08 -0700147 mStackScroller.setStatusBar(mBar);
148 mStackScroller.setScrimController(mock(ScrimController.class));
Rohan Shah524cf7b2018-03-15 14:40:02 -0700149 mStackScroller.setHeadsUpManager(mHeadsUpManager);
150 mStackScroller.setGroupManager(mGroupManager);
151 mStackScroller.setEmptyShadeView(mEmptyShadeView);
152
153 // Stub out functionality that isn't necessary to test.
154 doNothing().when(mBar)
155 .executeRunnableDismissingKeyguard(any(Runnable.class),
156 any(Runnable.class),
157 anyBoolean(),
158 anyBoolean(),
159 anyBoolean());
160 doNothing().when(mGroupManager).collapseAllGroups();
161 doNothing().when(mExpandHelper).cancelImmediately();
162 doNothing().when(notificationShelf).setAnimationsEnabled(anyBoolean());
Lucas Dupin7fc9dc12019-01-03 09:19:43 -0800163 doNothing().when(notificationShelf).fadeInTranslating();
Gus Prevase2d6f042018-10-17 15:25:30 -0400164
165 mOriginalInterruptionModelSetting = Settings.Secure.getInt(mContext.getContentResolver(),
166 NOTIFICATION_NEW_INTERRUPTION_MODEL, 0);
167 Settings.Secure.putInt(mContext.getContentResolver(),
168 NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
169 }
170
171 @After
172 public void tearDown() {
173 Settings.Secure.putInt(mContext.getContentResolver(),
174 NOTIFICATION_NEW_INTERRUPTION_MODEL, mOriginalInterruptionModelSetting);
Selim Cinek8a9308d2017-08-24 09:31:08 -0700175 }
176
177 @Test
178 public void testNotDimmedOnKeyguard() {
Jason Monk1fd3fc32018-08-14 17:20:09 -0400179 when(mBarState.getState()).thenReturn(StatusBarState.SHADE);
Selim Cinek8a9308d2017-08-24 09:31:08 -0700180 mStackScroller.setDimmed(true /* dimmed */, false /* animate */);
181 mStackScroller.setDimmed(true /* dimmed */, true /* animate */);
Jason Monk297c04e2018-08-23 17:16:59 -0400182 assertFalse(mStackScroller.isDimmed());
Selim Cinek8a9308d2017-08-24 09:31:08 -0700183 }
184
Lucas Dupin0cd882f2018-01-30 12:19:49 -0800185 @Test
186 public void testAntiBurnInOffset() {
187 final int burnInOffset = 30;
188 mStackScroller.setAntiBurnInOffsetX(burnInOffset);
189 mStackScroller.setDark(false /* dark */, false /* animated */, null /* touch */);
190 Assert.assertEquals(0 /* expected */, mStackScroller.getTranslationX(), 0.01 /* delta */);
191 mStackScroller.setDark(true /* dark */, false /* animated */, null /* touch */);
192 Assert.assertEquals(burnInOffset /* expected */, mStackScroller.getTranslationX(),
193 0.01 /* delta */);
194 }
195
Julia Reynolds9cf17562018-03-14 09:49:35 -0400196 @Test
Julia Reynolds34f14962018-05-03 12:40:20 +0000197 public void updateEmptyView_dndSuppressing() {
198 when(mEmptyShadeView.willBeGone()).thenReturn(true);
199 when(mBar.areNotificationsHidden()).thenReturn(true);
200
201 mStackScroller.updateEmptyShadeView(true);
202
203 verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
204 }
205
206 @Test
207 public void updateEmptyView_dndNotSuppressing() {
208 mStackScroller.setEmptyShadeView(mEmptyShadeView);
209 when(mEmptyShadeView.willBeGone()).thenReturn(true);
210 when(mBar.areNotificationsHidden()).thenReturn(false);
211
212 mStackScroller.updateEmptyShadeView(true);
213
214 verify(mEmptyShadeView).setText(R.string.empty_shade_text);
215 }
216
217 @Test
218 public void updateEmptyView_noNotificationsToDndSuppressing() {
219 mStackScroller.setEmptyShadeView(mEmptyShadeView);
220 when(mEmptyShadeView.willBeGone()).thenReturn(true);
221 when(mBar.areNotificationsHidden()).thenReturn(false);
222 mStackScroller.updateEmptyShadeView(true);
223 verify(mEmptyShadeView).setText(R.string.empty_shade_text);
224
225 when(mBar.areNotificationsHidden()).thenReturn(true);
226 mStackScroller.updateEmptyShadeView(true);
227 verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
228 }
229
230 @Test
Rohan Shah524cf7b2018-03-15 14:40:02 -0700231 @UiThreadTest
232 public void testSetExpandedHeight_blockingHelperManagerReceivedCallbacks() {
233 mStackScroller.setExpandedHeight(0f);
234 verify(mBlockingHelperManager).setNotificationShadeExpanded(0f);
235 reset(mBlockingHelperManager);
236
237 mStackScroller.setExpandedHeight(100f);
238 verify(mBlockingHelperManager).setNotificationShadeExpanded(100f);
Julia Reynolds9cf17562018-03-14 09:49:35 -0400239 }
Julia Reynoldsed1c9af2018-03-21 15:21:09 -0400240
241 @Test
242 public void manageNotifications_visible() {
243 FooterView view = mock(FooterView.class);
244 mStackScroller.setFooterView(view);
245 when(view.willBeGone()).thenReturn(true);
Julia Reynoldsed1c9af2018-03-21 15:21:09 -0400246
247 mStackScroller.updateFooterView(true, false);
248
Selim Cinekd60ef9e2018-05-16 16:01:05 -0700249 verify(view).setVisible(eq(true), anyBoolean());
250 verify(view).setSecondaryVisible(eq(false), anyBoolean());
Julia Reynoldsed1c9af2018-03-21 15:21:09 -0400251 }
252
253 @Test
254 public void clearAll_visible() {
255 FooterView view = mock(FooterView.class);
256 mStackScroller.setFooterView(view);
257 when(view.willBeGone()).thenReturn(true);
Julia Reynoldsed1c9af2018-03-21 15:21:09 -0400258
259 mStackScroller.updateFooterView(true, true);
260
Selim Cinekd60ef9e2018-05-16 16:01:05 -0700261 verify(view).setVisible(eq(true), anyBoolean());
262 verify(view).setSecondaryVisible(eq(true), anyBoolean());
Julia Reynoldsed1c9af2018-03-21 15:21:09 -0400263 }
Jason Monke59dc402018-08-16 12:05:01 -0400264
265 @Test
266 public void testInflateFooterView() {
267 mStackScroller.inflateFooterView();
268 ArgumentCaptor<FooterView> captor = ArgumentCaptor.forClass(FooterView.class);
269 verify(mStackScroller).setFooterView(captor.capture());
270
271 assertNotNull(captor.getValue().findViewById(R.id.manage_text).hasOnClickListeners());
272 assertNotNull(captor.getValue().findViewById(R.id.dismiss_text).hasOnClickListeners());
273 }
274
275 @Test
276 public void testUpdateFooter_noNotifications() {
277 setBarStateForTest(StatusBarState.SHADE);
278 assertEquals(0, mNotificationData.getActiveNotifications().size());
279
280 mStackScroller.updateFooter();
Jason Monk297c04e2018-08-23 17:16:59 -0400281 verify(mStackScroller, atLeastOnce()).updateFooterView(false, false);
Jason Monke59dc402018-08-16 12:05:01 -0400282 }
283
284 @Test
285 public void testUpdateFooter_remoteInput() {
286 setBarStateForTest(StatusBarState.SHADE);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500287 ArrayList<NotificationEntry> entries = new ArrayList<>();
288 entries.add(mock(NotificationEntry.class));
Jason Monke59dc402018-08-16 12:05:01 -0400289 when(mNotificationData.getActiveNotifications()).thenReturn(entries);
290
291 ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
292 when(row.canViewBeDismissed()).thenReturn(true);
293 when(mStackScroller.getChildCount()).thenReturn(1);
294 when(mStackScroller.getChildAt(anyInt())).thenReturn(row);
295 when(mRemoteInputController.isRemoteInputActive()).thenReturn(true);
296
297 mStackScroller.updateFooter();
298 verify(mStackScroller).updateFooterView(false, true);
299 }
300
301 @Test
302 public void testUpdateFooter_oneClearableNotification() {
303 setBarStateForTest(StatusBarState.SHADE);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500304 ArrayList<NotificationEntry> entries = new ArrayList<>();
305 entries.add(mock(NotificationEntry.class));
Jason Monke59dc402018-08-16 12:05:01 -0400306 when(mNotificationData.getActiveNotifications()).thenReturn(entries);
307
308 ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
309 when(row.canViewBeDismissed()).thenReturn(true);
310 when(mStackScroller.getChildCount()).thenReturn(1);
311 when(mStackScroller.getChildAt(anyInt())).thenReturn(row);
312
313 mStackScroller.updateFooter();
314 verify(mStackScroller).updateFooterView(true, true);
315 }
316
317 @Test
318 public void testUpdateFooter_oneNonClearableNotification() {
319 setBarStateForTest(StatusBarState.SHADE);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500320 ArrayList<NotificationEntry> entries = new ArrayList<>();
321 entries.add(mock(NotificationEntry.class));
Jason Monk297c04e2018-08-23 17:16:59 -0400322 when(mEntryManager.getNotificationData().getActiveNotifications()).thenReturn(entries);
323 assertTrue(mEntryManager.getNotificationData().getActiveNotifications().size() != 0);
Jason Monke59dc402018-08-16 12:05:01 -0400324
325 mStackScroller.updateFooter();
326 verify(mStackScroller).updateFooterView(true, false);
327 }
328
329 @Test
330 public void testUpdateFooter_atEnd() {
331 // add footer
332 mStackScroller.inflateFooterView();
333
334 // add notification
335 ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
Ned Burnsf81c4c42019-01-07 14:10:43 -0500336 NotificationEntry entry = mock(NotificationEntry.class);
Evan Laird94492852018-10-25 13:43:01 -0400337 when(row.getEntry()).thenReturn(entry);
338 when(entry.isClearable()).thenReturn(true);
Jason Monke59dc402018-08-16 12:05:01 -0400339 mStackScroller.addContainerView(row);
340
341 mStackScroller.onUpdateRowStates();
342
343 // move footer to end
344 verify(mStackScroller).changeViewPosition(any(FooterView.class), eq(-1 /* end */));
345 }
346
347 @Test
Gus Prevase2d6f042018-10-17 15:25:30 -0400348 public void testUpdateGapIndex_allHighPriority() {
349 when(mStackScroller.getChildCount()).thenReturn(3);
350 for (int i = 0; i < 3; i++) {
351 ExpandableNotificationRow row = mock(ExpandableNotificationRow.class,
352 RETURNS_DEEP_STUBS);
353 String key = Integer.toString(i);
354 when(row.getStatusBarNotification().getKey()).thenReturn(key);
Gus Prevascaed15c2019-01-18 14:19:51 -0500355 when(row.getEntry().isHighPriority()).thenReturn(true);
Gus Prevase2d6f042018-10-17 15:25:30 -0400356 when(mStackScroller.getChildAt(i)).thenReturn(row);
357 }
358
359 mStackScroller.updateSectionBoundaries();
360 assertEquals(-1, mStackScroller.getSectionBoundaryIndex(0));
361 }
362
363 @Test
364 public void testUpdateGapIndex_allLowPriority() {
365 when(mStackScroller.getChildCount()).thenReturn(3);
366 for (int i = 0; i < 3; i++) {
367 ExpandableNotificationRow row = mock(ExpandableNotificationRow.class,
368 RETURNS_DEEP_STUBS);
369 String key = Integer.toString(i);
370 when(row.getStatusBarNotification().getKey()).thenReturn(key);
Gus Prevascaed15c2019-01-18 14:19:51 -0500371 when(row.getEntry().isHighPriority()).thenReturn(false);
Gus Prevase2d6f042018-10-17 15:25:30 -0400372 when(mStackScroller.getChildAt(i)).thenReturn(row);
373 }
374
375 mStackScroller.updateSectionBoundaries();
376 assertEquals(-1, mStackScroller.getSectionBoundaryIndex(0));
377 }
378
379 @Test
380 public void testUpdateGapIndex_gapExists() {
381 when(mStackScroller.getChildCount()).thenReturn(6);
382 for (int i = 0; i < 6; i++) {
383 ExpandableNotificationRow row = mock(ExpandableNotificationRow.class,
384 RETURNS_DEEP_STUBS);
385 String key = Integer.toString(i);
386 when(row.getStatusBarNotification().getKey()).thenReturn(key);
Gus Prevascaed15c2019-01-18 14:19:51 -0500387 when(row.getEntry().isHighPriority()).thenReturn(i < 3);
Gus Prevase2d6f042018-10-17 15:25:30 -0400388 when(mStackScroller.getChildAt(i)).thenReturn(row);
389 }
390
391 mStackScroller.updateSectionBoundaries();
392 assertEquals(3, mStackScroller.getSectionBoundaryIndex(0));
393 }
394
395 @Test
396 public void testUpdateGapIndex_empty() {
397 when(mStackScroller.getChildCount()).thenReturn(0);
398
399 mStackScroller.updateSectionBoundaries();
400 assertEquals(-1, mStackScroller.getSectionBoundaryIndex(0));
401 }
402
403 @Test
Jason Monke59dc402018-08-16 12:05:01 -0400404 public void testOnDensityOrFontScaleChanged_reInflatesFooterViews() {
405 clearInvocations(mStackScroller);
406 mStackScroller.onDensityOrFontScaleChanged();
407 verify(mStackScroller).setFooterView(any());
408 verify(mStackScroller).setEmptyShadeView(any());
409 }
410
Gus Prevas99ba4ba2018-10-01 16:40:23 -0400411 @Test
412 @UiThreadTest
413 public void testSetIsBeingDraggedResetsExposedMenu() {
414 NotificationSwipeHelper swipeActionHelper =
415 (NotificationSwipeHelper) mStackScroller.getSwipeActionHelper();
416 swipeActionHelper.setExposedMenuView(new View(mContext));
417 mStackScroller.setIsBeingDragged(true);
418 assertNull(swipeActionHelper.getExposedMenuView());
419 }
420
421 @Test
422 @UiThreadTest
423 public void testPanelTrackingStartResetsExposedMenu() {
424 NotificationSwipeHelper swipeActionHelper =
425 (NotificationSwipeHelper) mStackScroller.getSwipeActionHelper();
426 swipeActionHelper.setExposedMenuView(new View(mContext));
427 mStackScroller.onPanelTrackingStarted();
428 assertNull(swipeActionHelper.getExposedMenuView());
429 }
430
431 @Test
432 @UiThreadTest
433 public void testDarkModeResetsExposedMenu() {
434 NotificationSwipeHelper swipeActionHelper =
435 (NotificationSwipeHelper) mStackScroller.getSwipeActionHelper();
436 swipeActionHelper.setExposedMenuView(new View(mContext));
437 mStackScroller.setDarkAmount(0.1f, 0.1f);
438 assertNull(swipeActionHelper.getExposedMenuView());
439 }
440
Will Brockmane718d582019-01-17 16:38:38 -0500441 class LogMatcher implements ArgumentMatcher<LogMaker> {
442 private int mCategory, mType;
443
444 LogMatcher(int category, int type) {
445 mCategory = category;
446 mType = type;
447 }
448 public boolean matches(LogMaker l) {
449 return (l.getCategory() == mCategory)
450 && (l.getType() == mType);
451 }
452
453 public String toString() {
454 return String.format("LogMaker(%d, %d)", mCategory, mType);
455 }
456 }
457
458 private LogMaker logMatcher(int category, int type) {
459 return argThat(new LogMatcher(category, type));
460 }
461
462 @Test
463 @UiThreadTest
464 public void testOnMenuClickedLogging() {
465 // Set up the object under test to have a valid mLongPressListener. We're testing an
466 // anonymous-class member, mMenuEventListener, so we need to modify the state of the
467 // class itself, not the Mockito spy copied from it. See notes in setup.
468 mStackScrollerInternal.setLongPressListener(
469 mock(ExpandableNotificationRow.LongPressListener.class));
470
471 ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
472 when(row.getStatusBarNotification().getLogMaker()).thenReturn(new LogMaker(
473 MetricsProto.MetricsEvent.VIEW_UNKNOWN));
474
475 mStackScroller.mMenuEventListener.onMenuClicked(row, 0, 0, mock(
476 NotificationMenuRowPlugin.MenuItem.class));
477 verify(row.getStatusBarNotification()).getLogMaker(); // This writes most of the log data
478 verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_TOUCH_GEAR,
479 MetricsProto.MetricsEvent.TYPE_ACTION));
480 }
481
482 @Test
483 @UiThreadTest
484 public void testOnMenuShownLogging() {
485 // Set up the object under test to have a valid mHeadsUpManager. See notes in setup.
486 mStackScrollerInternal.setHeadsUpManager(mHeadsUpManager);
487
488 ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
489 when(row.getStatusBarNotification().getLogMaker()).thenReturn(new LogMaker(
490 MetricsProto.MetricsEvent.VIEW_UNKNOWN));
491
492 mStackScroller.mMenuEventListener.onMenuShown(row);
493 verify(row.getStatusBarNotification()).getLogMaker(); // This writes most of the log data
494 verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_REVEAL_GEAR,
495 MetricsProto.MetricsEvent.TYPE_ACTION));
496 }
497
Jason Monke59dc402018-08-16 12:05:01 -0400498 private void setBarStateForTest(int state) {
Jason Monk297c04e2018-08-23 17:16:59 -0400499 // Can't inject this through the listener or we end up on the actual implementation
500 // rather than the mock because the spy just coppied the anonymous inner /shruggie.
501 mStackScroller.setStatusBarState(state);
Jason Monke59dc402018-08-16 12:05:01 -0400502 }
Selim Cinek8a9308d2017-08-24 09:31:08 -0700503}