Commit c9b0b3bb authored by xster's avatar xster Committed by GitHub

Fix iOS last up event velocity calculation - version 3 (#11571)

* Add synthesized property to pointer events

* test
parent 680d581d
......@@ -170,7 +170,8 @@ class PointerEventConverter {
radiusMin: datum.radiusMin,
radiusMax: datum.radiusMax,
orientation: datum.orientation,
tilt: datum.tilt
tilt: datum.tilt,
synthesized: true,
);
state.lastPosition = position;
}
......@@ -257,7 +258,8 @@ class PointerEventConverter {
radiusMin: datum.radiusMin,
radiusMax: datum.radiusMax,
orientation: datum.orientation,
tilt: datum.tilt
tilt: datum.tilt,
synthesized: true,
);
state.lastPosition = position;
}
......
......@@ -113,7 +113,8 @@ abstract class PointerEvent {
this.radiusMin: 0.0,
this.radiusMax: 0.0,
this.orientation: 0.0,
this.tilt: 0.0
this.tilt: 0.0,
this.synthesized: false,
});
/// Time of event dispatch, relative to an arbitrary timeline.
......@@ -235,6 +236,18 @@ abstract class PointerEvent {
/// the stylus is flat on that surface).
final double tilt;
/// We occasionally synthesize PointerEvents that aren't exact translations
/// of [ui.PointerData] from the engine to cover small cross-OS discrepancies
/// in pointer behaviours.
///
/// For instance, on end events, Android always drops any location changes
/// that happened between its reporting intervals when emiting the end events.
///
/// On iOS, minor incorrect location changes from the previous move events
/// can be reported on end events. We synthesize a [PointerEvent] to cover
/// the difference between the 2 events in that case.
final bool synthesized;
@override
String toString() => '$runtimeType($position)';
......@@ -261,7 +274,8 @@ abstract class PointerEvent {
'radiusMin: $radiusMin, '
'radiusMax: $radiusMax, '
'orientation: $orientation, '
'tilt: $tilt'
'tilt: $tilt, '
'synthesized: $synthesized'
')';
}
}
......@@ -365,7 +379,8 @@ class PointerHoverEvent extends PointerEvent {
double radiusMin: 0.0,
double radiusMax: 0.0,
double orientation: 0.0,
double tilt: 0.0
double tilt: 0.0,
bool synthesized: false,
}) : super(
timeStamp: timeStamp,
kind: kind,
......@@ -384,7 +399,8 @@ class PointerHoverEvent extends PointerEvent {
radiusMin: radiusMin,
radiusMax: radiusMax,
orientation: orientation,
tilt: tilt
tilt: tilt,
synthesized: synthesized,
);
}
......@@ -463,7 +479,8 @@ class PointerMoveEvent extends PointerEvent {
double radiusMin: 0.0,
double radiusMax: 0.0,
double orientation: 0.0,
double tilt: 0.0
double tilt: 0.0,
bool synthesized: false,
}) : super(
timeStamp: timeStamp,
pointer: pointer,
......@@ -484,7 +501,8 @@ class PointerMoveEvent extends PointerEvent {
radiusMin: radiusMin,
radiusMax: radiusMax,
orientation: orientation,
tilt: tilt
tilt: tilt,
synthesized: synthesized,
);
}
......
......@@ -130,7 +130,8 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
if (event is PointerMoveEvent) {
final VelocityTracker tracker = _velocityTrackers[event.pointer];
assert(tracker != null);
tracker.addPosition(event.timeStamp, event.position);
if (!event.synthesized)
tracker.addPosition(event.timeStamp, event.position);
final Offset delta = event.delta;
if (_state == _DragState.accepted) {
if (onUpdate != null) {
......
......@@ -62,7 +62,8 @@ abstract class MultiDragPointerState {
void _move(PointerMoveEvent event) {
assert(_arenaEntry != null);
_velocityTracker.addPosition(event.timeStamp, event.position);
if (!event.synthesized)
_velocityTracker.addPosition(event.timeStamp, event.position);
if (_client != null) {
assert(pendingDelta == null);
// Call client last to avoid reentrancy.
......
......@@ -152,7 +152,8 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
if (event is PointerMoveEvent) {
final VelocityTracker tracker = _velocityTrackers[event.pointer];
assert(tracker != null);
tracker.addPosition(event.timeStamp, event.position);
if (!event.synthesized)
tracker.addPosition(event.timeStamp, event.position);
_pointerLocations[event.pointer] = event.position;
shouldStartIfAccepted = true;
} else if (event is PointerDownEvent) {
......
......@@ -236,6 +236,38 @@ void main() {
drag.dispose();
});
testGesture('Synthesized pointer events are ignored for velocity tracking', (GestureTester tester) {
final HorizontalDragGestureRecognizer drag = new HorizontalDragGestureRecognizer();
Velocity velocity;
drag.onEnd = (DragEndDetails details) {
velocity = details.velocity;
};
final TestPointer pointer = new TestPointer(1);
final PointerDownEvent down = pointer.down(const Offset(10.0, 25.0), timeStamp: const Duration(milliseconds: 10));
drag.addPointer(down);
tester.closeArena(1);
tester.route(down);
tester.route(pointer.move(const Offset(20.0, 25.0), timeStamp: const Duration(milliseconds: 20)));
tester.route(pointer.move(const Offset(30.0, 25.0), timeStamp: const Duration(milliseconds: 30)));
tester.route(pointer.move(const Offset(40.0, 25.0), timeStamp: const Duration(milliseconds: 40)));
tester.route(pointer.move(const Offset(50.0, 25.0), timeStamp: const Duration(milliseconds: 50)));
tester.route(new PointerMoveEvent(
pointer: 1,
// Simulate a small synthesized wobble which would have slowed down the
// horizontal velocity from 1 px/ms and introduced a slight vertical velocity.
position: const Offset(51.0, 26.0),
timeStamp: const Duration(milliseconds: 60),
synthesized: true,
));
tester.route(pointer.up(timeStamp: const Duration(milliseconds: 20)));
expect(velocity.pixelsPerSecond.dx, moreOrLessEquals(1000.0));
expect(velocity.pixelsPerSecond.dy, moreOrLessEquals(0.0));
drag.dispose();
});
testGesture('Drag details', (GestureTester tester) {
expect(new DragDownDetails(), hasOneLineDescription);
expect(new DragStartDetails(), hasOneLineDescription);
......
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