diff --git a/packages/flutter/lib/src/gestures/mouse_tracking.dart b/packages/flutter/lib/src/gestures/mouse_tracking.dart index 3b5fa1d44f..b181c0d70f 100644 --- a/packages/flutter/lib/src/gestures/mouse_tracking.dart +++ b/packages/flutter/lib/src/gestures/mouse_tracking.dart @@ -121,7 +121,9 @@ class MouseTracker { void detachAnnotation(MouseTrackerAnnotation annotation) { final _TrackedAnnotation trackedAnnotation = _findAnnotation(annotation); for (int deviceId in trackedAnnotation.activeDevices) { - annotation.onExit(PointerExitEvent.fromMouseEvent(_lastMouseEvent[deviceId])); + if (annotation.onExit != null) { + annotation.onExit(PointerExitEvent.fromMouseEvent(_lastMouseEvent[deviceId])); + } } _trackedAnnotations.remove(annotation); } diff --git a/packages/flutter/test/gestures/mouse_tracking_test.dart b/packages/flutter/test/gestures/mouse_tracking_test.dart index 294065283f..c2483ac7e2 100644 --- a/packages/flutter/test/gestures/mouse_tracking_test.dart +++ b/packages/flutter/test/gestures/mouse_tracking_test.dart @@ -44,7 +44,13 @@ void main() { onHover: (PointerHoverEvent event) => move.add(event), onExit: (PointerExitEvent event) => exit.add(event), ); - bool isInHitRegion; + // Only respond to some mouse events. + final MouseTrackerAnnotation partialAnnotation = MouseTrackerAnnotation( + onEnter: (PointerEnterEvent event) => enter.add(event), + onHover: (PointerHoverEvent event) => move.add(event), + ); + bool isInHitRegionOne; + bool isInHitRegionTwo; MouseTracker tracker; void clear() { @@ -55,10 +61,17 @@ void main() { setUp(() { clear(); - isInHitRegion = true; + isInHitRegionOne = true; + isInHitRegionTwo = false; tracker = MouseTracker( GestureBinding.instance.pointerRouter, - (Offset _) => isInHitRegion ? annotation : null, + (Offset _) { + if (isInHitRegionOne) + return annotation; + else if (isInHitRegionTwo) + return partialAnnotation; + return null; + }, ); }); @@ -103,7 +116,7 @@ void main() { ), ]); tracker.attachAnnotation(annotation); - isInHitRegion = true; + isInHitRegionOne = true; ui.window.onPointerDataPacket(packet1); tracker.collectMousePositions(); expect(enter.length, equals(1), reason: 'enter contains $enter'); @@ -189,7 +202,7 @@ void main() { kind: PointerDeviceKind.mouse, ), ]); - isInHitRegion = true; + isInHitRegionOne = true; tracker.attachAnnotation(annotation); ui.window.onPointerDataPacket(packet1); @@ -205,7 +218,7 @@ void main() { expect(exit.length, equals(0), reason: 'exit contains $exit'); // Simulate layer going away by detaching it. clear(); - isInHitRegion = false; + isInHitRegionOne = false; ui.window.onPointerDataPacket(packet2); tracker.collectMousePositions(); @@ -215,6 +228,37 @@ void main() { expect(exit.first.position, const Offset(1.0, 201.0)); expect(exit.first.device, equals(0)); expect(exit.first.runtimeType, equals(PointerExitEvent)); + + // Actually detatch annotation. Shouldn't receive hit. + tracker.detachAnnotation(annotation); + clear(); + isInHitRegionOne = false; + + ui.window.onPointerDataPacket(packet2); + tracker.collectMousePositions(); + expect(enter.length, equals(0), reason: 'enter contains $enter'); + expect(move.length, equals(0), reason: 'enter contains $move'); + expect(exit.length, equals(0), reason: 'enter contains $exit'); + }); + + test("don't flip out if not all mouse events are listened to", () { + final ui.PointerDataPacket packet = ui.PointerDataPacket(data: [ + ui.PointerData( + change: ui.PointerChange.hover, + physicalX: 1.0 * ui.window.devicePixelRatio, + physicalY: 101.0 * ui.window.devicePixelRatio, + kind: PointerDeviceKind.mouse, + ), + ]); + + isInHitRegionOne = false; + isInHitRegionTwo = true; + tracker.attachAnnotation(partialAnnotation); + + ui.window.onPointerDataPacket(packet); + tracker.collectMousePositions(); + tracker.detachAnnotation(partialAnnotation); + isInHitRegionTwo = false; }); test('detects exit when mouse goes away', () { final ui.PointerDataPacket packet1 = ui.PointerDataPacket(data: [ @@ -237,7 +281,7 @@ void main() { kind: PointerDeviceKind.mouse, ), ]); - isInHitRegion = true; + isInHitRegionOne = true; tracker.attachAnnotation(annotation); ui.window.onPointerDataPacket(packet1); tracker.collectMousePositions(); @@ -285,7 +329,7 @@ void main() { kind: PointerDeviceKind.mouse, ), ]); - isInHitRegion = true; + isInHitRegionOne = true; tracker.attachAnnotation(annotation); ui.window.onPointerDataPacket(packet1); tracker.collectMousePositions();