11package io .flutter .embedding .android ;
22
3+ import android .graphics .Matrix ;
34import android .os .Build ;
45import android .view .InputDevice ;
56import android .view .MotionEvent ;
@@ -69,6 +70,8 @@ public class AndroidTouchProcessor {
6970
7071 private static final int _POINTER_BUTTON_PRIMARY = 1 ;
7172
73+ private static final Matrix IDENTITY_TRANSFORM = new Matrix ();
74+
7275 private final boolean trackMotionEvents ;
7376
7477 /**
@@ -83,8 +86,12 @@ public AndroidTouchProcessor(@NonNull FlutterRenderer renderer, boolean trackMot
8386 this .trackMotionEvents = trackMotionEvents ;
8487 }
8588
86- /** Sends the given {@link MotionEvent} data to Flutter in a format that Flutter understands. */
8789 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 ) {
8895 int pointerCount = event .getPointerCount ();
8996
9097 // Prepare a data packet of the appropriate size and order.
@@ -102,26 +109,27 @@ public boolean onTouchEvent(@NonNull MotionEvent event) {
102109 || maskedAction == MotionEvent .ACTION_POINTER_UP );
103110 if (updateForSinglePointer ) {
104111 // ACTION_DOWN and ACTION_POINTER_DOWN always apply to a single pointer only.
105- addPointerForIndex (event , event .getActionIndex (), pointerChange , 0 , packet );
112+ addPointerForIndex (event , event .getActionIndex (), pointerChange , 0 , transformMatrix , packet );
106113 } else if (updateForMultiplePointers ) {
107114 // ACTION_UP and ACTION_POINTER_UP may contain position updates for other pointers.
108115 // We are converting these updates to move events here in order to preserve this data.
109116 // We also mark these events with a flag in order to help the framework reassemble
110117 // the original Android event later, should it need to forward it to a PlatformView.
111118 for (int p = 0 ; p < pointerCount ; p ++) {
112119 if (p != event .getActionIndex () && event .getToolType (p ) == MotionEvent .TOOL_TYPE_FINGER ) {
113- addPointerForIndex (event , p , PointerChange .MOVE , POINTER_DATA_FLAG_BATCHED , packet );
120+ addPointerForIndex (
121+ event , p , PointerChange .MOVE , POINTER_DATA_FLAG_BATCHED , transformMatrix , packet );
114122 }
115123 }
116124 // It's important that we're sending the UP event last. This allows PlatformView
117125 // to correctly batch everything back into the original Android event if needed.
118- addPointerForIndex (event , event .getActionIndex (), pointerChange , 0 , packet );
126+ addPointerForIndex (event , event .getActionIndex (), pointerChange , 0 , transformMatrix , packet );
119127 } else {
120128 // ACTION_MOVE may not actually mean all pointers have moved
121129 // but it's the responsibility of a later part of the system to
122130 // ignore 0-deltas if desired.
123131 for (int p = 0 ; p < pointerCount ; p ++) {
124- addPointerForIndex (event , p , pointerChange , 0 , packet );
132+ addPointerForIndex (event , p , pointerChange , 0 , transformMatrix , packet );
125133 }
126134 }
127135
@@ -163,7 +171,7 @@ public boolean onGenericMotionEvent(@NonNull MotionEvent event) {
163171 packet .order (ByteOrder .LITTLE_ENDIAN );
164172
165173 // ACTION_HOVER_MOVE always applies to a single pointer only.
166- addPointerForIndex (event , event .getActionIndex (), pointerChange , 0 , packet );
174+ addPointerForIndex (event , event .getActionIndex (), pointerChange , 0 , IDENTITY_TRANSFORM , packet );
167175 if (packet .position () % (POINTER_DATA_FIELD_COUNT * BYTES_PER_FIELD ) != 0 ) {
168176 throw new AssertionError ("Packet position is not on field boundary." );
169177 }
@@ -174,7 +182,12 @@ public boolean onGenericMotionEvent(@NonNull MotionEvent event) {
174182 // TODO(mattcarroll): consider creating a PointerPacket class instead of using a procedure that
175183 // mutates inputs.
176184 private void addPointerForIndex (
177- 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 ) {
178191 if (pointerChange == -1 ) {
179192 return ;
180193 }
@@ -201,8 +214,14 @@ private void addPointerForIndex(
201214 packet .putLong (signalKind ); // signal_kind
202215 packet .putLong (event .getPointerId (pointerIndex )); // device
203216 packet .putLong (0 ); // pointer_identifier, will be generated in pointer_data_packet_converter.cc.
204- packet .putDouble (event .getRawX (pointerIndex )); // physical_x
205- packet .putDouble (event .getRawY (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+
206225 packet .putDouble (
207226 0.0 ); // physical_delta_x, will be generated in pointer_data_packet_converter.cc.
208227 packet .putDouble (
0 commit comments