From c6537779a66c9af4689e2399eb6d777bdeb34d18 Mon Sep 17 00:00:00 2001 From: Xiaohu Hu Date: Mon, 24 Jul 2023 17:17:59 +0800 Subject: [PATCH] Fix unexpected pointer change (#129765) and add test case Signed-off-by: Xiaohu Hu --- .../android/AndroidTouchProcessor.java | 25 ++++++--- .../android/AndroidTouchProcessorTest.java | 56 +++++++++++++++++++ 2 files changed, 72 insertions(+), 9 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java index b3db5df1eb99b..de60256fccd40 100644 --- a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java +++ b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java @@ -224,12 +224,6 @@ private void addPointerForIndex( return; } - long motionEventId = 0; - if (trackMotionEvents) { - MotionEventTracker.MotionEventId trackedEvent = motionEventTracker.track(event); - motionEventId = trackedEvent.getId(); - } - int pointerKind = getPointerDeviceTypeForToolType(event.getToolType(pointerIndex)); // We use this in lieu of using event.getRawX and event.getRawY as we wish to support // earlier versions than API level 29. @@ -252,7 +246,20 @@ private void addPointerForIndex( buttons = 0; } + int panZoomType = -1; boolean isTrackpadPan = ongoingPans.containsKey(event.getPointerId(pointerIndex)); + if (isTrackpadPan) { + panZoomType = getPointerChangeForPanZoom(pointerChange); + if (panZoomType == -1) { + return; + } + } + + long motionEventId = 0; + if (trackMotionEvents) { + MotionEventTracker.MotionEventId trackedEvent = motionEventTracker.track(event); + motionEventId = trackedEvent.getId(); + } int signalKind = event.getActionMasked() == MotionEvent.ACTION_SCROLL @@ -264,7 +271,7 @@ private void addPointerForIndex( packet.putLong(motionEventId); // motionEventId packet.putLong(timeStamp); // time_stamp if (isTrackpadPan) { - packet.putLong(getPointerChangeForPanZoom(pointerChange)); // change + packet.putLong(panZoomType); // change packet.putLong(PointerDeviceKind.TRACKPAD); // kind } else { packet.putLong(pointerChange); // change @@ -355,7 +362,7 @@ private void addPointerForIndex( packet.putDouble(1.0); // scale packet.putDouble(0.0); // rotation - if (isTrackpadPan && getPointerChangeForPanZoom(pointerChange) == PointerChange.PAN_ZOOM_END) { + if (isTrackpadPan && (panZoomType == PointerChange.PAN_ZOOM_END)) { ongoingPans.remove(event.getPointerId(pointerIndex)); } } @@ -401,7 +408,7 @@ private int getPointerChangeForPanZoom(int pointerChange) { } else if (pointerChange == PointerChange.UP || pointerChange == PointerChange.CANCEL) { return PointerChange.PAN_ZOOM_END; } - throw new AssertionError("Unexpected pointer change"); + return -1; } @PointerDeviceKind diff --git a/shell/platform/android/test/io/flutter/embedding/android/AndroidTouchProcessorTest.java b/shell/platform/android/test/io/flutter/embedding/android/AndroidTouchProcessorTest.java index dd3b896c37512..09e53be9b0a07 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/AndroidTouchProcessorTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/AndroidTouchProcessorTest.java @@ -89,6 +89,7 @@ MotionEvent mockEvent(int action, float x, float y, int buttonState) { when(event.getX(0)).thenReturn(x); when(event.getY(0)).thenReturn(y); when(event.getToolType(0)).thenReturn(toolType); + when(event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)).thenReturn(true); return event; } } @@ -218,4 +219,59 @@ public void unexpectedMaskedAction() { touchProcessor.onTouchEvent(mocker.mockEvent(MotionEvent.ACTION_BUTTON_PRESS, 0.0f, 0.0f, 0)); verify(mockRenderer, never()).dispatchPointerDataPacket(ByteBuffer.allocate(0), 0); } + + @Test + public void unexpectedPointerChange() { + // Regression test for https://github.com/flutter/flutter/issues/129765 + + MotionEventMocker mocker = + new MotionEventMocker(0, InputDevice.SOURCE_MOUSE, MotionEvent.TOOL_TYPE_MOUSE); + + touchProcessor.onTouchEvent(mocker.mockEvent(MotionEvent.ACTION_DOWN, 0.0f, 0.0f, 0)); + InOrder inOrder = inOrder(mockRenderer); + inOrder + .verify(mockRenderer) + .dispatchPointerDataPacket(packetCaptor.capture(), packetSizeCaptor.capture()); + ByteBuffer packet = packetCaptor.getValue(); + assertEquals(AndroidTouchProcessor.PointerChange.PAN_ZOOM_START, readPointerChange(packet)); + assertEquals(AndroidTouchProcessor.PointerDeviceKind.TRACKPAD, readPointerDeviceKind(packet)); + assertEquals(AndroidTouchProcessor.PointerSignalKind.NONE, readPointerSignalKind(packet)); + assertEquals(0.0, readPointerPhysicalX(packet)); + assertEquals(0.0, readPointerPhysicalY(packet)); + + touchProcessor.onTouchEvent(mocker.mockEvent(MotionEvent.ACTION_MOVE, 10.0f, 5.0f, 0)); + inOrder + .verify(mockRenderer) + .dispatchPointerDataPacket(packetCaptor.capture(), packetSizeCaptor.capture()); + packet = packetCaptor.getValue(); + assertEquals(AndroidTouchProcessor.PointerChange.PAN_ZOOM_UPDATE, readPointerChange(packet)); + assertEquals(AndroidTouchProcessor.PointerDeviceKind.TRACKPAD, readPointerDeviceKind(packet)); + assertEquals(AndroidTouchProcessor.PointerSignalKind.NONE, readPointerSignalKind(packet)); + assertEquals(0.0, readPointerPhysicalX(packet)); + assertEquals(0.0, readPointerPhysicalY(packet)); + assertEquals(10.0, readPointerPanX(packet)); + assertEquals(5.0, readPointerPanY(packet)); + + touchProcessor.onGenericMotionEvent(mocker.mockEvent(MotionEvent.ACTION_SCROLL, 0.0f, 0.0f, 0)); + inOrder + .verify(mockRenderer) + .dispatchPointerDataPacket(packetCaptor.capture(), packetSizeCaptor.capture()); + packet = packetCaptor.getValue(); + packet.rewind(); + while (packet.hasRemaining()) { + assertEquals(0, packet.get()); + } + + touchProcessor.onTouchEvent(mocker.mockEvent(MotionEvent.ACTION_UP, 10.0f, 5.0f, 0)); + inOrder + .verify(mockRenderer) + .dispatchPointerDataPacket(packetCaptor.capture(), packetSizeCaptor.capture()); + packet = packetCaptor.getValue(); + assertEquals(AndroidTouchProcessor.PointerChange.PAN_ZOOM_END, readPointerChange(packet)); + assertEquals(AndroidTouchProcessor.PointerDeviceKind.TRACKPAD, readPointerDeviceKind(packet)); + assertEquals(AndroidTouchProcessor.PointerSignalKind.NONE, readPointerSignalKind(packet)); + assertEquals(0.0, readPointerPhysicalX(packet)); + assertEquals(0.0, readPointerPhysicalY(packet)); + inOrder.verifyNoMoreInteractions(); + } }