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