blob: a5e272bdd2753d4179def50a138b29877d2a277b [file] [log] [blame]
// 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 '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';
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();
testWidgets('PointerEvent resampling on a widget', (WidgetTester tester) async {
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(
data: <ui.PointerData>[
ui.PointerData(
change: ui.PointerChange.add,
timeStamp: epoch,
),
ui.PointerData(
change: ui.PointerChange.down,
timeStamp: epoch,
),
ui.PointerData(
change: ui.PointerChange.move,
physicalX: 15.0,
timeStamp: epoch + const Duration(milliseconds: 10),
),
ui.PointerData(
change: ui.PointerChange.move,
physicalX: 30.0,
timeStamp: epoch + const Duration(milliseconds: 20),
),
ui.PointerData(
change: ui.PointerChange.move,
physicalX: 45.0,
timeStamp: epoch + const Duration(milliseconds: 30),
),
ui.PointerData(
change: ui.PointerChange.move,
physicalX: 50.0,
timeStamp: epoch + const Duration(milliseconds: 40),
),
ui.PointerData(
change: ui.PointerChange.up,
physicalX: 60.0,
timeStamp: epoch + const Duration(milliseconds: 40),
),
ui.PointerData(
change: ui.PointerChange.remove,
physicalX: 60.0,
timeStamp: epoch + const Duration(milliseconds: 40),
),
],
);
final List<PointerEvent> events = <PointerEvent>[];
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Listener(
onPointerDown: (PointerDownEvent event) => events.add(event),
onPointerMove: (PointerMoveEvent event) => events.add(event),
onPointerUp: (PointerUpEvent event) => events.add(event),
child: const Text('test'),
),
),
);
GestureBinding.instance!.resamplingEnabled = true;
const Duration kSamplingOffset = Duration(milliseconds: -5);
GestureBinding.instance!.samplingOffset = kSamplingOffset;
ui.window.onPointerDataPacket!(packet);
expect(events.length, 0);
requestFrame();
await tester.pump(const Duration(milliseconds: 10));
expect(events.length, 1);
expect(events[0], isA<PointerDownEvent>());
expect(events[0].timeStamp, currentTestFrameTime() + kSamplingOffset);
expect(events[0].position, Offset(7.5 / ui.window.devicePixelRatio, 0.0));
// Now the system time is epoch + 20ms
requestFrame();
await tester.pump(const Duration(milliseconds: 10));
expect(events.length, 2);
expect(events[1].timeStamp, currentTestFrameTime() + kSamplingOffset);
expect(events[1], isA<PointerMoveEvent>());
expect(events[1].position, Offset(22.5 / ui.window.devicePixelRatio, 0.0));
expect(events[1].delta, Offset(15.0 / ui.window.devicePixelRatio, 0.0));
// Now the system time is epoch + 30ms
requestFrame();
await tester.pump(const Duration(milliseconds: 10));
expect(events.length, 4);
expect(events[2].timeStamp, currentTestFrameTime() + kSamplingOffset);
expect(events[2], isA<PointerMoveEvent>());
expect(events[2].position, Offset(37.5 / ui.window.devicePixelRatio, 0.0));
expect(events[2].delta, Offset(15.0 / ui.window.devicePixelRatio, 0.0));
expect(events[3].timeStamp, currentTestFrameTime() + kSamplingOffset);
expect(events[3], isA<PointerUpEvent>());
});
}