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