1
1
package io .flutter .embedding .android ;
2
2
3
+ import android .graphics .Matrix ;
3
4
import android .os .Build ;
4
5
import android .view .InputDevice ;
5
6
import android .view .MotionEvent ;
@@ -69,19 +70,28 @@ public class AndroidTouchProcessor {
69
70
70
71
private static final int _POINTER_BUTTON_PRIMARY = 1 ;
71
72
73
+ private static final Matrix IDENTITY_TRANSFORM = new Matrix ();
74
+
75
+ private final boolean trackMotionEvents ;
76
+
72
77
/**
73
78
* Constructs an {@code AndroidTouchProcessor} that will send touch event data to the Flutter
74
79
* execution context represented by the given {@link FlutterRenderer}.
75
80
*/
76
81
// TODO(mattcarroll): consider moving packet behavior to a FlutterInteractionSurface instead of
77
82
// FlutterRenderer
78
- public AndroidTouchProcessor (@ NonNull FlutterRenderer renderer ) {
83
+ public AndroidTouchProcessor (@ NonNull FlutterRenderer renderer , boolean trackMotionEvents ) {
79
84
this .renderer = renderer ;
80
85
this .motionEventTracker = MotionEventTracker .getInstance ();
86
+ this .trackMotionEvents = trackMotionEvents ;
81
87
}
82
88
83
- /** Sends the given {@link MotionEvent} data to Flutter in a format that Flutter understands. */
84
89
public boolean onTouchEvent (@ NonNull MotionEvent event ) {
90
+ return onTouchEvent (event , IDENTITY_TRANSFORM );
91
+ }
92
+
93
+ /** Sends the given {@link MotionEvent} data to Flutter in a format that Flutter understands. */
94
+ public boolean onTouchEvent (@ NonNull MotionEvent event , Matrix transformMatrix ) {
85
95
int pointerCount = event .getPointerCount ();
86
96
87
97
// Prepare a data packet of the appropriate size and order.
@@ -99,26 +109,27 @@ public boolean onTouchEvent(@NonNull MotionEvent event) {
99
109
|| maskedAction == MotionEvent .ACTION_POINTER_UP );
100
110
if (updateForSinglePointer ) {
101
111
// ACTION_DOWN and ACTION_POINTER_DOWN always apply to a single pointer only.
102
- addPointerForIndex (event , event .getActionIndex (), pointerChange , 0 , packet );
112
+ addPointerForIndex (event , event .getActionIndex (), pointerChange , 0 , transformMatrix , packet );
103
113
} else if (updateForMultiplePointers ) {
104
114
// ACTION_UP and ACTION_POINTER_UP may contain position updates for other pointers.
105
115
// We are converting these updates to move events here in order to preserve this data.
106
116
// We also mark these events with a flag in order to help the framework reassemble
107
117
// the original Android event later, should it need to forward it to a PlatformView.
108
118
for (int p = 0 ; p < pointerCount ; p ++) {
109
119
if (p != event .getActionIndex () && event .getToolType (p ) == MotionEvent .TOOL_TYPE_FINGER ) {
110
- addPointerForIndex (event , p , PointerChange .MOVE , POINTER_DATA_FLAG_BATCHED , packet );
120
+ addPointerForIndex (
121
+ event , p , PointerChange .MOVE , POINTER_DATA_FLAG_BATCHED , transformMatrix , packet );
111
122
}
112
123
}
113
124
// It's important that we're sending the UP event last. This allows PlatformView
114
125
// to correctly batch everything back into the original Android event if needed.
115
- addPointerForIndex (event , event .getActionIndex (), pointerChange , 0 , packet );
126
+ addPointerForIndex (event , event .getActionIndex (), pointerChange , 0 , transformMatrix , packet );
116
127
} else {
117
128
// ACTION_MOVE may not actually mean all pointers have moved
118
129
// but it's the responsibility of a later part of the system to
119
130
// ignore 0-deltas if desired.
120
131
for (int p = 0 ; p < pointerCount ; p ++) {
121
- addPointerForIndex (event , p , pointerChange , 0 , packet );
132
+ addPointerForIndex (event , p , pointerChange , 0 , transformMatrix , packet );
122
133
}
123
134
}
124
135
@@ -160,7 +171,7 @@ public boolean onGenericMotionEvent(@NonNull MotionEvent event) {
160
171
packet .order (ByteOrder .LITTLE_ENDIAN );
161
172
162
173
// ACTION_HOVER_MOVE always applies to a single pointer only.
163
- addPointerForIndex (event , event .getActionIndex (), pointerChange , 0 , packet );
174
+ addPointerForIndex (event , event .getActionIndex (), pointerChange , 0 , IDENTITY_TRANSFORM , packet );
164
175
if (packet .position () % (POINTER_DATA_FIELD_COUNT * BYTES_PER_FIELD ) != 0 ) {
165
176
throw new AssertionError ("Packet position is not on field boundary." );
166
177
}
@@ -171,13 +182,21 @@ public boolean onGenericMotionEvent(@NonNull MotionEvent event) {
171
182
// TODO(mattcarroll): consider creating a PointerPacket class instead of using a procedure that
172
183
// mutates inputs.
173
184
private void addPointerForIndex (
174
- MotionEvent event , int pointerIndex , int pointerChange , int pointerData , ByteBuffer packet ) {
185
+ MotionEvent event ,
186
+ int pointerIndex ,
187
+ int pointerChange ,
188
+ int pointerData ,
189
+ Matrix transformMatrix ,
190
+ ByteBuffer packet ) {
175
191
if (pointerChange == -1 ) {
176
192
return ;
177
193
}
178
194
179
- // TODO (kaushikiska) : pass this in when we have a way to evict framework only events.
180
- // MotionEventTracker.MotionEventId motionEventId = motionEventTracker.track(event);
195
+ long motionEventId = 0 ;
196
+ if (trackMotionEvents ) {
197
+ MotionEventTracker .MotionEventId trackedEvent = motionEventTracker .track (event );
198
+ motionEventId = trackedEvent .getId ();
199
+ }
181
200
182
201
int pointerKind = getPointerDeviceTypeForToolType (event .getToolType (pointerIndex ));
183
202
@@ -188,15 +207,21 @@ private void addPointerForIndex(
188
207
189
208
long timeStamp = event .getEventTime () * 1000 ; // Convert from milliseconds to microseconds.
190
209
191
- packet .putLong (0 ); // motionEventId
210
+ packet .putLong (motionEventId ); // motionEventId
192
211
packet .putLong (timeStamp ); // time_stamp
193
212
packet .putLong (pointerChange ); // change
194
213
packet .putLong (pointerKind ); // kind
195
214
packet .putLong (signalKind ); // signal_kind
196
215
packet .putLong (event .getPointerId (pointerIndex )); // device
197
216
packet .putLong (0 ); // pointer_identifier, will be generated in pointer_data_packet_converter.cc.
198
- packet .putDouble (event .getX (pointerIndex )); // physical_x
199
- packet .putDouble (event .getY (pointerIndex )); // physical_y
217
+
218
+ // We use this in lieu of using event.getRawX and event.getRawY as we wish to support
219
+ // earlier versions than API level 29.
220
+ float viewToScreenCoords [] = {event .getX (pointerIndex ), event .getY (pointerIndex )};
221
+ transformMatrix .mapPoints (viewToScreenCoords );
222
+ packet .putDouble (viewToScreenCoords [0 ]); // physical_x
223
+ packet .putDouble (viewToScreenCoords [1 ]); // physical_y
224
+
200
225
packet .putDouble (
201
226
0.0 ); // physical_delta_x, will be generated in pointer_data_packet_converter.cc.
202
227
packet .putDouble (
0 commit comments