1 /*
<lambda>null2 * 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
17 package androidx.compose.ui.input.pointer
18
19 import android.util.SparseLongArray
20 import android.view.InputDevice
21 import android.view.MotionEvent
22 import android.view.MotionEvent.ACTION_CANCEL
23 import android.view.MotionEvent.ACTION_DOWN
24 import android.view.MotionEvent.ACTION_HOVER_ENTER
25 import android.view.MotionEvent.ACTION_HOVER_EXIT
26 import android.view.MotionEvent.ACTION_MOVE
27 import android.view.MotionEvent.ACTION_POINTER_DOWN
28 import android.view.MotionEvent.ACTION_POINTER_UP
29 import android.view.MotionEvent.ACTION_SCROLL
30 import android.view.MotionEvent.ACTION_UP
31 import android.view.MotionEvent.AXIS_HSCROLL
32 import android.view.MotionEvent.AXIS_VSCROLL
33 import android.view.MotionEvent.TOOL_TYPE_FINGER
34 import android.view.MotionEvent.TOOL_TYPE_MOUSE
35 import androidx.compose.ui.geometry.Offset
36 import androidx.test.ext.junit.runners.AndroidJUnit4
37 import androidx.test.filters.SmallTest
38 import com.google.common.truth.Truth.assertThat
39 import org.junit.Before
40 import org.junit.Test
41 import org.junit.runner.RunWith
42
43 @SmallTest
44 @RunWith(AndroidJUnit4::class)
45 class MotionEventAdapterTest {
46
47 private lateinit var motionEventAdapter: MotionEventAdapter
48 private val positionCalculator =
49 object : PositionCalculator {
50 override fun screenToLocal(positionOnScreen: Offset): Offset = positionOnScreen
51
52 override fun localToScreen(localPosition: Offset): Offset = localPosition
53 }
54
55 @Before
56 fun setup() {
57 motionEventAdapter = MotionEventAdapter()
58 }
59
60 @Test
61 fun convertToolType() {
62 val types =
63 mapOf(
64 MotionEvent.TOOL_TYPE_FINGER to PointerType.Touch,
65 MotionEvent.TOOL_TYPE_UNKNOWN to PointerType.Unknown,
66 MotionEvent.TOOL_TYPE_ERASER to PointerType.Eraser,
67 MotionEvent.TOOL_TYPE_STYLUS to PointerType.Stylus,
68 MotionEvent.TOOL_TYPE_MOUSE to PointerType.Mouse,
69 )
70 types.entries.forEach { (toolType, pointerType) ->
71 motionEventAdapter = MotionEventAdapter()
72 val motionEvent =
73 MotionEvent(
74 2894,
75 ACTION_DOWN,
76 1,
77 0,
78 arrayOf(
79 PointerProperties(1000, toolType),
80 ),
81 arrayOf(
82 PointerCoords(2967f, 5928f),
83 )
84 )
85 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)!!
86 assertPointerInputEventData(
87 pointerInputEvent.pointers[0],
88 PointerId(0),
89 true,
90 2967f,
91 5928f,
92 pointerType
93 )
94 }
95 }
96
97 @Test
98 fun hoverEventsStay() {
99 // When a hover event happens, the pointer ID should stick around until it is removed.
100 val hoverEnter =
101 MotionEvent(
102 0,
103 ACTION_HOVER_ENTER,
104 1,
105 0,
106 arrayOf(PointerProperties(1, TOOL_TYPE_MOUSE)),
107 arrayOf(PointerCoords(10f, 10f))
108 )
109 val hoverEnterEvent = motionEventAdapter.convertToPointerInputEvent(hoverEnter)!!
110 assertThat(hoverEnterEvent.pointers).hasSize(1)
111 val hoverEnterId = hoverEnterEvent.pointers[0].id
112
113 val hoverExit =
114 MotionEvent(
115 1,
116 ACTION_HOVER_EXIT,
117 1,
118 0,
119 arrayOf(PointerProperties(1, TOOL_TYPE_MOUSE)),
120 arrayOf(PointerCoords(10f, 10f))
121 )
122
123 val hoverExitEvent = motionEventAdapter.convertToPointerInputEvent(hoverExit)!!
124 assertThat(hoverExitEvent.pointers).hasSize(1)
125 assertThat(hoverExitEvent.pointers[0].id).isEqualTo(hoverEnterId)
126
127 val down =
128 MotionEvent(
129 1,
130 ACTION_DOWN,
131 1,
132 0,
133 arrayOf(PointerProperties(1, TOOL_TYPE_MOUSE)),
134 arrayOf(PointerCoords(10f, 10f))
135 )
136
137 val downEvent = motionEventAdapter.convertToPointerInputEvent(down)!!
138 assertThat(downEvent.pointers).hasSize(1)
139 assertThat(downEvent.pointers[0].id).isEqualTo(hoverEnterId)
140
141 val up =
142 MotionEvent(
143 2,
144 ACTION_UP,
145 1,
146 0,
147 arrayOf(PointerProperties(1, TOOL_TYPE_MOUSE)),
148 arrayOf(PointerCoords(10f, 10f))
149 )
150
151 val upEvent = motionEventAdapter.convertToPointerInputEvent(up)!!
152 assertThat(upEvent.pointers).hasSize(1)
153 assertThat(upEvent.pointers[0].id).isEqualTo(hoverEnterId)
154
155 val hoverEnterEvent2 = motionEventAdapter.convertToPointerInputEvent(hoverEnter)!!
156 assertThat(hoverEnterEvent2.pointers).hasSize(1)
157 assertThat(hoverEnterEvent2.pointers[0].id).isEqualTo(hoverEnterId)
158 motionEventAdapter.convertToPointerInputEvent(hoverExit)!!
159
160 val touchDown =
161 MotionEvent(
162 3,
163 ACTION_DOWN,
164 1,
165 0,
166 arrayOf(PointerProperties(1, TOOL_TYPE_FINGER)),
167 arrayOf(PointerCoords(10f, 10f))
168 )
169 val touchDownEvent = motionEventAdapter.convertToPointerInputEvent(touchDown)!!
170 assertThat(touchDownEvent.pointers).hasSize(1)
171 assertThat(touchDownEvent.pointers[0].id).isNotEqualTo(hoverEnterId)
172 val touchDownId = touchDownEvent.pointers[0].id
173
174 val touchUp =
175 MotionEvent(
176 4,
177 ACTION_UP,
178 1,
179 0,
180 arrayOf(PointerProperties(1, TOOL_TYPE_FINGER)),
181 arrayOf(PointerCoords(10f, 10f))
182 )
183 val touchUpEvent = motionEventAdapter.convertToPointerInputEvent(touchUp)!!
184 assertThat(touchUpEvent.pointers).hasSize(1)
185 assertThat(touchUpEvent.pointers[0].id).isEqualTo(touchDownEvent.pointers[0].id)
186
187 val hoverEnterEvent3 = motionEventAdapter.convertToPointerInputEvent(hoverEnter)!!
188 assertThat(hoverEnterEvent3.pointers).hasSize(1)
189 assertThat(hoverEnterEvent3.pointers[0].id).isNotEqualTo(touchDownId)
190 assertThat(hoverEnterEvent3.pointers[0].id).isNotEqualTo(hoverEnterId)
191 }
192
193 @Test
194 fun robustIdConversion() {
195 // When an ID shows up unexpectedly, it shouldn't crash
196 val hoverExit =
197 MotionEvent(
198 3,
199 ACTION_HOVER_EXIT,
200 1,
201 0,
202 arrayOf(PointerProperties(1, TOOL_TYPE_MOUSE)),
203 arrayOf(PointerCoords(10f, 10f))
204 )
205 val event = motionEventAdapter.convertToPointerInputEvent(hoverExit)!!
206 assertThat(event.pointers).hasSize(1)
207 }
208
209 @Test
210 fun convertToPointerInputEvent_1pointerActionDown_convertsCorrectly() {
211 val motionEvent =
212 MotionEvent(
213 2894,
214 ACTION_DOWN,
215 1,
216 0,
217 arrayOf(PointerProperties(8290)),
218 arrayOf(PointerCoords(2967f, 5928f))
219 )
220
221 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
222 assertThat(pointerInputEvent).isNotNull()
223
224 val uptime = pointerInputEvent!!.uptime
225 val pointers = pointerInputEvent.pointers
226 val platformEvent = pointerInputEvent.motionEvent
227 assertThat(uptime).isEqualTo(2_894L)
228 assertThat(pointers).hasSize(1)
229 assertPointerInputEventData(pointers[0], PointerId(0), true, 2967f, 5928f)
230 assertThat(platformEvent).isSameInstanceAs(motionEvent)
231 }
232
233 @Test
234 fun convertToPointerInputEvent_1pointerActionMove_convertsCorrectly() {
235 motionEventAdapter.convertToPointerInputEvent(
236 MotionEvent(
237 1,
238 ACTION_DOWN,
239 1,
240 0,
241 arrayOf(PointerProperties(2)),
242 arrayOf(PointerCoords(3f, 4f))
243 )
244 )
245 val motionEvent =
246 MotionEvent(
247 5,
248 ACTION_MOVE,
249 1,
250 0,
251 arrayOf(PointerProperties(2)),
252 arrayOf(PointerCoords(6f, 7f))
253 )
254
255 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
256 assertThat(pointerInputEvent).isNotNull()
257
258 val uptime = pointerInputEvent!!.uptime
259 val pointers = pointerInputEvent.pointers
260 assertThat(uptime).isEqualTo(5L)
261 assertThat(pointers).hasSize(1)
262 assertPointerInputEventData(pointers[0], PointerId(0), true, 6f, 7f)
263 }
264
265 @Test
266 fun convertToPointerInputEvent_1pointerActionUp_convertsCorrectly() {
267 motionEventAdapter.convertToPointerInputEvent(
268 MotionEvent(
269 10,
270 ACTION_DOWN,
271 1,
272 0,
273 arrayOf(PointerProperties(46)),
274 arrayOf(PointerCoords(3f, 4f))
275 )
276 )
277 val motionEvent =
278 MotionEvent(
279 34,
280 ACTION_UP,
281 1,
282 0,
283 arrayOf(PointerProperties(46)),
284 arrayOf(PointerCoords(3f, 4f))
285 )
286
287 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
288 assertThat(pointerInputEvent).isNotNull()
289
290 val uptime = pointerInputEvent!!.uptime
291 val pointers = pointerInputEvent.pointers
292 assertThat(uptime).isEqualTo(34L)
293 assertThat(uptime).isEqualTo(34L)
294 assertThat(pointers).hasSize(1)
295 assertPointerInputEventData(pointers[0], PointerId(0), false, 3f, 4f)
296 }
297
298 @Test
299 fun convertToPointerInputEvent_2pointers1stPointerActionPointerDown_convertsCorrectly() {
300 motionEventAdapter.convertToPointerInputEvent(
301 MotionEvent(
302 1,
303 ACTION_DOWN,
304 1,
305 0,
306 arrayOf(PointerProperties(2)),
307 arrayOf(PointerCoords(3f, 4f))
308 )
309 )
310 val motionEvent =
311 MotionEvent(
312 4,
313 ACTION_POINTER_DOWN,
314 2,
315 0,
316 arrayOf(PointerProperties(5), PointerProperties(2)),
317 arrayOf(PointerCoords(7f, 8f), PointerCoords(3f, 4f))
318 )
319
320 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
321 assertThat(pointerInputEvent).isNotNull()
322
323 val uptime = pointerInputEvent!!.uptime
324 val pointers = pointerInputEvent.pointers
325 assertThat(uptime).isEqualTo(4L)
326 assertThat(pointers).hasSize(2)
327 assertPointerInputEventData(pointers[0], PointerId(1), true, 7f, 8f)
328 assertPointerInputEventData(pointers[1], PointerId(0), true, 3f, 4f)
329 }
330
331 @Test
332 fun convertToPointerInputEvent_2pointers2ndPointerActionPointerDown_convertsCorrectly() {
333 motionEventAdapter.convertToPointerInputEvent(
334 MotionEvent(
335 1,
336 ACTION_DOWN,
337 1,
338 0,
339 arrayOf(PointerProperties(2)),
340 arrayOf(PointerCoords(3f, 4f))
341 )
342 )
343 val motionEvent =
344 MotionEvent(
345 4,
346 ACTION_POINTER_DOWN,
347 2,
348 1,
349 arrayOf(PointerProperties(2), PointerProperties(5)),
350 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f))
351 )
352
353 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
354 assertThat(pointerInputEvent).isNotNull()
355
356 val uptime = pointerInputEvent!!.uptime
357 val pointers = pointerInputEvent.pointers
358 assertThat(uptime).isEqualTo(4L)
359 assertThat(pointers).hasSize(2)
360 assertPointerInputEventData(pointers[0], PointerId(0), true, 3f, 4f)
361 assertPointerInputEventData(pointers[1], PointerId(1), true, 7f, 8f)
362 }
363
364 @Test
365 fun convertToPointerInputEvent_3pointers1stPointerActionPointerDown_convertsCorrectly() {
366 motionEventAdapter.convertToPointerInputEvent(
367 MotionEvent(
368 1,
369 ACTION_DOWN,
370 1,
371 0,
372 arrayOf(PointerProperties(2)),
373 arrayOf(PointerCoords(3f, 4f))
374 )
375 )
376 motionEventAdapter.convertToPointerInputEvent(
377 MotionEvent(
378 4,
379 ACTION_POINTER_DOWN,
380 2,
381 1,
382 arrayOf(PointerProperties(2), PointerProperties(5)),
383 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f))
384 )
385 )
386 val motionEvent =
387 MotionEvent(
388 12,
389 ACTION_POINTER_DOWN,
390 3,
391 0,
392 arrayOf(PointerProperties(9), PointerProperties(2), PointerProperties(5)),
393 arrayOf(PointerCoords(10f, 11f), PointerCoords(3f, 4f), PointerCoords(7f, 8f))
394 )
395
396 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
397 assertThat(pointerInputEvent).isNotNull()
398
399 val uptime = pointerInputEvent!!.uptime
400 val pointers = pointerInputEvent.pointers
401 assertThat(uptime).isEqualTo(12L)
402 assertThat(pointers).hasSize(3)
403 assertPointerInputEventData(pointers[0], PointerId(2), true, 10f, 11f)
404 assertPointerInputEventData(pointers[1], PointerId(0), true, 3f, 4f)
405 assertPointerInputEventData(pointers[2], PointerId(1), true, 7f, 8f)
406 }
407
408 @Test
409 fun convertToPointerInputEvent_3pointers2ndPointerActionPointerDown_convertsCorrectly() {
410 motionEventAdapter.convertToPointerInputEvent(
411 MotionEvent(
412 1,
413 ACTION_DOWN,
414 1,
415 0,
416 arrayOf(PointerProperties(2)),
417 arrayOf(PointerCoords(3f, 4f))
418 )
419 )
420 motionEventAdapter.convertToPointerInputEvent(
421 MotionEvent(
422 4,
423 ACTION_POINTER_DOWN,
424 2,
425 1,
426 arrayOf(PointerProperties(2), PointerProperties(5)),
427 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f))
428 )
429 )
430 val motionEvent =
431 MotionEvent(
432 12,
433 ACTION_POINTER_DOWN,
434 3,
435 1,
436 arrayOf(PointerProperties(2), PointerProperties(9), PointerProperties(5)),
437 arrayOf(PointerCoords(3f, 4f), PointerCoords(10f, 11f), PointerCoords(7f, 8f))
438 )
439
440 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
441 assertThat(pointerInputEvent).isNotNull()
442
443 val uptime = pointerInputEvent!!.uptime
444 val pointers = pointerInputEvent.pointers
445 assertThat(uptime).isEqualTo(12L)
446 assertThat(pointers).hasSize(3)
447 assertPointerInputEventData(pointers[0], PointerId(0), true, 3f, 4f)
448 assertPointerInputEventData(pointers[1], PointerId(2), true, 10f, 11f)
449 assertPointerInputEventData(pointers[2], PointerId(1), true, 7f, 8f)
450 }
451
452 @Test
453 fun convertToPointerInputEvent_3pointers3rdPointerActionPointerDown_convertsCorrectly() {
454 motionEventAdapter.convertToPointerInputEvent(
455 MotionEvent(
456 1,
457 ACTION_DOWN,
458 1,
459 0,
460 arrayOf(PointerProperties(2)),
461 arrayOf(PointerCoords(3f, 4f))
462 )
463 )
464 motionEventAdapter.convertToPointerInputEvent(
465 MotionEvent(
466 4,
467 ACTION_POINTER_DOWN,
468 2,
469 1,
470 arrayOf(PointerProperties(2), PointerProperties(5)),
471 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f))
472 )
473 )
474 val motionEvent =
475 MotionEvent(
476 12,
477 ACTION_POINTER_DOWN,
478 3,
479 2,
480 arrayOf(PointerProperties(2), PointerProperties(5), PointerProperties(9)),
481 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f), PointerCoords(10f, 11f))
482 )
483
484 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
485 assertThat(pointerInputEvent).isNotNull()
486
487 val uptime = pointerInputEvent!!.uptime
488 val pointers = pointerInputEvent.pointers
489 assertThat(uptime).isEqualTo(12L)
490 assertThat(pointers).hasSize(3)
491 assertPointerInputEventData(pointers[0], PointerId(0), true, 3f, 4f)
492 assertPointerInputEventData(pointers[1], PointerId(1), true, 7f, 8f)
493 assertPointerInputEventData(pointers[2], PointerId(2), true, 10f, 11f)
494 }
495
496 @Test
497 fun convertToPointerInputEvent_2pointersActionMove_convertsCorrectly() {
498 motionEventAdapter.convertToPointerInputEvent(
499 MotionEvent(
500 1,
501 ACTION_DOWN,
502 1,
503 0,
504 arrayOf(PointerProperties(2)),
505 arrayOf(PointerCoords(3f, 4f))
506 )
507 )
508 motionEventAdapter.convertToPointerInputEvent(
509 MotionEvent(
510 4,
511 ACTION_POINTER_DOWN,
512 2,
513 1,
514 arrayOf(PointerProperties(2), PointerProperties(5)),
515 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f))
516 )
517 )
518 val motionEvent =
519 MotionEvent(
520 10,
521 ACTION_MOVE,
522 2,
523 0,
524 arrayOf(PointerProperties(2), PointerProperties(5)),
525 arrayOf(PointerCoords(11f, 12f), PointerCoords(13f, 15f))
526 )
527
528 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
529 assertThat(pointerInputEvent).isNotNull()
530
531 val uptime = pointerInputEvent!!.uptime
532 val pointers = pointerInputEvent.pointers
533 assertThat(uptime).isEqualTo(10L)
534 assertThat(pointers).hasSize(2)
535 assertPointerInputEventData(pointers[0], PointerId(0), true, 11f, 12f)
536 assertPointerInputEventData(pointers[1], PointerId(1), true, 13f, 15f)
537 }
538
539 @Test
540 fun convertToPointerInputEvent_2pointers1stPointerActionPointerUP_convertsCorrectly() {
541 motionEventAdapter.convertToPointerInputEvent(
542 MotionEvent(
543 1,
544 ACTION_DOWN,
545 1,
546 0,
547 arrayOf(PointerProperties(2)),
548 arrayOf(PointerCoords(3f, 4f))
549 )
550 )
551 motionEventAdapter.convertToPointerInputEvent(
552 MotionEvent(
553 4,
554 ACTION_POINTER_DOWN,
555 2,
556 1,
557 arrayOf(PointerProperties(2), PointerProperties(5)),
558 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f))
559 )
560 )
561
562 val motionEvent =
563 MotionEvent(
564 10,
565 ACTION_POINTER_UP,
566 2,
567 0,
568 arrayOf(PointerProperties(2), PointerProperties(5)),
569 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f))
570 )
571 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
572 assertThat(pointerInputEvent).isNotNull()
573
574 val uptime = pointerInputEvent!!.uptime
575 val pointers = pointerInputEvent.pointers
576 assertThat(uptime).isEqualTo(10L)
577 assertThat(pointers).hasSize(2)
578 assertPointerInputEventData(pointers[0], PointerId(0), false, 3f, 4f)
579 assertPointerInputEventData(pointers[1], PointerId(1), true, 7f, 8f)
580 }
581
582 @Test
583 fun convertToPointerInputEvent_2pointers2ndPointerActionPointerUp_convertsCorrectly() {
584 motionEventAdapter.convertToPointerInputEvent(
585 MotionEvent(
586 1,
587 ACTION_DOWN,
588 1,
589 0,
590 arrayOf(PointerProperties(2)),
591 arrayOf(PointerCoords(3f, 4f))
592 )
593 )
594 motionEventAdapter.convertToPointerInputEvent(
595 MotionEvent(
596 4,
597 ACTION_POINTER_DOWN,
598 2,
599 1,
600 arrayOf(PointerProperties(2), PointerProperties(5)),
601 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f))
602 )
603 )
604
605 val motionEvent =
606 MotionEvent(
607 10,
608 ACTION_POINTER_UP,
609 2,
610 1,
611 arrayOf(PointerProperties(2), PointerProperties(5)),
612 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f))
613 )
614 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
615 assertThat(pointerInputEvent).isNotNull()
616
617 val uptime = pointerInputEvent!!.uptime
618 val pointers = pointerInputEvent.pointers
619 assertThat(uptime).isEqualTo(10L)
620 assertThat(pointers).hasSize(2)
621 assertPointerInputEventData(pointers[0], PointerId(0), true, 3f, 4f)
622 assertPointerInputEventData(pointers[1], PointerId(1), false, 7f, 8f)
623 }
624
625 @Test
626 fun convertToPointerInputEvent_3pointers1stPointerActionPointerUp_convertsCorrectly() {
627 motionEventAdapter.convertToPointerInputEvent(
628 MotionEvent(
629 1,
630 ACTION_DOWN,
631 1,
632 0,
633 arrayOf(PointerProperties(2)),
634 arrayOf(PointerCoords(3f, 4f))
635 )
636 )
637 motionEventAdapter.convertToPointerInputEvent(
638 MotionEvent(
639 4,
640 ACTION_POINTER_DOWN,
641 2,
642 1,
643 arrayOf(PointerProperties(2), PointerProperties(5)),
644 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f))
645 )
646 )
647 motionEventAdapter.convertToPointerInputEvent(
648 MotionEvent(
649 12,
650 ACTION_POINTER_DOWN,
651 3,
652 2,
653 arrayOf(PointerProperties(2), PointerProperties(5), PointerProperties(9)),
654 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f), PointerCoords(10f, 11f))
655 )
656 )
657
658 val motionEvent =
659 MotionEvent(
660 20,
661 ACTION_POINTER_UP,
662 3,
663 0,
664 arrayOf(PointerProperties(2), PointerProperties(5), PointerProperties(9)),
665 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f), PointerCoords(10f, 11f))
666 )
667
668 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
669 assertThat(pointerInputEvent).isNotNull()
670
671 val uptime = pointerInputEvent!!.uptime
672 val pointers = pointerInputEvent.pointers
673 assertThat(uptime).isEqualTo(20L)
674 assertThat(pointers).hasSize(3)
675 assertPointerInputEventData(pointers[0], PointerId(0), false, 3f, 4f)
676 assertPointerInputEventData(pointers[1], PointerId(1), true, 7f, 8f)
677 assertPointerInputEventData(pointers[2], PointerId(2), true, 10f, 11f)
678 }
679
680 @Test
681 fun convertToPointerInputEvent_3pointers2ndPointerActionPointerUp_convertsCorrectly() {
682 motionEventAdapter.convertToPointerInputEvent(
683 MotionEvent(
684 1,
685 ACTION_DOWN,
686 1,
687 0,
688 arrayOf(PointerProperties(2)),
689 arrayOf(PointerCoords(3f, 4f))
690 )
691 )
692 motionEventAdapter.convertToPointerInputEvent(
693 MotionEvent(
694 4,
695 ACTION_POINTER_DOWN,
696 2,
697 1,
698 arrayOf(PointerProperties(2), PointerProperties(5)),
699 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f))
700 )
701 )
702 motionEventAdapter.convertToPointerInputEvent(
703 MotionEvent(
704 12,
705 ACTION_POINTER_DOWN,
706 3,
707 2,
708 arrayOf(PointerProperties(2), PointerProperties(5), PointerProperties(9)),
709 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f), PointerCoords(10f, 11f))
710 )
711 )
712
713 val motionEvent =
714 MotionEvent(
715 20,
716 ACTION_POINTER_UP,
717 3,
718 1,
719 arrayOf(PointerProperties(2), PointerProperties(5), PointerProperties(9)),
720 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f), PointerCoords(10f, 11f))
721 )
722
723 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
724 assertThat(pointerInputEvent).isNotNull()
725
726 val uptime = pointerInputEvent!!.uptime
727 val pointers = pointerInputEvent.pointers
728 assertThat(uptime).isEqualTo(20L)
729 assertThat(pointers).hasSize(3)
730 assertPointerInputEventData(pointers[0], PointerId(0), true, 3f, 4f)
731 assertPointerInputEventData(pointers[1], PointerId(1), false, 7f, 8f)
732 assertPointerInputEventData(pointers[2], PointerId(2), true, 10f, 11f)
733 }
734
735 @Test
736 fun convertToPointerInputEvent_3pointers3rdPointerActionPointerUp_convertsCorrectly() {
737 motionEventAdapter.convertToPointerInputEvent(
738 MotionEvent(
739 1,
740 ACTION_DOWN,
741 1,
742 0,
743 arrayOf(PointerProperties(2)),
744 arrayOf(PointerCoords(3f, 4f))
745 )
746 )
747 motionEventAdapter.convertToPointerInputEvent(
748 MotionEvent(
749 4,
750 ACTION_POINTER_DOWN,
751 2,
752 1,
753 arrayOf(PointerProperties(2), PointerProperties(5)),
754 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f))
755 )
756 )
757 motionEventAdapter.convertToPointerInputEvent(
758 MotionEvent(
759 12,
760 ACTION_POINTER_DOWN,
761 3,
762 2,
763 arrayOf(PointerProperties(2), PointerProperties(5), PointerProperties(9)),
764 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f), PointerCoords(10f, 11f))
765 )
766 )
767
768 val motionEvent =
769 MotionEvent(
770 20,
771 ACTION_POINTER_UP,
772 3,
773 2,
774 arrayOf(PointerProperties(2), PointerProperties(5), PointerProperties(9)),
775 arrayOf(PointerCoords(3f, 4f), PointerCoords(7f, 8f), PointerCoords(10f, 11f))
776 )
777
778 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
779 assertThat(pointerInputEvent).isNotNull()
780
781 val uptime = pointerInputEvent!!.uptime
782 val pointers = pointerInputEvent.pointers
783 assertThat(uptime).isEqualTo(20L)
784 assertThat(pointers).hasSize(3)
785 assertPointerInputEventData(pointers[0], PointerId(0), true, 3f, 4f)
786 assertPointerInputEventData(pointers[1], PointerId(1), true, 7f, 8f)
787 assertPointerInputEventData(pointers[2], PointerId(2), false, 10f, 11f)
788 }
789
790 @Test
791 fun convertToPointerInputEvent_downUpDownUpDownUpSameMotionEventId_pointerIdsAreUnique() {
792 val down1 =
793 MotionEvent(
794 100,
795 ACTION_DOWN,
796 1,
797 0,
798 arrayOf(PointerProperties(0)),
799 arrayOf(PointerCoords(10f, 11f))
800 )
801
802 val up1 =
803 MotionEvent(
804 200,
805 ACTION_UP,
806 1,
807 0,
808 arrayOf(PointerProperties(0)),
809 arrayOf(PointerCoords(10f, 11f))
810 )
811
812 val down2 =
813 MotionEvent(
814 300,
815 ACTION_DOWN,
816 1,
817 0,
818 arrayOf(PointerProperties(0)),
819 arrayOf(PointerCoords(20f, 21f))
820 )
821
822 val up2 =
823 MotionEvent(
824 400,
825 ACTION_UP,
826 1,
827 0,
828 arrayOf(PointerProperties(0)),
829 arrayOf(PointerCoords(20f, 21f))
830 )
831
832 val down3 =
833 MotionEvent(
834 500,
835 ACTION_DOWN,
836 1,
837 0,
838 arrayOf(PointerProperties(0)),
839 arrayOf(PointerCoords(30f, 31f))
840 )
841
842 val up3 =
843 MotionEvent(
844 600,
845 ACTION_UP,
846 1,
847 0,
848 arrayOf(PointerProperties(0)),
849 arrayOf(PointerCoords(30f, 31f))
850 )
851
852 // Test the different events sequentially, since the returned event contains a list that
853 // will be reused by convertToPointerInputEvent for performance, so it shouldn't be held
854 // for longer than needed during the sequential dispatch.
855
856 val pointerInputEventDown1 = motionEventAdapter.convertToPointerInputEvent(down1)
857 assertThat(pointerInputEventDown1).isNotNull()
858 assertThat(pointerInputEventDown1!!.pointers[0].id).isEqualTo(PointerId(0))
859
860 val pointerInputEventUp1 = motionEventAdapter.convertToPointerInputEvent(up1)
861 assertThat(pointerInputEventUp1).isNotNull()
862 assertThat(pointerInputEventUp1!!.pointers[0].id).isEqualTo(PointerId(0))
863
864 val pointerInputEventDown2 = motionEventAdapter.convertToPointerInputEvent(down2)
865 assertThat(pointerInputEventDown2).isNotNull()
866 assertThat(pointerInputEventDown2!!.pointers[0].id).isEqualTo(PointerId(1))
867
868 val pointerInputEventUp2 = motionEventAdapter.convertToPointerInputEvent(up2)
869 assertThat(pointerInputEventUp2).isNotNull()
870 assertThat(pointerInputEventUp2!!.pointers[0].id).isEqualTo(PointerId(1))
871
872 val pointerInputEventDown3 = motionEventAdapter.convertToPointerInputEvent(down3)
873 assertThat(pointerInputEventDown3).isNotNull()
874 assertThat(pointerInputEventDown3!!.pointers[0].id).isEqualTo(PointerId(2))
875
876 val pointerInputEventUp3 = motionEventAdapter.convertToPointerInputEvent(up3)
877 assertThat(pointerInputEventUp3).isNotNull()
878 assertThat(pointerInputEventUp3!!.pointers[0].id).isEqualTo(PointerId(2))
879 }
880
881 @Test
882 fun convertToPointerInputEvent_downDownDownRandomMotionEventIds_pointerIdsAreUnique() {
883 val down1 =
884 MotionEvent(
885 100,
886 ACTION_DOWN,
887 1,
888 0,
889 arrayOf(PointerProperties(9276)),
890 arrayOf(PointerCoords(10f, 11f))
891 )
892
893 val down2 =
894 MotionEvent(
895 200,
896 ACTION_POINTER_DOWN,
897 2,
898 1,
899 arrayOf(PointerProperties(9276), PointerProperties(1759)),
900 arrayOf(PointerCoords(10f, 11f), PointerCoords(20f, 21f))
901 )
902
903 val down3 =
904 MotionEvent(
905 300,
906 ACTION_POINTER_DOWN,
907 3,
908 2,
909 arrayOf(PointerProperties(9276), PointerProperties(1759), PointerProperties(5043)),
910 arrayOf(PointerCoords(10f, 11f), PointerCoords(20f, 21f), PointerCoords(30f, 31f))
911 )
912
913 // Test the different events sequentially, since the returned event contains a list that
914 // will be reused by convertToPointerInputEvent for performance, so it shouldn't be held
915 // for longer than needed during the sequential dispatch.
916
917 val pointerInputEventDown1 = motionEventAdapter.convertToPointerInputEvent(down1)
918
919 assertThat(pointerInputEventDown1).isNotNull()
920 assertThat(pointerInputEventDown1!!.pointers).hasSize(1)
921 assertThat(pointerInputEventDown1.pointers[0].id).isEqualTo(PointerId(0))
922
923 val pointerInputEventDown2 = motionEventAdapter.convertToPointerInputEvent(down2)
924
925 assertThat(pointerInputEventDown2).isNotNull()
926 assertThat(pointerInputEventDown2!!.pointers).hasSize(2)
927 assertThat(pointerInputEventDown2.pointers[0].id).isEqualTo(PointerId(0))
928 assertThat(pointerInputEventDown2.pointers[1].id).isEqualTo(PointerId(1))
929
930 val pointerInputEventDown3 = motionEventAdapter.convertToPointerInputEvent(down3)
931
932 assertThat(pointerInputEventDown3).isNotNull()
933 assertThat(pointerInputEventDown3!!.pointers).hasSize(3)
934 assertThat(pointerInputEventDown2.pointers[0].id).isEqualTo(PointerId(0))
935 assertThat(pointerInputEventDown2.pointers[1].id).isEqualTo(PointerId(1))
936 assertThat(pointerInputEventDown3.pointers[2].id).isEqualTo(PointerId(2))
937 }
938
939 @Test
940 fun convertToPointerInputEvent_motionEventOffset_usesRawCoordinatesInsteadOfOffset() {
941 val motionEvent =
942 MotionEvent(
943 0,
944 ACTION_DOWN,
945 1,
946 0,
947 arrayOf(PointerProperties(0)),
948 arrayOf(PointerCoords(1f, 2f))
949 )
950
951 motionEvent.offsetLocation(10f, 20f)
952
953 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
954 assertThat(pointerInputEvent).isNotNull()
955
956 val uptime = pointerInputEvent!!.uptime
957 val pointers = pointerInputEvent.pointers
958 assertThat(uptime).isEqualTo(0L)
959 assertThat(pointers).hasSize(1)
960 assertPointerInputEventData(
961 pointers[0],
962 PointerId(0),
963 true,
964 1f,
965 2f,
966 originalX = 11f,
967 originalY = 22f
968 )
969 }
970
971 @Test
972 fun convertToPointerInputEvent_actionCancel_returnsNull() {
973 val motionEvent =
974 MotionEvent(
975 0,
976 ACTION_CANCEL,
977 1,
978 0,
979 arrayOf(PointerProperties(0)),
980 arrayOf(PointerCoords(1f, 2f))
981 )
982
983 motionEvent.offsetLocation(10f, 20f)
984
985 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
986 assertThat(pointerInputEvent).isNull()
987 }
988
989 @Test
990 fun convertToPointerInputEvent_downUp_noPointersTracked() {
991 val motionEvent1 =
992 MotionEvent(
993 2894,
994 ACTION_DOWN,
995 1,
996 0,
997 arrayOf(PointerProperties(8290)),
998 arrayOf(PointerCoords(2967f, 5928f))
999 )
1000 val motionEvent2 =
1001 MotionEvent(
1002 2894,
1003 ACTION_UP,
1004 1,
1005 0,
1006 arrayOf(PointerProperties(8290)),
1007 arrayOf(PointerCoords(2967f, 5928f))
1008 )
1009
1010 motionEventAdapter.convertToPointerInputEvent(motionEvent1)
1011 motionEventAdapter.convertToPointerInputEvent(motionEvent2)
1012
1013 assertThat(motionEventAdapter.motionEventToComposePointerIdMap.size()).isEqualTo(0)
1014 }
1015
1016 @Test
1017 fun convertToPointerInputEvent_downDown_correctPointersTracked() {
1018 val motionEvent1 =
1019 MotionEvent(
1020 1,
1021 ACTION_DOWN,
1022 1,
1023 0,
1024 arrayOf(PointerProperties(2)),
1025 arrayOf(PointerCoords(3f, 4f))
1026 )
1027 val motionEvent2 =
1028 MotionEvent(
1029 4,
1030 ACTION_POINTER_DOWN,
1031 2,
1032 0,
1033 arrayOf(PointerProperties(5), PointerProperties(2)),
1034 arrayOf(PointerCoords(7f, 8f), PointerCoords(3f, 4f))
1035 )
1036
1037 motionEventAdapter.convertToPointerInputEvent(motionEvent1)
1038 motionEventAdapter.convertToPointerInputEvent(motionEvent2)
1039
1040 assertThat(motionEventAdapter.motionEventToComposePointerIdMap.toMap())
1041 .containsExactlyEntriesIn(mapOf(2 to PointerId(0), 5 to PointerId(1)))
1042 }
1043
1044 @Test
1045 fun convertToPointerInputEvent_downDownFirstUp_correctPointerTracked() {
1046 val motionEvent1 =
1047 MotionEvent(
1048 1,
1049 ACTION_DOWN,
1050 1,
1051 0,
1052 arrayOf(PointerProperties(2)),
1053 arrayOf(PointerCoords(3f, 4f))
1054 )
1055 val motionEvent2 =
1056 MotionEvent(
1057 4,
1058 ACTION_POINTER_DOWN,
1059 2,
1060 0,
1061 arrayOf(PointerProperties(5), PointerProperties(2)),
1062 arrayOf(PointerCoords(7f, 8f), PointerCoords(3f, 4f))
1063 )
1064 val motionEvent3 =
1065 MotionEvent(
1066 10,
1067 ACTION_POINTER_UP,
1068 2,
1069 0,
1070 arrayOf(PointerProperties(5), PointerProperties(2)),
1071 arrayOf(PointerCoords(7f, 8f), PointerCoords(3f, 4f))
1072 )
1073
1074 motionEventAdapter.convertToPointerInputEvent(motionEvent1)
1075 motionEventAdapter.convertToPointerInputEvent(motionEvent2)
1076 motionEventAdapter.convertToPointerInputEvent(motionEvent3)
1077
1078 assertThat(motionEventAdapter.motionEventToComposePointerIdMap.toMap())
1079 .containsExactlyEntriesIn(mapOf(2 to PointerId(0)))
1080 }
1081
1082 @Test
1083 fun convertToPointerInputEvent_downDownSecondUp_correctPointerTracked() {
1084 val motionEvent1 =
1085 MotionEvent(
1086 1,
1087 ACTION_DOWN,
1088 1,
1089 0,
1090 arrayOf(PointerProperties(2)),
1091 arrayOf(PointerCoords(3f, 4f))
1092 )
1093 val motionEvent2 =
1094 MotionEvent(
1095 4,
1096 ACTION_POINTER_DOWN,
1097 2,
1098 0,
1099 arrayOf(PointerProperties(5), PointerProperties(2)),
1100 arrayOf(PointerCoords(7f, 8f), PointerCoords(3f, 4f))
1101 )
1102 val motionEvent3 =
1103 MotionEvent(
1104 10,
1105 ACTION_POINTER_UP,
1106 2,
1107 1,
1108 arrayOf(PointerProperties(5), PointerProperties(2)),
1109 arrayOf(PointerCoords(7f, 8f), PointerCoords(3f, 4f))
1110 )
1111
1112 motionEventAdapter.convertToPointerInputEvent(motionEvent1)
1113 motionEventAdapter.convertToPointerInputEvent(motionEvent2)
1114 motionEventAdapter.convertToPointerInputEvent(motionEvent3)
1115
1116 assertThat(motionEventAdapter.motionEventToComposePointerIdMap.toMap())
1117 .containsExactlyEntriesIn(mapOf(5 to PointerId(1)))
1118 }
1119
1120 @Test
1121 fun convertToPointerInputEvent_downDownUpUp_noPointersTracked() {
1122 val motionEvent1 =
1123 MotionEvent(
1124 1,
1125 ACTION_DOWN,
1126 1,
1127 0,
1128 arrayOf(PointerProperties(2)),
1129 arrayOf(PointerCoords(3f, 4f))
1130 )
1131 val motionEvent2 =
1132 MotionEvent(
1133 4,
1134 ACTION_POINTER_DOWN,
1135 2,
1136 0,
1137 arrayOf(PointerProperties(5), PointerProperties(2)),
1138 arrayOf(PointerCoords(7f, 8f), PointerCoords(3f, 4f))
1139 )
1140 val motionEvent3 =
1141 MotionEvent(
1142 10,
1143 ACTION_POINTER_UP,
1144 2,
1145 0,
1146 arrayOf(PointerProperties(5), PointerProperties(2)),
1147 arrayOf(PointerCoords(7f, 8f), PointerCoords(3f, 4f))
1148 )
1149 val motionEvent4 =
1150 MotionEvent(
1151 20,
1152 ACTION_UP,
1153 1,
1154 0,
1155 arrayOf(PointerProperties(2)),
1156 arrayOf(PointerCoords(3f, 4f))
1157 )
1158
1159 motionEventAdapter.convertToPointerInputEvent(motionEvent1)
1160 motionEventAdapter.convertToPointerInputEvent(motionEvent2)
1161 motionEventAdapter.convertToPointerInputEvent(motionEvent3)
1162 motionEventAdapter.convertToPointerInputEvent(motionEvent4)
1163
1164 assertThat(motionEventAdapter.motionEventToComposePointerIdMap.toMap()).isEmpty()
1165 }
1166
1167 @Test
1168 fun convertToPointerInputEvent_downCancel_noPointersTracked() {
1169 val motionEvent1 =
1170 MotionEvent(
1171 1,
1172 ACTION_DOWN,
1173 1,
1174 0,
1175 arrayOf(PointerProperties(2)),
1176 arrayOf(PointerCoords(3f, 4f))
1177 )
1178 val motionEvent2 =
1179 MotionEvent(
1180 4,
1181 ACTION_POINTER_DOWN,
1182 2,
1183 0,
1184 arrayOf(PointerProperties(5), PointerProperties(2)),
1185 arrayOf(PointerCoords(7f, 8f), PointerCoords(3f, 4f))
1186 )
1187 val motionEvent3 =
1188 MotionEvent(
1189 10,
1190 ACTION_CANCEL,
1191 2,
1192 0,
1193 arrayOf(PointerProperties(5), PointerProperties(2)),
1194 arrayOf(PointerCoords(7f, 8f), PointerCoords(3f, 4f))
1195 )
1196 motionEventAdapter.convertToPointerInputEvent(motionEvent1)
1197 motionEventAdapter.convertToPointerInputEvent(motionEvent2)
1198 motionEventAdapter.convertToPointerInputEvent(motionEvent3)
1199
1200 assertThat(motionEventAdapter.motionEventToComposePointerIdMap.toMap()).isEmpty()
1201 }
1202
1203 @Test
1204 fun convertToPointerInputEvent_doesNotSynchronouslyMutateMotionEvent() {
1205 val motionEvent =
1206 MotionEvent(
1207 1,
1208 ACTION_DOWN,
1209 1,
1210 0,
1211 arrayOf(PointerProperties(2)),
1212 arrayOf(PointerCoords(3f, 4f))
1213 )
1214 motionEvent.offsetLocation(10f, 100f)
1215
1216 motionEventAdapter.convertToPointerInputEvent(motionEvent)
1217
1218 assertThat(motionEvent.x).isEqualTo(13f)
1219 assertThat(motionEvent.y).isEqualTo(104f)
1220 }
1221
1222 @Test
1223 fun convertToPointerInputEvent_1PointerActionDown_includesMotionEvent() {
1224 val motionEvent =
1225 MotionEvent(
1226 2894,
1227 ACTION_DOWN,
1228 1,
1229 0,
1230 arrayOf(PointerProperties(8290)),
1231 arrayOf(PointerCoords(2967f, 5928f))
1232 )
1233
1234 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
1235 assertThat(pointerInputEvent).isNotNull()
1236
1237 assertThat(pointerInputEvent!!.motionEvent).isSameInstanceAs(motionEvent)
1238 }
1239
1240 @Test
1241 fun convertToPointerInputEvent_1pointerActionMove_includesMotionEvent() {
1242 motionEventAdapter.convertToPointerInputEvent(
1243 MotionEvent(
1244 1,
1245 ACTION_DOWN,
1246 1,
1247 0,
1248 arrayOf(PointerProperties(2)),
1249 arrayOf(PointerCoords(3f, 4f))
1250 )
1251 )
1252 val motionEvent =
1253 MotionEvent(
1254 5,
1255 ACTION_MOVE,
1256 1,
1257 0,
1258 arrayOf(PointerProperties(2)),
1259 arrayOf(PointerCoords(6f, 7f))
1260 )
1261
1262 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
1263 assertThat(pointerInputEvent).isNotNull()
1264
1265 assertThat(pointerInputEvent!!.motionEvent).isSameInstanceAs(motionEvent)
1266 }
1267
1268 @Test
1269 fun convertToPointerInputEvent_1pointerActionUp_includesMotionEvent() {
1270 motionEventAdapter.convertToPointerInputEvent(
1271 MotionEvent(
1272 10,
1273 ACTION_DOWN,
1274 1,
1275 0,
1276 arrayOf(PointerProperties(46)),
1277 arrayOf(PointerCoords(3f, 4f))
1278 )
1279 )
1280 val motionEvent =
1281 MotionEvent(
1282 34,
1283 ACTION_UP,
1284 1,
1285 0,
1286 arrayOf(PointerProperties(46)),
1287 arrayOf(PointerCoords(3f, 4f))
1288 )
1289
1290 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
1291 assertThat(pointerInputEvent).isNotNull()
1292
1293 assertThat(pointerInputEvent!!.motionEvent).isSameInstanceAs(motionEvent)
1294 }
1295
1296 @Test
1297 fun convertToPointerInputEvent_differentCoordinateSpace_useOriginalPointCoordinate() {
1298 motionEventAdapter.convertToPointerInputEvent(
1299 MotionEvent(
1300 10,
1301 ACTION_DOWN,
1302 1,
1303 0,
1304 arrayOf(PointerProperties(46)),
1305 arrayOf(PointerCoords(3f, 4f))
1306 )
1307 )
1308 val motionEvent =
1309 MotionEvent(
1310 34,
1311 ACTION_MOVE,
1312 1,
1313 0,
1314 arrayOf(PointerProperties(46)),
1315 arrayOf(PointerCoords(30f, 40f))
1316 )
1317
1318 val positionCalculator =
1319 object : PositionCalculator by positionCalculator {
1320 override fun screenToLocal(positionOnScreen: Offset): Offset {
1321 return positionOnScreen / 2f
1322 }
1323 }
1324
1325 val pointerInputEvent =
1326 motionEventAdapter.convertToPointerInputEvent(motionEvent, positionCalculator)
1327 assertPointerInputEventData(
1328 pointerInputEvent!!.pointers[0],
1329 PointerId(0),
1330 true,
1331 30f,
1332 40f,
1333 originalX = 30f,
1334 originalY = 40f
1335 )
1336 }
1337
1338 @Test
1339 fun convertScrollEvent_horizontalPositive() {
1340 val motionEvent =
1341 MotionEvent(
1342 eventTime = 1,
1343 action = ACTION_SCROLL,
1344 numPointers = 1,
1345 actionIndex = 0,
1346 pointerProperties = arrayOf(PointerProperties(2)),
1347 pointerCoords =
1348 arrayOf(PointerCoords(3f, 4f).apply { setAxisValue(AXIS_HSCROLL, 5f) })
1349 )
1350
1351 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
1352 assertThat(pointerInputEvent).isNotNull()
1353 assertThat(pointerInputEvent!!.pointers[0].scrollDelta).isEqualTo(Offset(5f, 0f))
1354 assertThat(pointerInputEvent.motionEvent).isSameInstanceAs(motionEvent)
1355 }
1356
1357 @Test
1358 fun convertScrollEvent_horizontalNegative() {
1359 val motionEvent =
1360 MotionEvent(
1361 eventTime = 1,
1362 action = ACTION_SCROLL,
1363 numPointers = 1,
1364 actionIndex = 0,
1365 pointerProperties = arrayOf(PointerProperties(2)),
1366 pointerCoords =
1367 arrayOf(PointerCoords(3f, 4f).apply { setAxisValue(AXIS_HSCROLL, -5f) })
1368 )
1369
1370 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
1371 assertThat(pointerInputEvent).isNotNull()
1372 assertThat(pointerInputEvent!!.pointers[0].scrollDelta).isEqualTo(Offset(-5f, 0f))
1373 assertThat(pointerInputEvent.motionEvent).isSameInstanceAs(motionEvent)
1374 }
1375
1376 @Test
1377 fun convertScrollEvent_verticalPositive() {
1378 val motionEvent =
1379 MotionEvent(
1380 eventTime = 1,
1381 action = ACTION_SCROLL,
1382 numPointers = 1,
1383 actionIndex = 0,
1384 pointerProperties = arrayOf(PointerProperties(2)),
1385 pointerCoords =
1386 arrayOf(PointerCoords(3f, 4f).apply { setAxisValue(AXIS_VSCROLL, 5f) })
1387 )
1388
1389 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
1390 assertThat(pointerInputEvent).isNotNull()
1391 // Note: y is inverted, per https://r.android.com/2071209
1392 assertThat(pointerInputEvent!!.pointers[0].scrollDelta).isEqualTo(Offset(0f, -5f))
1393 assertThat(pointerInputEvent.motionEvent).isSameInstanceAs(motionEvent)
1394 }
1395
1396 @Test
1397 fun convertScrollEvent_verticalNegative() {
1398 val motionEvent =
1399 MotionEvent(
1400 eventTime = 1,
1401 action = ACTION_SCROLL,
1402 numPointers = 1,
1403 actionIndex = 0,
1404 pointerProperties = arrayOf(PointerProperties(2)),
1405 pointerCoords =
1406 arrayOf(PointerCoords(3f, 4f).apply { setAxisValue(AXIS_VSCROLL, -5f) })
1407 )
1408
1409 val pointerInputEvent = motionEventAdapter.convertToPointerInputEvent(motionEvent)
1410 assertThat(pointerInputEvent).isNotNull()
1411 // Note: y is inverted, per https://r.android.com/2071209
1412 assertThat(pointerInputEvent!!.pointers[0].scrollDelta).isEqualTo(Offset(0f, 5f))
1413 assertThat(pointerInputEvent.motionEvent).isSameInstanceAs(motionEvent)
1414 }
1415
1416 private fun MotionEventAdapter.convertToPointerInputEvent(motionEvent: MotionEvent) =
1417 convertToPointerInputEvent(motionEvent, positionCalculator)
1418
1419 private fun SparseLongArray.toMap(): Map<Int, PointerId> {
1420 val map = mutableMapOf<Int, PointerId>()
1421 for (i in 0 until size()) {
1422 val key = keyAt(i)
1423 val value = valueAt(i)
1424 map[key] = PointerId(value)
1425 }
1426 return map
1427 }
1428 }
1429
1430 // Private helper functions
1431
MotionEventnull1432 private fun MotionEvent(
1433 eventTime: Int,
1434 action: Int,
1435 numPointers: Int,
1436 actionIndex: Int,
1437 pointerProperties: Array<MotionEvent.PointerProperties>,
1438 pointerCoords: Array<MotionEvent.PointerCoords>,
1439 downTime: Long = 0
1440 ) =
1441 MotionEvent.obtain(
1442 downTime,
1443 eventTime.toLong(),
1444 action + (actionIndex shl MotionEvent.ACTION_POINTER_INDEX_SHIFT),
1445 numPointers,
1446 pointerProperties,
1447 pointerCoords,
1448 0,
1449 0,
1450 0f,
1451 0f,
1452 0,
1453 0,
1454 InputDevice.SOURCE_TOUCHSCREEN,
1455 0
1456 )
1457
1458 private fun assertPointerInputEventData(
1459 actual: PointerInputEventData,
1460 id: PointerId,
1461 isDown: Boolean,
1462 x: Float,
1463 y: Float,
1464 type: PointerType = PointerType.Touch,
1465 originalX: Float = x,
1466 originalY: Float = y,
1467 ) {
1468 assertThat(actual.id).isEqualTo(id)
1469 assertThat(actual.down).isEqualTo(isDown)
1470 assertThat(actual.positionOnScreen.x).isEqualTo(x)
1471 assertThat(actual.positionOnScreen.y).isEqualTo(y)
1472 assertThat(actual.originalEventPosition.x).isEqualTo(originalX)
1473 assertThat(actual.originalEventPosition.y).isEqualTo(originalY)
1474 assertThat(actual.type).isEqualTo(type)
1475 }
1476