Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 154fc5a

Browse files
LoveJelloxiaohu.hxh
authored andcommitted
Fix unexpected pointer change (#129765)
Drop invalid scroll event for panZoom type MotionEvent.isFromSource() is not mockable because it's from super class in InputEvent. So we need to change if condition from "if (!isPointerEvent || !isMovementEvent)" to "if (isPointerEvent || isMovementEvent)". Without this change, this test case will end up with "wanted but not invoked" error. Signed-off-by: Xiaohu Hu <huxiaohu2007@gmail.com>
1 parent 3f70201 commit 154fc5a

File tree

2 files changed

+87
-24
lines changed

2 files changed

+87
-24
lines changed

shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -192,23 +192,24 @@ public boolean onGenericMotionEvent(@NonNull MotionEvent event) {
192192
boolean isMovementEvent =
193193
(event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE
194194
|| event.getActionMasked() == MotionEvent.ACTION_SCROLL);
195-
if (!isPointerEvent || !isMovementEvent) {
196-
return false;
197-
}
198195

199-
int pointerChange = getPointerChangeForAction(event.getActionMasked());
200-
ByteBuffer packet =
201-
ByteBuffer.allocateDirect(
202-
event.getPointerCount() * POINTER_DATA_FIELD_COUNT * BYTES_PER_FIELD);
203-
packet.order(ByteOrder.LITTLE_ENDIAN);
204-
205-
// ACTION_HOVER_MOVE always applies to a single pointer only.
206-
addPointerForIndex(event, event.getActionIndex(), pointerChange, 0, IDENTITY_TRANSFORM, packet);
207-
if (packet.position() % (POINTER_DATA_FIELD_COUNT * BYTES_PER_FIELD) != 0) {
208-
throw new AssertionError("Packet position is not on field boundary.");
196+
if (isPointerEvent || isMovementEvent) {
197+
int pointerChange = getPointerChangeForAction(event.getActionMasked());
198+
ByteBuffer packet =
199+
ByteBuffer.allocateDirect(
200+
event.getPointerCount() * POINTER_DATA_FIELD_COUNT * BYTES_PER_FIELD);
201+
packet.order(ByteOrder.LITTLE_ENDIAN);
202+
203+
// ACTION_HOVER_MOVE always applies to a single pointer only.
204+
addPointerForIndex(
205+
event, event.getActionIndex(), pointerChange, 0, IDENTITY_TRANSFORM, packet);
206+
if (packet.position() % (POINTER_DATA_FIELD_COUNT * BYTES_PER_FIELD) != 0) {
207+
throw new AssertionError("Packet position is not on field boundary.");
208+
}
209+
renderer.dispatchPointerDataPacket(packet, packet.position());
210+
return true;
209211
}
210-
renderer.dispatchPointerDataPacket(packet, packet.position());
211-
return true;
212+
return false;
212213
}
213214

214215
// TODO(mattcarroll): consider creating a PointerPacket class instead of using a procedure that
@@ -224,12 +225,6 @@ private void addPointerForIndex(
224225
return;
225226
}
226227

227-
long motionEventId = 0;
228-
if (trackMotionEvents) {
229-
MotionEventTracker.MotionEventId trackedEvent = motionEventTracker.track(event);
230-
motionEventId = trackedEvent.getId();
231-
}
232-
233228
int pointerKind = getPointerDeviceTypeForToolType(event.getToolType(pointerIndex));
234229
// We use this in lieu of using event.getRawX and event.getRawY as we wish to support
235230
// earlier versions than API level 29.
@@ -252,7 +247,20 @@ private void addPointerForIndex(
252247
buttons = 0;
253248
}
254249

250+
int panZoomType = -1;
255251
boolean isTrackpadPan = ongoingPans.containsKey(event.getPointerId(pointerIndex));
252+
if (isTrackpadPan) {
253+
panZoomType = getPointerChangeForPanZoom(pointerChange);
254+
if (panZoomType == -1) {
255+
return;
256+
}
257+
}
258+
259+
long motionEventId = 0;
260+
if (trackMotionEvents) {
261+
MotionEventTracker.MotionEventId trackedEvent = motionEventTracker.track(event);
262+
motionEventId = trackedEvent.getId();
263+
}
256264

257265
int signalKind =
258266
event.getActionMasked() == MotionEvent.ACTION_SCROLL
@@ -264,7 +272,7 @@ private void addPointerForIndex(
264272
packet.putLong(motionEventId); // motionEventId
265273
packet.putLong(timeStamp); // time_stamp
266274
if (isTrackpadPan) {
267-
packet.putLong(getPointerChangeForPanZoom(pointerChange)); // change
275+
packet.putLong(panZoomType); // change
268276
packet.putLong(PointerDeviceKind.TRACKPAD); // kind
269277
} else {
270278
packet.putLong(pointerChange); // change
@@ -355,7 +363,7 @@ private void addPointerForIndex(
355363
packet.putDouble(1.0); // scale
356364
packet.putDouble(0.0); // rotation
357365

358-
if (isTrackpadPan && getPointerChangeForPanZoom(pointerChange) == PointerChange.PAN_ZOOM_END) {
366+
if (isTrackpadPan && (panZoomType == PointerChange.PAN_ZOOM_END)) {
359367
ongoingPans.remove(event.getPointerId(pointerIndex));
360368
}
361369
}
@@ -401,7 +409,7 @@ private int getPointerChangeForPanZoom(int pointerChange) {
401409
} else if (pointerChange == PointerChange.UP || pointerChange == PointerChange.CANCEL) {
402410
return PointerChange.PAN_ZOOM_END;
403411
}
404-
throw new AssertionError("Unexpected pointer change");
412+
return -1;
405413
}
406414

407415
@PointerDeviceKind

shell/platform/android/test/io/flutter/embedding/android/AndroidTouchProcessorTest.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,4 +218,59 @@ public void unexpectedMaskedAction() {
218218
touchProcessor.onTouchEvent(mocker.mockEvent(MotionEvent.ACTION_BUTTON_PRESS, 0.0f, 0.0f, 0));
219219
verify(mockRenderer, never()).dispatchPointerDataPacket(ByteBuffer.allocate(0), 0);
220220
}
221+
222+
@Test
223+
public void unexpectedPointerChange() {
224+
// Regression test for https://github.com/flutter/flutter/issues/129765
225+
226+
MotionEventMocker mocker =
227+
new MotionEventMocker(0, InputDevice.SOURCE_MOUSE, MotionEvent.TOOL_TYPE_MOUSE);
228+
229+
touchProcessor.onTouchEvent(mocker.mockEvent(MotionEvent.ACTION_DOWN, 0.0f, 0.0f, 0));
230+
InOrder inOrder = inOrder(mockRenderer);
231+
inOrder
232+
.verify(mockRenderer)
233+
.dispatchPointerDataPacket(packetCaptor.capture(), packetSizeCaptor.capture());
234+
ByteBuffer packet = packetCaptor.getValue();
235+
assertEquals(AndroidTouchProcessor.PointerChange.PAN_ZOOM_START, readPointerChange(packet));
236+
assertEquals(AndroidTouchProcessor.PointerDeviceKind.TRACKPAD, readPointerDeviceKind(packet));
237+
assertEquals(AndroidTouchProcessor.PointerSignalKind.NONE, readPointerSignalKind(packet));
238+
assertEquals(0.0, readPointerPhysicalX(packet));
239+
assertEquals(0.0, readPointerPhysicalY(packet));
240+
241+
touchProcessor.onTouchEvent(mocker.mockEvent(MotionEvent.ACTION_MOVE, 10.0f, 5.0f, 0));
242+
inOrder
243+
.verify(mockRenderer)
244+
.dispatchPointerDataPacket(packetCaptor.capture(), packetSizeCaptor.capture());
245+
packet = packetCaptor.getValue();
246+
assertEquals(AndroidTouchProcessor.PointerChange.PAN_ZOOM_UPDATE, readPointerChange(packet));
247+
assertEquals(AndroidTouchProcessor.PointerDeviceKind.TRACKPAD, readPointerDeviceKind(packet));
248+
assertEquals(AndroidTouchProcessor.PointerSignalKind.NONE, readPointerSignalKind(packet));
249+
assertEquals(0.0, readPointerPhysicalX(packet));
250+
assertEquals(0.0, readPointerPhysicalY(packet));
251+
assertEquals(10.0, readPointerPanX(packet));
252+
assertEquals(5.0, readPointerPanY(packet));
253+
254+
touchProcessor.onGenericMotionEvent(mocker.mockEvent(MotionEvent.ACTION_SCROLL, 0.0f, 0.0f, 0));
255+
inOrder
256+
.verify(mockRenderer)
257+
.dispatchPointerDataPacket(packetCaptor.capture(), packetSizeCaptor.capture());
258+
packet = packetCaptor.getValue();
259+
packet.rewind();
260+
while (packet.hasRemaining()) {
261+
assertEquals(0, packet.get());
262+
}
263+
264+
touchProcessor.onTouchEvent(mocker.mockEvent(MotionEvent.ACTION_UP, 10.0f, 5.0f, 0));
265+
inOrder
266+
.verify(mockRenderer)
267+
.dispatchPointerDataPacket(packetCaptor.capture(), packetSizeCaptor.capture());
268+
packet = packetCaptor.getValue();
269+
assertEquals(AndroidTouchProcessor.PointerChange.PAN_ZOOM_END, readPointerChange(packet));
270+
assertEquals(AndroidTouchProcessor.PointerDeviceKind.TRACKPAD, readPointerDeviceKind(packet));
271+
assertEquals(AndroidTouchProcessor.PointerSignalKind.NONE, readPointerSignalKind(packet));
272+
assertEquals(0.0, readPointerPhysicalX(packet));
273+
assertEquals(0.0, readPointerPhysicalY(packet));
274+
inOrder.verifyNoMoreInteractions();
275+
}
221276
}

0 commit comments

Comments
 (0)