Unverified Commit c8aa37d1 authored by Dan Field's avatar Dan Field Committed by GitHub

Fix for #112403 and b/249091367 (#121615)

Fix monodrag gestures for #112403 and b/249091367
parent 0a1af28a
......@@ -222,6 +222,24 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
late OffsetPair _initialPosition;
late OffsetPair _pendingDragOffset;
Duration? _lastPendingEventTimestamp;
/// When asserts are enabled, returns the last tracked pending event timestamp
/// for this recognizer.
///
/// Otherwise, returns null.
///
/// This getter is intended for use in framework unit tests. Applications must
/// not depend on its value.
@visibleForTesting
Duration? get debugLastPendingEventTimestamp {
Duration? lastPendingEventTimestamp;
assert(() {
lastPendingEventTimestamp = _lastPendingEventTimestamp;
return true;
}());
return lastPendingEventTimestamp;
}
// The buttons sent by `PointerDownEvent`. If a `PointerMoveEvent` comes with a
// different set of buttons, the gesture is canceled.
int? _initialButtons;
......@@ -363,7 +381,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
if (_state != _DragState.accepted) {
_state = _DragState.accepted;
final OffsetPair delta = _pendingDragOffset;
final Duration timestamp = _lastPendingEventTimestamp!;
final Duration? timestamp = _lastPendingEventTimestamp;
final Matrix4? transform = _lastTransform;
final Offset localUpdateDelta;
switch (dragStartBehavior) {
......@@ -449,7 +467,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
}
}
void _checkStart(Duration timestamp, int pointer) {
void _checkStart(Duration? timestamp, int pointer) {
if (onStart != null) {
final DragStartDetails details = DragStartDetails(
sourceTimeStamp: timestamp,
......
......@@ -10,6 +10,31 @@ import 'gesture_tester.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
test('acceptGesture tolerates a null lastPendingEventTimestamp', () {
// Regression test for https://github.com/flutter/flutter/issues/112403
// and b/249091367
final DragGestureRecognizer recognizer = VerticalDragGestureRecognizer();
const PointerDownEvent event = PointerDownEvent(timeStamp: Duration(days: 10));
expect(recognizer.debugLastPendingEventTimestamp, null);
recognizer.addAllowedPointer(event);
expect(recognizer.debugLastPendingEventTimestamp, event.timeStamp);
// Normal case: acceptGesture called and we have a last timestamp set.
recognizer.acceptGesture(event.pointer);
expect(recognizer.debugLastPendingEventTimestamp, null);
// Reject the gesture to reset state and allow accepting it again.
recognizer.rejectGesture(event.pointer);
expect(recognizer.debugLastPendingEventTimestamp, null);
// Not entirely clear how this can happen, but the bugs mentioned above show
// we can end up in this state empircally.
recognizer.acceptGesture(event.pointer);
expect(recognizer.debugLastPendingEventTimestamp, null);
});
testGesture('do not crash on up event for a pending pointer after winning arena for another pointer', (GestureTester tester) {
// Regression test for https://github.com/flutter/flutter/issues/75061.
......
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