1/*
2 * Copyright 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.
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 androidx.recyclerview.selection;
18
19import static org.mockito.Matchers.any;
20import static org.mockito.Matchers.anyFloat;
21import static org.mockito.Mockito.never;
22import static org.mockito.Mockito.verify;
23
24import android.support.test.filters.SmallTest;
25import android.support.test.runner.AndroidJUnit4;
26import android.view.GestureDetector.OnDoubleTapListener;
27import android.view.GestureDetector.OnGestureListener;
28import android.view.MotionEvent;
29
30import androidx.recyclerview.selection.testing.TestEvents.Mouse;
31import androidx.recyclerview.selection.testing.TestEvents.Touch;
32
33import org.junit.Before;
34import org.junit.Test;
35import org.junit.runner.RunWith;
36import org.mockito.Mockito;
37
38@RunWith(AndroidJUnit4.class)
39@SmallTest
40public final class GestureRouterTest {
41
42    private TestHandler mHandler;
43    private TestHandler mAlt;
44    private GestureRouter<TestHandler> mRouter;
45
46    @Before
47    public void setUp() {
48        mAlt = new TestHandler();
49        mHandler = new TestHandler();
50    }
51
52    @Test
53    public void testDelegates() {
54        mRouter = new GestureRouter<>();
55        mRouter.register(MotionEvent.TOOL_TYPE_MOUSE, mHandler);
56        mRouter.register(MotionEvent.TOOL_TYPE_FINGER, mAlt);
57
58        mRouter.onDown(Mouse.CLICK);
59        mHandler.assertCalled_onDown(Mouse.CLICK);
60        mAlt.assertNotCalled_onDown();
61
62        mRouter.onShowPress(Mouse.CLICK);
63        mHandler.assertCalled_onShowPress(Mouse.CLICK);
64        mAlt.assertNotCalled_onShowPress();
65
66        mRouter.onSingleTapUp(Mouse.CLICK);
67        mHandler.assertCalled_onSingleTapUp(Mouse.CLICK);
68        mAlt.assertNotCalled_onSingleTapUp();
69
70        mRouter.onScroll(null, Mouse.CLICK, -1, -1);
71        mHandler.assertCalled_onScroll(null, Mouse.CLICK, -1, -1);
72        mAlt.assertNotCalled_onScroll();
73
74        mRouter.onLongPress(Mouse.CLICK);
75        mHandler.assertCalled_onLongPress(Mouse.CLICK);
76        mAlt.assertNotCalled_onLongPress();
77
78        mRouter.onFling(null, Mouse.CLICK, -1, -1);
79        mHandler.assertCalled_onFling(null, Mouse.CLICK, -1, -1);
80        mAlt.assertNotCalled_onFling();
81
82        mRouter.onSingleTapConfirmed(Mouse.CLICK);
83        mHandler.assertCalled_onSingleTapConfirmed(Mouse.CLICK);
84        mAlt.assertNotCalled_onSingleTapConfirmed();
85
86        mRouter.onDoubleTap(Mouse.CLICK);
87        mHandler.assertCalled_onDoubleTap(Mouse.CLICK);
88        mAlt.assertNotCalled_onDoubleTap();
89
90        mRouter.onDoubleTapEvent(Mouse.CLICK);
91        mHandler.assertCalled_onDoubleTapEvent(Mouse.CLICK);
92        mAlt.assertNotCalled_onDoubleTapEvent();
93    }
94
95    @Test
96    public void testFallsback() {
97        mRouter = new GestureRouter<>(mAlt);
98        mRouter.register(MotionEvent.TOOL_TYPE_MOUSE, mHandler);
99
100        mRouter.onDown(Touch.TAP);
101        mAlt.assertCalled_onDown(Touch.TAP);
102
103        mRouter.onShowPress(Touch.TAP);
104        mAlt.assertCalled_onShowPress(Touch.TAP);
105
106        mRouter.onSingleTapUp(Touch.TAP);
107        mAlt.assertCalled_onSingleTapUp(Touch.TAP);
108
109        mRouter.onScroll(null, Touch.TAP, -1, -1);
110        mAlt.assertCalled_onScroll(null, Touch.TAP, -1, -1);
111
112        mRouter.onLongPress(Touch.TAP);
113        mAlt.assertCalled_onLongPress(Touch.TAP);
114
115        mRouter.onFling(null, Touch.TAP, -1, -1);
116        mAlt.assertCalled_onFling(null, Touch.TAP, -1, -1);
117
118        mRouter.onSingleTapConfirmed(Touch.TAP);
119        mAlt.assertCalled_onSingleTapConfirmed(Touch.TAP);
120
121        mRouter.onDoubleTap(Touch.TAP);
122        mAlt.assertCalled_onDoubleTap(Touch.TAP);
123
124        mRouter.onDoubleTapEvent(Touch.TAP);
125        mAlt.assertCalled_onDoubleTapEvent(Touch.TAP);
126    }
127
128    @Test
129    public void testEatsEventsWhenNoFallback() {
130        mRouter = new GestureRouter<>();
131        // Register the the delegate on mouse so touch events don't get handled.
132        mRouter.register(MotionEvent.TOOL_TYPE_MOUSE, mHandler);
133
134        mRouter.onDown(Touch.TAP);
135        mAlt.assertNotCalled_onDown();
136
137        mRouter.onShowPress(Touch.TAP);
138        mAlt.assertNotCalled_onShowPress();
139
140        mRouter.onSingleTapUp(Touch.TAP);
141        mAlt.assertNotCalled_onSingleTapUp();
142
143        mRouter.onScroll(null, Touch.TAP, -1, -1);
144        mAlt.assertNotCalled_onScroll();
145
146        mRouter.onLongPress(Touch.TAP);
147        mAlt.assertNotCalled_onLongPress();
148
149        mRouter.onFling(null, Touch.TAP, -1, -1);
150        mAlt.assertNotCalled_onFling();
151
152        mRouter.onSingleTapConfirmed(Touch.TAP);
153        mAlt.assertNotCalled_onSingleTapConfirmed();
154
155        mRouter.onDoubleTap(Touch.TAP);
156        mAlt.assertNotCalled_onDoubleTap();
157
158        mRouter.onDoubleTapEvent(Touch.TAP);
159        mAlt.assertNotCalled_onDoubleTapEvent();
160    }
161
162    private static final class TestHandler implements OnGestureListener, OnDoubleTapListener {
163
164        private final Spy mSpy = Mockito.mock(Spy.class);
165
166        @Override
167        public boolean onDown(MotionEvent e) {
168            return mSpy.onDown(e);
169        }
170
171        @Override
172        public void onShowPress(MotionEvent e) {
173            mSpy.onShowPress(e);
174        }
175
176        @Override
177        public boolean onSingleTapUp(MotionEvent e) {
178            return mSpy.onSingleTapUp(e);
179        }
180
181        @Override
182        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
183            return mSpy.onScroll(e1, e2, distanceX, distanceY);
184        }
185
186        @Override
187        public void onLongPress(MotionEvent e) {
188            mSpy.onLongPress(e);
189        }
190
191        @Override
192        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
193            return mSpy.onFling(e1, e2, velocityX, velocityY);
194        }
195
196        @Override
197        public boolean onSingleTapConfirmed(MotionEvent e) {
198            return mSpy.onSingleTapConfirmed(e);
199        }
200
201        @Override
202        public boolean onDoubleTap(MotionEvent e) {
203            return mSpy.onDoubleTap(e);
204        }
205
206        @Override
207        public boolean onDoubleTapEvent(MotionEvent e) {
208            return mSpy.onDoubleTapEvent(e);
209        }
210
211        void assertCalled_onDown(MotionEvent e) {
212            verify(mSpy).onDown(e);
213        }
214
215        void assertCalled_onShowPress(MotionEvent e) {
216            verify(mSpy).onShowPress(e);
217        }
218
219        void assertCalled_onSingleTapUp(MotionEvent e) {
220            verify(mSpy).onSingleTapUp(e);
221        }
222
223        void assertCalled_onScroll(MotionEvent e1, MotionEvent e2, float x, float y) {
224            verify(mSpy).onScroll(e1, e2, x, y);
225        }
226
227        void assertCalled_onLongPress(MotionEvent e) {
228            verify(mSpy).onLongPress(e);
229        }
230
231        void assertCalled_onFling(MotionEvent e1, MotionEvent e2, float x, float y) {
232            Mockito.verify(mSpy).onFling(e1, e2, x, y);
233        }
234
235        void assertCalled_onSingleTapConfirmed(MotionEvent e) {
236            Mockito.verify(mSpy).onSingleTapConfirmed(e);
237        }
238
239        void assertCalled_onDoubleTap(MotionEvent e) {
240            Mockito.verify(mSpy).onDoubleTap(e);
241        }
242
243        void assertCalled_onDoubleTapEvent(MotionEvent e) {
244            Mockito.verify(mSpy).onDoubleTapEvent(e);
245        }
246
247        void assertNotCalled_onDown() {
248            verify(mSpy, never()).onDown((MotionEvent) any());
249        }
250
251        void assertNotCalled_onShowPress() {
252            verify(mSpy, never()).onShowPress((MotionEvent) any());
253        }
254
255        void assertNotCalled_onSingleTapUp() {
256            verify(mSpy, never()).onSingleTapUp((MotionEvent) any());
257        }
258
259        void assertNotCalled_onScroll() {
260            verify(mSpy, never()).onScroll(
261                    (MotionEvent) any(), (MotionEvent) any(), anyFloat(), anyFloat());
262        }
263
264        void assertNotCalled_onLongPress() {
265            verify(mSpy, never()).onLongPress((MotionEvent) any());
266        }
267
268        void assertNotCalled_onFling() {
269            Mockito.verify(mSpy, never()).onFling(
270                    (MotionEvent) any(), (MotionEvent) any(), anyFloat(), anyFloat());
271        }
272
273        void assertNotCalled_onSingleTapConfirmed() {
274            Mockito.verify(mSpy, never()).onSingleTapConfirmed((MotionEvent) any());
275        }
276
277        void assertNotCalled_onDoubleTap() {
278            Mockito.verify(mSpy, never()).onDoubleTap((MotionEvent) any());
279        }
280
281        void assertNotCalled_onDoubleTapEvent() {
282            Mockito.verify(mSpy, never()).onDoubleTapEvent((MotionEvent) any());
283        }
284    }
285
286    private interface Spy extends OnGestureListener, OnDoubleTapListener {
287    }
288}
289