Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
MotionEventTracker.java
Go to the documentation of this file.
1package io.flutter.embedding.android;
2
3import android.util.LongSparseArray;
4import android.view.MotionEvent;
5import androidx.annotation.NonNull;
6import androidx.annotation.Nullable;
7import java.util.PriorityQueue;
8import java.util.concurrent.atomic.AtomicLong;
9
10/** Tracks the motion events received by the FlutterView. */
11public final class MotionEventTracker {
12 private static final String TAG = "MotionEventTracker";
13 /** Represents a unique identifier corresponding to a motion event. */
14 public static class MotionEventId {
15 private static final AtomicLong ID_COUNTER = new AtomicLong(0);
16 private final long id;
17
18 private MotionEventId(long id) {
19 this.id = id;
20 }
21
22 @NonNull
23 public static MotionEventId from(long id) {
24 return new MotionEventId(id);
25 }
26
27 @NonNull
28 public static MotionEventId createUnique() {
29 return MotionEventId.from(ID_COUNTER.incrementAndGet());
30 }
31
32 public long getId() {
33 return id;
34 }
35 }
36
37 private final LongSparseArray<MotionEvent> eventById;
38 private final PriorityQueue<Long> unusedEvents;
39 private static MotionEventTracker INSTANCE;
40
41 @NonNull
43 if (INSTANCE == null) {
44 INSTANCE = new MotionEventTracker();
45 }
46 return INSTANCE;
47 }
48
49 private MotionEventTracker() {
50 eventById = new LongSparseArray<>();
51 unusedEvents = new PriorityQueue<>();
52 }
53
54 /** Tracks the event and returns a unique MotionEventId identifying the event. */
55 @NonNull
56 public MotionEventId track(@NonNull MotionEvent event) {
58 // We copy event here because the original MotionEvent delivered to us
59 // will be automatically recycled (`MotionEvent.recycle`) by the RootView and we need
60 // access to it after the RootView code runs.
61 // The return value of `MotionEvent.obtain(event)` is still verifiable if the input
62 // event was verifiable. Other overloads of `MotionEvent.obtain` do not have this
63 // guarantee and should be avoided when possible.
64 MotionEvent eventCopy = MotionEvent.obtain(event);
65 eventById.put(eventId.id, eventCopy);
66 unusedEvents.add(eventId.id);
67 return eventId;
68 }
69
70 /**
71 * Returns the MotionEvent corresponding to the eventId while discarding all the motion events
72 * that occurred prior to the event represented by the eventId. Returns null if this event was
73 * popped or discarded.
74 */
75 @Nullable
76 public MotionEvent pop(@NonNull MotionEventId eventId) {
77 // remove all the older events.
78 while (!unusedEvents.isEmpty() && unusedEvents.peek() < eventId.id) {
79 eventById.remove(unusedEvents.poll());
80 }
81
82 // remove the current event from the heap if it exists.
83 if (!unusedEvents.isEmpty() && unusedEvents.peek() == eventId.id) {
84 unusedEvents.poll();
85 }
86
87 MotionEvent event = eventById.get(eventId.id);
88 eventById.remove(eventId.id);
89 return event;
90 }
91}
MotionEventId track(@NonNull MotionEvent event)
MotionEvent pop(@NonNull MotionEventId eventId)
FlKeyEvent * event
const uintptr_t id