[go: nahoru, domu]

blob: 1de398223aebdff8e5931f27703641b6678f6cac [file] [log] [blame]
shepshapard648840f2019-07-17 14:28:50 -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 */
16
Shep Shapardca62bbb2020-05-15 16:20:52 -070017@file:OptIn(ExperimentalPointerInput::class)
18@file:Suppress("PrivatePropertyName")
19
shepshapard648840f2019-07-17 14:28:50 -070020package androidx.ui.core.gesture
21
22import androidx.ui.core.Direction
shepshapard648840f2019-07-17 14:28:50 -070023import androidx.ui.core.PointerEventPass
24import androidx.ui.core.consumeDownChange
Shep Shapardca62bbb2020-05-15 16:20:52 -070025import androidx.ui.core.gesture.scrollorientationlocking.InternalScrollOrientationLocker
26import androidx.ui.core.gesture.scrollorientationlocking.Orientation
27import androidx.ui.core.gesture.scrollorientationlocking.ScrollOrientationLocker
28import androidx.ui.core.gesture.scrollorientationlocking.ShareScrollOrientationLockerEvent
shepshapard648840f2019-07-17 14:28:50 -070029import androidx.ui.testutils.consume
30import androidx.ui.testutils.down
31import androidx.ui.testutils.invokeOverAllPasses
32import androidx.ui.testutils.invokeOverPasses
33import androidx.ui.testutils.moveBy
34import androidx.ui.testutils.moveTo
35import androidx.ui.testutils.up
George Mount842c8c12020-01-08 16:03:42 -080036import androidx.ui.unit.Duration
George Mount842c8c12020-01-08 16:03:42 -080037import androidx.ui.unit.milliseconds
shepshapard648840f2019-07-17 14:28:50 -070038import com.google.common.truth.Truth.assertThat
Shep Shapardca62bbb2020-05-15 16:20:52 -070039import com.nhaarman.mockitokotlin2.mock
shepshapard648840f2019-07-17 14:28:50 -070040import org.junit.Before
41import org.junit.Test
42import org.junit.runner.RunWith
43import org.junit.runners.JUnit4
44
45// TODO(shepshapard): Write the following tests.
46// Verify correct shape of slop area (should it be a square or circle)?
47// Test for cases with more than one pointer
48// Test for cases where things are reset when last pointer goes up
49// Verify all methods called during onPostUp
Shep Shapardad4e8152020-04-03 13:22:08 -070050// Verify default behavior when no callback provided for filter or canDrag
shepshapard648840f2019-07-17 14:28:50 -070051
52// Changing this value will break tests that expect the value to be 10.
53private const val TestTouchSlop = 10
54
55@RunWith(JUnit4::class)
Shep Shaparddd9e2bc2020-05-19 15:25:36 -070056class DragSlopExceededGestureFilterTest {
shepshapard648840f2019-07-17 14:28:50 -070057
Shep Shaparddd9e2bc2020-05-19 15:25:36 -070058 private val onDragSlopExceeded: () -> Unit = { onDragSlopExceededCallCount++ }
shepshapard648840f2019-07-17 14:28:50 -070059 private val canDrag: (Direction) -> Boolean = { direction ->
60 canDragDirections.add(direction)
61 canDragReturn
62 }
Shep Shaparddd9e2bc2020-05-19 15:25:36 -070063 private var onDragSlopExceededCallCount: Int = 0
shepshapard648840f2019-07-17 14:28:50 -070064 private var canDragReturn = false
65 private var canDragDirections: MutableList<Direction> = mutableListOf()
Shep Shaparddd9e2bc2020-05-19 15:25:36 -070066 private lateinit var filter: DragSlopExceededGestureFilter
shepshapard648840f2019-07-17 14:28:50 -070067
Shep Shapard4babf792020-02-13 16:37:14 -080068 private val TinyNum = .01f
69
shepshapard648840f2019-07-17 14:28:50 -070070 @Before
71 fun setup() {
Shep Shaparddd9e2bc2020-05-19 15:25:36 -070072 onDragSlopExceededCallCount = 0
shepshapard648840f2019-07-17 14:28:50 -070073 canDragReturn = true
74 canDragDirections.clear()
Shep Shapardad4e8152020-04-03 13:22:08 -070075 filter =
Nader Jawadfeb99f82020-05-21 13:07:36 -070076 DragSlopExceededGestureFilter(TestTouchSlop.toFloat())
Shep Shapardca62bbb2020-05-15 16:20:52 -070077 filter.setDraggableData(null, canDrag)
Shep Shaparddd9e2bc2020-05-19 15:25:36 -070078 filter.onDragSlopExceeded = onDragSlopExceeded
Shep Shapardca62bbb2020-05-15 16:20:52 -070079 filter.scrollOrientationLocker = ScrollOrientationLocker(mock())
shepshapard648840f2019-07-17 14:28:50 -070080 }
81
82 // Verify the circumstances under which canDrag should not be called.
83
84 @Test
85 fun onPointerInputChanges_down_canDragNotCalled() {
Shep Shapardad4e8152020-04-03 13:22:08 -070086 filter::onPointerInput.invokeOverAllPasses(down(0))
shepshapard648840f2019-07-17 14:28:50 -070087 assertThat(canDragDirections).isEmpty()
88 }
89
90 @Test
91 fun onPointerInputChanges_downUp_canDragNotCalled() {
Shep Shapard091fd692020-01-29 16:35:47 -080092 val down = down(0, duration = 0.milliseconds)
Shep Shapardad4e8152020-04-03 13:22:08 -070093 filter::onPointerInput.invokeOverAllPasses(down)
Shep Shaparde261df92019-11-15 11:24:31 -080094 val up = down.up(10.milliseconds)
Shep Shapardad4e8152020-04-03 13:22:08 -070095 filter::onPointerInput.invokeOverAllPasses(up)
shepshapard648840f2019-07-17 14:28:50 -070096
97 assertThat(canDragDirections).isEmpty()
98 }
99
100 @Test
101 fun onPointerInputChanges_downMoveFullyConsumed_canDragNotCalled() {
Shep Shapard091fd692020-01-29 16:35:47 -0800102 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700103 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700104 val move = down.moveBy(Duration(milliseconds = 10), 3f, 5f).consume(3f, 5f)
Shep Shapardad4e8152020-04-03 13:22:08 -0700105 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700106
107 assertThat(canDragDirections).isEmpty()
108 }
109
110 // Verify the circumstances under which canDrag should be called.
111
112 @Test
113 fun onPointerInputChanges_downMove1Dimension_canDragCalledOnce() {
Shep Shapard091fd692020-01-29 16:35:47 -0800114 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700115 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700116 val move = down.moveBy(Duration(milliseconds = 10), 3f, 0f)
Shep Shapardad4e8152020-04-03 13:22:08 -0700117 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700118
119 // Twice because while under touch slop, TouchSlopExceededGestureDetector checks during PostUp and PostDown
120 assertThat(canDragDirections).hasSize(2)
121 }
122
123 @Test
124 fun onPointerInputChanges_downMove2Dimensions_canDragCalledTwice() {
Shep Shapard091fd692020-01-29 16:35:47 -0800125 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700126 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700127 val move = down.moveBy(Duration(milliseconds = 10), 3f, 5f)
Shep Shapardad4e8152020-04-03 13:22:08 -0700128 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700129
130 // 4 times because while under touch slop, TouchSlopExceededGestureDetector checks during PostUp and
131 // PostDown
132 assertThat(canDragDirections).hasSize(4)
133 }
134
135 @Test
136 fun onPointerInputChanges_downMoveOneDimensionPartiallyConsumed_canDragCalledOnce() {
Shep Shapard091fd692020-01-29 16:35:47 -0800137 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700138 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700139 val move = down.moveBy(Duration(milliseconds = 10), 0f, 5f).consume(0f, 4f)
Shep Shapardad4e8152020-04-03 13:22:08 -0700140 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700141
142 // Twice because while under touch slop, DragGestureDetector checks during PostUp and
143 // PostDown
144 assertThat(canDragDirections).hasSize(2)
145 }
146
147 @Test
148 fun onPointerInputChanges_downMoveTwoDimensionPartiallyConsumed_canDragCalledTwice() {
Shep Shapard091fd692020-01-29 16:35:47 -0800149 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700150 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700151 val move = down.moveBy(Duration(milliseconds = 10), 3f, 5f).consume(2f, 4f)
Shep Shapardad4e8152020-04-03 13:22:08 -0700152 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700153
154 // 4 times because while under touch slop, DragGestureDetector checks during PostUp and
155 // PostDown
156 assertThat(canDragDirections).hasSize(4)
157 }
158
159 @Test
160 fun onPointerInputChanges_dragPastTouchSlopOneDimensionAndDrag3MoreTimes_canDragCalledOnce() {
Shep Shapard4babf792020-02-13 16:37:14 -0800161 val beyondSlop = TestTouchSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700162
Shep Shapard091fd692020-01-29 16:35:47 -0800163 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700164 filter::onPointerInput.invokeOverAllPasses(down)
Shep Shapard4babf792020-02-13 16:37:14 -0800165 var move = down.moveTo(10.milliseconds, 0f, beyondSlop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700166 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700167 repeat(3) {
168 move = move.moveBy(Duration(milliseconds = 10), 0f, 1f)
Shep Shapardad4e8152020-04-03 13:22:08 -0700169 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700170 }
171
172 // Once because although DragGestureDetector checks during PostUp and PostDown, slop is
173 // surpassed during PostUp, and thus isn't checked again.
174 assertThat(canDragDirections).hasSize(1)
175 }
176
177 @Test
178 fun onPointerInputChanges_downMoveUnderSlop3Times_canDragCalled3Times() {
Shep Shapard4babf792020-02-13 16:37:14 -0800179 val thirdSlop = TestTouchSlop / 3
shepshapard648840f2019-07-17 14:28:50 -0700180
Shep Shapard091fd692020-01-29 16:35:47 -0800181 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700182 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700183 var move = down
184 repeat(3) {
Shep Shapard4babf792020-02-13 16:37:14 -0800185 move = move.moveBy(Duration(milliseconds = 10), 0f, thirdSlop.toFloat())
Shep Shapardad4e8152020-04-03 13:22:08 -0700186 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700187 }
188
189 // 6 times because while under touch slop, DragGestureDetector checks during PostUp and
190 // PostDown
191 assertThat(canDragDirections).hasSize(6)
192 }
193
194 @Test
195 fun onPointerInputChanges_moveBeyondSlopThenIntoTouchSlopAreaAndOutAgain_canDragCalledOnce() {
Shep Shapard4babf792020-02-13 16:37:14 -0800196 val beyondSlop = TestTouchSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700197
Shep Shapard091fd692020-01-29 16:35:47 -0800198 var event = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700199 filter::onPointerInput.invokeOverAllPasses(event)
shepshapard648840f2019-07-17 14:28:50 -0700200 // Out of touch slop region
Shep Shapard4babf792020-02-13 16:37:14 -0800201 event = event.moveBy(Duration(milliseconds = 10), 0f, beyondSlop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700202 filter::onPointerInput.invokeOverAllPasses(event)
shepshapard648840f2019-07-17 14:28:50 -0700203 // Back into touch slop region
Shep Shapard4babf792020-02-13 16:37:14 -0800204 event = event.moveBy(Duration(milliseconds = 10), 0f, -beyondSlop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700205 filter::onPointerInput.invokeOverAllPasses(event)
shepshapard648840f2019-07-17 14:28:50 -0700206 // Out of touch slop region again
Shep Shapard4babf792020-02-13 16:37:14 -0800207 event = event.moveBy(Duration(milliseconds = 10), 0f, beyondSlop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700208 filter::onPointerInput.invokeOverAllPasses(event)
shepshapard648840f2019-07-17 14:28:50 -0700209
210 // Once because although DragGestureDetector checks during PostUp and PostDown, slop is
211 // surpassed during PostUp, and thus isn't checked again.
212 assertThat(canDragDirections).hasSize(1)
213 }
214
215 // Verification of correctness of values passed to canDrag.
216
217 @Test
218 fun onPointerInputChanges_canDragCalledWithCorrectDirection() {
219 onPointerInputChanges_canDragCalledWithCorrectDirection(
220 -1f, 0f, arrayOf(Direction.LEFT)
221 )
222 onPointerInputChanges_canDragCalledWithCorrectDirection(
223 0f, -1f, arrayOf(Direction.UP)
224 )
225 onPointerInputChanges_canDragCalledWithCorrectDirection(
226 1f, 0f, arrayOf(Direction.RIGHT)
227 )
228 onPointerInputChanges_canDragCalledWithCorrectDirection(
229 0f, 1f, arrayOf(Direction.DOWN)
230 )
231 onPointerInputChanges_canDragCalledWithCorrectDirection(
232 -1f, -1f, arrayOf(Direction.LEFT, Direction.UP)
233 )
234 onPointerInputChanges_canDragCalledWithCorrectDirection(
235 -1f, 1f, arrayOf(Direction.LEFT, Direction.DOWN)
236 )
237 onPointerInputChanges_canDragCalledWithCorrectDirection(
238 1f, -1f, arrayOf(Direction.RIGHT, Direction.UP)
239 )
240 onPointerInputChanges_canDragCalledWithCorrectDirection(
241 1f, 1f, arrayOf(Direction.RIGHT, Direction.DOWN)
242 )
243 }
244
245 private fun onPointerInputChanges_canDragCalledWithCorrectDirection(
246 dx: Float,
247 dy: Float,
248 expectedDirections: Array<Direction>
249 ) {
250 canDragDirections.clear()
Shep Shapard091fd692020-01-29 16:35:47 -0800251 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700252 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700253 val move = down.moveBy(Duration(milliseconds = 10), dx, dy)
Shep Shapardad4e8152020-04-03 13:22:08 -0700254 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700255
256 // Everything here is twice because DragGestureDetector checks during PostUp and PostDown.
257 assertThat(canDragDirections).hasSize(expectedDirections.size * 2)
258 expectedDirections.forEach { direction ->
259 assertThat(canDragDirections.count { it == direction })
260 .isEqualTo(2)
261 }
262 }
263
264 // Verify the circumstances under which onTouchSlopExceeded should not be called.
265
266 // TODO(b/129701831): This test assumes that if a pointer moves by slop in both x and y, we are
267 // still under slop even though sqrt(slop^2 + slop^2) > slop. This may be inaccurate and this
268 // test may therefore need to be updated.
269 @Test
270 fun onPointerInputChanges_downMoveWithinSlop_onTouchSlopExceededNotCalled() {
Shep Shapard091fd692020-01-29 16:35:47 -0800271 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700272 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700273 val move = down.moveBy(
274 Duration(milliseconds = 10),
275 TestTouchSlop.toFloat(),
276 TestTouchSlop.toFloat()
277 )
Shep Shapardad4e8152020-04-03 13:22:08 -0700278 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700279
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700280 assertThat(onDragSlopExceededCallCount).isEqualTo(0)
shepshapard648840f2019-07-17 14:28:50 -0700281 }
282
283 @Test
284 fun onPointerInputChanges_moveBeyondSlopInUnsupportedDirection_onTouchSlopExceededNotCalled() {
Shep Shapard4babf792020-02-13 16:37:14 -0800285 val beyondSlop = TestTouchSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700286 canDragReturn = false
287
Shep Shapard091fd692020-01-29 16:35:47 -0800288 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700289 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700290 val move = down.moveBy(
291 Duration(milliseconds = 10),
292 beyondSlop,
293 beyondSlop
294 )
Shep Shapardad4e8152020-04-03 13:22:08 -0700295 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700296
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700297 assertThat(onDragSlopExceededCallCount).isEqualTo(0)
shepshapard648840f2019-07-17 14:28:50 -0700298 }
299
300 @Test
301 fun onPointerInputChanges_moveBeyondSlopButConsumeUnder_onTouchSlopExceededNotCalled() {
302
Shep Shapard091fd692020-01-29 16:35:47 -0800303 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700304 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700305
Shep Shapard4babf792020-02-13 16:37:14 -0800306 val move = down.moveBy(10.milliseconds, TestTouchSlop + TinyNum, 0f).consume(dx = 1f)
Shep Shapardad4e8152020-04-03 13:22:08 -0700307 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700308
309 // Assert
310
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700311 assertThat(onDragSlopExceededCallCount).isEqualTo(0)
shepshapard648840f2019-07-17 14:28:50 -0700312 }
313
314 @Test
315 fun onPointerInputChanges_moveUnderToPostUpThenModOverInOppDir_onTouchSlopExceededNotCalled() {
316
Shep Shapard091fd692020-01-29 16:35:47 -0800317 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700318 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700319
Shep Shapard091fd692020-01-29 16:35:47 -0800320 val move = down.moveBy(10.milliseconds, TestTouchSlop.toFloat(), 0f)
Shep Shapardad4e8152020-04-03 13:22:08 -0700321 filter::onPointerInput.invokeOverPasses(
shepshapard648840f2019-07-17 14:28:50 -0700322 listOf(move),
Shep Shapardbf513c52019-12-16 17:06:51 -0800323 listOf(
324 PointerEventPass.InitialDown,
325 PointerEventPass.PreUp,
326 PointerEventPass.PreDown,
327 PointerEventPass.PostUp
328 )
shepshapard648840f2019-07-17 14:28:50 -0700329 )
Shep Shapard4babf792020-02-13 16:37:14 -0800330 val move2 = move.consume(dx = (TestTouchSlop * 2f + TinyNum))
Shep Shapardad4e8152020-04-03 13:22:08 -0700331 filter::onPointerInput.invokeOverPasses(
Shep Shapardbf513c52019-12-16 17:06:51 -0800332 move2,
shepshapard648840f2019-07-17 14:28:50 -0700333 PointerEventPass.PostDown
334 )
335
336 // Assert
337
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700338 assertThat(onDragSlopExceededCallCount).isEqualTo(1)
shepshapard648840f2019-07-17 14:28:50 -0700339 }
340
341 // TODO(b/129701831): This test assumes that if a pointer moves by slop in both x and y, we are
342 // still under slop even though sqrt(slop^2 + slop^2) > slop. This may be inaccurate and this
343 // test may therefore need to be updated.
344 @Test
345 fun onPointerInputChanges_moveAroundWithinSlop_onTouchSlopExceededNotCalled() {
346 val slop = TestTouchSlop.toFloat()
347
Shep Shapard091fd692020-01-29 16:35:47 -0800348 var change = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700349 filter::onPointerInput.invokeOverAllPasses(change)
shepshapard648840f2019-07-17 14:28:50 -0700350
351 // Go around the border of the touch slop area
352
353 // To top left
Shep Shaparde261df92019-11-15 11:24:31 -0800354 change = change.moveTo(10.milliseconds, -slop, -slop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700355 filter::onPointerInput.invokeOverAllPasses(change)
shepshapard648840f2019-07-17 14:28:50 -0700356 // To bottom left
Shep Shaparde261df92019-11-15 11:24:31 -0800357 change = change.moveTo(20.milliseconds, -slop, slop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700358 filter::onPointerInput.invokeOverAllPasses(change)
shepshapard648840f2019-07-17 14:28:50 -0700359 // To bottom right
Shep Shaparde261df92019-11-15 11:24:31 -0800360 change = change.moveTo(30.milliseconds, slop, slop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700361 filter::onPointerInput.invokeOverAllPasses(change)
shepshapard648840f2019-07-17 14:28:50 -0700362 // To top right
Shep Shaparde261df92019-11-15 11:24:31 -0800363 change = change.moveTo(40.milliseconds, slop, -slop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700364 filter::onPointerInput.invokeOverAllPasses(change)
shepshapard648840f2019-07-17 14:28:50 -0700365
366 // Jump from corner to opposite corner and back
367
368 // To bottom left
Shep Shaparde261df92019-11-15 11:24:31 -0800369 change = change.moveTo(50.milliseconds, -slop, slop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700370 filter::onPointerInput.invokeOverAllPasses(change)
shepshapard648840f2019-07-17 14:28:50 -0700371 // To top right
Shep Shaparde261df92019-11-15 11:24:31 -0800372 change = change.moveTo(60.milliseconds, slop, -slop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700373 filter::onPointerInput.invokeOverAllPasses(change)
shepshapard648840f2019-07-17 14:28:50 -0700374
375 // Move the other diagonal
376
377 // To top left
Shep Shaparde261df92019-11-15 11:24:31 -0800378 change = change.moveTo(70.milliseconds, -slop, -slop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700379 filter::onPointerInput.invokeOverAllPasses(change)
shepshapard648840f2019-07-17 14:28:50 -0700380
381 // Jump from corner to opposite corner and back
382
383 // To bottom right
Shep Shaparde261df92019-11-15 11:24:31 -0800384 change = change.moveTo(80.milliseconds, slop, slop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700385 filter::onPointerInput.invokeOverAllPasses(change)
shepshapard648840f2019-07-17 14:28:50 -0700386 // To top left
Shep Shaparde261df92019-11-15 11:24:31 -0800387 change = change.moveTo(90.milliseconds, -slop, -slop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700388 filter::onPointerInput.invokeOverAllPasses(change)
shepshapard648840f2019-07-17 14:28:50 -0700389
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700390 assertThat(onDragSlopExceededCallCount).isEqualTo(0)
shepshapard648840f2019-07-17 14:28:50 -0700391 }
392
393 // Verify the circumstances under which onTouchSlopExceeded should be called.
394
395 @Test
396 fun onPointerInputChanges_movePassedSlop_onTouchSlopExceededCallOnce() {
Shep Shapard4babf792020-02-13 16:37:14 -0800397 val beyondSlop = TestTouchSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700398
Shep Shapard091fd692020-01-29 16:35:47 -0800399 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700400 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700401 val move = down.moveBy(
402 Duration(milliseconds = 100),
Shep Shapard4babf792020-02-13 16:37:14 -0800403 beyondSlop,
shepshapard648840f2019-07-17 14:28:50 -0700404 0f
405 )
Shep Shapardad4e8152020-04-03 13:22:08 -0700406 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700407
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700408 assertThat(onDragSlopExceededCallCount).isEqualTo(1)
shepshapard648840f2019-07-17 14:28:50 -0700409 }
410
411 @Test
412 fun onPointerInputChanges_movePassedSlopIn2Events_onTouchSlopExceededCallOnce() {
413
Shep Shapard091fd692020-01-29 16:35:47 -0800414 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700415 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700416 val move = down.moveBy(
417 Duration(milliseconds = 100),
418 TestTouchSlop.toFloat(),
419 0f
420 )
Shep Shapardad4e8152020-04-03 13:22:08 -0700421 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700422 val move2 = down.moveBy(
423 Duration(milliseconds = 100),
424 1f,
425 0f
426 )
Shep Shapardad4e8152020-04-03 13:22:08 -0700427 filter::onPointerInput.invokeOverAllPasses(move2)
shepshapard648840f2019-07-17 14:28:50 -0700428
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700429 assertThat(onDragSlopExceededCallCount).isEqualTo(1)
shepshapard648840f2019-07-17 14:28:50 -0700430 }
431
432 @Test
433 fun onPointerInputChanges_passSlopThenInSlopAreaThenOut_onTouchSlopExceededCallOnce() {
Shep Shapard4babf792020-02-13 16:37:14 -0800434 val beyondSlop = TestTouchSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700435
Shep Shapard091fd692020-01-29 16:35:47 -0800436 var event = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700437 filter::onPointerInput.invokeOverAllPasses(event)
shepshapard648840f2019-07-17 14:28:50 -0700438 // Out of touch slop region
Shep Shapard4babf792020-02-13 16:37:14 -0800439 event = event.moveBy(Duration(milliseconds = 10), 0f, beyondSlop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700440 filter::onPointerInput.invokeOverAllPasses(event)
shepshapard648840f2019-07-17 14:28:50 -0700441 // Back into touch slop region
Shep Shapard4babf792020-02-13 16:37:14 -0800442 event = event.moveBy(Duration(milliseconds = 10), 0f, -beyondSlop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700443 filter::onPointerInput.invokeOverAllPasses(event)
shepshapard648840f2019-07-17 14:28:50 -0700444 // Out of touch slop region again
Shep Shapard4babf792020-02-13 16:37:14 -0800445 event = event.moveBy(Duration(milliseconds = 10), 0f, beyondSlop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700446 filter::onPointerInput.invokeOverAllPasses(event)
shepshapard648840f2019-07-17 14:28:50 -0700447
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700448 assertThat(onDragSlopExceededCallCount).isEqualTo(1)
shepshapard648840f2019-07-17 14:28:50 -0700449 }
450
451 @Test
452 fun onPointerInputChanges_downConsumedMovePassedSlop_onTouchSlopExceededCallOnce() {
Shep Shapard4babf792020-02-13 16:37:14 -0800453 val beyondSlop = TestTouchSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700454
Shep Shapard091fd692020-01-29 16:35:47 -0800455 val down = down(0).consumeDownChange()
Shep Shapardad4e8152020-04-03 13:22:08 -0700456 filter::onPointerInput.invokeOverAllPasses(down)
Shep Shapard4babf792020-02-13 16:37:14 -0800457 val move = down.moveBy(Duration(milliseconds = 100), beyondSlop, 0f)
Shep Shapardad4e8152020-04-03 13:22:08 -0700458 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700459
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700460 assertThat(onDragSlopExceededCallCount).isEqualTo(1)
shepshapard648840f2019-07-17 14:28:50 -0700461 }
462
463 @Test
464 fun onPointerInputChanges_beyondInUnsupportThenBeyondInSupport_onTouchSlopExceededCallOnce() {
Shep Shapard4babf792020-02-13 16:37:14 -0800465 val beyondSlop = TestTouchSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700466
Shep Shapard091fd692020-01-29 16:35:47 -0800467 var change = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700468 filter::onPointerInput.invokeOverAllPasses(change)
shepshapard648840f2019-07-17 14:28:50 -0700469 canDragReturn = false
470 change = change.moveBy(
471 Duration(milliseconds = 10),
472 0f,
Shep Shapard4babf792020-02-13 16:37:14 -0800473 beyondSlop
shepshapard648840f2019-07-17 14:28:50 -0700474 )
475 // Sanity check that onTouchSlopExceeded has not been called.
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700476 assertThat(onDragSlopExceededCallCount).isEqualTo(0)
shepshapard648840f2019-07-17 14:28:50 -0700477
478 canDragReturn = true
Shep Shapardad4e8152020-04-03 13:22:08 -0700479 filter::onPointerInput.invokeOverAllPasses(change)
shepshapard648840f2019-07-17 14:28:50 -0700480 change = change.moveBy(
481 Duration(milliseconds = 10),
482 0f,
Shep Shapard4babf792020-02-13 16:37:14 -0800483 -beyondSlop
shepshapard648840f2019-07-17 14:28:50 -0700484 )
Shep Shapardad4e8152020-04-03 13:22:08 -0700485 filter::onPointerInput.invokeOverAllPasses(change)
shepshapard648840f2019-07-17 14:28:50 -0700486
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700487 assertThat(onDragSlopExceededCallCount).isEqualTo(1)
shepshapard648840f2019-07-17 14:28:50 -0700488 }
489
490 @Test
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700491 fun onPointerInputChanges_2PointsMoveInOpposite_onTouchSlopExceededNotCalled() {
shepshapard648840f2019-07-17 14:28:50 -0700492
493 // Arrange
494
Shep Shapard4babf792020-02-13 16:37:14 -0800495 val beyondSlop = TestTouchSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700496
497 var pointer1 = down(1)
498 var pointer2 = down(2)
Shep Shapardad4e8152020-04-03 13:22:08 -0700499 filter::onPointerInput.invokeOverAllPasses(pointer1, pointer2)
shepshapard648840f2019-07-17 14:28:50 -0700500
501 // Act
502
503 pointer1 = pointer1.moveBy(
504 Duration(milliseconds = 100),
Shep Shapard4babf792020-02-13 16:37:14 -0800505 beyondSlop,
shepshapard648840f2019-07-17 14:28:50 -0700506 0f
507 )
508 pointer2 = pointer2.moveBy(
509 Duration(milliseconds = 100),
Shep Shapard4babf792020-02-13 16:37:14 -0800510 -beyondSlop,
shepshapard648840f2019-07-17 14:28:50 -0700511 0f
512 )
Shep Shapardad4e8152020-04-03 13:22:08 -0700513 filter::onPointerInput.invokeOverAllPasses(pointer1, pointer2)
shepshapard648840f2019-07-17 14:28:50 -0700514
515 // Assert
516
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700517 assertThat(onDragSlopExceededCallCount).isEqualTo(0)
shepshapard648840f2019-07-17 14:28:50 -0700518 }
519
520 @Test
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700521 fun onPointerInputChanges_3PointsMoveAverage0_onDragSlopExceededNotCalled() {
shepshapard648840f2019-07-17 14:28:50 -0700522
523 // Arrange
524
Shep Shapard4babf792020-02-13 16:37:14 -0800525 val beyondSlop = TestTouchSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700526
Shep Shapardbf513c52019-12-16 17:06:51 -0800527 val pointers = arrayOf(down(0), down(1), down(2))
Shep Shapardad4e8152020-04-03 13:22:08 -0700528 filter::onPointerInput.invokeOverAllPasses(*pointers)
shepshapard648840f2019-07-17 14:28:50 -0700529
530 // Act
531
532 // These movements average to no movement.
533 pointers[0] =
534 pointers[0].moveBy(
535 Duration(milliseconds = 100),
Shep Shapard4babf792020-02-13 16:37:14 -0800536 beyondSlop * -1,
537 beyondSlop * -1
shepshapard648840f2019-07-17 14:28:50 -0700538 )
539 pointers[1] =
540 pointers[1].moveBy(
541 Duration(milliseconds = 100),
Shep Shapard4babf792020-02-13 16:37:14 -0800542 beyondSlop * 1,
543 beyondSlop * -1
shepshapard648840f2019-07-17 14:28:50 -0700544 )
545 pointers[2] =
546 pointers[2].moveBy(
547 Duration(milliseconds = 100),
548 0f,
Shep Shapard4babf792020-02-13 16:37:14 -0800549 beyondSlop * 2
shepshapard648840f2019-07-17 14:28:50 -0700550 )
Shep Shapardad4e8152020-04-03 13:22:08 -0700551 filter::onPointerInput.invokeOverAllPasses(*pointers)
shepshapard648840f2019-07-17 14:28:50 -0700552
553 // Assert
554
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700555 assertThat(onDragSlopExceededCallCount).isEqualTo(0)
shepshapard648840f2019-07-17 14:28:50 -0700556 }
557
558 @Test
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700559 fun onPointerInputChanges_2Points1MoveJustBeyondSlop_onDragSlopExceededNotCalled() {
shepshapard648840f2019-07-17 14:28:50 -0700560
561 // Arrange
562
Shep Shapard4babf792020-02-13 16:37:14 -0800563 val beyondSlop = TestTouchSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700564
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700565 var pointer1 = down(0)
566 var pointer2 = down(1)
567 filter::onPointerInput.invokeOverAllPasses(pointer1, pointer2)
shepshapard648840f2019-07-17 14:28:50 -0700568
569 // Act
570
571 // These movements average to no movement.
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700572
573 pointer1 =
574 pointer1.moveBy(
shepshapard648840f2019-07-17 14:28:50 -0700575 Duration(milliseconds = 100),
576 0f,
577 0f
578 )
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700579 pointer2 =
580 pointer2.moveBy(
shepshapard648840f2019-07-17 14:28:50 -0700581 Duration(milliseconds = 100),
Shep Shapard4babf792020-02-13 16:37:14 -0800582 beyondSlop * -1,
shepshapard648840f2019-07-17 14:28:50 -0700583 0f
584 )
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700585 filter::onPointerInput.invokeOverAllPasses(pointer1, pointer2)
shepshapard648840f2019-07-17 14:28:50 -0700586
587 // Assert
588
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700589 assertThat(onDragSlopExceededCallCount).isEqualTo(0)
shepshapard648840f2019-07-17 14:28:50 -0700590 }
591
592 @Test
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700593 fun onPointerInputChanges_2Points1MoveJustUnderTwiceSlop_onDragSlopExceededNotCalled() {
594
595 // Arrange
596
597 val beyondSlop = TestTouchSlop + TinyNum
598
599 var pointer1 = down(0)
600 var pointer2 = down(1)
601 filter::onPointerInput.invokeOverAllPasses(pointer1, pointer2)
602
603 // Act
604
605 // These movements average to no movement.
606
607 pointer1 =
608 pointer1.moveBy(
609 Duration(milliseconds = 100),
610 0f,
611 0f
612 )
613 pointer2 =
614 pointer2.moveBy(
615 Duration(milliseconds = 100),
616 beyondSlop * 2 - 1,
617 0f
618 )
619 filter::onPointerInput.invokeOverAllPasses(pointer1, pointer2)
620
621 // Assert
622
623 assertThat(onDragSlopExceededCallCount).isEqualTo(0)
624 }
625
626 @Test
627 fun onPointerInputChanges_2Points1MoveToTwiceSlop_onDragSlopExceededNotCalled() {
628
629 // Arrange
630
631 val beyondSlop = TestTouchSlop + TinyNum
632
633 var pointer1 = down(0)
634 var pointer2 = down(1)
635 filter::onPointerInput.invokeOverAllPasses(pointer1, pointer2)
636
637 // Act
638
639 // These movements average to no movement.
640
641 pointer1 =
642 pointer1.moveBy(
643 Duration(milliseconds = 100),
644 0f,
645 0f
646 )
647 pointer2 =
648 pointer2.moveBy(
649 Duration(milliseconds = 100),
650 beyondSlop * 2,
651 0f
652 )
653 filter::onPointerInput.invokeOverAllPasses(pointer1, pointer2)
654
655 // Assert
656
657 assertThat(onDragSlopExceededCallCount).isEqualTo(1)
658 }
659
660 @Test
661 fun onPointerInputChanges_1PointMovesBeyondSlopAndThenManyTimes_onDragSlopExceededCallOnce() {
shepshapard648840f2019-07-17 14:28:50 -0700662
663 // Arrange
664
Shep Shapard4babf792020-02-13 16:37:14 -0800665 val beyondSlop = TestTouchSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700666
667 var pointer = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700668 filter::onPointerInput.invokeOverAllPasses(pointer)
shepshapard648840f2019-07-17 14:28:50 -0700669
670 // Act
671
672 repeat(5) {
Shep Shapard4babf792020-02-13 16:37:14 -0800673 pointer = pointer.moveBy(100.milliseconds, beyondSlop, beyondSlop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700674 filter::onPointerInput.invokeOverAllPasses(pointer)
shepshapard648840f2019-07-17 14:28:50 -0700675 }
676
677 // Assert
678
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700679 assertThat(onDragSlopExceededCallCount).isEqualTo(1)
shepshapard648840f2019-07-17 14:28:50 -0700680 }
681
682 @Test
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700683 fun onPointerInputChanges_1ModifiedToMoveBeyondSlopBeforePostUp_onDragSlopExceededCallOnce() {
Shep Shapard4babf792020-02-13 16:37:14 -0800684 val beyondSlop = TestTouchSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700685
Shep Shapard091fd692020-01-29 16:35:47 -0800686 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700687 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700688
Shep Shapard4babf792020-02-13 16:37:14 -0800689 val move = down.moveBy(10.milliseconds, 0f, 0f).consume(dx = beyondSlop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700690 filter::onPointerInput.invokeOverPasses(
shepshapard648840f2019-07-17 14:28:50 -0700691 listOf(move),
Shep Shapardbf513c52019-12-16 17:06:51 -0800692 listOf(
693 PointerEventPass.InitialDown,
694 PointerEventPass.PreUp,
695 PointerEventPass.PreDown,
696 PointerEventPass.PostUp
697 )
shepshapard648840f2019-07-17 14:28:50 -0700698 )
699
700 // Assert
701
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700702 assertThat(onDragSlopExceededCallCount).isEqualTo(1)
shepshapard648840f2019-07-17 14:28:50 -0700703 }
704
705 @Test
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700706 fun onPointerInputChanges_1ModedToMoveBeyondSlopBeforePostDown_onDragSlopExceededCallOnce() {
Shep Shapard4babf792020-02-13 16:37:14 -0800707 val beyondSlop = TestTouchSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700708
Shep Shapard091fd692020-01-29 16:35:47 -0800709 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700710 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700711
Shep Shapard091fd692020-01-29 16:35:47 -0800712 val move = down.moveBy(10.milliseconds, 0f, 0f)
Shep Shapardad4e8152020-04-03 13:22:08 -0700713 filter::onPointerInput.invokeOverPasses(
shepshapard648840f2019-07-17 14:28:50 -0700714 listOf(move),
Shep Shapardbf513c52019-12-16 17:06:51 -0800715 listOf(
716 PointerEventPass.InitialDown,
717 PointerEventPass.PreUp,
718 PointerEventPass.PreDown,
719 PointerEventPass.PostUp
720 )
shepshapard648840f2019-07-17 14:28:50 -0700721 )
722
Shep Shapard4babf792020-02-13 16:37:14 -0800723 val moveConsumed = move.consume(dx = beyondSlop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700724 filter::onPointerInput.invokeOverPasses(
Shep Shapardbf513c52019-12-16 17:06:51 -0800725 moveConsumed,
shepshapard648840f2019-07-17 14:28:50 -0700726 PointerEventPass.PostDown
727 )
728
729 // Assert
730
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700731 assertThat(onDragSlopExceededCallCount).isEqualTo(1)
shepshapard648840f2019-07-17 14:28:50 -0700732 }
733
734 @Test
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700735 fun onPointerInputChanges_moveUnderToPostUpThenModOverToPostDown_onDragSlopExceededCallOnce() {
shepshapard648840f2019-07-17 14:28:50 -0700736 val halfSlop = TestTouchSlop / 2
Shep Shapard4babf792020-02-13 16:37:14 -0800737 val restOfSlopAndBeyond = TestTouchSlop - halfSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700738
Shep Shapard091fd692020-01-29 16:35:47 -0800739 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700740 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700741
Shep Shapard091fd692020-01-29 16:35:47 -0800742 val move = down.moveBy(10.milliseconds, halfSlop.toFloat(), 0f)
Shep Shapardad4e8152020-04-03 13:22:08 -0700743 filter::onPointerInput.invokeOverPasses(
shepshapard648840f2019-07-17 14:28:50 -0700744 listOf(move),
Shep Shapardbf513c52019-12-16 17:06:51 -0800745 listOf(
746 PointerEventPass.InitialDown,
747 PointerEventPass.PreUp,
748 PointerEventPass.PreDown,
749 PointerEventPass.PostUp
750 )
shepshapard648840f2019-07-17 14:28:50 -0700751 )
752
Shep Shapard4babf792020-02-13 16:37:14 -0800753 val moveConsumed = move.consume(dx = -restOfSlopAndBeyond)
Shep Shapardad4e8152020-04-03 13:22:08 -0700754 filter::onPointerInput.invokeOverPasses(
Shep Shapardbf513c52019-12-16 17:06:51 -0800755 moveConsumed,
shepshapard648840f2019-07-17 14:28:50 -0700756 PointerEventPass.PostDown
757 )
758
759 // Assert
760
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700761 assertThat(onDragSlopExceededCallCount).isEqualTo(1)
shepshapard648840f2019-07-17 14:28:50 -0700762 }
763
764 @Test
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700765 fun onPointerInputChanges_moveBeyondSlopAllPassesUpToPostUp_onDragSlopExceededCallOnce() {
Shep Shapard4babf792020-02-13 16:37:14 -0800766 val beyondSlop = TestTouchSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700767
Shep Shapard091fd692020-01-29 16:35:47 -0800768 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700769 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700770
Shep Shapard4babf792020-02-13 16:37:14 -0800771 val move = down.moveBy(10.milliseconds, beyondSlop, 0f)
Shep Shapardad4e8152020-04-03 13:22:08 -0700772 filter::onPointerInput.invokeOverPasses(
shepshapard648840f2019-07-17 14:28:50 -0700773 listOf(move),
Shep Shapardbf513c52019-12-16 17:06:51 -0800774 listOf(
775 PointerEventPass.InitialDown,
776 PointerEventPass.PreUp,
777 PointerEventPass.PreDown,
778 PointerEventPass.PostUp
779 )
shepshapard648840f2019-07-17 14:28:50 -0700780 )
781
782 // Assert
783
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700784 assertThat(onDragSlopExceededCallCount).isEqualTo(1)
shepshapard648840f2019-07-17 14:28:50 -0700785 }
786
787 // Verification that TouchSlopExceededGestureDetector does not consume any changes.
788
789 @Test
790 fun onPointerInputChanges_1Down_nothingConsumed() {
791
Shep Shapardad4e8152020-04-03 13:22:08 -0700792 val result = filter::onPointerInput.invokeOverAllPasses(down(0))
shepshapard648840f2019-07-17 14:28:50 -0700793
794 // Assert
795
Shep Shapardbf513c52019-12-16 17:06:51 -0800796 assertThat(result.consumed.downChange).isFalse()
Nader Jawade6a9b332020-05-21 13:49:20 -0700797 assertThat(result.consumed.positionChange.x).isEqualTo(0f)
798 assertThat(result.consumed.positionChange.y).isEqualTo(0f)
shepshapard648840f2019-07-17 14:28:50 -0700799 }
800
801 @Test
802 fun onPointerInputChanges_1MoveUnderSlop_nothingConsumed() {
803
Shep Shapard091fd692020-01-29 16:35:47 -0800804 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700805 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700806
Shep Shapard091fd692020-01-29 16:35:47 -0800807 val move = down.moveBy(10.milliseconds, TestTouchSlop.toFloat(), TestTouchSlop.toFloat())
Shep Shapardad4e8152020-04-03 13:22:08 -0700808 val result = filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700809
810 // Assert
811
Shep Shapardbf513c52019-12-16 17:06:51 -0800812 assertThat(result.consumed.downChange).isFalse()
Nader Jawade6a9b332020-05-21 13:49:20 -0700813 assertThat(result.consumed.positionChange.x).isEqualTo(0f)
814 assertThat(result.consumed.positionChange.y).isEqualTo(0f)
shepshapard648840f2019-07-17 14:28:50 -0700815 }
816
817 @Test
818 fun onPointerInputChanges_1MoveUnderSlopThenUp_nothingConsumed() {
819
Shep Shapard091fd692020-01-29 16:35:47 -0800820 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700821 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700822
Shep Shapard091fd692020-01-29 16:35:47 -0800823 val move = down.moveBy(10.milliseconds, TestTouchSlop.toFloat(), TestTouchSlop.toFloat())
Shep Shapardad4e8152020-04-03 13:22:08 -0700824 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700825
Shep Shaparde261df92019-11-15 11:24:31 -0800826 val up = move.up(20.milliseconds)
Shep Shapardad4e8152020-04-03 13:22:08 -0700827 val result = filter::onPointerInput.invokeOverAllPasses(up)
shepshapard648840f2019-07-17 14:28:50 -0700828
829 // Assert
830
Shep Shapardbf513c52019-12-16 17:06:51 -0800831 assertThat(result.consumed.downChange).isFalse()
Nader Jawade6a9b332020-05-21 13:49:20 -0700832 assertThat(result.consumed.positionChange.x).isEqualTo(0f)
833 assertThat(result.consumed.positionChange.y).isEqualTo(0f)
shepshapard648840f2019-07-17 14:28:50 -0700834 }
835
836 @Test
837 fun onPointerInputChanges_1MoveOverSlop_nothingConsumed() {
Shep Shapard4babf792020-02-13 16:37:14 -0800838 val beyondSlop = TestTouchSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700839
Shep Shapard091fd692020-01-29 16:35:47 -0800840 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700841 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700842
Shep Shapard4babf792020-02-13 16:37:14 -0800843 val move = down.moveBy(10.milliseconds, beyondSlop, beyondSlop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700844 val result = filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700845
846 // Assert
847
Shep Shapardbf513c52019-12-16 17:06:51 -0800848 assertThat(result.consumed.downChange).isFalse()
Nader Jawade6a9b332020-05-21 13:49:20 -0700849 assertThat(result.consumed.positionChange.x).isEqualTo(0f)
850 assertThat(result.consumed.positionChange.y).isEqualTo(0f)
shepshapard648840f2019-07-17 14:28:50 -0700851 }
852
853 @Test
854 fun onPointerInputChanges_1MoveOverSlopThenUp_nothingConsumed() {
Shep Shapard4babf792020-02-13 16:37:14 -0800855 val beyondSlop = TestTouchSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700856
Shep Shapard091fd692020-01-29 16:35:47 -0800857 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700858 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700859
Shep Shapard4babf792020-02-13 16:37:14 -0800860 val move = down.moveBy(10.milliseconds, beyondSlop, beyondSlop)
Shep Shapardad4e8152020-04-03 13:22:08 -0700861 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700862
Shep Shaparde261df92019-11-15 11:24:31 -0800863 val up = move.up(20.milliseconds)
Shep Shapardad4e8152020-04-03 13:22:08 -0700864 val result = filter::onPointerInput.invokeOverAllPasses(up)
shepshapard648840f2019-07-17 14:28:50 -0700865
866 // Assert
867
Shep Shapardbf513c52019-12-16 17:06:51 -0800868 assertThat(result.consumed.downChange).isFalse()
Nader Jawade6a9b332020-05-21 13:49:20 -0700869 assertThat(result.consumed.positionChange.x).isEqualTo(0f)
870 assertThat(result.consumed.positionChange.y).isEqualTo(0f)
shepshapard648840f2019-07-17 14:28:50 -0700871 }
872
873 // Verification that TouchSlopExceededGestureDetector resets after up correctly.
874
875 @Test
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700876 fun onPointerInputChanges_MoveBeyondUpDownMoveBeyond_onDragSlopExceededCalledTwice() {
Shep Shapard4babf792020-02-13 16:37:14 -0800877 val beyondSlop = TestTouchSlop + TinyNum
shepshapard648840f2019-07-17 14:28:50 -0700878
879 repeat(2) {
Shep Shapard091fd692020-01-29 16:35:47 -0800880 val down = down(0)
Shep Shapardad4e8152020-04-03 13:22:08 -0700881 filter::onPointerInput.invokeOverAllPasses(down)
shepshapard648840f2019-07-17 14:28:50 -0700882
Shep Shapard4babf792020-02-13 16:37:14 -0800883 val move = down.moveBy(10.milliseconds, beyondSlop, 0f)
Shep Shapardad4e8152020-04-03 13:22:08 -0700884 filter::onPointerInput.invokeOverAllPasses(move)
shepshapard648840f2019-07-17 14:28:50 -0700885
Shep Shaparde261df92019-11-15 11:24:31 -0800886 val up = move.up(20.milliseconds)
Shep Shapardad4e8152020-04-03 13:22:08 -0700887 filter::onPointerInput.invokeOverAllPasses(up)
shepshapard648840f2019-07-17 14:28:50 -0700888 }
889
Shep Shaparddd9e2bc2020-05-19 15:25:36 -0700890 assertThat(onDragSlopExceededCallCount).isEqualTo(2)
shepshapard648840f2019-07-17 14:28:50 -0700891 }
Shep Shapardbf513c52019-12-16 17:06:51 -0800892
Shep Shapardca62bbb2020-05-15 16:20:52 -0700893 // Orientation tests
894
895 // Tests that verify correct behavior when orientation is set.
896
897 @Test
898 fun onPointerInput_filterIsHorizontalMovementVertical_canDragNotCalled() {
899 filter.setDraggableData(Orientation.Horizontal, canDrag)
900
901 val down = down(0)
902 filter::onPointerInput.invokeOverAllPasses(down)
903 val move1 = down.moveBy(Duration(milliseconds = 10), 0f, 1f)
904 filter::onPointerInput.invokeOverAllPasses(move1)
905 val move2 = down.moveBy(Duration(milliseconds = 10), 0f, -1f)
906 filter::onPointerInput.invokeOverAllPasses(move2)
907
908 assertThat(canDragDirections).isEmpty()
909 }
910
911 @Test
912 fun onPointerInput_filterIsVerticalMovementIsHorizontal_canDragNotCalled() {
913 filter.setDraggableData(Orientation.Vertical, canDrag)
914
915 val down = down(0)
916 filter::onPointerInput.invokeOverAllPasses(down)
917 val move1 = down.moveBy(Duration(milliseconds = 10), 1f, 0f)
918 filter::onPointerInput.invokeOverAllPasses(move1)
919 val move2 = down.moveBy(Duration(milliseconds = 10), -1f, 0f)
920 filter::onPointerInput.invokeOverAllPasses(move2)
921
922 assertThat(canDragDirections).isEmpty()
923 }
924
925 @Test
926 fun onPointerInput_filterIsHorizontalMovementHorizontal_canDragCalled() {
927 filter.setDraggableData(Orientation.Horizontal, canDrag)
928
929 val down = down(0)
930 filter::onPointerInput.invokeOverAllPasses(down)
931 val move1 = down.moveBy(Duration(milliseconds = 10), 1f, 0f)
932 filter::onPointerInput.invokeOverAllPasses(move1)
933 val move2 = down.moveBy(Duration(milliseconds = 10), -1f, 0f)
934 filter::onPointerInput.invokeOverAllPasses(move2)
935
936 // 2 for each because canDrag is currently checked on both postUp and postDown
937 assertThat(canDragDirections.filter { it == Direction.LEFT }).hasSize(2)
938 assertThat(canDragDirections.filter { it == Direction.RIGHT }).hasSize(2)
939 }
940
941 @Test
942 fun onPointerInput_filterIsVerticalMovementIsVertical_canDragCalled() {
943 filter.setDraggableData(Orientation.Vertical, canDrag)
944
945 val down = down(0)
946 filter::onPointerInput.invokeOverAllPasses(down)
947 val move1 = down.moveBy(Duration(milliseconds = 10), 0f, 1f)
948 filter::onPointerInput.invokeOverAllPasses(move1)
949 val move2 = down.moveBy(Duration(milliseconds = 10), 0f, -1f)
950 filter::onPointerInput.invokeOverAllPasses(move2)
951
952 // 2 for each because canDrag is currently checked on both postUp and postDown
953 assertThat(canDragDirections.filter { it == Direction.UP }).hasSize(2)
954 assertThat(canDragDirections.filter { it == Direction.DOWN }).hasSize(2)
955 }
956
957 @Test
958 fun onPointerInput_filterIsHorizontalMoveLeftPassedSlop_onTouchSlopExceededCalled() {
959 onPointerInput_filterHasOrientationMovePassedSlop(Orientation.Horizontal, -1, 0, 1)
960 }
961
962 @Test
963 fun onPointerInput_filterIsHorizontalMoveUpPassedSlop_onTouchSlopExceededNotCalled() {
964 onPointerInput_filterHasOrientationMovePassedSlop(Orientation.Horizontal, 0, -1, 0)
965 }
966
967 @Test
968 fun onPointerInput_filterIsHorizontalMoveRightPassedSlop_onTouchSlopExceededCalled() {
969 onPointerInput_filterHasOrientationMovePassedSlop(Orientation.Horizontal, 1, 0, 1)
970 }
971
972 @Test
973 fun onPointerInput_filterIsHorizontalMoveDownPassedSlop_onTouchSlopExceededNotCalled() {
974 onPointerInput_filterHasOrientationMovePassedSlop(Orientation.Horizontal, 0, 1, 0)
975 }
976
977 @Test
978 fun onPointerInput_filterIsVerticalMoveLeftPassedSlop_onTouchSlopExceededNotCalled() {
979 onPointerInput_filterHasOrientationMovePassedSlop(Orientation.Vertical, -1, 0, 0)
980 }
981
982 @Test
983 fun onPointerInput_filterIsVerticalMoveUpPassedSlop_onTouchSlopExceededCalled() {
984 onPointerInput_filterHasOrientationMovePassedSlop(Orientation.Vertical, 0, -1, 1)
985 }
986
987 @Test
988 fun onPointerInput_filterIsVerticalMoveRightPassedSlop_onTouchSlopExceededNotCalled() {
989 onPointerInput_filterHasOrientationMovePassedSlop(Orientation.Vertical, 1, 0, 0)
990 }
991
992 @Test
993 fun onPointerInput_filterIsVerticalMoveDownPassedSlop_onTouchSlopExceededCalled() {
994 onPointerInput_filterHasOrientationMovePassedSlop(Orientation.Vertical, 0, 1, 1)
995 }
996
997 private fun onPointerInput_filterHasOrientationMovePassedSlop(
998 filterOrientation: Orientation,
999 horizontalDirection: Int,
1000 verticalDirection: Int,
1001 expectecdOnDragSlopExceededCallCount: Int
1002 ) {
1003 val beyondSlop = TestTouchSlop + TinyNum
1004
1005 filter.setDraggableData(filterOrientation, canDrag)
1006
1007 val down = down(0)
1008 filter::onPointerInput.invokeOverAllPasses(down)
1009 val move = down.moveBy(
1010 Duration(milliseconds = 100),
1011 horizontalDirection * beyondSlop,
1012 verticalDirection * beyondSlop
1013 )
1014 filter::onPointerInput.invokeOverAllPasses(move)
1015
1016 assertThat(onDragSlopExceededCallCount).isEqualTo(expectecdOnDragSlopExceededCallCount)
1017 }
1018
1019 @Test
1020 fun onPointerInput_filterHorizontalPointerVerticalMovesLeftPastSlop_callBackNotCalled() {
1021 onPointerInput_pointerIsLockedMovesPassedSlop(
1022 Orientation.Horizontal, Orientation.Vertical, -1, 0, 0
1023 )
1024 }
1025
1026 @Test
1027 fun onPointerInput_filterHorizontalPointerVerticalMovesRightPastSlop_callBackNotCalled() {
1028 onPointerInput_pointerIsLockedMovesPassedSlop(
1029 Orientation.Horizontal, Orientation.Vertical, 1, 0, 0
1030 )
1031 }
1032
1033 @Test
1034 fun onPointerInput_filterHorizontalPointerHorizontalMovesLeftPastSlop_callBackCalled() {
1035 onPointerInput_pointerIsLockedMovesPassedSlop(
1036 Orientation.Horizontal, Orientation.Horizontal, -1, 0, 1
1037 )
1038 }
1039
1040 @Test
1041 fun onPointerInput_filterHorizontalPointerHorizontallMovesRightPastSlop_callBackCalled() {
1042 onPointerInput_pointerIsLockedMovesPassedSlop(
1043 Orientation.Horizontal, Orientation.Horizontal, 1, 0, 1
1044 )
1045 }
1046
1047 @Test
1048 fun onPointerInput_filterVerticalPointerHorizontalMovesUpPastSlop_callBackNotCalled() {
1049 onPointerInput_pointerIsLockedMovesPassedSlop(
1050 Orientation.Vertical, Orientation.Horizontal, 0, -1, 0
1051 )
1052 }
1053
1054 @Test
1055 fun onPointerInput_filterVerticalPointerHorizontalMovesDownPastSlop_callBackNotCalled() {
1056 onPointerInput_pointerIsLockedMovesPassedSlop(
1057 Orientation.Vertical, Orientation.Horizontal, 0, 1, 0
1058 )
1059 }
1060
1061 @Test
1062 fun onPointerInput_filterVerticalPointerVerticalMovesUpPastSlop_callBackCalled() {
1063 onPointerInput_pointerIsLockedMovesPassedSlop(
1064 Orientation.Vertical, Orientation.Vertical, 0, -1, 1
1065 )
1066 }
1067
1068 @Test
1069 fun onPointerInput_filterVerticalPointerVerticalMovesDownPastSlop_callBackCalled() {
1070 onPointerInput_pointerIsLockedMovesPassedSlop(
1071 Orientation.Vertical, Orientation.Vertical, 0, 1, 1
1072 )
1073 }
1074
1075 private fun onPointerInput_pointerIsLockedMovesPassedSlop(
1076 filterOrientation: Orientation,
1077 lockedOrientation: Orientation,
1078 horizontalDirection: Int,
1079 verticalDirection: Int,
1080 expectedOnDragSlopExceededCallCount: Int
1081 ) {
1082 val beyondSlop = TestTouchSlop + TinyNum
1083
1084 filter.onInit(mock())
1085 val scrollOrientationLocker = InternalScrollOrientationLocker()
1086 filter::onCustomEvent.invokeOverAllPasses(
1087 ShareScrollOrientationLockerEvent(scrollOrientationLocker)
1088 )
1089
1090 filter.setDraggableData(filterOrientation, canDrag)
1091
1092 val down = down(0)
1093 filter::onPointerInput.invokeOverAllPasses(down)
1094 val move = down.moveBy(
1095 Duration(milliseconds = 100),
1096 horizontalDirection * beyondSlop,
1097 verticalDirection * beyondSlop
1098 )
1099 scrollOrientationLocker.attemptToLockPointers(listOf(move), lockedOrientation)
1100
1101 filter::onPointerInput.invokeOverAllPasses(move)
1102
1103 assertThat(onDragSlopExceededCallCount).isEqualTo(expectedOnDragSlopExceededCallCount)
1104 }
1105
Shep Shapardbf513c52019-12-16 17:06:51 -08001106 // Verification that cancellation behavior is correct.
1107
1108 @Test
Shep Shaparddd9e2bc2020-05-19 15:25:36 -07001109 fun onCancel_underSlopCancelUnderSlop_onDragSlopExceededNotCalled() {
Shep Shapard4babf792020-02-13 16:37:14 -08001110 val underSlop = TestTouchSlop - TinyNum
Shep Shapardbf513c52019-12-16 17:06:51 -08001111
1112 // Arrange
1113
1114 var pointer = down(0, 0.milliseconds, 0f, 0f)
Shep Shapardad4e8152020-04-03 13:22:08 -07001115 filter::onPointerInput.invokeOverAllPasses(pointer)
Shep Shapardbf513c52019-12-16 17:06:51 -08001116
1117 pointer = pointer.moveTo(
1118 10.milliseconds,
Shep Shapard4babf792020-02-13 16:37:14 -08001119 underSlop,
Shep Shapardbf513c52019-12-16 17:06:51 -08001120 0f
1121 )
Shep Shapardad4e8152020-04-03 13:22:08 -07001122 filter::onPointerInput.invokeOverAllPasses(pointer)
Shep Shapardbf513c52019-12-16 17:06:51 -08001123
1124 // Act
1125
Shep Shapardad4e8152020-04-03 13:22:08 -07001126 filter.onCancel()
Shep Shapardbf513c52019-12-16 17:06:51 -08001127
1128 pointer = down(0, 0.milliseconds, 0f, 0f)
Shep Shapardad4e8152020-04-03 13:22:08 -07001129 filter::onPointerInput.invokeOverAllPasses(pointer)
Shep Shapardbf513c52019-12-16 17:06:51 -08001130
1131 pointer = pointer.moveTo(
1132 10.milliseconds,
Shep Shapard4babf792020-02-13 16:37:14 -08001133 underSlop,
Shep Shapardbf513c52019-12-16 17:06:51 -08001134 0f
1135 )
Shep Shapardad4e8152020-04-03 13:22:08 -07001136 filter::onPointerInput.invokeOverAllPasses(pointer)
Shep Shapardbf513c52019-12-16 17:06:51 -08001137
1138 // Assert
1139
Shep Shaparddd9e2bc2020-05-19 15:25:36 -07001140 assertThat(onDragSlopExceededCallCount).isEqualTo(0)
Shep Shapardbf513c52019-12-16 17:06:51 -08001141 }
1142
1143 @Test
Shep Shapard6c9f1da2020-03-24 14:12:35 -07001144 fun onCancel_pastSlopCancelPastSlop_onScaleSlopExceededCalledTwice() {
Shep Shapard4babf792020-02-13 16:37:14 -08001145 val overSlop = TestTouchSlop + TinyNum
Shep Shapardbf513c52019-12-16 17:06:51 -08001146
1147 // Arrange
1148
1149 var pointer = down(0, 0.milliseconds, 0f, 0f)
Shep Shapardad4e8152020-04-03 13:22:08 -07001150 filter::onPointerInput.invokeOverAllPasses(pointer)
Shep Shapardbf513c52019-12-16 17:06:51 -08001151
1152 pointer = pointer.moveTo(
1153 10.milliseconds,
Shep Shapard4babf792020-02-13 16:37:14 -08001154 overSlop,
Shep Shapardbf513c52019-12-16 17:06:51 -08001155 0f
1156 )
Shep Shapardad4e8152020-04-03 13:22:08 -07001157 filter::onPointerInput.invokeOverAllPasses(pointer)
Shep Shapardbf513c52019-12-16 17:06:51 -08001158
1159 // Act
1160
Shep Shapardad4e8152020-04-03 13:22:08 -07001161 filter.onCancel()
Shep Shapardbf513c52019-12-16 17:06:51 -08001162
1163 pointer = down(0, 0.milliseconds, 0f, 0f)
Shep Shapardad4e8152020-04-03 13:22:08 -07001164 filter::onPointerInput.invokeOverAllPasses(pointer)
Shep Shapardbf513c52019-12-16 17:06:51 -08001165
1166 pointer = pointer.moveTo(
1167 10.milliseconds,
Shep Shapard4babf792020-02-13 16:37:14 -08001168 overSlop,
Shep Shapardbf513c52019-12-16 17:06:51 -08001169 0f
1170 )
Shep Shapardad4e8152020-04-03 13:22:08 -07001171 filter::onPointerInput.invokeOverAllPasses(pointer)
Shep Shapardbf513c52019-12-16 17:06:51 -08001172
1173 // Assert
1174
Shep Shaparddd9e2bc2020-05-19 15:25:36 -07001175 assertThat(onDragSlopExceededCallCount).isEqualTo(2)
Shep Shapardbf513c52019-12-16 17:06:51 -08001176 }
shepshapard648840f2019-07-17 14:28:50 -07001177}