diff --git a/packages/flutter/lib/src/gestures/binding.dart b/packages/flutter/lib/src/gestures/binding.dart index 383badd440b..023b0d57edc 100644 --- a/packages/flutter/lib/src/gestures/binding.dart +++ b/packages/flutter/lib/src/gestures/binding.dart @@ -287,9 +287,18 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H void _handlePointerDataPacket(ui.PointerDataPacket packet) { // We convert pointer data to logical pixels so that e.g. the touch slop can be // defined in a device-independent manner. - _pendingPointerEvents.addAll(PointerEventConverter.expand(packet.data, window.devicePixelRatio)); - if (!locked) { - _flushPointerEventQueue(); + try { + _pendingPointerEvents.addAll(PointerEventConverter.expand(packet.data, window.devicePixelRatio)); + if (!locked) { + _flushPointerEventQueue(); + } + } catch (error, stack) { + FlutterError.reportError(FlutterErrorDetails( + exception: error, + stack: stack, + library: 'gestures library', + context: ErrorDescription('while handling a pointer data packet'), + )); } } diff --git a/packages/flutter/test/gestures/gesture_binding_test.dart b/packages/flutter/test/gestures/gesture_binding_test.dart index 223d0d1fad4..328dd4bbd73 100644 --- a/packages/flutter/test/gestures/gesture_binding_test.dart +++ b/packages/flutter/test/gestures/gesture_binding_test.dart @@ -35,14 +35,20 @@ class TestGestureFlutterBinding extends BindingBase with GestureBinding, Schedul return _instance!; } - HandleEventCallback? callback; + HandleEventCallback? onHandlePointerEvent; + + @override + void handlePointerEvent(PointerEvent event) { + onHandlePointerEvent?.call(event); + super.handlePointerEvent(event); + } + + HandleEventCallback? onHandleEvent; @override void handleEvent(PointerEvent event, HitTestEntry entry) { super.handleEvent(event, entry); - if (callback != null) { - callback?.call(event); - } + onHandleEvent?.call(event); } } @@ -58,7 +64,7 @@ void main() { ); final List events = []; - binding.callback = events.add; + binding.onHandleEvent = events.add; GestureBinding.instance.platformDispatcher.onPointerDataPacket?.call(packet); expect(events.length, 2); @@ -76,7 +82,7 @@ void main() { ); final List events = []; - binding.callback = events.add; + binding.onHandleEvent = events.add; GestureBinding.instance.platformDispatcher.onPointerDataPacket?.call(packet); expect(events.length, 3); @@ -101,7 +107,7 @@ void main() { GestureBinding.instance.pointerRouter.addGlobalRoute(pointerRouterEvents.add); final List events = []; - binding.callback = events.add; + binding.onHandleEvent = events.add; GestureBinding.instance.platformDispatcher.onPointerDataPacket?.call(packet); expect(events.length, 3); @@ -126,7 +132,7 @@ void main() { ); final List events = []; - binding.callback = events.add; + binding.onHandleEvent = events.add; GestureBinding.instance.platformDispatcher.onPointerDataPacket?.call(packet); expect(events.length, 2); @@ -143,7 +149,7 @@ void main() { ); final List events = []; - binding.callback = (PointerEvent event) { + binding.onHandleEvent = (PointerEvent event) { events.add(event); if (event is PointerDownEvent) { binding.cancelPointer(event.pointer); @@ -389,7 +395,7 @@ void main() { ); final List events = []; - binding.callback = events.add; + binding.onHandleEvent = events.add; binding.platformDispatcher.onPointerDataPacket?.call(packet); expect(events.length, 3); @@ -397,4 +403,28 @@ void main() { expect(events[1], isA()); expect(events[2], isA()); }); + + test('Error handling', () { + const ui.PointerDataPacket packet = ui.PointerDataPacket( + data: [ + ui.PointerData(change: ui.PointerChange.down), + ui.PointerData(change: ui.PointerChange.up), + ], + ); + + final List events = []; + binding.onHandlePointerEvent = (PointerEvent event) { throw Exception('zipzapzooey $event'); }; + FlutterError.onError = (FlutterErrorDetails details) { events.add(details.toString()); }; + try { + GestureBinding.instance.platformDispatcher.onPointerDataPacket?.call(packet); + expect(events.length, 1); + expect(events[0], contains('while handling a pointer data\npacket')); // The default stringifying behavior uses 65 character wrapWidth. + expect(events[0], contains('zipzapzooey')); + expect(events[0], contains('PointerDownEvent')); + expect(events[0], isNot(contains('PointerUpEvent'))); // Failure happens on the first message, remaining messages aren't processed. + } finally { + binding.onHandlePointerEvent = null; + FlutterError.onError = FlutterError.presentError; + } + }); }