From dfbd99b3d9025c362d01eda5bf93887e0fcba752 Mon Sep 17 00:00:00 2001 From: Stanislav Baranov Date: Fri, 2 Nov 2018 10:51:35 -0700 Subject: [PATCH] Propagate positions of secondary pointers in UP events on Android (flutter/engine#6716) --- engine/src/flutter/lib/ui/hooks.dart | 5 ++- engine/src/flutter/lib/ui/pointer.dart | 9 ++++- .../src/flutter/lib/ui/window/pointer_data.cc | 2 +- .../src/flutter/lib/ui/window/pointer_data.h | 1 + .../android/io/flutter/view/FlutterView.java | 38 ++++++++++++++----- 5 files changed, 41 insertions(+), 14 deletions(-) diff --git a/engine/src/flutter/lib/ui/hooks.dart b/engine/src/flutter/lib/ui/hooks.dart index dcd8d6d093..7c449a5047 100644 --- a/engine/src/flutter/lib/ui/hooks.dart +++ b/engine/src/flutter/lib/ui/hooks.dart @@ -196,7 +196,7 @@ void _invoke3(void callback(A1 a1, A2 a2, A3 a3), Zone zone, A1 arg1 // // * pointer_data.cc // * FlutterView.java -const int _kPointerDataFieldCount = 20; +const int _kPointerDataFieldCount = 21; PointerDataPacket _unpackPointerDataPacket(ByteData packet) { const int kStride = Int64List.bytesPerElement; @@ -226,7 +226,8 @@ PointerDataPacket _unpackPointerDataPacket(ByteData packet) { radiusMin: packet.getFloat64(kStride * offset++, _kFakeHostEndian), radiusMax: packet.getFloat64(kStride * offset++, _kFakeHostEndian), orientation: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - tilt: packet.getFloat64(kStride * offset++, _kFakeHostEndian) + tilt: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + platformData: packet.getInt64(kStride * offset++, _kFakeHostEndian), ); assert(offset == (i + 1) * _kPointerDataFieldCount); } diff --git a/engine/src/flutter/lib/ui/pointer.dart b/engine/src/flutter/lib/ui/pointer.dart index a55086ece6..63993cf42b 100644 --- a/engine/src/flutter/lib/ui/pointer.dart +++ b/engine/src/flutter/lib/ui/pointer.dart @@ -77,7 +77,8 @@ class PointerData { this.radiusMin: 0.0, this.radiusMax: 0.0, this.orientation: 0.0, - this.tilt: 0.0 + this.tilt: 0.0, + this.platformData: 0, }); /// Time of event dispatch, relative to an arbitrary timeline. @@ -199,6 +200,9 @@ class PointerData { /// the stylus is flat on that surface). final double tilt; + /// Opaque platform-specific data associated with the event. + final int platformData; + @override String toString() => '$runtimeType(x: $physicalX, y: $physicalY)'; @@ -223,7 +227,8 @@ class PointerData { 'radiusMin: $radiusMin, ' 'radiusMax: $radiusMax, ' 'orientation: $orientation, ' - 'tilt: $tilt' + 'tilt: $tilt, ' + 'platformData: $platformData' ')'; } } diff --git a/engine/src/flutter/lib/ui/window/pointer_data.cc b/engine/src/flutter/lib/ui/window/pointer_data.cc index e657460cf2..563d6bc2e4 100644 --- a/engine/src/flutter/lib/ui/window/pointer_data.cc +++ b/engine/src/flutter/lib/ui/window/pointer_data.cc @@ -9,7 +9,7 @@ namespace blink { // If this value changes, update the pointer data unpacking code in hooks.dart. -static constexpr int kPointerDataFieldCount = 20; +static constexpr int kPointerDataFieldCount = 21; static_assert(sizeof(PointerData) == sizeof(int64_t) * kPointerDataFieldCount, "PointerData has the wrong size"); diff --git a/engine/src/flutter/lib/ui/window/pointer_data.h b/engine/src/flutter/lib/ui/window/pointer_data.h index 1d7fe09cea..44f10a6abf 100644 --- a/engine/src/flutter/lib/ui/window/pointer_data.h +++ b/engine/src/flutter/lib/ui/window/pointer_data.h @@ -50,6 +50,7 @@ struct alignas(8) PointerData { double radius_max; double orientation; double tilt; + int64_t platformData; void Clear(); }; diff --git a/engine/src/flutter/shell/platform/android/io/flutter/view/FlutterView.java b/engine/src/flutter/shell/platform/android/io/flutter/view/FlutterView.java index a2c12cc785..7609aaf77e 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/view/FlutterView.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/view/FlutterView.java @@ -447,8 +447,8 @@ public class FlutterView extends SurfaceView } } - private void addPointerForIndex(MotionEvent event, int pointerIndex, ByteBuffer packet) { - int pointerChange = getPointerChangeForAction(event.getActionMasked()); + private void addPointerForIndex(MotionEvent event, int pointerIndex, int pointerChange, + int pointerData, ByteBuffer packet) { if (pointerChange == -1) { return; } @@ -503,6 +503,8 @@ public class FlutterView extends SurfaceView } else { packet.putDouble(0.0); // tilt } + + packet.putLong(pointerData); // platformData } @Override @@ -521,26 +523,44 @@ public class FlutterView extends SurfaceView } // These values must match the unpacking code in hooks.dart. - final int kPointerDataFieldCount = 20; + final int kPointerDataFieldCount = 21; final int kBytePerField = 8; + // This value must match the value in framework's platform_view.dart. + // This flag indicates whether the original Android pointer events were batched together. + final int kPointerDataFlagBatched = 1; + int pointerCount = event.getPointerCount(); ByteBuffer packet = ByteBuffer.allocateDirect(pointerCount * kPointerDataFieldCount * kBytePerField); packet.order(ByteOrder.LITTLE_ENDIAN); int maskedAction = event.getActionMasked(); - // ACTION_UP, ACTION_POINTER_UP, ACTION_DOWN, and ACTION_POINTER_DOWN - // only apply to a single pointer, other events apply to all pointers. - if (maskedAction == MotionEvent.ACTION_UP || maskedAction == MotionEvent.ACTION_POINTER_UP - || maskedAction == MotionEvent.ACTION_DOWN || maskedAction == MotionEvent.ACTION_POINTER_DOWN) { - addPointerForIndex(event, event.getActionIndex(), packet); + int pointerChange = getPointerChangeForAction(event.getActionMasked()); + if (maskedAction == MotionEvent.ACTION_DOWN || maskedAction == MotionEvent.ACTION_POINTER_DOWN) { + // ACTION_DOWN and ACTION_POINTER_DOWN always apply to a single pointer only. + addPointerForIndex(event, event.getActionIndex(), pointerChange, 0, packet); + } else if (maskedAction == MotionEvent.ACTION_UP || maskedAction == MotionEvent.ACTION_POINTER_UP) { + // ACTION_UP and ACTION_POINTER_UP may contain position updates for other pointers. + // We are converting these updates to move events here in order to preserve this data. + // We also mark these events with a flag in order to help the framework reassemble + // the original Android event later, should it need to forward it to a PlatformView. + for (int p = 0; p < pointerCount; p++) { + if (p != event.getActionIndex()) { + if (event.getToolType(p) == MotionEvent.TOOL_TYPE_FINGER) { + addPointerForIndex(event, p, kPointerChangeMove, kPointerDataFlagBatched, packet); + } + } + } + // It's important that we're sending the UP event last. This allows PlatformView + // to correctly batch everything back into the original Android event if needed. + addPointerForIndex(event, event.getActionIndex(), pointerChange, 0, packet); } else { // ACTION_MOVE may not actually mean all pointers have moved // but it's the responsibility of a later part of the system to // ignore 0-deltas if desired. for (int p = 0; p < pointerCount; p++) { - addPointerForIndex(event, p, packet); + addPointerForIndex(event, p, pointerChange, 0, packet); } }