[go: nahoru, domu]

blob: a24c272d4be4451f110c36a36bf182f06baca80a [file] [log] [blame]
shepshapardd9f05232019-08-08 10:21:47 -07001/*
2 * Copyright 2019 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 */
16package androidx.ui.core.gesture
17
18import android.view.MotionEvent
19import android.view.View
20import android.view.ViewGroup
Louis Pullen-Freiliche46bcf02020-02-12 16:06:21 +000021import androidx.compose.emptyContent
Shep Shapardbf513c52019-12-16 17:06:51 -080022import androidx.test.filters.LargeTest
Shep Shapardbf513c52019-12-16 17:06:51 -080023import androidx.ui.core.Layout
Shep Shapard70a8cfe2020-03-30 16:17:26 -070024import androidx.ui.core.Modifier
shepshapardd9f05232019-08-08 10:21:47 -070025import androidx.ui.core.setContent
26import androidx.ui.framework.test.TestActivity
Louis Pullen-Freilich623e4052020-07-19 20:24:03 +010027import androidx.compose.foundation.layout.Stack
Nader Jawad6df06122020-06-03 15:27:08 -070028import androidx.ui.geometry.Offset
shepshapardd9f05232019-08-08 10:21:47 -070029import com.nhaarman.mockitokotlin2.any
Shep Shapardbf513c52019-12-16 17:06:51 -080030import com.nhaarman.mockitokotlin2.inOrder
31import com.nhaarman.mockitokotlin2.spy
32import com.nhaarman.mockitokotlin2.times
shepshapardd9f05232019-08-08 10:21:47 -070033import com.nhaarman.mockitokotlin2.verify
34import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions
35import org.junit.Assert.assertTrue
36import org.junit.Before
37import org.junit.Rule
38import org.junit.Test
39import org.junit.runner.RunWith
40import org.junit.runners.JUnit4
41import java.util.concurrent.CountDownLatch
42import java.util.concurrent.TimeUnit
Shep Shapardbf513c52019-12-16 17:06:51 -080043
44// TODO(shepshapard): Figure out how to test composite gesture detectors better. There should be
45// more tests, but hopefully they can also be easier to write then what is currently available.
46// Should possibly wait till we have host side testing that does not require the Android runtime.
shepshapardd9f05232019-08-08 10:21:47 -070047
48@LargeTest
49@RunWith(JUnit4::class)
Shep Shapardad4e8152020-04-03 13:22:08 -070050class LongPressDragGestureFilterTest {
Aurimas Liutikas506ab64d2020-06-02 14:37:26 -070051 @Suppress("DEPRECATION")
shepshapardd9f05232019-08-08 10:21:47 -070052 @get:Rule
Aurimas Liutikas506ab64d2020-06-02 14:37:26 -070053 val activityTestRule = androidx.test.rule.ActivityTestRule<TestActivity>(
54 TestActivity::class.java
55 )
shepshapardd9f05232019-08-08 10:21:47 -070056 private lateinit var longPressDragObserver: LongPressDragObserver
57 private lateinit var longPressCountDownLatch: CountDownLatch
58 private lateinit var view: View
59
60 @Before
61 fun setup() {
62 longPressDragObserver = spy(MyLongPressDragObserver {
63 longPressCountDownLatch.countDown()
64 })
65
66 val activity = activityTestRule.activity
Adam Powella1f55b92020-04-20 16:32:38 -070067 assertTrue("timed out waiting for activity focus",
68 activity.hasFocusLatch.await(5, TimeUnit.SECONDS))
shepshapardd9f05232019-08-08 10:21:47 -070069
70 val setupLatch = CountDownLatch(2)
71 activityTestRule.runOnUiThreadIR {
72 activity.setContent {
Mihai Popa376868d2020-03-30 10:27:56 +010073 Stack {
74 Layout(
75 modifier = Modifier.longPressDragGestureFilter(longPressDragObserver),
Anastasia Soboleva5e382dd2020-06-17 21:51:38 +010076 measureBlock = { _, _ ->
George Mount8f237572020-04-30 12:08:30 -070077 layout(100, 100) {
Mihai Popa376868d2020-03-30 10:27:56 +010078 setupLatch.countDown()
79 }
80 }, children = emptyContent()
81 )
82 }
shepshapardd9f05232019-08-08 10:21:47 -070083 }
84
85 view = activity.findViewById<ViewGroup>(android.R.id.content)
86 setupLatch.countDown()
87 }
Adam Powella1f55b92020-04-20 16:32:38 -070088 assertTrue("timed out waiting for setup completion",
89 setupLatch.await(1000, TimeUnit.SECONDS))
shepshapardd9f05232019-08-08 10:21:47 -070090 }
91
shepshapardd9f05232019-08-08 10:21:47 -070092 @Test
93 fun ui_downMoveUpBeforeLongPressTimeout_noCallbacksCalled() {
94
95 val down = MotionEvent(
96 0,
97 MotionEvent.ACTION_DOWN,
98 1,
99 0,
100 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700101 arrayOf(PointerCoords(50f, 50f)),
102 view
shepshapardd9f05232019-08-08 10:21:47 -0700103 )
104 val move = MotionEvent(
105 0,
106 MotionEvent.ACTION_MOVE,
107 1,
108 0,
109 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700110 arrayOf(PointerCoords(51f, 50f)),
111 view
shepshapardd9f05232019-08-08 10:21:47 -0700112 )
113 val up = MotionEvent(
114 0,
115 MotionEvent.ACTION_UP,
116 1,
117 0,
118 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700119 arrayOf(PointerCoords(51f, 50f)),
120 view
shepshapardd9f05232019-08-08 10:21:47 -0700121 )
122 activityTestRule.runOnUiThreadIR {
123 view.dispatchTouchEvent(down)
124 view.dispatchTouchEvent(move)
125 view.dispatchTouchEvent(up)
126 }
127
128 verifyNoMoreInteractions(longPressDragObserver)
129 }
130
Shep Shapardbf513c52019-12-16 17:06:51 -0800131 @Test
132 fun ui_downMoveCancelBeforeLongPressTimeout_noCallbacksCalled() {
133
134 val down = MotionEvent(
135 0,
136 MotionEvent.ACTION_DOWN,
137 1,
138 0,
139 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700140 arrayOf(PointerCoords(50f, 50f)),
141 view
Shep Shapardbf513c52019-12-16 17:06:51 -0800142 )
143 val move = MotionEvent(
144 0,
145 MotionEvent.ACTION_MOVE,
146 1,
147 0,
148 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700149 arrayOf(PointerCoords(51f, 50f)),
150 view
Shep Shapardbf513c52019-12-16 17:06:51 -0800151 )
152 val cancel = MotionEvent(
153 0,
154 MotionEvent.ACTION_CANCEL,
155 1,
156 0,
157 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700158 arrayOf(PointerCoords(51f, 50f)),
159 view
Shep Shapardbf513c52019-12-16 17:06:51 -0800160 )
161 activityTestRule.runOnUiThreadIR {
162 view.dispatchTouchEvent(down)
163 view.dispatchTouchEvent(move)
164 view.dispatchTouchEvent(cancel)
165 }
166
167 verifyNoMoreInteractions(longPressDragObserver)
168 }
shepshapardd9f05232019-08-08 10:21:47 -0700169
170 @Test
Shep Shapardbf513c52019-12-16 17:06:51 -0800171 fun ui_downWaitForLongPress_onlyOnLongPressCalled() {
shepshapardd9f05232019-08-08 10:21:47 -0700172
173 val down = MotionEvent(
174 0,
175 MotionEvent.ACTION_DOWN,
176 1,
177 0,
178 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700179 arrayOf(PointerCoords(50f, 50f)),
180 view
shepshapardd9f05232019-08-08 10:21:47 -0700181 )
182 waitForLongPress {
183 view.dispatchTouchEvent(down)
184 }
185
186 verify(longPressDragObserver).onLongPress(any())
187 verifyNoMoreInteractions(longPressDragObserver)
188 }
189
shepshapardd9f05232019-08-08 10:21:47 -0700190 @Test
Shep Shapardbf513c52019-12-16 17:06:51 -0800191 fun ui_downWaitForLongPressMove_callbacksCorrect() {
shepshapardd9f05232019-08-08 10:21:47 -0700192
shepshapardd9f05232019-08-08 10:21:47 -0700193 val down = MotionEvent(
194 0,
195 MotionEvent.ACTION_DOWN,
196 1,
197 0,
198 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700199 arrayOf(PointerCoords(50f, 50f)),
200 view
shepshapardd9f05232019-08-08 10:21:47 -0700201 )
202 waitForLongPress {
203 view.dispatchTouchEvent(down)
204 }
205 val move = MotionEvent(
206 0,
207 MotionEvent.ACTION_MOVE,
208 1,
209 0,
210 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700211 arrayOf(PointerCoords(51f, 50f)),
212 view
shepshapardd9f05232019-08-08 10:21:47 -0700213 )
214 view.dispatchTouchEvent(move)
shepshapardd9f05232019-08-08 10:21:47 -0700215
Shep Shapardbf513c52019-12-16 17:06:51 -0800216 inOrder(longPressDragObserver) {
217 verify(longPressDragObserver).onLongPress(any())
218 verify(longPressDragObserver).onDragStart()
219 // Twice because DragGestureDetector dispatches onDrag during 2 passes.
220 verify(longPressDragObserver, times(2)).onDrag(any())
221 }
shepshapardd9f05232019-08-08 10:21:47 -0700222 verifyNoMoreInteractions(longPressDragObserver)
223 }
224
225 @Test
Shep Shapardbf513c52019-12-16 17:06:51 -0800226 fun ui_downWaitForLongPressUp_callbacksCorrect() {
shepshapardd9f05232019-08-08 10:21:47 -0700227
shepshapardd9f05232019-08-08 10:21:47 -0700228 val down = MotionEvent(
229 0,
230 MotionEvent.ACTION_DOWN,
231 1,
232 0,
233 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700234 arrayOf(PointerCoords(50f, 50f)),
235 view
shepshapardd9f05232019-08-08 10:21:47 -0700236 )
237 waitForLongPress {
238 view.dispatchTouchEvent(down)
239 }
shepshapardd9f05232019-08-08 10:21:47 -0700240 val up = MotionEvent(
241 0,
242 MotionEvent.ACTION_UP,
243 1,
244 0,
245 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700246 arrayOf(PointerCoords(51f, 50f)),
247 view
shepshapardd9f05232019-08-08 10:21:47 -0700248 )
249 view.dispatchTouchEvent(up)
250
251 // Assert.
Shep Shapardbf513c52019-12-16 17:06:51 -0800252 inOrder(longPressDragObserver) {
253 verify(longPressDragObserver).onLongPress(any())
254 verify(longPressDragObserver).onStop(any())
255 }
256 verifyNoMoreInteractions(longPressDragObserver)
257 }
258
259 @Test
260 fun ui_downWaitForLongPressMoveUp_callbacksCorrect() {
261
262 val down = MotionEvent(
263 0,
264 MotionEvent.ACTION_DOWN,
265 1,
266 0,
267 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700268 arrayOf(PointerCoords(50f, 50f)),
269 view
Shep Shapardbf513c52019-12-16 17:06:51 -0800270 )
271 waitForLongPress {
272 view.dispatchTouchEvent(down)
273 }
274 val move = MotionEvent(
275 0,
276 MotionEvent.ACTION_MOVE,
277 1,
278 0,
279 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700280 arrayOf(PointerCoords(51f, 50f)),
281 view
Shep Shapardbf513c52019-12-16 17:06:51 -0800282 )
283 view.dispatchTouchEvent(move)
284 val up = MotionEvent(
285 0,
286 MotionEvent.ACTION_UP,
287 1,
288 0,
289 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700290 arrayOf(PointerCoords(51f, 50f)),
291 view
Shep Shapardbf513c52019-12-16 17:06:51 -0800292 )
293 view.dispatchTouchEvent(up)
294
295 inOrder(longPressDragObserver) {
296 verify(longPressDragObserver).onLongPress(any())
297 verify(longPressDragObserver).onDragStart()
298 // Twice because DragGestureDetector dispatches onDrag during 2 passes.
299 verify(longPressDragObserver, times(2)).onDrag(any())
300 verify(longPressDragObserver).onStop(any())
301 }
302 verifyNoMoreInteractions(longPressDragObserver)
303 }
304
305 @Test
306 fun ui_downWaitForLongPressCancel_callbacksCorrect() {
307
308 val down = MotionEvent(
309 0,
310 MotionEvent.ACTION_DOWN,
311 1,
312 0,
313 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700314 arrayOf(PointerCoords(50f, 50f)),
315 view
Shep Shapardbf513c52019-12-16 17:06:51 -0800316 )
317 waitForLongPress {
318 view.dispatchTouchEvent(down)
319 }
320 val cancel = MotionEvent(
321 0,
322 MotionEvent.ACTION_CANCEL,
323 1,
324 0,
325 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700326 arrayOf(PointerCoords(50f, 50f)),
327 view
Shep Shapardbf513c52019-12-16 17:06:51 -0800328 )
329 view.dispatchTouchEvent(cancel)
330
331 inOrder(longPressDragObserver) {
332 verify(longPressDragObserver).onLongPress(any())
333 verify(longPressDragObserver).onCancel()
334 }
335 verifyNoMoreInteractions(longPressDragObserver)
336 }
337
338 @Test
339 fun ui_downWaitForLongPressMoveCancel_callbacksCorrect() {
340
341 val down = MotionEvent(
342 0,
343 MotionEvent.ACTION_DOWN,
344 1,
345 0,
346 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700347 arrayOf(PointerCoords(50f, 50f)),
348 view
Shep Shapardbf513c52019-12-16 17:06:51 -0800349 )
350 waitForLongPress {
351 view.dispatchTouchEvent(down)
352 }
353 val move = MotionEvent(
354 0,
355 MotionEvent.ACTION_MOVE,
356 1,
357 0,
358 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700359 arrayOf(PointerCoords(51f, 50f)),
360 view
Shep Shapardbf513c52019-12-16 17:06:51 -0800361 )
362 view.dispatchTouchEvent(move)
363 val cancel = MotionEvent(
364 0,
365 MotionEvent.ACTION_CANCEL,
366 1,
367 0,
368 arrayOf(PointerProperties(0)),
Shep Shaparde87a1002020-07-16 12:32:35 -0700369 arrayOf(PointerCoords(51f, 50f)),
370 view
Shep Shapardbf513c52019-12-16 17:06:51 -0800371 )
372 view.dispatchTouchEvent(cancel)
373
374 inOrder(longPressDragObserver) {
375 verify(longPressDragObserver).onLongPress(any())
376 verify(longPressDragObserver).onDragStart()
377 // Twice because DragGestureDetector dispatches onDrag during 2 passes.
378 verify(longPressDragObserver, times(2)).onDrag(any())
379 verify(longPressDragObserver).onCancel()
380 }
shepshapardd9f05232019-08-08 10:21:47 -0700381 verifyNoMoreInteractions(longPressDragObserver)
382 }
383
384 private fun waitForLongPress(block: () -> Unit) {
385 longPressCountDownLatch = CountDownLatch(1)
Louis Pullen-Freilich54b4c112019-10-23 19:05:56 +0100386 activityTestRule.runOnUiThreadIR(block)
Adam Powella1f55b92020-04-20 16:32:38 -0700387 assertTrue("timed out waiting for long press",
388 longPressCountDownLatch.await(750, TimeUnit.MILLISECONDS))
shepshapardd9f05232019-08-08 10:21:47 -0700389 }
390}
391
392@Suppress("RedundantOverride")
393open class MyLongPressDragObserver(val onLongPress: () -> Unit) : LongPressDragObserver {
Nader Jawad6df06122020-06-03 15:27:08 -0700394 override fun onLongPress(pxPosition: Offset) {
shepshapardd9f05232019-08-08 10:21:47 -0700395 onLongPress()
396 }
397
Shep Shapardbf513c52019-12-16 17:06:51 -0800398 override fun onDragStart() {}
shepshapardd9f05232019-08-08 10:21:47 -0700399
Nader Jawad6df06122020-06-03 15:27:08 -0700400 override fun onDrag(dragDistance: Offset): Offset {
shepshapardd9f05232019-08-08 10:21:47 -0700401 return super.onDrag(dragDistance)
402 }
403
Nader Jawad6df06122020-06-03 15:27:08 -0700404 override fun onStop(velocity: Offset) {}
shepshapardb14d6432019-08-05 17:13:22 -0700405}