Commit 2447f918 authored by xster's avatar xster Committed by GitHub

Pass on original pointer event timestamps to drag events (#11988)

* Record original pointer event timestamp

* review

* review

* review
parent 8566777d
...@@ -52,9 +52,15 @@ class DragStartDetails { ...@@ -52,9 +52,15 @@ class DragStartDetails {
/// Creates details for a [GestureDragStartCallback]. /// Creates details for a [GestureDragStartCallback].
/// ///
/// The [globalPosition] argument must not be null. /// The [globalPosition] argument must not be null.
DragStartDetails({ this.globalPosition: Offset.zero }) DragStartDetails({ this.sourceTimeStamp, this.globalPosition: Offset.zero })
: assert(globalPosition != null); : assert(globalPosition != null);
/// Recorded timestamp of the source pointer event that triggered the drag
/// event.
///
/// Could be null if triggered from proxied events such as accessibility.
final Duration sourceTimeStamp;
/// The global position at which the pointer contacted the screen. /// The global position at which the pointer contacted the screen.
/// ///
/// Defaults to the origin if not specified in the constructor. /// Defaults to the origin if not specified in the constructor.
...@@ -94,6 +100,7 @@ class DragUpdateDetails { ...@@ -94,6 +100,7 @@ class DragUpdateDetails {
/// ///
/// The [globalPosition] argument must be provided and must not be null. /// The [globalPosition] argument must be provided and must not be null.
DragUpdateDetails({ DragUpdateDetails({
this.sourceTimeStamp,
this.delta: Offset.zero, this.delta: Offset.zero,
this.primaryDelta, this.primaryDelta,
@required this.globalPosition @required this.globalPosition
...@@ -102,6 +109,12 @@ class DragUpdateDetails { ...@@ -102,6 +109,12 @@ class DragUpdateDetails {
|| (primaryDelta == delta.dx && delta.dy == 0.0) || (primaryDelta == delta.dx && delta.dy == 0.0)
|| (primaryDelta == delta.dy && delta.dx == 0.0)); || (primaryDelta == delta.dy && delta.dx == 0.0));
/// Recorded timestamp of the source pointer event that triggered the drag
/// event.
///
/// Could be null if triggered from proxied events such as accessibility.
final Duration sourceTimeStamp;
/// The amount the pointer has moved since the previous update. /// The amount the pointer has moved since the previous update.
/// ///
/// If the [GestureDragUpdateCallback] is for a one-dimensional drag (e.g., /// If the [GestureDragUpdateCallback] is for a one-dimensional drag (e.g.,
......
...@@ -101,6 +101,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -101,6 +101,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
_DragState _state = _DragState.ready; _DragState _state = _DragState.ready;
Offset _initialPosition; Offset _initialPosition;
Offset _pendingDragOffset; Offset _pendingDragOffset;
Duration _lastPendingEventTimestamp;
bool _isFlingGesture(VelocityEstimate estimate); bool _isFlingGesture(VelocityEstimate estimate);
Offset _getDeltaForDetails(Offset delta); Offset _getDeltaForDetails(Offset delta);
...@@ -117,6 +118,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -117,6 +118,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
_state = _DragState.possible; _state = _DragState.possible;
_initialPosition = event.position; _initialPosition = event.position;
_pendingDragOffset = Offset.zero; _pendingDragOffset = Offset.zero;
_lastPendingEventTimestamp = event.timeStamp;
if (onDown != null) if (onDown != null)
invokeCallback<Null>('onDown', () => onDown(new DragDownDetails(globalPosition: _initialPosition))); // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504 invokeCallback<Null>('onDown', () => onDown(new DragDownDetails(globalPosition: _initialPosition))); // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504
} else if (_state == _DragState.accepted) { } else if (_state == _DragState.accepted) {
...@@ -139,6 +141,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -139,6 +141,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
if (_state == _DragState.accepted) { if (_state == _DragState.accepted) {
if (onUpdate != null) { if (onUpdate != null) {
invokeCallback<Null>('onUpdate', () => onUpdate(new DragUpdateDetails( // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504 invokeCallback<Null>('onUpdate', () => onUpdate(new DragUpdateDetails( // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504
sourceTimeStamp: event.timeStamp,
delta: _getDeltaForDetails(delta), delta: _getDeltaForDetails(delta),
primaryDelta: _getPrimaryValueFromOffset(delta), primaryDelta: _getPrimaryValueFromOffset(delta),
globalPosition: event.position, globalPosition: event.position,
...@@ -146,6 +149,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -146,6 +149,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
} }
} else { } else {
_pendingDragOffset += delta; _pendingDragOffset += delta;
_lastPendingEventTimestamp = event.timeStamp;
if (_hasSufficientPendingDragDeltaToAccept) if (_hasSufficientPendingDragDeltaToAccept)
resolve(GestureDisposition.accepted); resolve(GestureDisposition.accepted);
} }
...@@ -158,14 +162,18 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -158,14 +162,18 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
if (_state != _DragState.accepted) { if (_state != _DragState.accepted) {
_state = _DragState.accepted; _state = _DragState.accepted;
final Offset delta = _pendingDragOffset; final Offset delta = _pendingDragOffset;
final Duration timestamp = _lastPendingEventTimestamp;
_pendingDragOffset = Offset.zero; _pendingDragOffset = Offset.zero;
_lastPendingEventTimestamp = null;
if (onStart != null) { if (onStart != null) {
invokeCallback<Null>('onStart', () => onStart(new DragStartDetails( // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504 invokeCallback<Null>('onStart', () => onStart(new DragStartDetails( // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504
sourceTimeStamp: timestamp,
globalPosition: _initialPosition, globalPosition: _initialPosition,
))); )));
} }
if (delta != Offset.zero && onUpdate != null) { if (delta != Offset.zero && onUpdate != null) {
invokeCallback<Null>('onUpdate', () => onUpdate(new DragUpdateDetails( // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504 invokeCallback<Null>('onUpdate', () => onUpdate(new DragUpdateDetails( // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504
sourceTimeStamp: timestamp,
delta: _getDeltaForDetails(delta), delta: _getDeltaForDetails(delta),
primaryDelta: _getPrimaryValueFromOffset(delta), primaryDelta: _getPrimaryValueFromOffset(delta),
globalPosition: _initialPosition, globalPosition: _initialPosition,
......
...@@ -45,6 +45,8 @@ abstract class MultiDragPointerState { ...@@ -45,6 +45,8 @@ abstract class MultiDragPointerState {
Offset get pendingDelta => _pendingDelta; Offset get pendingDelta => _pendingDelta;
Offset _pendingDelta = Offset.zero; Offset _pendingDelta = Offset.zero;
Duration _lastPendingEventTimestamp;
GestureArenaEntry _arenaEntry; GestureArenaEntry _arenaEntry;
void _setArenaEntry(GestureArenaEntry entry) { void _setArenaEntry(GestureArenaEntry entry) {
assert(_arenaEntry == null); assert(_arenaEntry == null);
...@@ -68,12 +70,14 @@ abstract class MultiDragPointerState { ...@@ -68,12 +70,14 @@ abstract class MultiDragPointerState {
assert(pendingDelta == null); assert(pendingDelta == null);
// Call client last to avoid reentrancy. // Call client last to avoid reentrancy.
_client.update(new DragUpdateDetails( _client.update(new DragUpdateDetails(
sourceTimeStamp: event.timeStamp,
delta: event.delta, delta: event.delta,
globalPosition: event.position, globalPosition: event.position,
)); ));
} else { } else {
assert(pendingDelta != null); assert(pendingDelta != null);
_pendingDelta += event.delta; _pendingDelta += event.delta;
_lastPendingEventTimestamp = event.timeStamp;
checkForResolutionAfterMove(); checkForResolutionAfterMove();
} }
} }
...@@ -101,6 +105,7 @@ abstract class MultiDragPointerState { ...@@ -101,6 +105,7 @@ abstract class MultiDragPointerState {
assert(_client == null); assert(_client == null);
assert(pendingDelta != null); assert(pendingDelta != null);
_pendingDelta = null; _pendingDelta = null;
_lastPendingEventTimestamp = null;
_arenaEntry = null; _arenaEntry = null;
} }
...@@ -111,10 +116,12 @@ abstract class MultiDragPointerState { ...@@ -111,10 +116,12 @@ abstract class MultiDragPointerState {
assert(pendingDelta != null); assert(pendingDelta != null);
_client = client; _client = client;
final DragUpdateDetails details = new DragUpdateDetails( final DragUpdateDetails details = new DragUpdateDetails(
sourceTimeStamp: _lastPendingEventTimestamp,
delta: pendingDelta, delta: pendingDelta,
globalPosition: initialPosition, globalPosition: initialPosition,
); );
_pendingDelta = null; _pendingDelta = null;
_lastPendingEventTimestamp = null;
// Call client last to avoid reentrancy. // Call client last to avoid reentrancy.
_client.update(details); _client.update(details);
} }
...@@ -131,6 +138,7 @@ abstract class MultiDragPointerState { ...@@ -131,6 +138,7 @@ abstract class MultiDragPointerState {
} else { } else {
assert(pendingDelta != null); assert(pendingDelta != null);
_pendingDelta = null; _pendingDelta = null;
_lastPendingEventTimestamp = null;
} }
} }
...@@ -145,6 +153,7 @@ abstract class MultiDragPointerState { ...@@ -145,6 +153,7 @@ abstract class MultiDragPointerState {
} else { } else {
assert(pendingDelta != null); assert(pendingDelta != null);
_pendingDelta = null; _pendingDelta = null;
_lastPendingEventTimestamp = null;
} }
} }
......
...@@ -133,6 +133,37 @@ void main() { ...@@ -133,6 +133,37 @@ void main() {
drag.dispose(); drag.dispose();
}); });
testGesture('Should report original timestamps', (GestureTester tester) {
final HorizontalDragGestureRecognizer drag = new HorizontalDragGestureRecognizer();
Duration startTimestamp;
drag.onStart = (DragStartDetails details) {
startTimestamp = details.sourceTimeStamp;
};
Duration updatedTimestamp;
drag.onUpdate = (DragUpdateDetails details) {
updatedTimestamp = details.sourceTimeStamp;
};
final TestPointer pointer = new TestPointer(5);
final PointerDownEvent down = pointer.down(const Offset(10.0, 10.0), timeStamp: const Duration(milliseconds: 100));
drag.addPointer(down);
tester.closeArena(5);
expect(startTimestamp, isNull);
tester.route(down);
expect(startTimestamp, const Duration(milliseconds: 100));
tester.route(pointer.move(const Offset(20.0, 25.0), timeStamp: const Duration(milliseconds: 200)));
expect(updatedTimestamp, const Duration(milliseconds: 200));
tester.route(pointer.move(const Offset(20.0, 25.0), timeStamp: const Duration(milliseconds: 300)));
expect(updatedTimestamp, const Duration(milliseconds: 300));
drag.dispose();
});
testGesture('Drag with multiple pointers', (GestureTester tester) { testGesture('Drag with multiple pointers', (GestureTester tester) {
final HorizontalDragGestureRecognizer drag1 = new HorizontalDragGestureRecognizer(); final HorizontalDragGestureRecognizer drag1 = new HorizontalDragGestureRecognizer();
final VerticalDragGestureRecognizer drag2 = new VerticalDragGestureRecognizer(); final VerticalDragGestureRecognizer drag2 = new VerticalDragGestureRecognizer();
......
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