Unverified Commit 6afbb25a authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Reject unaccepted pointers in Drag recognizer (#75943)

parent 46b8ea8f
...@@ -309,15 +309,16 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -309,15 +309,16 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
} }
} }
if (event is PointerUpEvent || event is PointerCancelEvent) { if (event is PointerUpEvent || event is PointerCancelEvent) {
_giveUpPointer( _giveUpPointer(event.pointer);
event.pointer,
reject: event is PointerCancelEvent || _state ==_DragState.possible,
);
} }
} }
final Set<int> _acceptedActivePointers = <int>{};
@override @override
void acceptGesture(int pointer) { void acceptGesture(int pointer) {
assert(!_acceptedActivePointers.contains(pointer));
_acceptedActivePointers.add(pointer);
if (_state != _DragState.accepted) { if (_state != _DragState.accepted) {
_state = _DragState.accepted; _state = _DragState.accepted;
final OffsetPair delta = _pendingDragOffset; final OffsetPair delta = _pendingDragOffset;
...@@ -384,33 +385,37 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -384,33 +385,37 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
_state = _DragState.ready; _state = _DragState.ready;
} }
void _giveUpPointer(int pointer, {bool reject = true}) { void _giveUpPointer(int pointer) {
stopTrackingPointer(pointer); stopTrackingPointer(pointer);
if (reject) // If we never accepted the pointer, we reject it since we are no longer
// interested in winning the gesture arena for it.
if (!_acceptedActivePointers.remove(pointer))
resolvePointer(pointer, GestureDisposition.rejected); resolvePointer(pointer, GestureDisposition.rejected);
} }
void _checkDown() { void _checkDown() {
assert(_initialButtons == kPrimaryButton); assert(_initialButtons == kPrimaryButton);
if (onDown != null) {
final DragDownDetails details = DragDownDetails( final DragDownDetails details = DragDownDetails(
globalPosition: _initialPosition.global, globalPosition: _initialPosition.global,
localPosition: _initialPosition.local, localPosition: _initialPosition.local,
); );
if (onDown != null)
invokeCallback<void>('onDown', () => onDown!(details)); invokeCallback<void>('onDown', () => onDown!(details));
} }
}
void _checkStart(Duration timestamp, int pointer) { void _checkStart(Duration timestamp, int pointer) {
assert(_initialButtons == kPrimaryButton); assert(_initialButtons == kPrimaryButton);
if (onStart != null) {
final DragStartDetails details = DragStartDetails( final DragStartDetails details = DragStartDetails(
sourceTimeStamp: timestamp, sourceTimeStamp: timestamp,
globalPosition: _initialPosition.global, globalPosition: _initialPosition.global,
localPosition: _initialPosition.local, localPosition: _initialPosition.local,
kind: getKindForPointer(pointer), kind: getKindForPointer(pointer),
); );
if (onStart != null)
invokeCallback<void>('onStart', () => onStart!(details)); invokeCallback<void>('onStart', () => onStart!(details));
} }
}
void _checkUpdate({ void _checkUpdate({
Duration? sourceTimeStamp, Duration? sourceTimeStamp,
...@@ -420,6 +425,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -420,6 +425,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
Offset? localPosition, Offset? localPosition,
}) { }) {
assert(_initialButtons == kPrimaryButton); assert(_initialButtons == kPrimaryButton);
if (onUpdate != null) {
final DragUpdateDetails details = DragUpdateDetails( final DragUpdateDetails details = DragUpdateDetails(
sourceTimeStamp: sourceTimeStamp, sourceTimeStamp: sourceTimeStamp,
delta: delta, delta: delta,
...@@ -427,9 +433,9 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -427,9 +433,9 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
globalPosition: globalPosition, globalPosition: globalPosition,
localPosition: localPosition, localPosition: localPosition,
); );
if (onUpdate != null)
invokeCallback<void>('onUpdate', () => onUpdate!(details)); invokeCallback<void>('onUpdate', () => onUpdate!(details));
} }
}
void _checkEnd(int pointer) { void _checkEnd(int pointer) {
assert(_initialButtons == kPrimaryButton); assert(_initialButtons == kPrimaryButton);
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/gestures.dart';
import 'package:flutter_test/flutter_test.dart';
import 'gesture_tester.dart';
void main() {
setUp(ensureGestureBinding);
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.
final VerticalDragGestureRecognizer v = VerticalDragGestureRecognizer()
..onStart = (_) { };
final HorizontalDragGestureRecognizer h = HorizontalDragGestureRecognizer()
..onStart = (_) { };
const PointerDownEvent down90 = PointerDownEvent(
pointer: 90,
position: Offset(10.0, 10.0),
);
const PointerUpEvent up90 = PointerUpEvent(
pointer: 90,
position: Offset(10.0, 10.0),
);
const PointerDownEvent down91 = PointerDownEvent(
pointer: 91,
position: Offset(20.0, 20.0),
);
const PointerUpEvent up91 = PointerUpEvent(
pointer: 91,
position: Offset(20.0, 20.0),
);
v.addPointer(down90);
GestureBinding.instance!.gestureArena.close(90);
h.addPointer(down91);
v.addPointer(down91);
GestureBinding.instance!.gestureArena.close(91);
tester.async.flushMicrotasks();
GestureBinding.instance!.handleEvent(up90, HitTestEntry(MockHitTestTarget()));
GestureBinding.instance!.handleEvent(up91, HitTestEntry(MockHitTestTarget()));
});
}
class MockHitTestTarget implements HitTestTarget {
@override
void handleEvent(PointerEvent event, HitTestEntry entry) { }
}
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