blob: 06a2eecd208cb637930524cf586ea2c9392925f7 [file] [log] [blame]
Aaron Heuckroth45d20be2018-09-18 13:47:26 -04001/*
2 * Copyright (C) 2018 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 * * http://www.apache.org/licenses/LICENSE-2.0 *
7 * 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
14package com.android.systemui.statusbar.notification.stack;
15
16import static junit.framework.Assert.assertEquals;
17import static junit.framework.Assert.assertFalse;
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040018import static junit.framework.Assert.assertTrue;
19
20import static org.mockito.ArgumentMatchers.any;
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040021import static org.mockito.Mockito.doAnswer;
22import static org.mockito.Mockito.doNothing;
23import static org.mockito.Mockito.doReturn;
24import static org.mockito.Mockito.mock;
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040025import static org.mockito.Mockito.spy;
26import static org.mockito.Mockito.times;
27import static org.mockito.Mockito.verify;
28import static org.mockito.Mockito.when;
29
30import android.animation.Animator;
31import android.animation.ValueAnimator.AnimatorUpdateListener;
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040032import android.os.Handler;
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040033import android.service.notification.StatusBarNotification;
Aaron Heuckroth3c1f0212018-11-15 14:50:46 -050034import android.testing.AndroidTestingRunner;
35import android.testing.TestableLooper;
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040036import android.view.MotionEvent;
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040037import android.view.View;
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040038
Brett Chabot84151d92019-02-27 15:37:59 -080039import androidx.test.filters.SmallTest;
40
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040041import com.android.systemui.SwipeHelper;
42import com.android.systemui.SysuiTestCase;
Dave Mankoff781ef7e2019-06-28 16:33:25 -040043import com.android.systemui.classifier.FalsingManagerFake;
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040044import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
45import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
46import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040047
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040048import org.junit.Before;
49import org.junit.Rule;
50import org.junit.Test;
51import org.junit.runner.RunWith;
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040052import org.mockito.junit.MockitoJUnit;
53import org.mockito.junit.MockitoRule;
54import org.mockito.stubbing.Answer;
55
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040056/**
57 * Tests for {@link NotificationSwipeHelper}.
58 */
59@SmallTest
Aaron Heuckroth3c1f0212018-11-15 14:50:46 -050060@RunWith(AndroidTestingRunner.class)
61@TestableLooper.RunWithLooper()
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040062public class NotificationSwipeHelperTest extends SysuiTestCase {
63
64 private NotificationSwipeHelper mSwipeHelper;
65 private NotificationSwipeHelper.NotificationCallback mCallback;
66 private NotificationMenuRowPlugin.OnMenuEventListener mListener;
67 private View mView;
68 private MotionEvent mEvent;
69 private NotificationMenuRowPlugin mMenuRow;
70 private Handler mHandler;
71 private ExpandableNotificationRow mNotificationRow;
72 private Runnable mFalsingCheck;
73
74 @Rule public MockitoRule mockito = MockitoJUnit.rule();
75
76 @Before
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040077 public void setUp() throws Exception {
78 mCallback = mock(NotificationSwipeHelper.NotificationCallback.class);
79 mListener = mock(NotificationMenuRowPlugin.OnMenuEventListener.class);
Dave Mankoff781ef7e2019-06-28 16:33:25 -040080 mSwipeHelper = spy(new NotificationSwipeHelper(
81 SwipeHelper.X, mCallback, mContext, mListener, new FalsingManagerFake()));
Aaron Heuckroth45d20be2018-09-18 13:47:26 -040082 mView = mock(View.class);
83 mEvent = mock(MotionEvent.class);
84 mMenuRow = mock(NotificationMenuRowPlugin.class);
85 mNotificationRow = mock(ExpandableNotificationRow.class);
86 mHandler = mock(Handler.class);
87 mFalsingCheck = mock(Runnable.class);
88 }
89
90 @Test
91 public void testSetExposedMenuView() {
92 assertEquals("intialized with null exposed menu view", null,
93 mSwipeHelper.getExposedMenuView());
94 mSwipeHelper.setExposedMenuView(mView);
95 assertEquals("swipe helper has correct exposedMenuView after setExposedMenuView to a view",
96 mView, mSwipeHelper.getExposedMenuView());
97 mSwipeHelper.setExposedMenuView(null);
98 assertEquals("swipe helper has null exposedMenuView after setExposedMenuView to null",
99 null, mSwipeHelper.getExposedMenuView());
100 }
101
102 @Test
103 public void testClearExposedMenuView() {
104 doNothing().when(mSwipeHelper).setExposedMenuView(mView);
105 mSwipeHelper.clearExposedMenuView();
106 verify(mSwipeHelper, times(1)).setExposedMenuView(null);
107 }
108
109 @Test
110 public void testGetTranslatingParentView() {
111 assertEquals("intialized with null translating parent view", null,
112 mSwipeHelper.getTranslatingParentView());
113 mSwipeHelper.setTranslatingParentView(mView);
114 assertEquals("has translating parent view after setTranslatingParentView with a view",
115 mView, mSwipeHelper.getTranslatingParentView());
116 }
117
118 @Test
119 public void testClearTranslatingParentView() {
120 doNothing().when(mSwipeHelper).setTranslatingParentView(null);
121 mSwipeHelper.clearTranslatingParentView();
122 verify(mSwipeHelper, times(1)).setTranslatingParentView(null);
123 }
124
125 @Test
126 public void testSetCurrentMenuRow() {
127 assertEquals("currentMenuRow initializes to null", null,
128 mSwipeHelper.getCurrentMenuRow());
129 mSwipeHelper.setCurrentMenuRow(mMenuRow);
130 assertEquals("currentMenuRow set correctly after setCurrentMenuRow", mMenuRow,
131 mSwipeHelper.getCurrentMenuRow());
132 mSwipeHelper.setCurrentMenuRow(null);
133 assertEquals("currentMenuRow set to null after setCurrentMenuRow to null",
134 null, mSwipeHelper.getCurrentMenuRow());
135 }
136
137 @Test
138 public void testClearCurrentMenuRow() {
139 doNothing().when(mSwipeHelper).setCurrentMenuRow(null);
140 mSwipeHelper.clearCurrentMenuRow();
141 verify(mSwipeHelper, times(1)).setCurrentMenuRow(null);
142 }
143
144 @Test
145 public void testOnDownUpdate_ExpandableNotificationRow() {
146 when(mSwipeHelper.getHandler()).thenReturn(mHandler);
147 when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck);
148 doNothing().when(mSwipeHelper).resetExposedMenuView(true, false);
149 doNothing().when(mSwipeHelper).clearCurrentMenuRow();
150 doNothing().when(mSwipeHelper).initializeRow(any());
151
152 mSwipeHelper.onDownUpdate(mNotificationRow, mEvent);
153
154 verify(mSwipeHelper, times(1)).clearCurrentMenuRow();
155 verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
156 verify(mSwipeHelper, times(1)).resetExposedMenuView(true, false);
157 verify(mSwipeHelper, times(1)).initializeRow(mNotificationRow);
158 }
159
160 @Test
161 public void testOnDownUpdate_notExpandableNotificationRow() {
162 when(mSwipeHelper.getHandler()).thenReturn(mHandler);
163 when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck);
164 doNothing().when(mSwipeHelper).resetExposedMenuView(true, false);
165 doNothing().when(mSwipeHelper).clearCurrentMenuRow();
166 doNothing().when(mSwipeHelper).initializeRow(any());
167
168 mSwipeHelper.onDownUpdate(mView, mEvent);
169
170 verify(mSwipeHelper, times(1)).clearCurrentMenuRow();
171 verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
172 verify(mSwipeHelper, times(1)).resetExposedMenuView(true, false);
173 verify(mSwipeHelper, times(0)).initializeRow(any());
174 }
175
176 @Test
177 public void testOnMoveUpdate_menuRow() {
178 when(mSwipeHelper.getCurrentMenuRow()).thenReturn(mMenuRow);
179 when(mSwipeHelper.getHandler()).thenReturn(mHandler);
180 when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck);
181
182 mSwipeHelper.onMoveUpdate(mView, mEvent, 0, 10);
183
184 verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
185 verify(mMenuRow, times(1)).onTouchMove(10);
186 }
187
188 @Test
189 public void testOnMoveUpdate_noMenuRow() {
190 when(mSwipeHelper.getHandler()).thenReturn(mHandler);
191 when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck);
192
193 mSwipeHelper.onMoveUpdate(mView, mEvent, 0, 10);
194
195 verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
196 }
197
198 @Test
199 public void testHandleUpEvent_noMenuRow() {
200 assertFalse("Menu row does not exist",
201 mSwipeHelper.handleUpEvent(mEvent, mView, 0, 0));
202 }
203
204 @Test
205 public void testHandleUpEvent_menuRow() {
206 when(mSwipeHelper.getCurrentMenuRow()).thenReturn(mMenuRow);
207 doNothing().when(mSwipeHelper).handleMenuRowSwipe(mEvent, mView, 0, mMenuRow);
208
209 assertTrue("Menu row exists",
210 mSwipeHelper.handleUpEvent(mEvent, mView, 0, 0));
211 verify(mMenuRow, times(1)).onTouchEnd();
212 verify(mSwipeHelper, times(1)).handleMenuRowSwipe(mEvent, mView, 0, mMenuRow);
213 }
214
215 @Test
216 public void testDismissChild_notExpanded() {
Selim Cinekae55d832019-02-22 17:43:43 -0800217 when(mCallback.shouldDismissQuickly()).thenReturn(false);
Aaron Heuckroth45d20be2018-09-18 13:47:26 -0400218 doNothing().when(mSwipeHelper).superDismissChild(mView, 0, false);
219 doNothing().when(mSwipeHelper).handleMenuCoveredOrDismissed();
220
221 mSwipeHelper.dismissChild(mView, 0, false);
222
223 verify(mSwipeHelper, times(1)).superDismissChild(mView, 0, false);
224 verify(mCallback, times(0)).handleChildViewDismissed(mView);
225 verify(mCallback, times(1)).onDismiss();
226 verify(mSwipeHelper, times(1)).handleMenuCoveredOrDismissed();
227 }
228
229 @Test
230 public void testSnapchild_targetIsZero() {
231 doNothing().when(mSwipeHelper).superSnapChild(mView, 0, 0);
232 mSwipeHelper.snapChild(mView, 0, 0);
233
234 verify(mCallback, times(1)).onDragCancelled(mView);
235 verify(mSwipeHelper, times(1)).superSnapChild(mView, 0, 0);
236 verify(mSwipeHelper, times(1)).handleMenuCoveredOrDismissed();
237 }
238
239
240 @Test
241 public void testSnapchild_targetNotZero() {
242 doNothing().when(mSwipeHelper).superSnapChild(mView, 10, 0);
243 mSwipeHelper.snapChild(mView, 10, 0);
244
245 verify(mCallback, times(1)).onDragCancelled(mView);
246 verify(mSwipeHelper, times(1)).superSnapChild(mView, 10, 0);
247 verify(mSwipeHelper, times(0)).handleMenuCoveredOrDismissed();
248 }
249
250 @Test
251 public void testSnooze() {
252 StatusBarNotification sbn = mock(StatusBarNotification.class);
253 SnoozeOption snoozeOption = mock(SnoozeOption.class);
254 mSwipeHelper.snooze(sbn, snoozeOption);
255 verify(mCallback, times(1)).onSnooze(sbn, snoozeOption);
256 }
257
258 @Test
259 public void testGetViewTranslationAnimator_notExpandableNotificationRow() {
260 Animator animator = mock(Animator.class);
261 AnimatorUpdateListener listener = mock(AnimatorUpdateListener.class);
262 doReturn(animator).when(mSwipeHelper).superGetViewTranslationAnimator(mView, 0, listener);
263
264 assertEquals("returns the correct animator from super", animator,
265 mSwipeHelper.getViewTranslationAnimator(mView, 0, listener));
266
267 verify(mSwipeHelper, times(1)).superGetViewTranslationAnimator(mView, 0, listener);
268 }
269
270 @Test
271 public void testGetViewTranslationAnimator_expandableNotificationRow() {
272 Animator animator = mock(Animator.class);
273 AnimatorUpdateListener listener = mock(AnimatorUpdateListener.class);
274 doReturn(animator).when(mNotificationRow).getTranslateViewAnimator(0, listener);
275
276 assertEquals("returns the correct animator from super when view is an ENR", animator,
277 mSwipeHelper.getViewTranslationAnimator(mNotificationRow, 0, listener));
278
279 verify(mNotificationRow, times(1)).getTranslateViewAnimator(0, listener);
280 }
281
282 @Test
283 public void testSetTranslation() {
284 mSwipeHelper.setTranslation(mNotificationRow, 0);
285 verify(mNotificationRow, times(1)).setTranslation(0);
286 }
287
288 @Test
289 public void testGetTranslation() {
290 doReturn(30f).when(mNotificationRow).getTranslation();
291
292 assertEquals("Returns getTranslation for the ENR",
293 mSwipeHelper.getTranslation(mNotificationRow), 30f);
294
295 verify(mNotificationRow, times(1)).getTranslation();
296 }
297
298 @Test
299 public void testDismiss() {
300 doNothing().when(mSwipeHelper).dismissChild(mView, 0, true);
301 doReturn(false).when(mSwipeHelper).swipedFastEnough();
302
303 mSwipeHelper.dismiss(mView, 0);
304
305 verify(mSwipeHelper, times(1)).swipedFastEnough();
306 verify(mSwipeHelper, times(1)).dismissChild(mView, 0, true);
307 }
308
309 @Test
310 public void testSnapOpen() {
311 doNothing().when(mSwipeHelper).snapChild(mView, 30, 0);
312
313 mSwipeHelper.snapOpen(mView, 30, 0);
314
315 verify(mSwipeHelper, times(1)).snapChild(mView, 30, 0);
316 }
317
318 @Test
319 public void testSnapClosed() {
320 doNothing().when(mSwipeHelper).snapChild(mView, 0, 0);
321
322 mSwipeHelper.snapClosed(mView, 0);
323
324 verify(mSwipeHelper, times(1)).snapChild(mView, 0, 0);
325 }
326
327 @Test
328 public void testGetMinDismissVelocity() {
329 doReturn(30f).when(mSwipeHelper).getEscapeVelocity();
330
331 assertEquals("Returns getEscapeVelocity", 30f, mSwipeHelper.getMinDismissVelocity());
332 }
333
334 @Test
335 public void onMenuShown_noAntiFalsing() {
336 doNothing().when(mSwipeHelper).setExposedMenuView(mView);
337 doReturn(mView).when(mSwipeHelper).getTranslatingParentView();
338 doReturn(mHandler).when(mSwipeHelper).getHandler();
339 doReturn(false).when(mCallback).isAntiFalsingNeeded();
340 doReturn(mFalsingCheck).when(mSwipeHelper).getFalsingCheck();
341
342 mSwipeHelper.onMenuShown(mView);
343
344 verify(mSwipeHelper, times(1)).setExposedMenuView(mView);
345 verify(mCallback, times(1)).onDragCancelled(mView);
346 verify(mCallback, times(1)).isAntiFalsingNeeded();
347
348 verify(mHandler, times(0)).removeCallbacks(mFalsingCheck);
349 verify(mHandler, times(0)).postDelayed(mFalsingCheck, mSwipeHelper.COVER_MENU_DELAY);
350 }
351
352 @Test
353 public void onMenuShown_antiFalsing() {
354 doNothing().when(mSwipeHelper).setExposedMenuView(mView);
355 doReturn(mView).when(mSwipeHelper).getTranslatingParentView();
356 doReturn(mHandler).when(mSwipeHelper).getHandler();
357 doReturn(true).when(mCallback).isAntiFalsingNeeded();
358 doReturn(mFalsingCheck).when(mSwipeHelper).getFalsingCheck();
359
360 mSwipeHelper.onMenuShown(mView);
361
362 verify(mSwipeHelper, times(1)).setExposedMenuView(mView);
363 verify(mCallback, times(1)).onDragCancelled(mView);
364 verify(mCallback, times(1)).isAntiFalsingNeeded();
365
366 verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
367 verify(mHandler, times(1)).postDelayed(mFalsingCheck, mSwipeHelper.COVER_MENU_DELAY);
368 }
369
370 @Test
371 public void testResetExposedMenuView_noReset() {
372 doReturn(false).when(mSwipeHelper).shouldResetMenu(false);
373 doNothing().when(mSwipeHelper).clearExposedMenuView();
374
375 mSwipeHelper.resetExposedMenuView(false, false);
376
377 verify(mSwipeHelper, times(1)).shouldResetMenu(false);
378
379 // should not clear exposed menu row
380 verify(mSwipeHelper, times(0)).clearExposedMenuView();
381 }
382
383 @Test
384 public void testResetExposedMenuView_animate() {
385 Animator animator = mock(Animator.class);
386
387 doReturn(true).when(mSwipeHelper).shouldResetMenu(false);
388 doReturn(mNotificationRow).when(mSwipeHelper).getExposedMenuView();
389 doReturn(false).when(mNotificationRow).isRemoved();
390 doReturn(animator).when(mSwipeHelper).getViewTranslationAnimator(mNotificationRow, 0, null);
391 doNothing().when(mSwipeHelper).clearExposedMenuView();
392
393 mSwipeHelper.resetExposedMenuView(true, false);
394
395 verify(mSwipeHelper, times(1)).shouldResetMenu(false);
396
397 // should retrieve and start animator
398 verify(mSwipeHelper, times(1)).getViewTranslationAnimator(mNotificationRow, 0, null);
399 verify(animator, times(1)).start();
400
401 // should not reset translation on row directly
402 verify(mNotificationRow, times(0)).resetTranslation();
403
404 // should clear exposed menu row
405 verify(mSwipeHelper, times(1)).clearExposedMenuView();
406 }
407
408
409 @Test
410 public void testResetExposedMenuView_noAnimate() {
411 Animator animator = mock(Animator.class);
412
413 doReturn(true).when(mSwipeHelper).shouldResetMenu(false);
414 doReturn(mNotificationRow).when(mSwipeHelper).getExposedMenuView();
415 doReturn(false).when(mNotificationRow).isRemoved();
416 doReturn(animator).when(mSwipeHelper).getViewTranslationAnimator(mNotificationRow, 0, null);
417 doNothing().when(mSwipeHelper).clearExposedMenuView();
418
419 mSwipeHelper.resetExposedMenuView(false, false);
420
421 verify(mSwipeHelper, times(1)).shouldResetMenu(false);
422
423 // should not retrieve and start animator
424 verify(mSwipeHelper, times(0)).getViewTranslationAnimator(mNotificationRow, 0, null);
425 verify(animator, times(0)).start();
426
427 // should reset translation on row directly
428 verify(mNotificationRow, times(1)).resetTranslation();
429
430 // should clear exposed menu row
431 verify(mSwipeHelper, times(1)).clearExposedMenuView();
432 }
433
434 @Test
435 public void testIsTouchInView() {
436 assertEquals("returns false when view is null", false,
437 NotificationSwipeHelper.isTouchInView(mEvent, null));
438
439 doReturn(5f).when(mEvent).getRawX();
440 doReturn(10f).when(mEvent).getRawY();
441
442 doReturn(20).when(mView).getWidth();
443 doReturn(20).when(mView).getHeight();
444
445 Answer answer = (Answer) invocation -> {
446 int[] arr = invocation.getArgument(0);
447 arr[0] = 0;
448 arr[1] = 0;
449 return null;
450 };
451 doAnswer(answer).when(mView).getLocationOnScreen(any());
452
453 assertTrue("Touch is within the view",
454 mSwipeHelper.isTouchInView(mEvent, mView));
455
456 doReturn(50f).when(mEvent).getRawX();
457
458 assertFalse("Touch is not within the view",
459 mSwipeHelper.isTouchInView(mEvent, mView));
460 }
461
462 @Test
463 public void testIsTouchInView_expandable() {
464 assertEquals("returns false when view is null", false,
465 NotificationSwipeHelper.isTouchInView(mEvent, null));
466
467 doReturn(5f).when(mEvent).getRawX();
468 doReturn(10f).when(mEvent).getRawY();
469
470 doReturn(20).when(mNotificationRow).getWidth();
471 doReturn(20).when(mNotificationRow).getActualHeight();
472
473 Answer answer = (Answer) invocation -> {
474 int[] arr = invocation.getArgument(0);
475 arr[0] = 0;
476 arr[1] = 0;
477 return null;
478 };
479 doAnswer(answer).when(mNotificationRow).getLocationOnScreen(any());
480
481 assertTrue("Touch is within the view",
482 mSwipeHelper.isTouchInView(mEvent, mNotificationRow));
483
484 doReturn(50f).when(mEvent).getRawX();
485
486 assertFalse("Touch is not within the view",
487 mSwipeHelper.isTouchInView(mEvent, mNotificationRow));
488 }
489}