diff --git a/packages/flutter/lib/src/gestures/binding.dart b/packages/flutter/lib/src/gestures/binding.dart index 3f17a9fa36..0dec4b054b 100644 --- a/packages/flutter/lib/src/gestures/binding.dart +++ b/packages/flutter/lib/src/gestures/binding.dart @@ -366,7 +366,7 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H if (resamplingEnabled) { _resampler.addOrDispatch(event); - _resampler.sample(samplingOffset, samplingClock); + _resampler.sample(samplingOffset, _samplingClock); return; } @@ -505,10 +505,16 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H _hitTests.clear(); } + /// Overrides the sampling clock for debugging and testing. + /// + /// This value is ignored in non-debug builds. + @protected + SamplingClock? get debugSamplingClock => null; + void _handleSampleTimeChanged() { if (!locked) { if (resamplingEnabled) { - _resampler.sample(samplingOffset, samplingClock); + _resampler.sample(samplingOffset, _samplingClock); } else { _resampler.stop(); @@ -516,18 +522,7 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H } } - /// Overrides the [samplingClock] for debugging and testing. - /// - /// This value is ignored in non-debug builds. - @protected - SamplingClock? get debugSamplingClock => null; - - /// Provides access to the current [DateTime] and `StopWatch` objects for - /// sampling. - /// - /// Overridden by [debugSamplingClock] for debug builds and testing. Using - /// this object under test will maintain synchronization with [FakeAsync]. - SamplingClock get samplingClock { + SamplingClock get _samplingClock { SamplingClock value = SamplingClock(); assert(() { final SamplingClock? debugValue = debugSamplingClock; diff --git a/packages/flutter/lib/src/gestures/velocity_tracker.dart b/packages/flutter/lib/src/gestures/velocity_tracker.dart index 3644769688..ca7aa468a0 100644 --- a/packages/flutter/lib/src/gestures/velocity_tracker.dart +++ b/packages/flutter/lib/src/gestures/velocity_tracker.dart @@ -5,7 +5,6 @@ import 'package:flutter/foundation.dart'; -import 'binding.dart'; import 'events.dart'; import 'lsq_solver.dart'; @@ -150,21 +149,12 @@ class VelocityTracker { /// The kind of pointer this tracker is for. final PointerDeviceKind kind; - // Time difference since the last sample was added - Stopwatch get _sinceLastSample { - _stopwatch ??= GestureBinding.instance.samplingClock.stopwatch(); - return _stopwatch!; - } - Stopwatch? _stopwatch; - // Circular buffer; current sample at _index. final List<_PointAtTime?> _samples = List<_PointAtTime?>.filled(_historySize, null); int _index = 0; /// Adds a position as the given time to the tracker. void addPosition(Duration time, Offset position) { - _sinceLastSample.start(); - _sinceLastSample.reset(); _index += 1; if (_index == _historySize) { _index = 0; @@ -179,16 +169,6 @@ class VelocityTracker { /// /// Returns null if there is no data on which to base an estimate. VelocityEstimate? getVelocityEstimate() { - // Has user recently moved since last sample? - if (_sinceLastSample.elapsedMilliseconds > VelocityTracker._assumePointerMoveStoppedMilliseconds) { - return const VelocityEstimate( - pixelsPerSecond: Offset.zero, - confidence: 1.0, - duration: Duration.zero, - offset: Offset.zero, - ); - } - final List x = []; final List y = []; final List w = []; @@ -215,7 +195,7 @@ class VelocityTracker { final double age = (newestSample.time - sample.time).inMicroseconds.toDouble() / 1000; final double delta = (sample.time - previousSample.time).inMicroseconds.abs().toDouble() / 1000; previousSample = sample; - if (age > _horizonMilliseconds || delta > VelocityTracker._assumePointerMoveStoppedMilliseconds) { + if (age > _horizonMilliseconds || delta > _assumePointerMoveStoppedMilliseconds) { break; } @@ -308,8 +288,6 @@ class IOSScrollViewFlingVelocityTracker extends VelocityTracker { @override void addPosition(Duration time, Offset position) { - _sinceLastSample.start(); - _sinceLastSample.reset(); assert(() { final _PointAtTime? previousPoint = _touchSamples[_index]; if (previousPoint == null || previousPoint.time <= time) { @@ -348,16 +326,6 @@ class IOSScrollViewFlingVelocityTracker extends VelocityTracker { @override VelocityEstimate getVelocityEstimate() { - // Has user recently moved since last sample? - if (_sinceLastSample.elapsedMilliseconds > VelocityTracker._assumePointerMoveStoppedMilliseconds) { - return const VelocityEstimate( - pixelsPerSecond: Offset.zero, - confidence: 1.0, - duration: Duration.zero, - offset: Offset.zero, - ); - } - // The velocity estimated using this expression is an approximation of the // scroll velocity of an iOS scroll view at the moment the user touch was // released, not the final velocity of the iOS pan gesture recognizer @@ -419,16 +387,6 @@ class MacOSScrollViewFlingVelocityTracker extends IOSScrollViewFlingVelocityTrac @override VelocityEstimate getVelocityEstimate() { - // Has user recently moved since last sample? - if (_sinceLastSample.elapsedMilliseconds > VelocityTracker._assumePointerMoveStoppedMilliseconds) { - return const VelocityEstimate( - pixelsPerSecond: Offset.zero, - confidence: 1.0, - duration: Duration.zero, - offset: Offset.zero, - ); - } - // The velocity estimated using this expression is an approximation of the // scroll velocity of a macOS scroll view at the moment the user touch was // released. diff --git a/packages/flutter/test/gestures/gesture_binding_resample_event_on_widget_test.dart b/packages/flutter/test/gestures/gesture_binding_resample_event_on_widget_test.dart index 27b6dabd7e..76d0d82be2 100644 --- a/packages/flutter/test/gestures/gesture_binding_resample_event_on_widget_test.dart +++ b/packages/flutter/test/gestures/gesture_binding_resample_event_on_widget_test.dart @@ -4,18 +4,35 @@ import 'dart:ui' as ui; +import 'package:clock/clock.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; +class TestResampleEventFlutterBinding extends AutomatedTestWidgetsFlutterBinding { + @override + SamplingClock? get debugSamplingClock => TestSamplingClock(this.clock); +} + +class TestSamplingClock implements SamplingClock { + TestSamplingClock(this._clock); + + @override + DateTime now() => _clock.now(); + + @override + Stopwatch stopwatch() => _clock.stopwatch(); + + final Clock _clock; +} void main() { + final TestWidgetsFlutterBinding binding = TestResampleEventFlutterBinding(); testWidgetsWithLeakTracking('PointerEvent resampling on a widget', (WidgetTester tester) async { - Duration currentTestFrameTime() => Duration( - milliseconds: TestWidgetsFlutterBinding.instance.clock.now().millisecondsSinceEpoch, - ); + assert(WidgetsBinding.instance == binding); + Duration currentTestFrameTime() => Duration(milliseconds: binding.clock.now().millisecondsSinceEpoch); void requestFrame() => SchedulerBinding.instance.scheduleFrameCallback((_) {}); final Duration epoch = currentTestFrameTime(); final ui.PointerDataPacket packet = ui.PointerDataPacket( diff --git a/packages/flutter/test/gestures/gesture_tester.dart b/packages/flutter/test/gestures/gesture_tester.dart index 602d1ca04a..0679d947d0 100644 --- a/packages/flutter/test/gestures/gesture_tester.dart +++ b/packages/flutter/test/gestures/gesture_tester.dart @@ -4,7 +4,7 @@ import 'package:fake_async/fake_async.dart'; import 'package:flutter/gestures.dart'; -import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; +import 'package:flutter_test/flutter_test.dart'; import 'package:meta/meta.dart'; class GestureTester { @@ -26,7 +26,7 @@ typedef GestureTest = void Function(GestureTester tester); @isTest void testGesture(String description, GestureTest callback) { - testWidgetsWithLeakTracking(description, (_) async { + test(description, () { FakeAsync().run((FakeAsync async) { callback(GestureTester._(async)); }); diff --git a/packages/flutter/test/gestures/velocity_tracker_test.dart b/packages/flutter/test/gestures/velocity_tracker_test.dart index 0aa5138b03..3e6b94534b 100644 --- a/packages/flutter/test/gestures/velocity_tracker_test.dart +++ b/packages/flutter/test/gestures/velocity_tracker_test.dart @@ -4,7 +4,6 @@ import 'package:flutter/gestures.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'velocity_tracker_data.dart'; bool _withinTolerance(double actual, double expected) { @@ -35,7 +34,7 @@ void main() { Offset(-71.51939428321249, 3716.7385187526947), ]; - testWidgetsWithLeakTracking('Velocity tracker gives expected results', (WidgetTester tester) async { + test('Velocity tracker gives expected results', () { final VelocityTracker tracker = VelocityTracker.withKind(PointerDeviceKind.touch); int i = 0; for (final PointerEvent event in velocityEventData) { @@ -49,7 +48,7 @@ void main() { } }); - testWidgetsWithLeakTracking('Velocity control test', (WidgetTester tester) async { + test('Velocity control test', () { const Velocity velocity1 = Velocity(pixelsPerSecond: Offset(7.0, 0.0)); const Velocity velocity2 = Velocity(pixelsPerSecond: Offset(12.0, 0.0)); expect(velocity1, equals(const Velocity(pixelsPerSecond: Offset(7.0, 0.0)))); @@ -61,7 +60,7 @@ void main() { expect(velocity1, hasOneLineDescription); }); - testWidgetsWithLeakTracking('Interrupted velocity estimation', (WidgetTester tester) async { + test('Interrupted velocity estimation', () { // Regression test for https://github.com/flutter/flutter/pull/7510 final VelocityTracker tracker = VelocityTracker.withKind(PointerDeviceKind.touch); for (final PointerEvent event in interruptedVelocityEventData) { @@ -74,12 +73,12 @@ void main() { } }); - testWidgetsWithLeakTracking('No data velocity estimation', (WidgetTester tester) async { + test('No data velocity estimation', () { final VelocityTracker tracker = VelocityTracker.withKind(PointerDeviceKind.touch); expect(tracker.getVelocity(), Velocity.zero); }); - testWidgetsWithLeakTracking('FreeScrollStartVelocityTracker.getVelocity throws when no points', (WidgetTester tester) async { + test('FreeScrollStartVelocityTracker.getVelocity throws when no points', () { final IOSScrollViewFlingVelocityTracker tracker = IOSScrollViewFlingVelocityTracker(PointerDeviceKind.touch); AssertionError? exception; try { @@ -91,7 +90,7 @@ void main() { expect(exception?.toString(), contains('at least 1 point')); }); - testWidgetsWithLeakTracking('FreeScrollStartVelocityTracker.getVelocity throws when the new point precedes the previous point', (WidgetTester tester) async { + test('FreeScrollStartVelocityTracker.getVelocity throws when the new point precedes the previous point', () { final IOSScrollViewFlingVelocityTracker tracker = IOSScrollViewFlingVelocityTracker(PointerDeviceKind.touch); AssertionError? exception; @@ -106,7 +105,7 @@ void main() { expect(exception?.toString(), contains('has a smaller timestamp')); }); - testWidgetsWithLeakTracking('Estimate does not throw when there are more than 1 point', (WidgetTester tester) async { + test('Estimate does not throw when there are more than 1 point', () { final IOSScrollViewFlingVelocityTracker tracker = IOSScrollViewFlingVelocityTracker(PointerDeviceKind.touch); Offset position = Offset.zero; Duration time = Duration.zero; @@ -128,7 +127,7 @@ void main() { } }); - testWidgetsWithLeakTracking('Makes consistent velocity estimates with consistent velocity', (WidgetTester tester) async { + test('Makes consistent velocity estimates with consistent velocity', () { final IOSScrollViewFlingVelocityTracker tracker = IOSScrollViewFlingVelocityTracker(PointerDeviceKind.touch); Offset position = Offset.zero; Duration time = Duration.zero; @@ -145,55 +144,4 @@ void main() { } } }); - - testWidgetsWithLeakTracking('Assume zero velocity when there are no recent samples - base VelocityTracker', (WidgetTester tester) async { - final VelocityTracker tracker = VelocityTracker.withKind(PointerDeviceKind.touch); - Offset position = Offset.zero; - Duration time = Duration.zero; - const Offset positionDelta = Offset(0, -1); - const Duration durationDelta = Duration(seconds: 1); - - for (int i = 0; i < 10; i+=1) { - position += positionDelta; - time += durationDelta; - tracker.addPosition(time, position); - } - await tester.pumpAndSettle(); - - expect(tracker.getVelocity().pixelsPerSecond, Offset.zero); - }); - - testWidgetsWithLeakTracking('Assume zero velocity when there are no recent samples - IOS', (WidgetTester tester) async { - final IOSScrollViewFlingVelocityTracker tracker = IOSScrollViewFlingVelocityTracker(PointerDeviceKind.touch); - Offset position = Offset.zero; - Duration time = Duration.zero; - const Offset positionDelta = Offset(0, -1); - const Duration durationDelta = Duration(seconds: 1); - - for (int i = 0; i < 10; i+=1) { - position += positionDelta; - time += durationDelta; - tracker.addPosition(time, position); - } - await tester.pumpAndSettle(); - - expect(tracker.getVelocity().pixelsPerSecond, Offset.zero); - }); - - testWidgetsWithLeakTracking('Assume zero velocity when there are no recent samples - MacOS', (WidgetTester tester) async { - final MacOSScrollViewFlingVelocityTracker tracker = MacOSScrollViewFlingVelocityTracker(PointerDeviceKind.touch); - Offset position = Offset.zero; - Duration time = Duration.zero; - const Offset positionDelta = Offset(0, -1); - const Duration durationDelta = Duration(seconds: 1); - - for (int i = 0; i < 10; i+=1) { - position += positionDelta; - time += durationDelta; - tracker.addPosition(time, position); - } - await tester.pumpAndSettle(); - - expect(tracker.getVelocity().pixelsPerSecond, Offset.zero); - }); } diff --git a/packages/flutter/test/rendering/editable_gesture_test.dart b/packages/flutter/test/rendering/editable_gesture_test.dart index f3764aaae5..c53b9ea012 100644 --- a/packages/flutter/test/rendering/editable_gesture_test.dart +++ b/packages/flutter/test/rendering/editable_gesture_test.dart @@ -8,9 +8,9 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { - final TestWidgetsFlutterBinding binding = _GestureBindingSpy(); - testWidgets('attach and detach correctly handle gesture', (_) async { - assert(WidgetsBinding.instance == binding); + setUp(() => _GestureBindingSpy()); + + test('attach and detach correctly handle gesture', () { final TextSelectionDelegate delegate = FakeEditableTextState(); final RenderEditable editable = RenderEditable( backgroundCursorColor: Colors.grey, diff --git a/packages/flutter_test/lib/src/binding.dart b/packages/flutter_test/lib/src/binding.dart index c5095e8cae..5a54b24901 100644 --- a/packages/flutter_test/lib/src/binding.dart +++ b/packages/flutter_test/lib/src/binding.dart @@ -425,9 +425,6 @@ abstract class TestWidgetsFlutterBinding extends BindingBase /// actual current wall-clock time. Clock get clock; - @override - SamplingClock? get debugSamplingClock => _TestSamplingClock(clock); - /// Triggers a frame sequence (build/layout/paint/etc), /// then flushes microtasks. /// @@ -2152,18 +2149,6 @@ class TestViewConfiguration extends ViewConfiguration { String toString() => 'TestViewConfiguration'; } -class _TestSamplingClock implements SamplingClock { - _TestSamplingClock(this._clock); - - @override - DateTime now() => _clock.now(); - - @override - Stopwatch stopwatch() => _clock.stopwatch(); - - final Clock _clock; -} - const int _kPointerDecay = -2; class _LiveTestPointerRecord {