[flutter] Handle the skip ahead case correctly
Make sure pointer up changes are not lost if something causes
sampling to skip ahead.
Test: fx run-host-tests dart_widget_tests
Change-Id: Ib5e34c2c3a83a3b5259e6828730e083e0f70f50e
Reviewed-on: https://fuchsia-review.googlesource.com/c/experiences/+/400416
Reviewed-by: Sanjay Chouksey <sanjayc@google.com>
Testability-Review: Sanjay Chouksey <sanjayc@google.com>
Commit-Queue: David Reveman <reveman@google.com>
diff --git a/settings/lib/widgets/lib/src/utils/pointer_events_listener.dart b/settings/lib/widgets/lib/src/utils/pointer_events_listener.dart
index 8de20e5..4ea4975 100644
--- a/settings/lib/widgets/lib/src/utils/pointer_events_listener.dart
+++ b/settings/lib/widgets/lib/src/utils/pointer_events_listener.dart
@@ -249,7 +249,15 @@
break;
case PointerEventPhase.up:
case PointerEventPhase.cancel:
- _downPointers.remove(event.p.pointerId);
+ final p = _downPointers[event.p.pointerId];
+ if (p != null) {
+ // Remove _DownPointer if `up` phase has been handled.
+ if (p.last.p.phase == PointerEventPhase.up) {
+ _downPointers.remove(event.p.pointerId);
+ } else {
+ _downPointers[event.p.pointerId].next = event;
+ }
+ }
break;
case PointerEventPhase.add:
case PointerEventPhase.remove:
diff --git a/settings/lib/widgets/test/pointer_events_listener_test.dart b/settings/lib/widgets/test/pointer_events_listener_test.dart
index 51a322f..f10984b 100644
--- a/settings/lib/widgets/test/pointer_events_listener_test.dart
+++ b/settings/lib/widgets/test/pointer_events_listener_test.dart
@@ -151,7 +151,7 @@
expect(result[1].change, ui.PointerChange.up);
});
- test('move without a previous pointer down.', () {
+ test('move without a previous pointer down', () {
final event0 =
_createSimulatedPointerEvent(PointerEventPhase.move, 1000, 0.0, 0.0);
final event1 =
@@ -214,4 +214,68 @@
expect(result[1].physicalDeltaX, 20.0 * ui.window.devicePixelRatio);
expect(result[1].physicalDeltaY, 0.0);
});
+
+ test('skip ahead', () {
+ final event0 =
+ _createSimulatedPointerEvent(PointerEventPhase.down, 1000, 0.0, 0.0);
+ final event1 =
+ _createSimulatedPointerEvent(PointerEventPhase.move, 2000, 10.0, 0.0);
+ final event2 =
+ _createSimulatedPointerEvent(PointerEventPhase.move, 3000, 20.0, 0.0);
+ final event3 =
+ _createSimulatedPointerEvent(PointerEventPhase.up, 4000, 30.0, 0.0);
+
+ var frameTime = Duration(milliseconds: 6);
+ when(scheduler.currentSystemFrameTimeStamp).thenReturn(frameTime);
+
+ pointerEventsListener
+ ..onPointerEvent(event0)
+ ..onPointerEvent(event1)
+ ..onPointerEvent(event2)
+ ..onPointerEvent(event3);
+
+ // No pointer events should have been dispatched yet.
+ expect(result.isEmpty, true);
+
+ // Frame callback should have been requested.
+ FrameCallback callback =
+ verify(scheduler.scheduleFrameCallback(captureThat(isNotNull)))
+ .captured
+ .single;
+ verify(scheduler.scheduleFrame());
+ clearInteractions(scheduler);
+
+ frameTime = Duration(milliseconds: 7);
+ when(scheduler.currentSystemFrameTimeStamp).thenReturn(frameTime);
+ callback(Duration());
+
+ // One pointer event should have been dispatched.
+ expect(result.length, 1);
+ expect(result[0].timeStamp, frameTime + _samplingOffset);
+ expect(result[0].change, ui.PointerChange.down);
+ expect(result[0].physicalX, 5.0 * ui.window.devicePixelRatio);
+ expect(result[0].physicalY, 0.0);
+ expect(result[0].physicalDeltaX, 0.0);
+ expect(result[0].physicalDeltaY, 0.0);
+
+ // Another frame callback should have been requested.
+ callback = verify(scheduler.scheduleFrameCallback(captureThat(isNotNull)))
+ .captured
+ .single;
+ verify(scheduler.scheduleFrame());
+ clearInteractions(scheduler);
+
+ frameTime = Duration(milliseconds: 16);
+ when(scheduler.currentSystemFrameTimeStamp).thenReturn(frameTime);
+ callback(Duration());
+
+ // Last pointer event should have been dispatched.
+ expect(result.length, 2);
+ expect(result[1].timeStamp, frameTime + _samplingOffset);
+ expect(result[1].change, ui.PointerChange.up);
+ expect(result[1].physicalX, 30.0 * ui.window.devicePixelRatio);
+ expect(result[1].physicalY, 0.0);
+ expect(result[1].physicalDeltaX, 25.0 * ui.window.devicePixelRatio);
+ expect(result[1].physicalDeltaY, 0.0);
+ });
}