Unverified Commit 4aad058a authored by David Reveman's avatar David Reveman Committed by GitHub

Improve resampling of up and remove events. (#69096)

* Improve resampling of up and remove events.

This improves resampling of these events by searching
for them until the next approximate sample time.
Co-authored-by: 's avatarDavid Reveman <reveman@google.com>
parent d306c37b
......@@ -74,9 +74,11 @@ class _Resampler {
//
// `samplingOffset` is relative to the current frame time, which
// can be in the past when we're not actively resampling.
// `samplingInterval` is used to determine the approximate next
// time for resampling.
// `currentSystemFrameTimeStamp` is used to determine the current
// frame time.
void sample(Duration samplingOffset) {
void sample(Duration samplingOffset, Duration samplingInterval) {
final SchedulerBinding? scheduler = SchedulerBinding.instance;
assert(scheduler != null);
......@@ -86,10 +88,14 @@ class _Resampler {
// resampling events.
final Duration sampleTime = _frameTime + samplingOffset;
// Determine next sample time by adding the sampling interval
// to the current sample time.
final Duration nextSampleTime = sampleTime + samplingInterval;
// Iterate over active resamplers and sample pointer events for
// current sample time.
for (final PointerEventResampler resampler in _resamplers.values) {
resampler.sample(sampleTime, _handlePointerEvent);
resampler.sample(sampleTime, nextSampleTime, _handlePointerEvent);
}
// Remove inactive resamplers.
......@@ -138,6 +144,13 @@ class _Resampler {
// 4.666 ms margin is added for this.
const Duration _defaultSamplingOffset = Duration(milliseconds: -38);
// The sampling interval.
//
// Sampling interval is used to determine the approximate time for subsequent
// sampling. This is used to decide if early processing of up and removed events
// is appropriate. 16667 us for 60hz sampling interval.
const Duration _samplingInterval = Duration(microseconds: 16667);
/// A binding for the gesture subsystem.
///
/// ## Lifecycle of pointer events and the gesture arena
......@@ -257,7 +270,7 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H
if (resamplingEnabled) {
_resampler.addOrDispatch(event);
_resampler.sample(samplingOffset);
_resampler.sample(samplingOffset, _samplingInterval);
return;
}
......@@ -388,7 +401,7 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H
void _handleSampleTimeChanged() {
if (!locked) {
if (resamplingEnabled) {
_resampler.sample(samplingOffset);
_resampler.sample(samplingOffset, _samplingInterval);
}
else {
_resampler.stop();
......
......@@ -164,51 +164,44 @@ class PointerEventResampler {
void _dequeueAndSampleNonHoverOrMovePointerEventsUntil(
Duration sampleTime,
Duration nextSampleTime,
HandleEventCallback callback,
) {
while (_queuedEvents.isNotEmpty) {
final PointerEvent event = _queuedEvents.first;
Duration endTime = sampleTime;
// Scan queued events to determine end time.
final Iterator<PointerEvent> it = _queuedEvents.iterator;
while (it.moveNext()) {
final PointerEvent event = it.current;
// Potentially stop dispatching events if more recent than `sampleTime`.
if (event.timeStamp > sampleTime) {
// Stop if event is not up or removed. Otherwise, continue to
// allow early processing of up and remove events as this improves
// resampling of these events, which is important for fling
// animations.
if (event is! PointerUpEvent && event is! PointerRemovedEvent) {
// Definitely stop if more recent than `nextSampleTime`.
if (event.timeStamp >= nextSampleTime) {
break;
}
// When this line is reached, the following two invariants hold:
// (1) `event.timeStamp > sampleTime`
// (2) `_next` has the smallest time stamp that's no less than
// `sampleTime`
//
// Therefore, event must satisfy `event.timeStamp >= _next.timeStamp`.
//
// Those events with the minimum `event.timeStamp == _next.timeStamp`
// time stamp are processed early for smoother fling. For events with
// `event.timeStamp > _next.timeStamp`, the following lines break the
// while loop to stop the early processing.
//
// Specifically, when `sampleTime < _next.timeStamp`, there must be
// at least one event with `_next.timeStamp == event.timeStamp`
// and that event is `_next` itself, and it will be processed early.
//
// When `sampleTime == _next.timeStamp`, all events with
// `event.timeStamp > sampleTime` must also have
// `event.timeStamp > _next.timeStamp` so no events will be processed
// early.
//
// When the input frequency is no greater than the sampling
// frequency, this early processing should guarantee that `up` and
// `remove` events are always re-sampled.
final Duration nextTimeStamp = _next?.timeStamp ?? Duration.zero;
assert(event.timeStamp >= nextTimeStamp);
if (event.timeStamp > nextTimeStamp) {
// Update `endTime` to allow early processing of up and removed
// events as this improves resampling of these events, which is
// important for fling animations.
if (event is PointerUpEvent || event is PointerRemovedEvent) {
endTime = event.timeStamp;
continue;
}
// Stop if event is not move or hover.
if (event is! PointerMoveEvent && event is! PointerHoverEvent) {
break;
}
}
}
while (_queuedEvents.isNotEmpty) {
final PointerEvent event = _queuedEvents.first;
// Stop dispatching events if more recent than `endTime`.
if (event.timeStamp > endTime) {
break;
}
final bool wasTracked = _isTracked;
final bool wasDown = _isDown;
......@@ -285,11 +278,19 @@ class PointerEventResampler {
/// state that has changed since last sample.
///
/// Calling [callback] must not add or sample events.
void sample(Duration sampleTime, HandleEventCallback callback) {
///
/// Positive value for `nextSampleTime` allow early processing of
/// up and removed events. This improves resampling of these events,
/// which is important for fling animations.
void sample(
Duration sampleTime,
Duration nextSampleTime,
HandleEventCallback callback,
) {
_processPointerEvents(sampleTime);
// Dequeue and sample pointer events until `sampleTime`.
_dequeueAndSampleNonHoverOrMovePointerEventsUntil(sampleTime, callback);
_dequeueAndSampleNonHoverOrMovePointerEventsUntil(sampleTime, nextSampleTime, callback);
// Dispatch resampled pointer location event if tracked.
if (_isTracked) {
......
......@@ -30,32 +30,37 @@ void main() {
ui.PointerData(
change: ui.PointerChange.down,
physicalX: 0.0,
timeStamp: epoch + const Duration(milliseconds: 1),
timeStamp: epoch + const Duration(milliseconds: 10),
),
ui.PointerData(
change: ui.PointerChange.move,
physicalX: 10.0,
timeStamp: epoch + const Duration(milliseconds: 2),
timeStamp: epoch + const Duration(milliseconds: 20),
),
ui.PointerData(
change: ui.PointerChange.move,
physicalX: 20.0,
timeStamp: epoch + const Duration(milliseconds: 3),
timeStamp: epoch + const Duration(milliseconds: 30),
),
ui.PointerData(
change: ui.PointerChange.move,
physicalX: 30.0,
timeStamp: epoch + const Duration(milliseconds: 4),
timeStamp: epoch + const Duration(milliseconds: 40),
),
ui.PointerData(
change: ui.PointerChange.move,
physicalX: 40.0,
timeStamp: epoch + const Duration(milliseconds: 50),
),
ui.PointerData(
change: ui.PointerChange.up,
physicalX: 40.0,
timeStamp: epoch + const Duration(milliseconds: 5),
timeStamp: epoch + const Duration(milliseconds: 60),
),
ui.PointerData(
change: ui.PointerChange.remove,
physicalX: 40.0,
timeStamp: epoch + const Duration(milliseconds: 6),
timeStamp: epoch + const Duration(milliseconds: 70),
),
],
);
......@@ -74,27 +79,27 @@ void main() {
);
GestureBinding.instance!.resamplingEnabled = true;
const Duration kSamplingOffset = Duration(microseconds: -5500);
const Duration kSamplingOffset = Duration(milliseconds: -5);
GestureBinding.instance!.samplingOffset = kSamplingOffset;
ui.window.onPointerDataPacket!(packet);
expect(events.length, 0);
await tester.pump(const Duration(milliseconds: 7));
await tester.pump(const Duration(milliseconds: 20));
expect(events.length, 1);
expect(events[0], isA<PointerDownEvent>());
expect(events[0].timeStamp, currentTestFrameTime() + kSamplingOffset);
expect(events[0].position, Offset(5.0 / ui.window.devicePixelRatio, 0.0));
// Now the system time is epoch + 9ms
await tester.pump(const Duration(milliseconds: 2));
// Now the system time is epoch + 40ms
await tester.pump(const Duration(milliseconds: 20));
expect(events.length, 2);
expect(events[1].timeStamp, currentTestFrameTime() + kSamplingOffset);
expect(events[1], isA<PointerMoveEvent>());
expect(events[1].position, Offset(25.0 / ui.window.devicePixelRatio, 0.0));
expect(events[1].delta, Offset(20.0 / ui.window.devicePixelRatio, 0.0));
// Now the system time is epoch + 11ms
await tester.pump(const Duration(milliseconds: 2));
// Now the system time is epoch + 60ms
await tester.pump(const Duration(milliseconds: 20));
expect(events.length, 4);
expect(events[2].timeStamp, currentTestFrameTime() + kSamplingOffset);
expect(events[2], isA<PointerMoveEvent>());
......
......@@ -56,6 +56,20 @@ void main() {
);
}
PointerEvent _createSimulatedPointerHoverEvent(
int timeStampUs,
double x,
double y,
double deltaX,
double deltaY,
) {
return PointerHoverEvent(
timeStamp: Duration(microseconds: timeStampUs),
position: Offset(x, y),
delta: Offset(deltaX, deltaY),
);
}
PointerEvent _createSimulatedPointerUpEvent(
int timeStampUs,
double x,
......@@ -70,11 +84,14 @@ void main() {
test('basic', () {
final PointerEventResampler resampler = PointerEventResampler();
final PointerEvent event0 = _createSimulatedPointerAddedEvent(1000, 0.0, 50.0);
final PointerEvent event1 = _createSimulatedPointerDownEvent(2000, 10.0, 40.0);
final PointerEvent event2 = _createSimulatedPointerMoveEvent(3000, 20.0, 30.0, 10.0, -10.0);
final PointerEvent event3 = _createSimulatedPointerMoveEvent(4000, 30.0, 20.0, 10.0, -10.0);
final PointerEvent event4 = _createSimulatedPointerUpEvent(5000, 40.0, 10.0);
final PointerEvent event5 = _createSimulatedPointerRemovedEvent(6000, 50.0, 0.0);
final PointerEvent event1 = _createSimulatedPointerHoverEvent(2000, 10.0, 40.0, 10.0, -10.0);
final PointerEvent event2 = _createSimulatedPointerDownEvent(2000, 10.0, 40.0);
final PointerEvent event3 = _createSimulatedPointerMoveEvent(3000, 20.0, 30.0, 10.0, -10.0);
final PointerEvent event4 = _createSimulatedPointerMoveEvent(4000, 30.0, 20.0, 10.0, -10.0);
final PointerEvent event5 = _createSimulatedPointerUpEvent(4000, 30.0, 20.0);
final PointerEvent event6 = _createSimulatedPointerHoverEvent(5000, 40.0, 10.0, 10.0, -10.0);
final PointerEvent event7 = _createSimulatedPointerHoverEvent(6000, 50.0, 0.0, 10.0, -10.0);
final PointerEvent event8 = _createSimulatedPointerRemovedEvent(6000, 50.0, 0.0);
resampler
..addEvent(event0)
......@@ -82,16 +99,19 @@ void main() {
..addEvent(event2)
..addEvent(event3)
..addEvent(event4)
..addEvent(event5);
..addEvent(event5)
..addEvent(event6)
..addEvent(event7)
..addEvent(event8);
final List<PointerEvent> result = <PointerEvent>[];
resampler.sample(const Duration(microseconds: 500), result.add);
resampler.sample(const Duration(microseconds: 500), Duration.zero, result.add);
// No pointer event should have been returned yet.
expect(result.isEmpty, true);
resampler.sample(const Duration(microseconds: 1500), result.add);
resampler.sample(const Duration(microseconds: 1500), Duration.zero, result.add);
// Add pointer event should have been returned.
expect(result.length, 1);
......@@ -100,7 +120,7 @@ void main() {
expect(result[0].position.dx, 5.0);
expect(result[0].position.dy, 45.0);
resampler.sample(const Duration(microseconds: 2500), result.add);
resampler.sample(const Duration(microseconds: 2500), Duration.zero, result.add);
// Hover and down pointer events should have been returned.
expect(result.length, 3);
......@@ -115,7 +135,7 @@ void main() {
expect(result[2].position.dx, 15.0);
expect(result[2].position.dy, 35.0);
resampler.sample(const Duration(microseconds: 3500), result.add);
resampler.sample(const Duration(microseconds: 3500), Duration.zero, result.add);
// Move pointer event should have been returned.
expect(result.length, 4);
......@@ -126,7 +146,7 @@ void main() {
expect(result[3].delta.dx, 10.0);
expect(result[3].delta.dy, -10.0);
resampler.sample(const Duration(microseconds: 4500), result.add);
resampler.sample(const Duration(microseconds: 4500), Duration.zero, result.add);
// Move and up pointer events should have been returned.
expect(result.length, 6);
......@@ -141,35 +161,49 @@ void main() {
expect(result[5].position.dx, 35.0);
expect(result[5].position.dy, 15.0);
resampler.sample(const Duration(microseconds: 5500), result.add);
resampler.sample(const Duration(microseconds: 5500), Duration.zero, result.add);
// Hover and remove pointer events should have been returned.
expect(result.length, 8);
// Hover pointer event should have been returned.
expect(result.length, 7);
expect(result[6].timeStamp, const Duration(microseconds: 5500));
expect(result[6] is PointerHoverEvent, true);
expect(result[6].position.dx, 45.0);
expect(result[6].position.dy, 5.0);
expect(result[6].delta.dx, 10.0);
expect(result[6].delta.dy, -10.0);
expect(result[7].timeStamp, const Duration(microseconds: 5500));
expect(result[7] is PointerRemovedEvent, true);
expect(result[7].position.dx, 45.0);
expect(result[7].position.dy, 5.0);
resampler.sample(const Duration(microseconds: 6500), result.add);
resampler.sample(const Duration(microseconds: 6500), Duration.zero, result.add);
// Hover and removed pointer events should have been returned.
expect(result.length, 9);
expect(result[7].timeStamp, const Duration(microseconds: 6500));
expect(result[7] is PointerHoverEvent, true);
expect(result[7].position.dx, 50.0);
expect(result[7].position.dy, 0.0);
expect(result[7].delta.dx, 5.0);
expect(result[7].delta.dy, -5.0);
expect(result[8].timeStamp, const Duration(microseconds: 6500));
expect(result[8] is PointerRemovedEvent, true);
expect(result[8].position.dx, 50.0);
expect(result[8].position.dy, 0.0);
resampler.sample(const Duration(microseconds: 7500), Duration.zero, result.add);
// No pointer event should have been returned.
expect(result.length, 8);
expect(result.length, 9);
});
test('stream', () {
final PointerEventResampler resampler = PointerEventResampler();
final PointerEvent event0 = _createSimulatedPointerAddedEvent(1000, 0.0, 50.0);
final PointerEvent event1 = _createSimulatedPointerDownEvent(2000, 10.0, 40.0);
final PointerEvent event2 = _createSimulatedPointerMoveEvent(3000, 20.0, 30.0, 10.0, -10.0);
final PointerEvent event3 = _createSimulatedPointerMoveEvent(4000, 30.0, 20.0, 10.0, -10.0);
final PointerEvent event4 = _createSimulatedPointerUpEvent(5000, 40.0, 10.0);
final PointerEvent event5 = _createSimulatedPointerRemovedEvent(6000, 50.0, 0.0);
final PointerEvent event1 = _createSimulatedPointerHoverEvent(2000, 10.0, 40.0, 10.0, -10.0);
final PointerEvent event2 = _createSimulatedPointerDownEvent(2000, 10.0, 40.0);
final PointerEvent event3 = _createSimulatedPointerMoveEvent(3000, 20.0, 30.0, 10.0, -10.0);
final PointerEvent event4 = _createSimulatedPointerMoveEvent(4000, 30.0, 20.0, 10.0, -10.0);
final PointerEvent event5 = _createSimulatedPointerUpEvent(4000, 30.0, 20.0);
final PointerEvent event6 = _createSimulatedPointerHoverEvent(5000, 40.0, 10.0, 10.0, -10.0);
final PointerEvent event7 = _createSimulatedPointerHoverEvent(6000, 50.0, 0.0, 10.0, -10.0);
final PointerEvent event8 = _createSimulatedPointerRemovedEvent(6000, 50.0, 0.0);
resampler.addEvent(event0);
......@@ -179,14 +213,16 @@ void main() {
final List<PointerEvent> result = <PointerEvent>[];
resampler.sample(const Duration(microseconds: 500), result.add);
resampler.sample(const Duration(microseconds: 500), Duration.zero, result.add);
// No pointer event should have been returned yet.
expect(result.isEmpty, true);
resampler.addEvent(event1);
resampler
..addEvent(event1)
..addEvent(event2);
resampler.sample(const Duration(microseconds: 500), result.add);
resampler.sample(const Duration(microseconds: 500), Duration.zero, result.add);
// No pointer event should have been returned yet.
expect(result.isEmpty, true);
......@@ -195,18 +231,18 @@ void main() {
// Advance sample time to 1.5 ms.
//
resampler.sample(const Duration(microseconds: 1500), result.add);
resampler.sample(const Duration(microseconds: 1500), Duration.zero, result.add);
// Add pointer event should have been returned.
// Added pointer event should have been returned.
expect(result.length, 1);
expect(result[0].timeStamp, const Duration(microseconds: 1500));
expect(result[0] is PointerAddedEvent, true);
expect(result[0].position.dx, 5.0);
expect(result[0].position.dy, 45.0);
resampler.addEvent(event2);
resampler.addEvent(event3);
resampler.sample(const Duration(microseconds: 1500), result.add);
resampler.sample(const Duration(microseconds: 1500), Duration.zero, result.add);
// No more pointer events should have been returned.
expect(result.length, 1);
......@@ -215,7 +251,7 @@ void main() {
// Advance sample time to 2.5 ms.
//
resampler.sample(const Duration(microseconds: 2500), result.add);
resampler.sample(const Duration(microseconds: 2500), Duration.zero, result.add);
// Hover and down pointer events should have been returned.
expect(result.length, 3);
......@@ -230,9 +266,11 @@ void main() {
expect(result[2].position.dx, 15.0);
expect(result[2].position.dy, 35.0);
resampler.addEvent(event3);
resampler
..addEvent(event4)
..addEvent(event5);
resampler.sample(const Duration(microseconds: 2500), result.add);
resampler.sample(const Duration(microseconds: 2500), Duration.zero, result.add);
// No more pointer events should have been returned.
expect(result.length, 3);
......@@ -241,7 +279,7 @@ void main() {
// Advance sample time to 3.5 ms.
//
resampler.sample(const Duration(microseconds: 3500), result.add);
resampler.sample(const Duration(microseconds: 3500), Duration.zero, result.add);
// Move pointer event should have been returned.
expect(result.length, 4);
......@@ -252,9 +290,9 @@ void main() {
expect(result[3].delta.dx, 10.0);
expect(result[3].delta.dy, -10.0);
resampler.addEvent(event4);
resampler.addEvent(event6);
resampler.sample(const Duration(microseconds: 3500), result.add);
resampler.sample(const Duration(microseconds: 3500), Duration.zero, result.add);
// No more pointer events should have been returned.
expect(result.length, 4);
......@@ -263,7 +301,7 @@ void main() {
// Advance sample time to 4.5 ms.
//
resampler.sample(const Duration(microseconds: 4500), result.add);
resampler.sample(const Duration(microseconds: 4500), Duration.zero, result.add);
// Move and up pointer events should have been returned.
expect(result.length, 6);
......@@ -278,9 +316,11 @@ void main() {
expect(result[5].position.dx, 35.0);
expect(result[5].position.dy, 15.0);
resampler.addEvent(event5);
resampler
..addEvent(event7)
..addEvent(event8);
resampler.sample(const Duration(microseconds: 4500), result.add);
resampler.sample(const Duration(microseconds: 4500), Duration.zero, result.add);
// No more pointer events should have been returned.
expect(result.length, 6);
......@@ -289,29 +329,44 @@ void main() {
// Advance sample time to 5.5 ms.
//
resampler.sample(const Duration(microseconds: 5500), result.add);
resampler.sample(const Duration(microseconds: 5500), Duration.zero, result.add);
// Hover and remove pointer event should have been returned.
expect(result.length, 8);
// Hover pointer event should have been returned.
expect(result.length, 7);
expect(result[6].timeStamp, const Duration(microseconds: 5500));
expect(result[6] is PointerHoverEvent, true);
expect(result[6].position.dx, 45.0);
expect(result[6].position.dy, 5.0);
expect(result[6].delta.dx, 10.0);
expect(result[6].delta.dy, -10.0);
expect(result[7].timeStamp, const Duration(microseconds: 5500));
expect(result[7] is PointerRemovedEvent, true);
expect(result[7].position.dx, 45.0);
expect(result[7].position.dy, 5.0);
//
// Advance sample time to 6.5 ms.
//
resampler.sample(const Duration(microseconds: 6500), result.add);
resampler.sample(const Duration(microseconds: 6500), Duration.zero, result.add);
// Hover and removed pointer event should have been returned.
expect(result.length, 9);
expect(result[7].timeStamp, const Duration(microseconds: 6500));
expect(result[7] is PointerHoverEvent, true);
expect(result[7].position.dx, 50.0);
expect(result[7].position.dy, 0.0);
expect(result[7].delta.dx, 5.0);
expect(result[7].delta.dy, -5.0);
expect(result[8].timeStamp, const Duration(microseconds: 6500));
expect(result[8] is PointerRemovedEvent, true);
expect(result[8].position.dx, 50.0);
expect(result[8].position.dy, 0.0);
//
// Advance sample time to 7.5 ms.
//
resampler.sample(const Duration(microseconds: 7500), Duration.zero, result.add);
// No pointer events should have been returned.
expect(result.length, 8);
expect(result.length, 9);
});
test('quick tap', () {
......@@ -329,7 +384,7 @@ void main() {
final List<PointerEvent> result = <PointerEvent>[];
resampler.sample(const Duration(microseconds: 1500), result.add);
resampler.sample(const Duration(microseconds: 1500), Duration.zero, result.add);
// All pointer events should have been returned.
expect(result.length, 4);
......@@ -356,19 +411,21 @@ void main() {
final PointerEvent event0 = _createSimulatedPointerAddedEvent(1000, 0.0, 0.0);
final PointerEvent event1 = _createSimulatedPointerDownEvent(1000, 0.0, 0.0);
final PointerEvent event2 = _createSimulatedPointerMoveEvent(2000, 10.0, 0.0, 10.0, 0.0);
final PointerEvent event3 = _createSimulatedPointerUpEvent(3000, 20.0, 0.0);
final PointerEvent event4 = _createSimulatedPointerRemovedEvent(3000, 20.0, 0.0);
final PointerEvent event3 = _createSimulatedPointerMoveEvent(3000, 20.0, 0.0, 10.0, 0.0);
final PointerEvent event4 = _createSimulatedPointerUpEvent(3000, 20.0, 0.0);
final PointerEvent event5 = _createSimulatedPointerRemovedEvent(3000, 20.0, 0.0);
resampler
..addEvent(event0)
..addEvent(event1)
..addEvent(event2)
..addEvent(event3)
..addEvent(event4);
..addEvent(event4)
..addEvent(event5);
final List<PointerEvent> result = <PointerEvent>[];
resampler.sample(const Duration(microseconds: 1500), result.add);
resampler.sample(const Duration(microseconds: 1500), Duration.zero, result.add);
// Added and down pointer events should have been returned.
expect(result.length, 2);
......@@ -381,12 +438,12 @@ void main() {
expect(result[1].position.dx, 5.0);
expect(result[1].position.dy, 0.0);
resampler.sample(const Duration(microseconds: 1500), result.add);
resampler.sample(const Duration(microseconds: 1500), Duration.zero, result.add);
// No pointer events should have been returned.
expect(result.length, 2);
resampler.sample(const Duration(microseconds: 1750), result.add);
resampler.sample(const Duration(microseconds: 1750), Duration.zero, result.add);
// Move pointer event should have been returned.
expect(result.length, 3);
......@@ -397,7 +454,7 @@ void main() {
expect(result[2].delta.dx, 2.5);
expect(result[2].delta.dy, 0.0);
resampler.sample(const Duration(microseconds: 2000), result.add);
resampler.sample(const Duration(microseconds: 2000), Duration.zero, result.add);
// Another move pointer event should have been returned.
expect(result.length, 4);
......@@ -408,23 +465,23 @@ void main() {
expect(result[3].delta.dx, 2.5);
expect(result[3].delta.dy, 0.0);
resampler.sample(const Duration(microseconds: 2500), result.add);
resampler.sample(const Duration(microseconds: 3000), Duration.zero, result.add);
// Move, up and removed pointer events should have been returned.
expect(result.length, 7);
expect(result[4].timeStamp, const Duration(microseconds: 2500));
expect(result[4].timeStamp, const Duration(microseconds: 3000));
expect(result[4] is PointerMoveEvent, true);
expect(result[4].position.dx, 15.0);
expect(result[4].position.dx, 20.0);
expect(result[4].position.dy, 0.0);
expect(result[4].delta.dx, 5.0);
expect(result[4].delta.dx, 10.0);
expect(result[4].delta.dy, 0.0);
expect(result[5].timeStamp, const Duration(microseconds: 2500));
expect(result[5].timeStamp, const Duration(microseconds: 3000));
expect(result[5] is PointerUpEvent, true);
expect(result[5].position.dx, 15.0);
expect(result[5].position.dx, 20.0);
expect(result[5].position.dy, 0.0);
expect(result[6].timeStamp, const Duration(microseconds: 2500));
expect(result[6].timeStamp, const Duration(microseconds: 3000));
expect(result[6] is PointerRemovedEvent, true);
expect(result[6].position.dx, 15.0);
expect(result[6].position.dx, 20.0);
expect(result[6].position.dy, 0.0);
});
......@@ -447,9 +504,9 @@ void main() {
final List<PointerEvent> result = <PointerEvent>[];
resampler.sample(const Duration(microseconds: 2500), result.add);
resampler.sample(const Duration(microseconds: 2500), Duration.zero, result.add);
// Add and down pointer events should have been returned.
// Addeds and down pointer events should have been returned.
expect(result.length, 2);
expect(result[0].timeStamp, const Duration(microseconds: 2500));
expect(result[0] is PointerAddedEvent, true);
......@@ -460,7 +517,7 @@ void main() {
expect(result[1].position.dx, 12.5);
expect(result[1].position.dy, 0.0);
resampler.sample(const Duration(microseconds: 5500), result.add);
resampler.sample(const Duration(microseconds: 5500), Duration.zero, result.add);
// Move, up and removed pointer events should have been returned.
expect(result.length, 5);
......@@ -479,7 +536,7 @@ void main() {
expect(result[4].position.dx, 30.0);
expect(result[4].position.dy, 0.0);
resampler.sample(const Duration(microseconds: 6500), result.add);
resampler.sample(const Duration(microseconds: 6500), Duration.zero, result.add);
// No pointer events should have been returned.
expect(result.length, 5);
......@@ -491,9 +548,11 @@ void main() {
final PointerEvent event1 = _createSimulatedPointerDownEvent(1000, 0.0, 0.0);
final PointerEvent event2 = _createSimulatedPointerMoveEvent(2000, 10.0, 0.0, 10.0, 0.0);
final PointerEvent event3 = _createSimulatedPointerUpEvent(3000, 10.0, 0.0);
final PointerEvent event4 = _createSimulatedPointerDownEvent(4000, 20.0, 0.0);
final PointerEvent event5 = _createSimulatedPointerUpEvent(5000, 30.0, 0.0);
final PointerEvent event6 = _createSimulatedPointerRemovedEvent(5000, 30.0, 0.0);
final PointerEvent event4 = _createSimulatedPointerHoverEvent(4000, 20.0, 0.0, 10.0, 0.0);
final PointerEvent event5 = _createSimulatedPointerDownEvent(4000, 20.0, 0.0);
final PointerEvent event6 = _createSimulatedPointerMoveEvent(5000, 30.0, 0.0, 10.0, 0.0);
final PointerEvent event7 = _createSimulatedPointerUpEvent(5000, 30.0, 0.0);
final PointerEvent event8 = _createSimulatedPointerRemovedEvent(5000, 30.0, 0.0);
resampler
..addEvent(event0)
......@@ -502,11 +561,13 @@ void main() {
..addEvent(event3)
..addEvent(event4)
..addEvent(event5)
..addEvent(event6);
..addEvent(event6)
..addEvent(event7)
..addEvent(event8);
final List<PointerEvent> result = <PointerEvent>[];
resampler.sample(const Duration(microseconds: 1500), result.add);
resampler.sample(const Duration(microseconds: 1500), Duration.zero, result.add);
// Added and down pointer events should have been returned.
expect(result.length, 2);
......@@ -519,34 +580,34 @@ void main() {
expect(result[1].position.dx, 5.0);
expect(result[1].position.dy, 0.0);
resampler.sample(const Duration(microseconds: 4500), result.add);
resampler.sample(const Duration(microseconds: 5500), Duration.zero, result.add);
// All remaining pointer events should have been returned.
expect(result.length, 7);
expect(result[2].timeStamp, const Duration(microseconds: 4500));
expect(result[2].timeStamp, const Duration(microseconds: 5500));
expect(result[2] is PointerMoveEvent, true);
expect(result[2].position.dx, 25.0);
expect(result[2].position.dx, 30.0);
expect(result[2].position.dy, 0.0);
expect(result[2].delta.dx, 20.0);
expect(result[2].delta.dx, 25.0);
expect(result[2].delta.dy, 0.0);
expect(result[3].timeStamp, const Duration(microseconds: 4500));
expect(result[3].timeStamp, const Duration(microseconds: 5500));
expect(result[3] is PointerUpEvent, true);
expect(result[3].position.dx, 25.0);
expect(result[3].position.dx, 30.0);
expect(result[3].position.dy, 0.0);
expect(result[4].timeStamp, const Duration(microseconds: 4500));
expect(result[4].timeStamp, const Duration(microseconds: 5500));
expect(result[4] is PointerDownEvent, true);
expect(result[4].position.dx, 25.0);
expect(result[4].position.dx, 30.0);
expect(result[4].position.dy, 0.0);
expect(result[5].timeStamp, const Duration(microseconds: 4500));
expect(result[5].timeStamp, const Duration(microseconds: 5500));
expect(result[5] is PointerUpEvent, true);
expect(result[5].position.dx, 25.0);
expect(result[5].position.dx, 30.0);
expect(result[5].position.dy, 0.0);
expect(result[6].timeStamp, const Duration(microseconds: 4500));
expect(result[6].timeStamp, const Duration(microseconds: 5500));
expect(result[6] is PointerRemovedEvent, true);
expect(result[6].position.dx, 25.0);
expect(result[6].position.dx, 30.0);
expect(result[6].position.dy, 0.0);
resampler.sample(const Duration(microseconds: 5500), result.add);
resampler.sample(const Duration(microseconds: 6500), Duration.zero, result.add);
// No pointer events should have been returned.
expect(result.length, 7);
......@@ -556,23 +617,25 @@ void main() {
final PointerEventResampler resampler = PointerEventResampler();
final PointerEvent event0 = _createSimulatedPointerAddedEvent(1000, 0.0, 0.0);
final PointerEvent event1 = _createSimulatedPointerDownEvent(1000, 0.0, 0.0);
final PointerEvent event2 = _createSimulatedPointerUpEvent(4000, 30.0, 0.0);
final PointerEvent event3 = _createSimulatedPointerRemovedEvent(4000, 30.0, 0.0);
final PointerEvent event2 = _createSimulatedPointerMoveEvent(4000, 30.0, 0.0, 30.0, 0.0);
final PointerEvent event3 = _createSimulatedPointerUpEvent(4000, 30.0, 0.0);
final PointerEvent event4 = _createSimulatedPointerRemovedEvent(4000, 30.0, 0.0);
resampler
..addEvent(event0)
..addEvent(event1)
..addEvent(event2)
..addEvent(event3);
..addEvent(event3)
..addEvent(event4);
final List<PointerEvent> result = <PointerEvent>[];
resampler.sample(const Duration(microseconds: 500), result.add);
resampler.sample(const Duration(microseconds: 500), Duration.zero, result.add);
// No pointer events should have been returned.
expect(result.isEmpty, true);
resampler.sample(const Duration(microseconds: 5500), result.add);
resampler.sample(const Duration(microseconds: 5500), Duration.zero, result.add);
// All remaining pointer events should have been returned.
expect(result.length, 4);
......@@ -593,7 +656,7 @@ void main() {
expect(result[3].position.dx, 30.0);
expect(result[3].position.dy, 0.0);
resampler.sample(const Duration(microseconds: 6500), result.add);
resampler.sample(const Duration(microseconds: 6500), Duration.zero, result.add);
// No pointer events should have been returned.
expect(result.length, 4);
......@@ -604,19 +667,21 @@ void main() {
final PointerEvent event0 = _createSimulatedPointerAddedEvent(1000, 0.0, 0.0);
final PointerEvent event1 = _createSimulatedPointerDownEvent(2000, 0.0, 0.0);
final PointerEvent event2 = _createSimulatedPointerMoveEvent(3000, 10.0, 0.0, 10.0, 0.0);
final PointerEvent event3 = _createSimulatedPointerUpEvent(4000, 20.0, 0.0);
final PointerEvent event4 = _createSimulatedPointerRemovedEvent(5000, 20.0, 0.0);
final PointerEvent event3 = _createSimulatedPointerMoveEvent(4000, 20.0, 0.0, 10.0, 0.0);
final PointerEvent event4 = _createSimulatedPointerUpEvent(4000, 20.0, 0.0);
final PointerEvent event5 = _createSimulatedPointerRemovedEvent(5000, 20.0, 0.0);
resampler
..addEvent(event0)
..addEvent(event1)
..addEvent(event2)
..addEvent(event3)
..addEvent(event4);
..addEvent(event4)
..addEvent(event5);
final List<PointerEvent> result = <PointerEvent>[];
resampler.sample(const Duration(microseconds: 500), result.add);
resampler.sample(const Duration(microseconds: 500), Duration.zero, result.add);
// No pointer events should have been returned.
expect(result.isEmpty, true);
......@@ -625,7 +690,7 @@ void main() {
// All pointer events should have been returned with orignal
// time stamps and positions.
expect(result.length, 5);
expect(result.length, 6);
expect(result[0].timeStamp, const Duration(microseconds: 1000));
expect(result[0] is PointerAddedEvent, true);
expect(result[0].position.dx, 0.0);
......@@ -641,18 +706,24 @@ void main() {
expect(result[2].delta.dx, 10.0);
expect(result[2].delta.dy, 0.0);
expect(result[3].timeStamp, const Duration(microseconds: 4000));
expect(result[3] is PointerUpEvent, true);
expect(result[3] is PointerMoveEvent, true);
expect(result[3].position.dx, 20.0);
expect(result[3].position.dy, 0.0);
expect(result[4].timeStamp, const Duration(microseconds: 5000));
expect(result[4] is PointerRemovedEvent, true);
expect(result[3].delta.dx, 10.0);
expect(result[3].delta.dy, 0.0);
expect(result[4].timeStamp, const Duration(microseconds: 4000));
expect(result[4] is PointerUpEvent, true);
expect(result[4].position.dx, 20.0);
expect(result[4].position.dy, 0.0);
expect(result[5].timeStamp, const Duration(microseconds: 5000));
expect(result[5] is PointerRemovedEvent, true);
expect(result[5].position.dx, 20.0);
expect(result[5].position.dy, 0.0);
resampler.sample(const Duration(microseconds: 10000), result.add);
resampler.sample(const Duration(microseconds: 10000), Duration.zero, result.add);
// No pointer events should have been returned.
expect(result.length, 5);
expect(result.length, 6);
});
test('synthetic move', () {
......@@ -672,12 +743,12 @@ void main() {
final List<PointerEvent> result = <PointerEvent>[];
resampler.sample(const Duration(microseconds: 500), result.add);
resampler.sample(const Duration(microseconds: 500), Duration.zero, result.add);
// No pointer events should have been returned.
expect(result.isEmpty, true);
resampler.sample(const Duration(microseconds: 2000), result.add);
resampler.sample(const Duration(microseconds: 2000), Duration.zero, result.add);
// Added and down pointer events should have been returned.
expect(result.length, 2);
......@@ -690,7 +761,7 @@ void main() {
expect(result[1].position.dx, 0.0);
expect(result[1].position.dy, 0.0);
resampler.sample(const Duration(microseconds: 5000), result.add);
resampler.sample(const Duration(microseconds: 5000), Duration.zero, result.add);
// All remaining pointer events and a synthetic move event should
// have been returned.
......@@ -710,9 +781,92 @@ void main() {
expect(result[4].position.dx, 10.0);
expect(result[4].position.dy, 0.0);
resampler.sample(const Duration(microseconds: 10000), result.add);
resampler.sample(const Duration(microseconds: 10000), Duration.zero, result.add);
// No pointer events should have been returned.
expect(result.length, 5);
});
test('next sample time', () {
final PointerEventResampler resampler = PointerEventResampler();
final PointerEvent event0 = _createSimulatedPointerAddedEvent(1000, 0.0, 0.0);
final PointerEvent event1 = _createSimulatedPointerDownEvent(1000, 0.0, 0.0);
final PointerEvent event2 = _createSimulatedPointerMoveEvent(2000, 10.0, 0.0, 10.0, 0.0);
final PointerEvent event3 = _createSimulatedPointerMoveEvent(3000, 20.0, 0.0, 10.0, 0.0);
final PointerEvent event4 = _createSimulatedPointerUpEvent(3000, 20.0, 0.0);
final PointerEvent event5 = _createSimulatedPointerHoverEvent(4000, 30.0, 0.0, 10.0, 0.0);
final PointerEvent event6 = _createSimulatedPointerRemovedEvent(4000, 30.0, 0.0);
resampler
..addEvent(event0)
..addEvent(event1)
..addEvent(event2)
..addEvent(event3)
..addEvent(event4)
..addEvent(event5)
..addEvent(event6);
final List<PointerEvent> result = <PointerEvent>[];
Duration sampleTime = const Duration(microseconds: 500);
Duration nextSampleTime = const Duration(microseconds: 1500);
resampler.sample(sampleTime, nextSampleTime, result.add);
// No pointer events should have been returned.
expect(result.isEmpty, true);
sampleTime = nextSampleTime;
nextSampleTime = const Duration(microseconds: 2500);
resampler.sample(sampleTime, nextSampleTime, result.add);
// Added and down pointer events should have been returned.
expect(result.length, 2);
expect(result[0].timeStamp, const Duration(microseconds: 1500));
expect(result[0] is PointerAddedEvent, true);
expect(result[0].position.dx, 5.0);
expect(result[0].position.dy, 0.0);
expect(result[1].timeStamp, const Duration(microseconds: 1500));
expect(result[1] is PointerDownEvent, true);
expect(result[1].position.dx, 5.0);
expect(result[1].position.dy, 0.0);
sampleTime = nextSampleTime;
nextSampleTime = const Duration(microseconds: 3500);
resampler.sample(sampleTime, nextSampleTime, result.add);
// Move and up pointer events should have been returned.
expect(result.length, 4);
expect(result[2].timeStamp, const Duration(microseconds: 2500));
expect(result[2] is PointerMoveEvent, true);
expect(result[2].position.dx, 15.0);
expect(result[2].position.dy, 0.0);
expect(result[2].delta.dx, 10.0);
expect(result[2].delta.dy, 0.0);
expect(result[3].timeStamp, const Duration(microseconds: 2500));
expect(result[3] is PointerUpEvent, true);
expect(result[3].position.dx, 15.0);
expect(result[3].position.dy, 0.0);
sampleTime = nextSampleTime;
nextSampleTime = const Duration(microseconds: 4500);
resampler.sample(sampleTime, nextSampleTime, result.add);
// All remaining pointer events should have been returned.
expect(result.length, 6);
expect(result[4].timeStamp, const Duration(microseconds: 3500));
expect(result[4] is PointerHoverEvent, true);
expect(result[4].position.dx, 25.0);
expect(result[4].position.dy, 0.0);
expect(result[4].delta.dx, 10.0);
expect(result[4].delta.dy, 0.0);
expect(result[5].timeStamp, const Duration(microseconds: 3500));
expect(result[5] is PointerRemovedEvent, true);
expect(result[5].position.dx, 25.0);
expect(result[5].position.dy, 0.0);
resampler.sample(const Duration(microseconds: 10000), Duration.zero, result.add);
// No pointer events should have been returned.
expect(result.length, 6);
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment