Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
02612bfe
Unverified
Commit
02612bfe
authored
Aug 24, 2020
by
David Reveman
Committed by
GitHub
Aug 24, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Pointer event resampler (#41118) (#60558)
parent
2f937703
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
2060 additions
and
2 deletions
+2060
-2
gestures.dart
packages/flutter/lib/gestures.dart
+1
-0
binding.dart
packages/flutter/lib/src/gestures/binding.dart
+169
-0
debug.dart
packages/flutter/lib/src/gestures/debug.dart
+16
-1
events.dart
packages/flutter/lib/src/gestures/events.dart
+564
-0
resampler.dart
packages/flutter/lib/src/gestures/resampler.dart
+305
-0
events_test.dart
packages/flutter/test/gestures/events_test.dart
+280
-0
gesture_binding_test.dart
packages/flutter/test/gestures/gesture_binding_test.dart
+120
-1
resampler_test.dart
packages/flutter/test/gestures/resampler_test.dart
+605
-0
No files found.
packages/flutter/lib/gestures.dart
View file @
02612bfe
...
@@ -26,6 +26,7 @@ export 'src/gestures/multitap.dart';
...
@@ -26,6 +26,7 @@ export 'src/gestures/multitap.dart';
export
'src/gestures/pointer_router.dart'
;
export
'src/gestures/pointer_router.dart'
;
export
'src/gestures/pointer_signal_resolver.dart'
;
export
'src/gestures/pointer_signal_resolver.dart'
;
export
'src/gestures/recognizer.dart'
;
export
'src/gestures/recognizer.dart'
;
export
'src/gestures/resampler.dart'
;
export
'src/gestures/scale.dart'
;
export
'src/gestures/scale.dart'
;
export
'src/gestures/tap.dart'
;
export
'src/gestures/tap.dart'
;
export
'src/gestures/team.dart'
;
export
'src/gestures/team.dart'
;
...
...
packages/flutter/lib/src/gestures/binding.dart
View file @
02612bfe
...
@@ -8,6 +8,7 @@ import 'dart:collection';
...
@@ -8,6 +8,7 @@ import 'dart:collection';
import
'dart:ui'
as
ui
show
PointerDataPacket
;
import
'dart:ui'
as
ui
show
PointerDataPacket
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/scheduler.dart'
;
import
'arena.dart'
;
import
'arena.dart'
;
import
'converter.dart'
;
import
'converter.dart'
;
...
@@ -16,6 +17,131 @@ import 'events.dart';
...
@@ -16,6 +17,131 @@ import 'events.dart';
import
'hit_test.dart'
;
import
'hit_test.dart'
;
import
'pointer_router.dart'
;
import
'pointer_router.dart'
;
import
'pointer_signal_resolver.dart'
;
import
'pointer_signal_resolver.dart'
;
import
'resampler.dart'
;
typedef
HandleSampleTimeChangedCallback
=
void
Function
();
// Class that handles resampling of touch events for multiple pointer
// devices.
//
// SchedulerBinding's `currentSystemFrameTimeStamp` is used to determine
// sample time.
class
_Resampler
{
_Resampler
(
this
.
_handlePointerEvent
,
this
.
_handleSampleTimeChanged
);
// Resamplers used to filter incoming pointer events.
final
Map
<
int
,
PointerEventResampler
>
_resamplers
=
<
int
,
PointerEventResampler
>{};
// Flag to track if a frame callback has been scheduled.
bool
_frameCallbackScheduled
=
false
;
// Current frame time for resampling.
Duration
_frameTime
=
Duration
.
zero
;
// Last sample time and time stamp of last event.
//
// Only used for debugPrint of resampling margin.
Duration
_lastSampleTime
=
Duration
.
zero
;
Duration
_lastEventTime
=
Duration
.
zero
;
// Callback used to handle pointer events.
final
HandleEventCallback
_handlePointerEvent
;
// Callback used to handle sample time changes.
final
HandleSampleTimeChangedCallback
_handleSampleTimeChanged
;
// Enqueue `events` for resampling or dispatch them directly if
// not a touch event.
void
addOrDispatchAll
(
Queue
<
PointerEvent
>
events
)
{
final
SchedulerBinding
?
scheduler
=
SchedulerBinding
.
instance
;
assert
(
scheduler
!=
null
);
while
(
events
.
isNotEmpty
)
{
final
PointerEvent
event
=
events
.
removeFirst
();
// Add touch event to resampler or dispatch pointer event directly.
if
(
event
.
kind
==
PointerDeviceKind
.
touch
)
{
// Save last event time for debugPrint of resampling margin.
_lastEventTime
=
event
.
timeStamp
;
final
PointerEventResampler
resampler
=
_resamplers
.
putIfAbsent
(
event
.
device
,
()
=>
PointerEventResampler
(),
);
resampler
.
addEvent
(
event
);
}
else
{
_handlePointerEvent
(
event
);
}
}
}
// Sample and dispatch events.
//
// `samplingOffset` is relative to the current frame time, which
// can be in the past when we're not actively resampling.
// `currentSystemFrameTimeStamp` is used to determine the current
// frame time.
void
sample
(
Duration
samplingOffset
)
{
final
SchedulerBinding
?
scheduler
=
SchedulerBinding
.
instance
;
assert
(
scheduler
!=
null
);
// Determine sample time by adding the offset to the current
// frame time. This is expected to be in the past and not
// result in any dispatched events unless we're actively
// resampling events.
final
Duration
sampleTime
=
_frameTime
+
samplingOffset
;
// Iterate over active resamplers and sample pointer events for
// current sample time.
for
(
final
PointerEventResampler
resampler
in
_resamplers
.
values
)
{
resampler
.
sample
(
sampleTime
,
_handlePointerEvent
);
}
// Remove inactive resamplers.
_resamplers
.
removeWhere
((
int
key
,
PointerEventResampler
resampler
)
{
return
!
resampler
.
hasPendingEvents
&&
!
resampler
.
isDown
;
});
// Save last sample time for debugPrint of resampling margin.
_lastSampleTime
=
sampleTime
;
// Schedule a frame callback if another call to `sample` is needed.
if
(!
_frameCallbackScheduled
&&
_resamplers
.
isNotEmpty
)
{
_frameCallbackScheduled
=
true
;
scheduler
?.
scheduleFrameCallback
((
_
)
{
_frameCallbackScheduled
=
false
;
// We use `currentSystemFrameTimeStamp` here as it's critical that
// sample time is in the same clock as the event time stamps, and
// never adjusted or scaled like `currentFrameTimeStamp`.
_frameTime
=
scheduler
.
currentSystemFrameTimeStamp
;
assert
(()
{
if
(
debugPrintResamplingMargin
)
{
final
Duration
resamplingMargin
=
_lastEventTime
-
_lastSampleTime
;
debugPrint
(
'
$resamplingMargin
'
);
}
return
true
;
}());
_handleSampleTimeChanged
();
});
}
}
// Stop all resampling and dispatched any queued events.
void
stop
()
{
for
(
final
PointerEventResampler
resampler
in
_resamplers
.
values
)
{
resampler
.
stop
(
_handlePointerEvent
);
}
_resamplers
.
clear
();
}
}
// The default sampling offset.
//
// Sampling offset is relative to presentation time. If we produce frames
// 16.667 ms before presentation and input rate is ~60hz, worst case latency
// is 33.334 ms. This however assumes zero latency from the input driver.
// 4.666 ms margin is added for this.
const
Duration
_defaultSamplingOffset
=
Duration
(
milliseconds:
-
38
);
/// A binding for the gesture subsystem.
/// A binding for the gesture subsystem.
///
///
...
@@ -99,6 +225,17 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H
...
@@ -99,6 +225,17 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H
void
_flushPointerEventQueue
()
{
void
_flushPointerEventQueue
()
{
assert
(!
locked
);
assert
(!
locked
);
if
(
resamplingEnabled
)
{
_resampler
.
addOrDispatchAll
(
_pendingPointerEvents
);
_resampler
.
sample
(
samplingOffset
);
return
;
}
// Stop resampler if resampling is not enabled. This is a no-op if
// resampling was never enabled.
_resampler
.
stop
();
while
(
_pendingPointerEvents
.
isNotEmpty
)
while
(
_pendingPointerEvents
.
isNotEmpty
)
_handlePointerEvent
(
_pendingPointerEvents
.
removeFirst
());
_handlePointerEvent
(
_pendingPointerEvents
.
removeFirst
());
}
}
...
@@ -226,6 +363,38 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H
...
@@ -226,6 +363,38 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H
pointerSignalResolver
.
resolve
(
event
);
pointerSignalResolver
.
resolve
(
event
);
}
}
}
}
void
_handleSampleTimeChanged
()
{
if
(!
locked
)
{
_flushPointerEventQueue
();
}
}
// Resampler used to filter incoming pointer events when resampling
// is enabled.
late
final
_Resampler
_resampler
=
_Resampler
(
_handlePointerEvent
,
_handleSampleTimeChanged
,
);
/// Enable pointer event resampling for touch devices by setting
/// this to true.
///
/// Resampling results in smoother touch event processing at the
/// cost of some added latency. Devices with low frequency sensors
/// or when the frequency is not a multiple of the display frequency
/// (e.g., 120Hz input and 90Hz display) benefit from this.
///
/// This is typically set during application initialization but
/// can be adjusted dynamically in case the application only
/// wants resampling for some period of time.
bool
resamplingEnabled
=
false
;
/// Offset relative to current frame time that should be used for
/// resampling. The [samplingOffset] is expected to be negative.
/// Non-negative [samplingOffset] is allowed but will effectively
/// disable resampling.
Duration
samplingOffset
=
_defaultSamplingOffset
;
}
}
/// Variant of [FlutterErrorDetails] with extra fields for the gesture
/// Variant of [FlutterErrorDetails] with extra fields for the gesture
...
...
packages/flutter/lib/src/gestures/debug.dart
View file @
02612bfe
...
@@ -50,6 +50,20 @@ bool debugPrintGestureArenaDiagnostics = false;
...
@@ -50,6 +50,20 @@ bool debugPrintGestureArenaDiagnostics = false;
/// arenas.
/// arenas.
bool
debugPrintRecognizerCallbacksTrace
=
false
;
bool
debugPrintRecognizerCallbacksTrace
=
false
;
/// Whether to print the resampling margin to the console.
///
/// When this is set, in debug mode, any time resampling is triggered by the
/// [GestureBinding] the resampling margin is dumped to the console. The
/// resampling margin is the delta between the time of the last received
/// touch event and the current sample time. Positive value indicates that
/// resampling is effective and the resampling offset can potentially be
/// reduced for improved latency. Negative value indicates that resampling
/// is failing and resampling offset needs to be increased for smooth
/// touch event processing.
///
/// This has no effect in release builds.
bool
debugPrintResamplingMargin
=
false
;
/// Returns true if none of the gestures library debug variables have been changed.
/// Returns true if none of the gestures library debug variables have been changed.
///
///
/// This function is used by the test framework to ensure that debug variables
/// This function is used by the test framework to ensure that debug variables
...
@@ -61,7 +75,8 @@ bool debugAssertAllGesturesVarsUnset(String reason) {
...
@@ -61,7 +75,8 @@ bool debugAssertAllGesturesVarsUnset(String reason) {
assert
(()
{
assert
(()
{
if
(
debugPrintHitTestResults
||
if
(
debugPrintHitTestResults
||
debugPrintGestureArenaDiagnostics
||
debugPrintGestureArenaDiagnostics
||
debugPrintRecognizerCallbacksTrace
)
debugPrintRecognizerCallbacksTrace
||
debugPrintResamplingMargin
)
throw
FlutterError
(
reason
);
throw
FlutterError
(
reason
);
return
true
;
return
true
;
}());
}());
...
...
packages/flutter/lib/src/gestures/events.dart
View file @
02612bfe
...
@@ -517,6 +517,36 @@ abstract class PointerEvent with Diagnosticable {
...
@@ -517,6 +517,36 @@ abstract class PointerEvent with Diagnosticable {
/// overridden by the provided `transform`.
/// overridden by the provided `transform`.
PointerEvent
transformed
(
Matrix4
?
transform
);
PointerEvent
transformed
(
Matrix4
?
transform
);
/// Creates a copy of event with the specified properties replaced.
PointerEvent
copyWith
({
Duration
?
timeStamp
,
int
?
pointer
,
PointerDeviceKind
?
kind
,
int
?
device
,
Offset
?
position
,
Offset
?
localPosition
,
Offset
?
delta
,
Offset
?
localDelta
,
int
?
buttons
,
bool
?
obscured
,
double
?
pressure
,
double
?
pressureMin
,
double
?
pressureMax
,
double
?
distance
,
double
?
distanceMax
,
double
?
size
,
double
?
radiusMajor
,
double
?
radiusMinor
,
double
?
radiusMin
,
double
?
radiusMax
,
double
?
orientation
,
double
?
tilt
,
bool
?
synthesized
,
Matrix4
?
transform
,
PointerEvent
?
original
,
int
?
embedderId
,
});
@override
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
super
.
debugFillProperties
(
properties
);
...
@@ -682,6 +712,56 @@ class PointerAddedEvent extends PointerEvent {
...
@@ -682,6 +712,56 @@ class PointerAddedEvent extends PointerEvent {
embedderId:
embedderId
,
embedderId:
embedderId
,
);
);
}
}
@override
PointerAddedEvent
copyWith
({
Duration
?
timeStamp
,
int
?
pointer
,
PointerDeviceKind
?
kind
,
int
?
device
,
Offset
?
position
,
Offset
?
localPosition
,
Offset
?
delta
,
Offset
?
localDelta
,
int
?
buttons
,
bool
?
obscured
,
double
?
pressure
,
double
?
pressureMin
,
double
?
pressureMax
,
double
?
distance
,
double
?
distanceMax
,
double
?
size
,
double
?
radiusMajor
,
double
?
radiusMinor
,
double
?
radiusMin
,
double
?
radiusMax
,
double
?
orientation
,
double
?
tilt
,
bool
?
synthesized
,
Matrix4
?
transform
,
PointerEvent
?
original
,
int
?
embedderId
,
})
{
return
PointerAddedEvent
(
timeStamp:
timeStamp
??
this
.
timeStamp
,
kind:
kind
??
this
.
kind
,
device:
device
??
this
.
device
,
position:
position
??
this
.
position
,
localPosition:
localPosition
??
this
.
localPosition
,
obscured:
obscured
??
this
.
obscured
,
pressureMin:
pressureMin
??
this
.
pressureMin
,
pressureMax:
pressureMax
??
this
.
pressureMax
,
distance:
distance
??
this
.
distance
,
distanceMax:
distanceMax
??
this
.
distanceMax
,
radiusMin:
radiusMin
??
this
.
radiusMin
,
radiusMax:
radiusMax
??
this
.
radiusMax
,
orientation:
orientation
??
this
.
orientation
,
tilt:
tilt
??
this
.
tilt
,
transform:
transform
??
this
.
transform
,
original:
original
as
PointerAddedEvent
?
??
this
,
embedderId:
embedderId
??
this
.
embedderId
,
);
}
}
}
/// The device is no longer tracking the pointer.
/// The device is no longer tracking the pointer.
...
@@ -747,6 +827,53 @@ class PointerRemovedEvent extends PointerEvent {
...
@@ -747,6 +827,53 @@ class PointerRemovedEvent extends PointerEvent {
embedderId:
embedderId
,
embedderId:
embedderId
,
);
);
}
}
@override
PointerRemovedEvent
copyWith
({
Duration
?
timeStamp
,
int
?
pointer
,
PointerDeviceKind
?
kind
,
int
?
device
,
Offset
?
position
,
Offset
?
localPosition
,
Offset
?
delta
,
Offset
?
localDelta
,
int
?
buttons
,
bool
?
obscured
,
double
?
pressure
,
double
?
pressureMin
,
double
?
pressureMax
,
double
?
distance
,
double
?
distanceMax
,
double
?
size
,
double
?
radiusMajor
,
double
?
radiusMinor
,
double
?
radiusMin
,
double
?
radiusMax
,
double
?
orientation
,
double
?
tilt
,
bool
?
synthesized
,
Matrix4
?
transform
,
PointerEvent
?
original
,
int
?
embedderId
,
})
{
return
PointerRemovedEvent
(
timeStamp:
timeStamp
??
this
.
timeStamp
,
kind:
kind
??
this
.
kind
,
device:
device
??
this
.
device
,
position:
position
??
this
.
position
,
localPosition:
localPosition
??
this
.
localPosition
,
obscured:
obscured
??
this
.
obscured
,
pressureMin:
pressureMin
??
this
.
pressureMin
,
pressureMax:
pressureMax
??
this
.
pressureMax
,
distanceMax:
distanceMax
??
this
.
distanceMax
,
radiusMin:
radiusMin
??
this
.
radiusMin
,
radiusMax:
radiusMax
??
this
.
radiusMax
,
transform:
transform
??
this
.
transform
,
original:
original
as
PointerRemovedEvent
?
??
this
,
embedderId:
embedderId
??
this
.
embedderId
,
);
}
}
}
/// The pointer has moved with respect to the device while the pointer is not
/// The pointer has moved with respect to the device while the pointer is not
...
@@ -857,6 +984,63 @@ class PointerHoverEvent extends PointerEvent {
...
@@ -857,6 +984,63 @@ class PointerHoverEvent extends PointerEvent {
embedderId:
embedderId
,
embedderId:
embedderId
,
);
);
}
}
@override
PointerHoverEvent
copyWith
({
Duration
?
timeStamp
,
int
?
pointer
,
PointerDeviceKind
?
kind
,
int
?
device
,
Offset
?
position
,
Offset
?
localPosition
,
Offset
?
delta
,
Offset
?
localDelta
,
int
?
buttons
,
bool
?
obscured
,
double
?
pressure
,
double
?
pressureMin
,
double
?
pressureMax
,
double
?
distance
,
double
?
distanceMax
,
double
?
size
,
double
?
radiusMajor
,
double
?
radiusMinor
,
double
?
radiusMin
,
double
?
radiusMax
,
double
?
orientation
,
double
?
tilt
,
bool
?
synthesized
,
Matrix4
?
transform
,
PointerEvent
?
original
,
int
?
embedderId
,
})
{
return
PointerHoverEvent
(
timeStamp:
timeStamp
??
this
.
timeStamp
,
kind:
kind
??
this
.
kind
,
device:
device
??
this
.
device
,
position:
position
??
this
.
position
,
localPosition:
localPosition
??
this
.
localPosition
,
delta:
delta
??
this
.
delta
,
localDelta:
localDelta
??
this
.
localDelta
,
buttons:
buttons
??
this
.
buttons
,
obscured:
obscured
??
this
.
obscured
,
pressureMin:
pressureMin
??
this
.
pressureMin
,
pressureMax:
pressureMax
??
this
.
pressureMax
,
distance:
distance
??
this
.
distance
,
distanceMax:
distanceMax
??
this
.
distanceMax
,
size:
size
??
this
.
size
,
radiusMajor:
radiusMajor
??
this
.
radiusMajor
,
radiusMinor:
radiusMinor
??
this
.
radiusMinor
,
radiusMin:
radiusMin
??
this
.
radiusMin
,
radiusMax:
radiusMax
??
this
.
radiusMax
,
orientation:
orientation
??
this
.
orientation
,
tilt:
tilt
??
this
.
tilt
,
synthesized:
synthesized
??
this
.
synthesized
,
transform:
transform
??
this
.
transform
,
original:
original
as
PointerHoverEvent
?
??
this
,
embedderId:
embedderId
??
this
.
embedderId
,
);
}
}
}
/// The pointer has moved with respect to the device while the pointer is or is
/// The pointer has moved with respect to the device while the pointer is or is
...
@@ -1008,6 +1192,63 @@ class PointerEnterEvent extends PointerEvent {
...
@@ -1008,6 +1192,63 @@ class PointerEnterEvent extends PointerEvent {
embedderId:
embedderId
,
embedderId:
embedderId
,
);
);
}
}
@override
PointerEnterEvent
copyWith
({
Duration
?
timeStamp
,
int
?
pointer
,
PointerDeviceKind
?
kind
,
int
?
device
,
Offset
?
position
,
Offset
?
localPosition
,
Offset
?
delta
,
Offset
?
localDelta
,
int
?
buttons
,
bool
?
obscured
,
double
?
pressure
,
double
?
pressureMin
,
double
?
pressureMax
,
double
?
distance
,
double
?
distanceMax
,
double
?
size
,
double
?
radiusMajor
,
double
?
radiusMinor
,
double
?
radiusMin
,
double
?
radiusMax
,
double
?
orientation
,
double
?
tilt
,
bool
?
synthesized
,
Matrix4
?
transform
,
PointerEvent
?
original
,
int
?
embedderId
,
})
{
return
PointerEnterEvent
(
timeStamp:
timeStamp
??
this
.
timeStamp
,
kind:
kind
??
this
.
kind
,
device:
device
??
this
.
device
,
position:
position
??
this
.
position
,
localPosition:
localPosition
??
this
.
localPosition
,
delta:
delta
??
this
.
delta
,
localDelta:
localDelta
??
this
.
localDelta
,
buttons:
buttons
??
this
.
buttons
,
obscured:
obscured
??
this
.
obscured
,
pressureMin:
pressureMin
??
this
.
pressureMin
,
pressureMax:
pressureMax
??
this
.
pressureMax
,
distance:
distance
??
this
.
distance
,
distanceMax:
distanceMax
??
this
.
distanceMax
,
size:
size
??
this
.
size
,
radiusMajor:
radiusMajor
??
this
.
radiusMajor
,
radiusMinor:
radiusMinor
??
this
.
radiusMinor
,
radiusMin:
radiusMin
??
this
.
radiusMin
,
radiusMax:
radiusMax
??
this
.
radiusMax
,
orientation:
orientation
??
this
.
orientation
,
tilt:
tilt
??
this
.
tilt
,
synthesized:
synthesized
??
this
.
synthesized
,
transform:
transform
??
this
.
transform
,
original:
original
as
PointerEnterEvent
?
??
this
,
embedderId:
embedderId
??
this
.
embedderId
,
);
}
}
}
/// The pointer has moved with respect to the device while the pointer is or is
/// The pointer has moved with respect to the device while the pointer is or is
...
@@ -1159,6 +1400,63 @@ class PointerExitEvent extends PointerEvent {
...
@@ -1159,6 +1400,63 @@ class PointerExitEvent extends PointerEvent {
embedderId:
embedderId
,
embedderId:
embedderId
,
);
);
}
}
@override
PointerExitEvent
copyWith
({
Duration
?
timeStamp
,
int
?
pointer
,
PointerDeviceKind
?
kind
,
int
?
device
,
Offset
?
position
,
Offset
?
localPosition
,
Offset
?
delta
,
Offset
?
localDelta
,
int
?
buttons
,
bool
?
obscured
,
double
?
pressure
,
double
?
pressureMin
,
double
?
pressureMax
,
double
?
distance
,
double
?
distanceMax
,
double
?
size
,
double
?
radiusMajor
,
double
?
radiusMinor
,
double
?
radiusMin
,
double
?
radiusMax
,
double
?
orientation
,
double
?
tilt
,
bool
?
synthesized
,
Matrix4
?
transform
,
PointerEvent
?
original
,
int
?
embedderId
,
})
{
return
PointerExitEvent
(
timeStamp:
timeStamp
??
this
.
timeStamp
,
kind:
kind
??
this
.
kind
,
device:
device
??
this
.
device
,
position:
position
??
this
.
position
,
localPosition:
localPosition
??
this
.
localPosition
,
delta:
delta
??
this
.
delta
,
localDelta:
localDelta
??
this
.
localDelta
,
buttons:
buttons
??
this
.
buttons
,
obscured:
obscured
??
this
.
obscured
,
pressureMin:
pressureMin
??
this
.
pressureMin
,
pressureMax:
pressureMax
??
this
.
pressureMax
,
distance:
distance
??
this
.
distance
,
distanceMax:
distanceMax
??
this
.
distanceMax
,
size:
size
??
this
.
size
,
radiusMajor:
radiusMajor
??
this
.
radiusMajor
,
radiusMinor:
radiusMinor
??
this
.
radiusMinor
,
radiusMin:
radiusMin
??
this
.
radiusMin
,
radiusMax:
radiusMax
??
this
.
radiusMax
,
orientation:
orientation
??
this
.
orientation
,
tilt:
tilt
??
this
.
tilt
,
synthesized:
synthesized
??
this
.
synthesized
,
transform:
transform
??
this
.
transform
,
original:
original
as
PointerExitEvent
?
??
this
,
embedderId:
embedderId
??
this
.
embedderId
,
);
}
}
}
/// The pointer has made contact with the device.
/// The pointer has made contact with the device.
...
@@ -1251,6 +1549,61 @@ class PointerDownEvent extends PointerEvent {
...
@@ -1251,6 +1549,61 @@ class PointerDownEvent extends PointerEvent {
embedderId:
embedderId
,
embedderId:
embedderId
,
);
);
}
}
@override
PointerDownEvent
copyWith
({
Duration
?
timeStamp
,
int
?
pointer
,
PointerDeviceKind
?
kind
,
int
?
device
,
Offset
?
position
,
Offset
?
localPosition
,
Offset
?
delta
,
Offset
?
localDelta
,
int
?
buttons
,
bool
?
obscured
,
double
?
pressure
,
double
?
pressureMin
,
double
?
pressureMax
,
double
?
distance
,
double
?
distanceMax
,
double
?
size
,
double
?
radiusMajor
,
double
?
radiusMinor
,
double
?
radiusMin
,
double
?
radiusMax
,
double
?
orientation
,
double
?
tilt
,
bool
?
synthesized
,
Matrix4
?
transform
,
PointerEvent
?
original
,
int
?
embedderId
,
})
{
return
PointerDownEvent
(
timeStamp:
timeStamp
??
this
.
timeStamp
,
pointer:
pointer
??
this
.
pointer
,
kind:
kind
??
this
.
kind
,
device:
device
??
this
.
device
,
position:
position
??
this
.
position
,
localPosition:
localPosition
??
this
.
localPosition
,
buttons:
buttons
??
this
.
buttons
,
obscured:
obscured
??
this
.
obscured
,
pressure:
pressure
??
this
.
pressure
,
pressureMin:
pressureMin
??
this
.
pressureMin
,
pressureMax:
pressureMax
??
this
.
pressureMax
,
distanceMax:
distanceMax
??
this
.
distanceMax
,
size:
size
??
this
.
size
,
radiusMajor:
radiusMajor
??
this
.
radiusMajor
,
radiusMinor:
radiusMinor
??
this
.
radiusMinor
,
radiusMin:
radiusMin
??
this
.
radiusMin
,
radiusMax:
radiusMax
??
this
.
radiusMax
,
orientation:
orientation
??
this
.
orientation
,
tilt:
tilt
??
this
.
tilt
,
transform:
transform
??
this
.
transform
,
original:
original
as
PointerDownEvent
?
??
this
,
embedderId:
embedderId
??
this
.
embedderId
,
);
}
}
}
/// The pointer has moved with respect to the device while the pointer is in
/// The pointer has moved with respect to the device while the pointer is in
...
@@ -1365,6 +1718,64 @@ class PointerMoveEvent extends PointerEvent {
...
@@ -1365,6 +1718,64 @@ class PointerMoveEvent extends PointerEvent {
embedderId:
embedderId
,
embedderId:
embedderId
,
);
);
}
}
@override
PointerMoveEvent
copyWith
({
Duration
?
timeStamp
,
int
?
pointer
,
PointerDeviceKind
?
kind
,
int
?
device
,
Offset
?
position
,
Offset
?
localPosition
,
Offset
?
delta
,
Offset
?
localDelta
,
int
?
buttons
,
bool
?
obscured
,
double
?
pressure
,
double
?
pressureMin
,
double
?
pressureMax
,
double
?
distance
,
double
?
distanceMax
,
double
?
size
,
double
?
radiusMajor
,
double
?
radiusMinor
,
double
?
radiusMin
,
double
?
radiusMax
,
double
?
orientation
,
double
?
tilt
,
bool
?
synthesized
,
Matrix4
?
transform
,
PointerEvent
?
original
,
int
?
embedderId
,
})
{
return
PointerMoveEvent
(
timeStamp:
timeStamp
??
this
.
timeStamp
,
pointer:
pointer
??
this
.
pointer
,
kind:
kind
??
this
.
kind
,
device:
device
??
this
.
device
,
position:
position
??
this
.
position
,
localPosition:
localPosition
??
this
.
localPosition
,
delta:
delta
??
this
.
delta
,
localDelta:
localDelta
??
this
.
localDelta
,
buttons:
buttons
??
this
.
buttons
,
obscured:
obscured
??
this
.
obscured
,
pressure:
pressure
??
this
.
pressure
,
pressureMin:
pressureMin
??
this
.
pressureMin
,
pressureMax:
pressureMax
??
this
.
pressureMax
,
distanceMax:
distanceMax
??
this
.
distanceMax
,
size:
size
??
this
.
size
,
radiusMajor:
radiusMajor
??
this
.
radiusMajor
,
radiusMinor:
radiusMinor
??
this
.
radiusMinor
,
radiusMin:
radiusMin
??
this
.
radiusMin
,
radiusMax:
radiusMax
??
this
.
radiusMax
,
orientation:
orientation
??
this
.
orientation
,
tilt:
tilt
??
this
.
tilt
,
synthesized:
synthesized
??
this
.
synthesized
,
transform:
transform
??
this
.
transform
,
original:
original
as
PointerMoveEvent
?
??
this
,
embedderId:
embedderId
??
this
.
embedderId
,
);
}
}
}
/// The pointer has stopped making contact with the device.
/// The pointer has stopped making contact with the device.
...
@@ -1461,6 +1872,62 @@ class PointerUpEvent extends PointerEvent {
...
@@ -1461,6 +1872,62 @@ class PointerUpEvent extends PointerEvent {
embedderId:
embedderId
,
embedderId:
embedderId
,
);
);
}
}
@override
PointerUpEvent
copyWith
({
Duration
?
timeStamp
,
int
?
pointer
,
PointerDeviceKind
?
kind
,
int
?
device
,
Offset
?
position
,
Offset
?
localPosition
,
Offset
?
delta
,
Offset
?
localDelta
,
int
?
buttons
,
bool
?
obscured
,
double
?
pressure
,
double
?
pressureMin
,
double
?
pressureMax
,
double
?
distance
,
double
?
distanceMax
,
double
?
size
,
double
?
radiusMajor
,
double
?
radiusMinor
,
double
?
radiusMin
,
double
?
radiusMax
,
double
?
orientation
,
double
?
tilt
,
bool
?
synthesized
,
Matrix4
?
transform
,
PointerEvent
?
original
,
int
?
embedderId
,
})
{
return
PointerUpEvent
(
timeStamp:
timeStamp
??
this
.
timeStamp
,
pointer:
pointer
??
this
.
pointer
,
kind:
kind
??
this
.
kind
,
device:
device
??
this
.
device
,
position:
position
??
this
.
position
,
localPosition:
localPosition
??
this
.
localPosition
,
buttons:
buttons
??
this
.
buttons
,
obscured:
obscured
??
this
.
obscured
,
pressure:
pressure
??
this
.
pressure
,
pressureMin:
pressureMin
??
this
.
pressureMin
,
pressureMax:
pressureMax
??
this
.
pressureMax
,
distance:
distance
??
this
.
distance
,
distanceMax:
distanceMax
??
this
.
distanceMax
,
size:
size
??
this
.
size
,
radiusMajor:
radiusMajor
??
this
.
radiusMajor
,
radiusMinor:
radiusMinor
??
this
.
radiusMinor
,
radiusMin:
radiusMin
??
this
.
radiusMin
,
radiusMax:
radiusMax
??
this
.
radiusMax
,
orientation:
orientation
??
this
.
orientation
,
tilt:
tilt
??
this
.
tilt
,
transform:
transform
??
this
.
transform
,
original:
original
as
PointerUpEvent
?
??
this
,
embedderId:
embedderId
??
this
.
embedderId
,
);
}
}
}
/// An event that corresponds to a discrete pointer signal.
/// An event that corresponds to a discrete pointer signal.
...
@@ -1559,6 +2026,48 @@ class PointerScrollEvent extends PointerSignalEvent {
...
@@ -1559,6 +2026,48 @@ class PointerScrollEvent extends PointerSignalEvent {
);
);
}
}
@override
PointerScrollEvent
copyWith
({
Duration
?
timeStamp
,
int
?
pointer
,
PointerDeviceKind
?
kind
,
int
?
device
,
Offset
?
position
,
Offset
?
localPosition
,
Offset
?
delta
,
Offset
?
localDelta
,
int
?
buttons
,
bool
?
obscured
,
double
?
pressure
,
double
?
pressureMin
,
double
?
pressureMax
,
double
?
distance
,
double
?
distanceMax
,
double
?
size
,
double
?
radiusMajor
,
double
?
radiusMinor
,
double
?
radiusMin
,
double
?
radiusMax
,
double
?
orientation
,
double
?
tilt
,
bool
?
synthesized
,
Matrix4
?
transform
,
PointerEvent
?
original
,
int
?
embedderId
,
})
{
return
PointerScrollEvent
(
timeStamp:
timeStamp
??
this
.
timeStamp
,
kind:
kind
??
this
.
kind
,
device:
device
??
this
.
device
,
position:
position
??
this
.
position
,
localPosition:
localPosition
??
this
.
localPosition
,
scrollDelta:
scrollDelta
,
transform:
transform
??
this
.
transform
,
original:
original
as
PointerScrollEvent
?
??
this
,
embedderId:
embedderId
??
this
.
embedderId
,
);
}
@override
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
super
.
debugFillProperties
(
properties
);
...
@@ -1656,4 +2165,59 @@ class PointerCancelEvent extends PointerEvent {
...
@@ -1656,4 +2165,59 @@ class PointerCancelEvent extends PointerEvent {
embedderId:
embedderId
,
embedderId:
embedderId
,
);
);
}
}
@override
PointerCancelEvent
copyWith
({
Duration
?
timeStamp
,
int
?
pointer
,
PointerDeviceKind
?
kind
,
int
?
device
,
Offset
?
position
,
Offset
?
localPosition
,
Offset
?
delta
,
Offset
?
localDelta
,
int
?
buttons
,
bool
?
obscured
,
double
?
pressure
,
double
?
pressureMin
,
double
?
pressureMax
,
double
?
distance
,
double
?
distanceMax
,
double
?
size
,
double
?
radiusMajor
,
double
?
radiusMinor
,
double
?
radiusMin
,
double
?
radiusMax
,
double
?
orientation
,
double
?
tilt
,
bool
?
synthesized
,
Matrix4
?
transform
,
PointerEvent
?
original
,
int
?
embedderId
,
})
{
return
PointerCancelEvent
(
timeStamp:
timeStamp
??
this
.
timeStamp
,
pointer:
pointer
??
this
.
pointer
,
kind:
kind
??
this
.
kind
,
device:
device
??
this
.
device
,
position:
position
??
this
.
position
,
localPosition:
localPosition
??
this
.
localPosition
,
buttons:
buttons
??
this
.
buttons
,
obscured:
obscured
??
this
.
obscured
,
pressureMin:
pressureMin
??
this
.
pressureMin
,
pressureMax:
pressureMax
??
this
.
pressureMax
,
distance:
distance
??
this
.
distance
,
distanceMax:
distanceMax
??
this
.
distanceMax
,
size:
size
??
this
.
size
,
radiusMajor:
radiusMajor
??
this
.
radiusMajor
,
radiusMinor:
radiusMinor
??
this
.
radiusMinor
,
radiusMin:
radiusMin
??
this
.
radiusMin
,
radiusMax:
radiusMax
??
this
.
radiusMax
,
orientation:
orientation
??
this
.
orientation
,
tilt:
tilt
??
this
.
tilt
,
transform:
transform
??
this
.
transform
,
original:
original
as
PointerCancelEvent
?
??
this
,
embedderId:
embedderId
??
this
.
embedderId
,
);
}
}
}
packages/flutter/lib/src/gestures/resampler.dart
0 → 100644
View file @
02612bfe
// 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:collection'
;
import
'events.dart'
;
typedef
HandleEventCallback
=
void
Function
(
PointerEvent
event
);
/// Class for pointer event resampling.
///
/// An instance of this class can be used to resample one sequence
/// of pointer events. Multiple instances are expected to be used for
/// multi-touch support. The sampling frequency and the sampling
/// offset is determined by the caller.
///
/// This can be used to get smooth touch event processing at the cost
/// of adding some latency. Devices with low frequency sensors or when
/// the frequency is not a multiple of the display frequency
/// (e.g., 120Hz input and 90Hz display) benefit from this.
///
/// The following pointer event types are supported:
/// [PointerAddedEvent], [PointerHoverEvent], [PointerDownEvent],
/// [PointerMoveEvent], [PointerCancelEvent], [PointerUpEvent],
/// [PointerRemovedEvent].
///
/// Resampling is currently limited to event position and delta. All
/// pointer event types except [PointerAddedEvent] will be resampled.
/// [PointerHoverEvent] and [PointerMoveEvent] will only be generated
/// when the position has changed.
class
PointerEventResampler
{
// Events queued for processing.
final
Queue
<
PointerEvent
>
_queuedEvents
=
Queue
<
PointerEvent
>();
// Pointer state required for resampling.
PointerEvent
?
_last
;
PointerEvent
?
_next
;
Offset
_position
=
Offset
.
zero
;
bool
_isTracked
=
false
;
bool
_isDown
=
false
;
int
_pointerIdentifier
=
0
;
PointerEvent
_toHoverEvent
(
PointerEvent
event
,
Offset
position
,
Offset
delta
,
Duration
timeStamp
,
)
{
return
PointerHoverEvent
(
timeStamp:
timeStamp
,
kind:
event
.
kind
,
device:
event
.
device
,
position:
position
,
delta:
delta
,
buttons:
event
.
buttons
,
obscured:
event
.
obscured
,
pressureMin:
event
.
pressureMin
,
pressureMax:
event
.
pressureMax
,
distance:
event
.
distance
,
distanceMax:
event
.
distanceMax
,
size:
event
.
size
,
radiusMajor:
event
.
radiusMajor
,
radiusMinor:
event
.
radiusMinor
,
radiusMin:
event
.
radiusMin
,
radiusMax:
event
.
radiusMax
,
orientation:
event
.
orientation
,
tilt:
event
.
tilt
,
synthesized:
event
.
synthesized
,
embedderId:
event
.
embedderId
,
);
}
PointerEvent
_toMoveEvent
(
PointerEvent
event
,
Offset
position
,
Offset
delta
,
int
pointerIdentifier
,
Duration
timeStamp
,
)
{
return
PointerMoveEvent
(
timeStamp:
timeStamp
,
pointer:
pointerIdentifier
,
kind:
event
.
kind
,
device:
event
.
device
,
position:
position
,
delta:
delta
,
buttons:
event
.
buttons
,
obscured:
event
.
obscured
,
pressure:
event
.
pressure
,
pressureMin:
event
.
pressureMin
,
pressureMax:
event
.
pressureMax
,
distanceMax:
event
.
distanceMax
,
size:
event
.
size
,
radiusMajor:
event
.
radiusMajor
,
radiusMinor:
event
.
radiusMinor
,
radiusMin:
event
.
radiusMin
,
radiusMax:
event
.
radiusMax
,
orientation:
event
.
orientation
,
tilt:
event
.
tilt
,
platformData:
event
.
platformData
,
synthesized:
event
.
synthesized
,
embedderId:
event
.
embedderId
,
);
}
Offset
_positionAt
(
Duration
sampleTime
)
{
// Use `next` position by default.
double
x
=
_next
?.
position
.
dx
??
0.0
;
double
y
=
_next
?.
position
.
dy
??
0.0
;
final
Duration
nextTimeStamp
=
_next
?.
timeStamp
??
Duration
.
zero
;
final
Duration
lastTimeStamp
=
_last
?.
timeStamp
??
Duration
.
zero
;
// Resample if `next` time stamp is past `sampleTime`.
if
(
nextTimeStamp
>
sampleTime
&&
nextTimeStamp
>
lastTimeStamp
)
{
final
double
interval
=
(
nextTimeStamp
-
lastTimeStamp
).
inMicroseconds
.
toDouble
();
final
double
scalar
=
(
sampleTime
-
lastTimeStamp
).
inMicroseconds
.
toDouble
()
/
interval
;
final
double
lastX
=
_last
?.
position
.
dx
??
0.0
;
final
double
lastY
=
_last
?.
position
.
dy
??
0.0
;
x
=
lastX
+
(
x
-
lastX
)
*
scalar
;
y
=
lastY
+
(
y
-
lastY
)
*
scalar
;
}
return
Offset
(
x
,
y
);
}
void
_processPointerEvents
(
Duration
sampleTime
)
{
final
Iterator
<
PointerEvent
>
it
=
_queuedEvents
.
iterator
;
while
(
it
.
moveNext
())
{
final
PointerEvent
event
=
it
.
current
;
// Update both `last` and `next` pointer event if time stamp is older
// or equal to `sampleTime`.
if
(
event
.
timeStamp
<=
sampleTime
||
_last
==
null
)
{
_last
=
event
;
_next
=
event
;
continue
;
}
// Update only `next` pointer event if time stamp is more recent than
// `sampleTime` and next event is not already more recent.
final
Duration
nextTimeStamp
=
_next
?.
timeStamp
??
Duration
.
zero
;
if
(
nextTimeStamp
<
sampleTime
)
{
_next
=
event
;
break
;
}
}
}
void
_dequeueAndSampleNonHoverOrMovePointerEventsUntil
(
Duration
sampleTime
,
HandleEventCallback
callback
,
)
{
while
(
_queuedEvents
.
isNotEmpty
)
{
final
PointerEvent
event
=
_queuedEvents
.
first
;
// Potentially stop dispatching events if more recent than `sampleTime`.
if
(
event
.
timeStamp
>
sampleTime
)
{
// Stop if event is not up or removed. Otherwise, continue to
// allow early processing of up and remove events as this improves
// resampling of these events, which is important for fling
// animations.
if
(
event
is
!
PointerUpEvent
&&
event
is
!
PointerRemovedEvent
)
{
break
;
}
// When this line is reached, the following two invariants hold:
// (1) `event.timeStamp > sampleTime`
// (2) `_next` has the smallest time stamp that's no less than
// `sampleTime`
//
// Therefore, event must satisfy `event.timeStamp >= _next.timeStamp`.
//
// Those events with the minimum `event.timeStamp == _next.timeStamp`
// time stamp are processed early for smoother fling. For events with
// `event.timeStamp > _next.timeStamp`, the following lines break the
// while loop to stop the early processing.
//
// Specifically, when `sampleTime < _next.timeStamp`, there must be
// at least one event with `_next.timeStamp == event.timeStamp`
// and that event is `_next` itself, and it will be processed early.
//
// When `sampleTime == _next.timeStamp`, all events with
// `event.timeStamp > sampleTime` must also have
// `event.timeStamp > _next.timeStamp` so no events will be processed
// early.
//
// When the input frequency is no greater than the sampling
// frequency, this early processing should guarantee that `up` and
// `remove` events are always re-sampled.
final
Duration
nextTimeStamp
=
_next
?.
timeStamp
??
Duration
.
zero
;
assert
(
event
.
timeStamp
>=
nextTimeStamp
);
if
(
event
.
timeStamp
>
nextTimeStamp
)
{
break
;
}
}
final
bool
wasTracked
=
_isTracked
;
final
bool
wasDown
=
_isDown
;
// Update pointer state.
_isTracked
=
event
is
!
PointerRemovedEvent
;
_isDown
=
event
.
down
;
// Position at `sampleTime`.
final
Offset
position
=
_positionAt
(
sampleTime
);
// Initialize position if we are starting to track this pointer.
if
(
_isTracked
&&
!
wasTracked
)
{
_position
=
position
;
}
// Current pointer identifier.
final
int
pointerIdentifier
=
event
.
pointer
;
// Initialize pointer identifier for `move` events.
// Identifier is expected to be the same while `down`.
assert
(!
wasDown
||
_pointerIdentifier
==
pointerIdentifier
);
_pointerIdentifier
=
pointerIdentifier
;
// Skip `move` and `hover` events as they are automatically
// generated when the position has changed.
if
(
event
is
!
PointerMoveEvent
&&
event
is
!
PointerHoverEvent
)
{
callback
(
event
.
copyWith
(
position:
position
,
delta:
position
-
_position
,
pointer:
pointerIdentifier
,
timeStamp:
sampleTime
,
));
_position
=
position
;
}
_queuedEvents
.
removeFirst
();
}
}
void
_samplePointerPosition
(
Duration
sampleTime
,
HandleEventCallback
callback
,
)
{
// Position at `sampleTime`.
final
Offset
position
=
_positionAt
(
sampleTime
);
// Add `move` or `hover` events if position has changed.
final
PointerEvent
?
next
=
_next
;
if
(
position
!=
_position
&&
next
!=
null
)
{
final
Offset
delta
=
position
-
_position
;
final
PointerEvent
event
=
_isDown
?
_toMoveEvent
(
next
,
position
,
delta
,
_pointerIdentifier
,
sampleTime
)
:
_toHoverEvent
(
next
,
position
,
delta
,
sampleTime
);
callback
(
event
);
_position
=
position
;
}
}
/// Enqueue pointer `event` for resampling.
void
addEvent
(
PointerEvent
event
)
{
_queuedEvents
.
add
(
event
);
}
/// Dispatch resampled pointer events for the specified `sampleTime`
/// by calling [callback].
///
/// This may dispatch multiple events if position is not the only
/// state that has changed since last sample.
///
/// Calling [callback] must not add or sample events.
void
sample
(
Duration
sampleTime
,
HandleEventCallback
callback
)
{
_processPointerEvents
(
sampleTime
);
// Dequeue and sample pointer events until `sampleTime`.
_dequeueAndSampleNonHoverOrMovePointerEventsUntil
(
sampleTime
,
callback
);
// Dispatch resampled pointer location event if tracked.
if
(
_isTracked
)
{
_samplePointerPosition
(
sampleTime
,
callback
);
}
}
/// Stop resampling.
///
/// This will dispatch pending events by calling [callback] and reset
/// internal state.
void
stop
(
HandleEventCallback
callback
)
{
while
(
_queuedEvents
.
isNotEmpty
)
{
callback
(
_queuedEvents
.
removeFirst
());
}
_pointerIdentifier
=
0
;
_isDown
=
false
;
_isTracked
=
false
;
_position
=
Offset
.
zero
;
_next
=
null
;
_last
=
null
;
}
/// Returns `true` if a call to [sample] can dispatch more events.
bool
get
hasPendingEvents
=>
_queuedEvents
.
isNotEmpty
;
/// Returns `true` if pointer is currently tracked.
bool
get
isTracked
=>
_isTracked
;
/// Returns `true` if pointer is currently down.
bool
get
isDown
=>
_isDown
;
}
packages/flutter/test/gestures/events_test.dart
View file @
02612bfe
...
@@ -498,6 +498,286 @@ void main() {
...
@@ -498,6 +498,286 @@ void main() {
localPosition:
localPosition
,
localPosition:
localPosition
,
);
);
});
});
group
(
'copyWith'
,
()
{
const
PointerEvent
added
=
PointerAddedEvent
(
timeStamp:
Duration
(
days:
1
),
kind:
PointerDeviceKind
.
unknown
,
device:
10
,
position:
Offset
(
101.0
,
202.0
),
obscured:
true
,
pressureMax:
2.1
,
pressureMin:
1.1
,
distance:
11
,
distanceMax:
110
,
radiusMin:
1.1
,
radiusMax:
22
,
orientation:
1.1
,
tilt:
1.1
,
);
const
PointerEvent
hover
=
PointerHoverEvent
(
timeStamp:
Duration
(
days:
1
),
kind:
PointerDeviceKind
.
unknown
,
device:
10
,
position:
Offset
(
101.0
,
202.0
),
buttons:
7
,
obscured:
true
,
pressureMax:
2.1
,
pressureMin:
1.1
,
distance:
11
,
distanceMax:
110
,
size:
11
,
radiusMajor:
11
,
radiusMinor:
9
,
radiusMin:
1.1
,
radiusMax:
22
,
orientation:
1.1
,
tilt:
1.1
,
synthesized:
true
,
);
const
PointerEvent
down
=
PointerDownEvent
(
timeStamp:
Duration
(
days:
1
),
pointer:
1
,
kind:
PointerDeviceKind
.
unknown
,
device:
10
,
position:
Offset
(
101.0
,
202.0
),
buttons:
7
,
obscured:
true
,
pressureMax:
2.1
,
pressureMin:
1.1
,
distanceMax:
110
,
size:
11
,
radiusMajor:
11
,
radiusMinor:
9
,
radiusMin:
1.1
,
radiusMax:
22
,
orientation:
1.1
,
tilt:
1.1
,
);
const
PointerEvent
move
=
PointerMoveEvent
(
timeStamp:
Duration
(
days:
1
),
pointer:
1
,
kind:
PointerDeviceKind
.
unknown
,
device:
10
,
position:
Offset
(
101.0
,
202.0
),
delta:
Offset
(
1.0
,
2.0
),
buttons:
7
,
obscured:
true
,
pressureMax:
2.1
,
pressureMin:
1.1
,
distanceMax:
110
,
size:
11
,
radiusMajor:
11
,
radiusMinor:
9
,
radiusMin:
1.1
,
radiusMax:
22
,
orientation:
1.1
,
tilt:
1.1
,
synthesized:
true
,
);
const
PointerEvent
up
=
PointerUpEvent
(
timeStamp:
Duration
(
days:
1
),
pointer:
1
,
kind:
PointerDeviceKind
.
unknown
,
device:
10
,
position:
Offset
(
101.0
,
202.0
),
buttons:
7
,
obscured:
true
,
pressureMax:
2.1
,
pressureMin:
1.1
,
distanceMax:
110
,
size:
11
,
radiusMajor:
11
,
radiusMinor:
9
,
radiusMin:
1.1
,
radiusMax:
22
,
orientation:
1.1
,
tilt:
1.1
,
);
const
PointerEvent
removed
=
PointerRemovedEvent
(
timeStamp:
Duration
(
days:
1
),
kind:
PointerDeviceKind
.
unknown
,
device:
10
,
position:
Offset
(
101.0
,
202.0
),
obscured:
true
,
pressureMax:
2.1
,
pressureMin:
1.1
,
distanceMax:
110
,
radiusMin:
1.1
,
radiusMax:
22
,
);
const
Offset
position
=
Offset
.
zero
;
const
Duration
timeStamp
=
Duration
(
days:
2
);
test
(
'PointerAddedEvent.copyWith()'
,
()
{
final
PointerEvent
event
=
added
.
copyWith
(
position:
position
,
timeStamp:
timeStamp
);
const
PointerEvent
empty
=
PointerAddedEvent
();
expect
(
event
.
timeStamp
,
timeStamp
);
expect
(
event
.
pointer
,
empty
.
pointer
);
expect
(
event
.
kind
,
added
.
kind
);
expect
(
event
.
device
,
added
.
device
);
expect
(
event
.
position
,
position
);
expect
(
event
.
delta
,
empty
.
delta
);
expect
(
event
.
buttons
,
added
.
buttons
);
expect
(
event
.
down
,
empty
.
down
);
expect
(
event
.
obscured
,
added
.
obscured
);
expect
(
event
.
pressure
,
empty
.
pressure
);
expect
(
event
.
pressureMin
,
added
.
pressureMin
);
expect
(
event
.
pressureMax
,
added
.
pressureMax
);
expect
(
event
.
distance
,
added
.
distance
);
expect
(
event
.
distanceMax
,
added
.
distanceMax
);
expect
(
event
.
distanceMax
,
added
.
distanceMax
);
expect
(
event
.
size
,
empty
.
size
);
expect
(
event
.
radiusMajor
,
empty
.
radiusMajor
);
expect
(
event
.
radiusMinor
,
empty
.
radiusMinor
);
expect
(
event
.
radiusMin
,
added
.
radiusMin
);
expect
(
event
.
radiusMax
,
added
.
radiusMax
);
expect
(
event
.
orientation
,
added
.
orientation
);
expect
(
event
.
tilt
,
added
.
tilt
);
expect
(
event
.
synthesized
,
empty
.
synthesized
);
});
test
(
'PointerHoverEvent.copyWith()'
,
()
{
final
PointerEvent
event
=
hover
.
copyWith
(
position:
position
,
timeStamp:
timeStamp
);
const
PointerEvent
empty
=
PointerHoverEvent
();
expect
(
event
.
timeStamp
,
timeStamp
);
expect
(
event
.
pointer
,
empty
.
pointer
);
expect
(
event
.
kind
,
hover
.
kind
);
expect
(
event
.
device
,
hover
.
device
);
expect
(
event
.
position
,
position
);
expect
(
event
.
delta
,
empty
.
delta
);
expect
(
event
.
buttons
,
hover
.
buttons
);
expect
(
event
.
down
,
empty
.
down
);
expect
(
event
.
obscured
,
hover
.
obscured
);
expect
(
event
.
pressure
,
empty
.
pressure
);
expect
(
event
.
pressureMin
,
hover
.
pressureMin
);
expect
(
event
.
pressureMax
,
hover
.
pressureMax
);
expect
(
event
.
distance
,
hover
.
distance
);
expect
(
event
.
distanceMax
,
hover
.
distanceMax
);
expect
(
event
.
distanceMax
,
hover
.
distanceMax
);
expect
(
event
.
size
,
hover
.
size
);
expect
(
event
.
radiusMajor
,
hover
.
radiusMajor
);
expect
(
event
.
radiusMinor
,
hover
.
radiusMinor
);
expect
(
event
.
radiusMin
,
hover
.
radiusMin
);
expect
(
event
.
radiusMax
,
hover
.
radiusMax
);
expect
(
event
.
orientation
,
hover
.
orientation
);
expect
(
event
.
tilt
,
hover
.
tilt
);
expect
(
event
.
synthesized
,
hover
.
synthesized
);
});
test
(
'PointerDownEvent.copyWith()'
,
()
{
final
PointerEvent
event
=
down
.
copyWith
(
position:
position
,
timeStamp:
timeStamp
);
const
PointerEvent
empty
=
PointerDownEvent
();
expect
(
event
.
timeStamp
,
timeStamp
);
expect
(
event
.
pointer
,
down
.
pointer
);
expect
(
event
.
kind
,
down
.
kind
);
expect
(
event
.
device
,
down
.
device
);
expect
(
event
.
position
,
position
);
expect
(
event
.
delta
,
empty
.
delta
);
expect
(
event
.
buttons
,
down
.
buttons
);
expect
(
event
.
down
,
empty
.
down
);
expect
(
event
.
obscured
,
down
.
obscured
);
expect
(
event
.
pressure
,
empty
.
pressure
);
expect
(
event
.
pressureMin
,
down
.
pressureMin
);
expect
(
event
.
pressureMax
,
down
.
pressureMax
);
expect
(
event
.
distance
,
down
.
distance
);
expect
(
event
.
distanceMax
,
down
.
distanceMax
);
expect
(
event
.
distanceMax
,
down
.
distanceMax
);
expect
(
event
.
size
,
down
.
size
);
expect
(
event
.
radiusMajor
,
down
.
radiusMajor
);
expect
(
event
.
radiusMinor
,
down
.
radiusMinor
);
expect
(
event
.
radiusMin
,
down
.
radiusMin
);
expect
(
event
.
radiusMax
,
down
.
radiusMax
);
expect
(
event
.
orientation
,
down
.
orientation
);
expect
(
event
.
tilt
,
down
.
tilt
);
expect
(
event
.
synthesized
,
empty
.
synthesized
);
});
test
(
'PointerMoveEvent.copyWith()'
,
()
{
final
PointerEvent
event
=
move
.
copyWith
(
position:
position
,
timeStamp:
timeStamp
);
const
PointerEvent
empty
=
PointerMoveEvent
();
expect
(
event
.
timeStamp
,
timeStamp
);
expect
(
event
.
pointer
,
move
.
pointer
);
expect
(
event
.
kind
,
move
.
kind
);
expect
(
event
.
device
,
move
.
device
);
expect
(
event
.
position
,
position
);
expect
(
event
.
delta
,
move
.
delta
);
expect
(
event
.
buttons
,
move
.
buttons
);
expect
(
event
.
down
,
move
.
down
);
expect
(
event
.
obscured
,
move
.
obscured
);
expect
(
event
.
pressure
,
empty
.
pressure
);
expect
(
event
.
pressureMin
,
move
.
pressureMin
);
expect
(
event
.
pressureMax
,
move
.
pressureMax
);
expect
(
event
.
distance
,
move
.
distance
);
expect
(
event
.
distanceMax
,
move
.
distanceMax
);
expect
(
event
.
distanceMax
,
move
.
distanceMax
);
expect
(
event
.
size
,
move
.
size
);
expect
(
event
.
radiusMajor
,
move
.
radiusMajor
);
expect
(
event
.
radiusMinor
,
move
.
radiusMinor
);
expect
(
event
.
radiusMin
,
move
.
radiusMin
);
expect
(
event
.
radiusMax
,
move
.
radiusMax
);
expect
(
event
.
orientation
,
move
.
orientation
);
expect
(
event
.
tilt
,
move
.
tilt
);
expect
(
event
.
synthesized
,
move
.
synthesized
);
});
test
(
'PointerUpEvent.copyWith()'
,
()
{
final
PointerEvent
event
=
up
.
copyWith
(
position:
position
,
timeStamp:
timeStamp
);
const
PointerEvent
empty
=
PointerUpEvent
();
expect
(
event
.
timeStamp
,
timeStamp
);
expect
(
event
.
pointer
,
up
.
pointer
);
expect
(
event
.
kind
,
up
.
kind
);
expect
(
event
.
device
,
up
.
device
);
expect
(
event
.
position
,
position
);
expect
(
event
.
delta
,
up
.
delta
);
expect
(
event
.
buttons
,
up
.
buttons
);
expect
(
event
.
down
,
empty
.
down
);
expect
(
event
.
obscured
,
up
.
obscured
);
expect
(
event
.
pressure
,
empty
.
pressure
);
expect
(
event
.
pressureMin
,
up
.
pressureMin
);
expect
(
event
.
pressureMax
,
up
.
pressureMax
);
expect
(
event
.
distance
,
up
.
distance
);
expect
(
event
.
distanceMax
,
up
.
distanceMax
);
expect
(
event
.
distanceMax
,
up
.
distanceMax
);
expect
(
event
.
size
,
up
.
size
);
expect
(
event
.
radiusMajor
,
up
.
radiusMajor
);
expect
(
event
.
radiusMinor
,
up
.
radiusMinor
);
expect
(
event
.
radiusMin
,
up
.
radiusMin
);
expect
(
event
.
radiusMax
,
up
.
radiusMax
);
expect
(
event
.
orientation
,
up
.
orientation
);
expect
(
event
.
tilt
,
up
.
tilt
);
expect
(
event
.
synthesized
,
empty
.
synthesized
);
});
test
(
'PointerRemovedEvent.copyWith()'
,
()
{
final
PointerEvent
event
=
removed
.
copyWith
(
position:
position
,
timeStamp:
timeStamp
);
const
PointerEvent
empty
=
PointerRemovedEvent
();
expect
(
event
.
timeStamp
,
timeStamp
);
expect
(
event
.
pointer
,
empty
.
pointer
);
expect
(
event
.
kind
,
removed
.
kind
);
expect
(
event
.
device
,
removed
.
device
);
expect
(
event
.
position
,
position
);
expect
(
event
.
delta
,
empty
.
delta
);
expect
(
event
.
buttons
,
removed
.
buttons
);
expect
(
event
.
down
,
empty
.
down
);
expect
(
event
.
obscured
,
removed
.
obscured
);
expect
(
event
.
pressure
,
empty
.
pressure
);
expect
(
event
.
pressureMin
,
removed
.
pressureMin
);
expect
(
event
.
pressureMax
,
removed
.
pressureMax
);
expect
(
event
.
distance
,
empty
.
distance
);
expect
(
event
.
distanceMax
,
removed
.
distanceMax
);
expect
(
event
.
distanceMax
,
removed
.
distanceMax
);
expect
(
event
.
size
,
empty
.
size
);
expect
(
event
.
radiusMajor
,
empty
.
radiusMajor
);
expect
(
event
.
radiusMinor
,
empty
.
radiusMinor
);
expect
(
event
.
radiusMin
,
removed
.
radiusMin
);
expect
(
event
.
radiusMax
,
removed
.
radiusMax
);
expect
(
event
.
orientation
,
empty
.
orientation
);
expect
(
event
.
tilt
,
empty
.
tilt
);
expect
(
event
.
synthesized
,
empty
.
synthesized
);
});
});
}
}
void
_expectTransformedEvent
(
{
void
_expectTransformedEvent
(
{
...
...
packages/flutter/test/gestures/gesture_binding_test.dart
View file @
02612bfe
...
@@ -8,13 +8,16 @@ import 'dart:ui' as ui;
...
@@ -8,13 +8,16 @@ import 'dart:ui' as ui;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/scheduler.dart'
;
import
'../flutter_test_alternative.dart'
;
import
'../flutter_test_alternative.dart'
;
typedef
HandleEventCallback
=
void
Function
(
PointerEvent
event
);
typedef
HandleEventCallback
=
void
Function
(
PointerEvent
event
);
class
TestGestureFlutterBinding
extends
BindingBase
with
GestureBinding
{
class
TestGestureFlutterBinding
extends
BindingBase
with
GestureBinding
,
SchedulerBinding
{
HandleEventCallback
callback
;
HandleEventCallback
callback
;
FrameCallback
frameCallback
;
Duration
frameTime
;
@override
@override
void
handleEvent
(
PointerEvent
event
,
HitTestEntry
entry
)
{
void
handleEvent
(
PointerEvent
event
,
HitTestEntry
entry
)
{
...
@@ -22,6 +25,18 @@ class TestGestureFlutterBinding extends BindingBase with GestureBinding {
...
@@ -22,6 +25,18 @@ class TestGestureFlutterBinding extends BindingBase with GestureBinding {
if
(
callback
!=
null
)
if
(
callback
!=
null
)
callback
(
event
);
callback
(
event
);
}
}
@override
Duration
get
currentSystemFrameTimeStamp
{
assert
(
frameTime
!=
null
);
return
frameTime
;
}
@override
int
scheduleFrameCallback
(
FrameCallback
callback
,
{
bool
rescheduling
=
false
})
{
frameCallback
=
callback
;
return
0
;
}
}
}
TestGestureFlutterBinding
_binding
=
TestGestureFlutterBinding
();
TestGestureFlutterBinding
_binding
=
TestGestureFlutterBinding
();
...
@@ -29,6 +44,7 @@ TestGestureFlutterBinding _binding = TestGestureFlutterBinding();
...
@@ -29,6 +44,7 @@ TestGestureFlutterBinding _binding = TestGestureFlutterBinding();
void
ensureTestGestureBinding
(
)
{
void
ensureTestGestureBinding
(
)
{
_binding
??=
TestGestureFlutterBinding
();
_binding
??=
TestGestureFlutterBinding
();
assert
(
GestureBinding
.
instance
!=
null
);
assert
(
GestureBinding
.
instance
!=
null
);
assert
(
SchedulerBinding
.
instance
!=
null
);
}
}
void
main
(
)
{
void
main
(
)
{
...
@@ -299,4 +315,107 @@ void main() {
...
@@ -299,4 +315,107 @@ void main() {
expect
(
events
[
4
].
buttons
,
equals
(
0
));
expect
(
events
[
4
].
buttons
,
equals
(
0
));
}
}
});
});
test
(
'Pointer event resampling'
,
()
{
const
ui
.
PointerDataPacket
packet
=
ui
.
PointerDataPacket
(
data:
<
ui
.
PointerData
>[
ui
.
PointerData
(
change:
ui
.
PointerChange
.
add
,
physicalX:
0.0
,
timeStamp:
Duration
(
milliseconds:
0
),
),
ui
.
PointerData
(
change:
ui
.
PointerChange
.
down
,
physicalX:
0.0
,
timeStamp:
Duration
(
milliseconds:
1
),
),
ui
.
PointerData
(
change:
ui
.
PointerChange
.
move
,
physicalX:
10.0
,
timeStamp:
Duration
(
milliseconds:
2
),
),
ui
.
PointerData
(
change:
ui
.
PointerChange
.
move
,
physicalX:
20.0
,
timeStamp:
Duration
(
milliseconds:
3
),
),
ui
.
PointerData
(
change:
ui
.
PointerChange
.
move
,
physicalX:
30.0
,
timeStamp:
Duration
(
milliseconds:
4
),
),
ui
.
PointerData
(
change:
ui
.
PointerChange
.
up
,
physicalX:
40.0
,
timeStamp:
Duration
(
milliseconds:
5
),
),
ui
.
PointerData
(
change:
ui
.
PointerChange
.
remove
,
physicalX:
40.0
,
timeStamp:
Duration
(
milliseconds:
6
),
),
],
);
final
List
<
PointerEvent
>
pointerRouterEvents
=
<
PointerEvent
>[];
GestureBinding
.
instance
.
pointerRouter
.
addGlobalRoute
(
pointerRouterEvents
.
add
);
final
List
<
PointerEvent
>
events
=
<
PointerEvent
>[];
_binding
.
callback
=
events
.
add
;
GestureBinding
.
instance
.
resamplingEnabled
=
true
;
GestureBinding
.
instance
.
samplingOffset
=
const
Duration
(
microseconds:
-
5500
);
ui
.
window
.
onPointerDataPacket
(
packet
);
// No pointer events should have been dispatched yet.
expect
(
events
.
length
,
0
);
// Frame callback should have been requested.
FrameCallback
callback
=
_binding
.
frameCallback
;
_binding
.
frameCallback
=
null
;
expect
(
callback
,
isNotNull
);
_binding
.
frameTime
=
const
Duration
(
milliseconds:
7
);
callback
(
Duration
.
zero
);
// One pointer event should have been dispatched.
expect
(
events
.
length
,
1
);
expect
(
events
[
0
].
runtimeType
,
equals
(
PointerDownEvent
));
expect
(
events
[
0
].
timeStamp
,
_binding
.
frameTime
+
GestureBinding
.
instance
.
samplingOffset
);
expect
(
events
[
0
].
position
,
Offset
(
5.0
/
ui
.
window
.
devicePixelRatio
,
0.0
));
// Second frame callback should have been requested.
callback
=
_binding
.
frameCallback
;
_binding
.
frameCallback
=
null
;
expect
(
callback
,
isNotNull
);
_binding
.
frameTime
=
const
Duration
(
milliseconds:
9
);
callback
(
Duration
.
zero
);
// Second pointer event should have been dispatched.
expect
(
events
.
length
,
2
);
expect
(
events
[
1
].
timeStamp
,
_binding
.
frameTime
+
GestureBinding
.
instance
.
samplingOffset
);
expect
(
events
[
1
].
runtimeType
,
equals
(
PointerMoveEvent
));
expect
(
events
[
1
].
position
,
Offset
(
25.0
/
ui
.
window
.
devicePixelRatio
,
0.0
));
expect
(
events
[
1
].
delta
,
Offset
(
20.0
/
ui
.
window
.
devicePixelRatio
,
0.0
));
// Third frame callback should have been requested.
callback
=
_binding
.
frameCallback
;
_binding
.
frameCallback
=
null
;
expect
(
callback
,
isNotNull
);
_binding
.
frameTime
=
const
Duration
(
milliseconds:
11
);
callback
(
Duration
.
zero
);
// Third pointer event should have been dispatched.
expect
(
events
.
length
,
3
);
expect
(
events
[
2
].
timeStamp
,
_binding
.
frameTime
+
GestureBinding
.
instance
.
samplingOffset
);
expect
(
events
[
2
].
runtimeType
,
equals
(
PointerUpEvent
));
expect
(
events
[
2
].
position
,
Offset
(
40.0
/
ui
.
window
.
devicePixelRatio
,
0.0
));
// No frame callback should have been requested.
callback
=
_binding
.
frameCallback
;
expect
(
callback
,
isNull
);
});
}
}
packages/flutter/test/gestures/resampler_test.dart
0 → 100644
View file @
02612bfe
// 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.
// @dart = 2.8
import
'dart:ui'
;
import
'package:flutter/gestures.dart'
;
import
'../flutter_test_alternative.dart'
;
void
main
(
)
{
PointerEvent
_createSimulatedPointerAddedEvent
(
int
timeStampUs
,
double
x
,
double
y
,
)
{
return
PointerAddedEvent
(
timeStamp:
Duration
(
microseconds:
timeStampUs
),
position:
Offset
(
x
,
y
),
);
}
PointerEvent
_createSimulatedPointerRemovedEvent
(
int
timeStampUs
,
double
x
,
double
y
,
)
{
return
PointerRemovedEvent
(
timeStamp:
Duration
(
microseconds:
timeStampUs
),
position:
Offset
(
x
,
y
),
);
}
PointerEvent
_createSimulatedPointerDownEvent
(
int
timeStampUs
,
double
x
,
double
y
,
)
{
return
PointerDownEvent
(
timeStamp:
Duration
(
microseconds:
timeStampUs
),
position:
Offset
(
x
,
y
),
);
}
PointerEvent
_createSimulatedPointerMoveEvent
(
int
timeStampUs
,
double
x
,
double
y
,
double
deltaX
,
double
deltaY
,
)
{
return
PointerMoveEvent
(
timeStamp:
Duration
(
microseconds:
timeStampUs
),
position:
Offset
(
x
,
y
),
delta:
Offset
(
deltaX
,
deltaY
),
);
}
PointerEvent
_createSimulatedPointerUpEvent
(
int
timeStampUs
,
double
x
,
double
y
,
)
{
return
PointerUpEvent
(
timeStamp:
Duration
(
microseconds:
timeStampUs
),
position:
Offset
(
x
,
y
),
);
}
test
(
'basic'
,
()
{
final
PointerEventResampler
resampler
=
PointerEventResampler
();
final
PointerEvent
event0
=
_createSimulatedPointerAddedEvent
(
1000
,
0.0
,
50.0
);
final
PointerEvent
event1
=
_createSimulatedPointerDownEvent
(
2000
,
10.0
,
40.0
);
final
PointerEvent
event2
=
_createSimulatedPointerMoveEvent
(
3000
,
20.0
,
30.0
,
10.0
,
-
10.0
);
final
PointerEvent
event3
=
_createSimulatedPointerMoveEvent
(
4000
,
30.0
,
20.0
,
10.0
,
-
10.0
);
final
PointerEvent
event4
=
_createSimulatedPointerUpEvent
(
5000
,
40.0
,
10.0
);
final
PointerEvent
event5
=
_createSimulatedPointerRemovedEvent
(
6000
,
50.0
,
0.0
);
resampler
..
addEvent
(
event0
)
..
addEvent
(
event1
)
..
addEvent
(
event2
)
..
addEvent
(
event3
)
..
addEvent
(
event4
)
..
addEvent
(
event5
);
final
List
<
PointerEvent
>
result
=
<
PointerEvent
>[];
resampler
.
sample
(
const
Duration
(
microseconds:
500
),
result
.
add
);
// No pointer event should have been returned yet.
expect
(
result
.
isEmpty
,
true
);
resampler
.
sample
(
const
Duration
(
microseconds:
1500
),
result
.
add
);
// Add pointer event should have been returned.
expect
(
result
.
length
,
1
);
expect
(
result
[
0
].
timeStamp
,
const
Duration
(
microseconds:
1500
));
expect
(
result
[
0
]
is
PointerAddedEvent
,
true
);
expect
(
result
[
0
].
position
.
dx
,
5.0
);
expect
(
result
[
0
].
position
.
dy
,
45.0
);
resampler
.
sample
(
const
Duration
(
microseconds:
2500
),
result
.
add
);
// Down pointer event should have been returned.
expect
(
result
.
length
,
2
);
expect
(
result
[
1
].
timeStamp
,
const
Duration
(
microseconds:
2500
));
expect
(
result
[
1
]
is
PointerDownEvent
,
true
);
expect
(
result
[
1
].
position
.
dx
,
15.0
);
expect
(
result
[
1
].
position
.
dy
,
35.0
);
resampler
.
sample
(
const
Duration
(
microseconds:
3500
),
result
.
add
);
// Move pointer event should have been returned.
expect
(
result
.
length
,
3
);
expect
(
result
[
2
].
timeStamp
,
const
Duration
(
microseconds:
3500
));
expect
(
result
[
2
]
is
PointerMoveEvent
,
true
);
expect
(
result
[
2
].
position
.
dx
,
25.0
);
expect
(
result
[
2
].
position
.
dy
,
25.0
);
expect
(
result
[
2
].
delta
.
dx
,
10.0
);
expect
(
result
[
2
].
delta
.
dy
,
-
10.0
);
resampler
.
sample
(
const
Duration
(
microseconds:
4500
),
result
.
add
);
// Up pointer event should have been returned.
expect
(
result
.
length
,
4
);
expect
(
result
[
3
].
timeStamp
,
const
Duration
(
microseconds:
4500
));
expect
(
result
[
3
]
is
PointerUpEvent
,
true
);
expect
(
result
[
3
].
position
.
dx
,
35.0
);
expect
(
result
[
3
].
position
.
dy
,
15.0
);
resampler
.
sample
(
const
Duration
(
microseconds:
5500
),
result
.
add
);
// Remove pointer event should have been returned.
expect
(
result
.
length
,
5
);
expect
(
result
[
4
].
timeStamp
,
const
Duration
(
microseconds:
5500
));
expect
(
result
[
4
]
is
PointerRemovedEvent
,
true
);
expect
(
result
[
4
].
position
.
dx
,
45.0
);
expect
(
result
[
4
].
position
.
dy
,
5.0
);
resampler
.
sample
(
const
Duration
(
microseconds:
6500
),
result
.
add
);
// No pointer event should have been returned.
expect
(
result
.
length
,
5
);
});
test
(
'stream'
,
()
{
final
PointerEventResampler
resampler
=
PointerEventResampler
();
final
PointerEvent
event0
=
_createSimulatedPointerAddedEvent
(
1000
,
0.0
,
50.0
);
final
PointerEvent
event1
=
_createSimulatedPointerDownEvent
(
2000
,
10.0
,
40.0
);
final
PointerEvent
event2
=
_createSimulatedPointerMoveEvent
(
3000
,
20.0
,
30.0
,
10.0
,
-
10.0
);
final
PointerEvent
event3
=
_createSimulatedPointerMoveEvent
(
4000
,
30.0
,
20.0
,
10.0
,
-
10.0
);
final
PointerEvent
event4
=
_createSimulatedPointerUpEvent
(
5000
,
40.0
,
10.0
);
final
PointerEvent
event5
=
_createSimulatedPointerRemovedEvent
(
6000
,
50.0
,
0.0
);
resampler
.
addEvent
(
event0
);
//
// Initial sample time a 0.5 ms.
//
final
List
<
PointerEvent
>
result
=
<
PointerEvent
>[];
resampler
.
sample
(
const
Duration
(
microseconds:
500
),
result
.
add
);
// No pointer event should have been returned yet.
expect
(
result
.
isEmpty
,
true
);
resampler
.
addEvent
(
event1
);
resampler
.
sample
(
const
Duration
(
microseconds:
500
),
result
.
add
);
// No pointer event should have been returned yet.
expect
(
result
.
isEmpty
,
true
);
//
// Advance sample time to 1.5 ms.
//
resampler
.
sample
(
const
Duration
(
microseconds:
1500
),
result
.
add
);
// Add pointer event should have been returned.
expect
(
result
.
length
,
1
);
expect
(
result
[
0
].
timeStamp
,
const
Duration
(
microseconds:
1500
));
expect
(
result
[
0
]
is
PointerAddedEvent
,
true
);
expect
(
result
[
0
].
position
.
dx
,
5.0
);
expect
(
result
[
0
].
position
.
dy
,
45.0
);
resampler
.
addEvent
(
event2
);
resampler
.
sample
(
const
Duration
(
microseconds:
1500
),
result
.
add
);
// No more pointer events should have been returned.
expect
(
result
.
length
,
1
);
//
// Advance sample time to 2.5 ms.
//
resampler
.
sample
(
const
Duration
(
microseconds:
2500
),
result
.
add
);
// Down pointer event should have been returned.
expect
(
result
.
length
,
2
);
expect
(
result
[
1
].
timeStamp
,
const
Duration
(
microseconds:
2500
));
expect
(
result
[
1
]
is
PointerDownEvent
,
true
);
expect
(
result
[
1
].
position
.
dx
,
15.0
);
expect
(
result
[
1
].
position
.
dy
,
35.0
);
resampler
.
addEvent
(
event3
);
resampler
.
sample
(
const
Duration
(
microseconds:
2500
),
result
.
add
);
// No more pointer events should have been returned.
expect
(
result
.
length
,
2
);
//
// Advance sample time to 3.5 ms.
//
resampler
.
sample
(
const
Duration
(
microseconds:
3500
),
result
.
add
);
// Move pointer event should have been returned.
expect
(
result
.
length
,
3
);
expect
(
result
[
2
].
timeStamp
,
const
Duration
(
microseconds:
3500
));
expect
(
result
[
2
]
is
PointerMoveEvent
,
true
);
expect
(
result
[
2
].
position
.
dx
,
25.0
);
expect
(
result
[
2
].
position
.
dy
,
25.0
);
expect
(
result
[
2
].
delta
.
dx
,
10.0
);
expect
(
result
[
2
].
delta
.
dy
,
-
10.0
);
resampler
.
addEvent
(
event4
);
resampler
.
sample
(
const
Duration
(
microseconds:
3500
),
result
.
add
);
// No more pointer events should have been returned.
expect
(
result
.
length
,
3
);
//
// Advance sample time to 4.5 ms.
//
resampler
.
sample
(
const
Duration
(
microseconds:
4500
),
result
.
add
);
// Up pointer event should have been returned.
expect
(
result
.
length
,
4
);
expect
(
result
[
3
].
timeStamp
,
const
Duration
(
microseconds:
4500
));
expect
(
result
[
3
]
is
PointerUpEvent
,
true
);
expect
(
result
[
3
].
position
.
dx
,
35.0
);
expect
(
result
[
3
].
position
.
dy
,
15.0
);
resampler
.
addEvent
(
event5
);
resampler
.
sample
(
const
Duration
(
microseconds:
4500
),
result
.
add
);
// No more pointer events should have been returned.
expect
(
result
.
length
,
4
);
//
// Advance sample time to 5.5 ms.
//
resampler
.
sample
(
const
Duration
(
microseconds:
5500
),
result
.
add
);
// Remove pointer event should have been returned.
expect
(
result
.
length
,
5
);
expect
(
result
[
4
].
timeStamp
,
const
Duration
(
microseconds:
5500
));
expect
(
result
[
4
]
is
PointerRemovedEvent
,
true
);
expect
(
result
[
4
].
position
.
dx
,
45.0
);
expect
(
result
[
4
].
position
.
dy
,
5.0
);
//
// Advance sample time to 6.5 ms.
//
resampler
.
sample
(
const
Duration
(
microseconds:
6500
),
result
.
add
);
// No pointer events should have been returned.
expect
(
result
.
length
,
5
);
});
test
(
'quick tap'
,
()
{
final
PointerEventResampler
resampler
=
PointerEventResampler
();
final
PointerEvent
event0
=
_createSimulatedPointerAddedEvent
(
1000
,
0.0
,
0.0
);
final
PointerEvent
event1
=
_createSimulatedPointerDownEvent
(
1000
,
0.0
,
0.0
);
final
PointerEvent
event2
=
_createSimulatedPointerUpEvent
(
1000
,
0.0
,
0.0
);
final
PointerEvent
event3
=
_createSimulatedPointerRemovedEvent
(
1000
,
0.0
,
0.0
);
resampler
..
addEvent
(
event0
)
..
addEvent
(
event1
)
..
addEvent
(
event2
)
..
addEvent
(
event3
);
final
List
<
PointerEvent
>
result
=
<
PointerEvent
>[];
resampler
.
sample
(
const
Duration
(
microseconds:
1500
),
result
.
add
);
// All pointer events should have been returned.
expect
(
result
.
length
,
4
);
expect
(
result
[
0
].
timeStamp
,
const
Duration
(
microseconds:
1500
));
expect
(
result
[
0
]
is
PointerAddedEvent
,
true
);
expect
(
result
[
0
].
position
.
dx
,
0.0
);
expect
(
result
[
0
].
position
.
dy
,
0.0
);
expect
(
result
[
1
].
timeStamp
,
const
Duration
(
microseconds:
1500
));
expect
(
result
[
1
]
is
PointerDownEvent
,
true
);
expect
(
result
[
1
].
position
.
dx
,
0.0
);
expect
(
result
[
1
].
position
.
dy
,
0.0
);
expect
(
result
[
2
].
timeStamp
,
const
Duration
(
microseconds:
1500
));
expect
(
result
[
2
]
is
PointerUpEvent
,
true
);
expect
(
result
[
2
].
position
.
dx
,
0.0
);
expect
(
result
[
2
].
position
.
dy
,
0.0
);
expect
(
result
[
3
].
timeStamp
,
const
Duration
(
microseconds:
1500
));
expect
(
result
[
3
]
is
PointerRemovedEvent
,
true
);
expect
(
result
[
3
].
position
.
dx
,
0.0
);
expect
(
result
[
3
].
position
.
dy
,
0.0
);
});
test
(
'advance slowly'
,
()
{
final
PointerEventResampler
resampler
=
PointerEventResampler
();
final
PointerEvent
event0
=
_createSimulatedPointerAddedEvent
(
1000
,
0.0
,
0.0
);
final
PointerEvent
event1
=
_createSimulatedPointerDownEvent
(
1000
,
0.0
,
0.0
);
final
PointerEvent
event2
=
_createSimulatedPointerMoveEvent
(
2000
,
10.0
,
0.0
,
10.0
,
0.0
);
final
PointerEvent
event3
=
_createSimulatedPointerUpEvent
(
3000
,
20.0
,
0.0
);
final
PointerEvent
event4
=
_createSimulatedPointerRemovedEvent
(
3000
,
20.0
,
0.0
);
resampler
..
addEvent
(
event0
)
..
addEvent
(
event1
)
..
addEvent
(
event2
)
..
addEvent
(
event3
)
..
addEvent
(
event4
);
final
List
<
PointerEvent
>
result
=
<
PointerEvent
>[];
resampler
.
sample
(
const
Duration
(
microseconds:
1500
),
result
.
add
);
// Added and down pointer events should have been returned.
expect
(
result
.
length
,
2
);
expect
(
result
[
0
].
timeStamp
,
const
Duration
(
microseconds:
1500
));
expect
(
result
[
0
]
is
PointerAddedEvent
,
true
);
expect
(
result
[
0
].
position
.
dx
,
5.0
);
expect
(
result
[
0
].
position
.
dy
,
0.0
);
expect
(
result
[
1
].
timeStamp
,
const
Duration
(
microseconds:
1500
));
expect
(
result
[
1
]
is
PointerDownEvent
,
true
);
expect
(
result
[
1
].
position
.
dx
,
5.0
);
expect
(
result
[
1
].
position
.
dy
,
0.0
);
resampler
.
sample
(
const
Duration
(
microseconds:
1500
),
result
.
add
);
// No pointer events should have been returned.
expect
(
result
.
length
,
2
);
resampler
.
sample
(
const
Duration
(
microseconds:
1750
),
result
.
add
);
// Move pointer event should have been returned.
expect
(
result
.
length
,
3
);
expect
(
result
[
2
].
timeStamp
,
const
Duration
(
microseconds:
1750
));
expect
(
result
[
2
]
is
PointerMoveEvent
,
true
);
expect
(
result
[
2
].
position
.
dx
,
7.5
);
expect
(
result
[
2
].
position
.
dy
,
0.0
);
expect
(
result
[
2
].
delta
.
dx
,
2.5
);
expect
(
result
[
2
].
delta
.
dy
,
0.0
);
resampler
.
sample
(
const
Duration
(
microseconds:
2000
),
result
.
add
);
// Another move pointer event should have been returned.
expect
(
result
.
length
,
4
);
expect
(
result
[
3
].
timeStamp
,
const
Duration
(
microseconds:
2000
));
expect
(
result
[
3
]
is
PointerMoveEvent
,
true
);
expect
(
result
[
3
].
position
.
dx
,
10.0
);
expect
(
result
[
3
].
position
.
dy
,
0.0
);
expect
(
result
[
3
].
delta
.
dx
,
2.5
);
expect
(
result
[
3
].
delta
.
dy
,
0.0
);
resampler
.
sample
(
const
Duration
(
microseconds:
2500
),
result
.
add
);
// Last two pointer events should have been returned.
expect
(
result
.
length
,
6
);
expect
(
result
[
4
].
timeStamp
,
const
Duration
(
microseconds:
2500
));
expect
(
result
[
4
]
is
PointerUpEvent
,
true
);
expect
(
result
[
4
].
position
.
dx
,
15.0
);
expect
(
result
[
4
].
position
.
dy
,
0.0
);
expect
(
result
[
5
].
timeStamp
,
const
Duration
(
microseconds:
2500
));
expect
(
result
[
5
]
is
PointerRemovedEvent
,
true
);
expect
(
result
[
5
].
position
.
dx
,
15.0
);
expect
(
result
[
5
].
position
.
dy
,
0.0
);
});
test
(
'advance fast'
,
()
{
final
PointerEventResampler
resampler
=
PointerEventResampler
();
final
PointerEvent
event0
=
_createSimulatedPointerAddedEvent
(
1000
,
0.0
,
0.0
);
final
PointerEvent
event1
=
_createSimulatedPointerDownEvent
(
1000
,
0.0
,
0.0
);
final
PointerEvent
event2
=
_createSimulatedPointerMoveEvent
(
2000
,
5.0
,
0.0
,
5.0
,
0.0
);
final
PointerEvent
event3
=
_createSimulatedPointerMoveEvent
(
3000
,
20.0
,
0.0
,
15.0
,
0.0
);
final
PointerEvent
event4
=
_createSimulatedPointerUpEvent
(
4000
,
30.0
,
0.0
);
final
PointerEvent
event5
=
_createSimulatedPointerRemovedEvent
(
4000
,
30.0
,
0.0
);
resampler
..
addEvent
(
event0
)
..
addEvent
(
event1
)
..
addEvent
(
event2
)
..
addEvent
(
event3
)
..
addEvent
(
event4
)
..
addEvent
(
event5
);
final
List
<
PointerEvent
>
result
=
<
PointerEvent
>[];
resampler
.
sample
(
const
Duration
(
microseconds:
2500
),
result
.
add
);
// Add and down pointer events should have been returned.
expect
(
result
.
length
,
2
);
expect
(
result
[
0
].
timeStamp
,
const
Duration
(
microseconds:
2500
));
expect
(
result
[
0
]
is
PointerAddedEvent
,
true
);
expect
(
result
[
0
].
position
.
dx
,
12.5
);
expect
(
result
[
0
].
position
.
dy
,
0.0
);
expect
(
result
[
1
].
timeStamp
,
const
Duration
(
microseconds:
2500
));
expect
(
result
[
1
]
is
PointerDownEvent
,
true
);
expect
(
result
[
1
].
position
.
dx
,
12.5
);
expect
(
result
[
1
].
position
.
dy
,
0.0
);
resampler
.
sample
(
const
Duration
(
microseconds:
5500
),
result
.
add
);
// Up and removed pointer events should have been returned.
expect
(
result
.
length
,
4
);
expect
(
result
[
2
].
timeStamp
,
const
Duration
(
microseconds:
5500
));
expect
(
result
[
2
]
is
PointerUpEvent
,
true
);
expect
(
result
[
2
].
position
.
dx
,
30.0
);
expect
(
result
[
2
].
position
.
dy
,
0.0
);
expect
(
result
[
3
].
timeStamp
,
const
Duration
(
microseconds:
5500
));
expect
(
result
[
3
]
is
PointerRemovedEvent
,
true
);
expect
(
result
[
3
].
position
.
dx
,
30.0
);
expect
(
result
[
3
].
position
.
dy
,
0.0
);
resampler
.
sample
(
const
Duration
(
microseconds:
6500
),
result
.
add
);
// No pointer events should have been returned.
expect
(
result
.
length
,
4
);
});
test
(
'skip'
,
()
{
final
PointerEventResampler
resampler
=
PointerEventResampler
();
final
PointerEvent
event0
=
_createSimulatedPointerAddedEvent
(
1000
,
0.0
,
0.0
);
final
PointerEvent
event1
=
_createSimulatedPointerDownEvent
(
1000
,
0.0
,
0.0
);
final
PointerEvent
event2
=
_createSimulatedPointerMoveEvent
(
2000
,
10.0
,
0.0
,
10.0
,
0.0
);
final
PointerEvent
event3
=
_createSimulatedPointerUpEvent
(
3000
,
10.0
,
0.0
);
final
PointerEvent
event4
=
_createSimulatedPointerDownEvent
(
4000
,
20.0
,
0.0
);
final
PointerEvent
event5
=
_createSimulatedPointerUpEvent
(
5000
,
30.0
,
0.0
);
final
PointerEvent
event6
=
_createSimulatedPointerRemovedEvent
(
5000
,
30.0
,
0.0
);
resampler
..
addEvent
(
event0
)
..
addEvent
(
event1
)
..
addEvent
(
event2
)
..
addEvent
(
event3
)
..
addEvent
(
event4
)
..
addEvent
(
event5
)
..
addEvent
(
event6
);
final
List
<
PointerEvent
>
result
=
<
PointerEvent
>[];
resampler
.
sample
(
const
Duration
(
microseconds:
1500
),
result
.
add
);
// Added and down pointer events should have been returned.
expect
(
result
.
length
,
2
);
expect
(
result
[
0
].
timeStamp
,
const
Duration
(
microseconds:
1500
));
expect
(
result
[
0
]
is
PointerAddedEvent
,
true
);
expect
(
result
[
0
].
position
.
dx
,
5.0
);
expect
(
result
[
0
].
position
.
dy
,
0.0
);
expect
(
result
[
1
].
timeStamp
,
const
Duration
(
microseconds:
1500
));
expect
(
result
[
1
]
is
PointerDownEvent
,
true
);
expect
(
result
[
1
].
position
.
dx
,
5.0
);
expect
(
result
[
1
].
position
.
dy
,
0.0
);
resampler
.
sample
(
const
Duration
(
microseconds:
4500
),
result
.
add
);
// All remaining pointer events should have been returned.
expect
(
result
.
length
,
6
);
expect
(
result
[
2
].
timeStamp
,
const
Duration
(
microseconds:
4500
));
expect
(
result
[
2
]
is
PointerUpEvent
,
true
);
expect
(
result
[
2
].
position
.
dx
,
25.0
);
expect
(
result
[
2
].
position
.
dy
,
0.0
);
expect
(
result
[
3
].
timeStamp
,
const
Duration
(
microseconds:
4500
));
expect
(
result
[
3
]
is
PointerDownEvent
,
true
);
expect
(
result
[
3
].
position
.
dx
,
25.0
);
expect
(
result
[
3
].
position
.
dy
,
0.0
);
expect
(
result
[
4
].
timeStamp
,
const
Duration
(
microseconds:
4500
));
expect
(
result
[
4
]
is
PointerUpEvent
,
true
);
expect
(
result
[
4
].
position
.
dx
,
25.0
);
expect
(
result
[
4
].
position
.
dy
,
0.0
);
expect
(
result
[
5
].
timeStamp
,
const
Duration
(
microseconds:
4500
));
expect
(
result
[
5
]
is
PointerRemovedEvent
,
true
);
expect
(
result
[
5
].
position
.
dx
,
25.0
);
expect
(
result
[
5
].
position
.
dy
,
0.0
);
resampler
.
sample
(
const
Duration
(
microseconds:
5500
),
result
.
add
);
// No pointer events should have been returned.
expect
(
result
.
length
,
6
);
});
test
(
'skip all'
,
()
{
final
PointerEventResampler
resampler
=
PointerEventResampler
();
final
PointerEvent
event0
=
_createSimulatedPointerAddedEvent
(
1000
,
0.0
,
0.0
);
final
PointerEvent
event1
=
_createSimulatedPointerDownEvent
(
1000
,
0.0
,
0.0
);
final
PointerEvent
event2
=
_createSimulatedPointerUpEvent
(
4000
,
30.0
,
0.0
);
final
PointerEvent
event3
=
_createSimulatedPointerRemovedEvent
(
4000
,
30.0
,
0.0
);
resampler
..
addEvent
(
event0
)
..
addEvent
(
event1
)
..
addEvent
(
event2
)
..
addEvent
(
event3
);
final
List
<
PointerEvent
>
result
=
<
PointerEvent
>[];
resampler
.
sample
(
const
Duration
(
microseconds:
500
),
result
.
add
);
// No pointer events should have been returned.
expect
(
result
.
isEmpty
,
true
);
resampler
.
sample
(
const
Duration
(
microseconds:
5500
),
result
.
add
);
// All remaining pointer events should have been returned.
expect
(
result
.
length
,
4
);
expect
(
result
[
0
].
timeStamp
,
const
Duration
(
microseconds:
5500
));
expect
(
result
[
0
]
is
PointerAddedEvent
,
true
);
expect
(
result
[
0
].
position
.
dx
,
30.0
);
expect
(
result
[
0
].
position
.
dy
,
0.0
);
expect
(
result
[
1
].
timeStamp
,
const
Duration
(
microseconds:
5500
));
expect
(
result
[
1
]
is
PointerDownEvent
,
true
);
expect
(
result
[
1
].
position
.
dx
,
30.0
);
expect
(
result
[
1
].
position
.
dy
,
0.0
);
expect
(
result
[
2
].
timeStamp
,
const
Duration
(
microseconds:
5500
));
expect
(
result
[
2
]
is
PointerUpEvent
,
true
);
expect
(
result
[
2
].
position
.
dx
,
30.0
);
expect
(
result
[
2
].
position
.
dy
,
0.0
);
expect
(
result
[
3
].
timeStamp
,
const
Duration
(
microseconds:
5500
));
expect
(
result
[
3
]
is
PointerRemovedEvent
,
true
);
expect
(
result
[
3
].
position
.
dx
,
30.0
);
expect
(
result
[
3
].
position
.
dy
,
0.0
);
resampler
.
sample
(
const
Duration
(
microseconds:
6500
),
result
.
add
);
// No pointer events should have been returned.
expect
(
result
.
length
,
4
);
});
test
(
'stop'
,
()
{
final
PointerEventResampler
resampler
=
PointerEventResampler
();
final
PointerEvent
event0
=
_createSimulatedPointerAddedEvent
(
1000
,
0.0
,
0.0
);
final
PointerEvent
event1
=
_createSimulatedPointerDownEvent
(
2000
,
0.0
,
0.0
);
final
PointerEvent
event2
=
_createSimulatedPointerMoveEvent
(
3000
,
10.0
,
0.0
,
10.0
,
0.0
);
final
PointerEvent
event3
=
_createSimulatedPointerUpEvent
(
4000
,
20.0
,
0.0
);
final
PointerEvent
event4
=
_createSimulatedPointerRemovedEvent
(
5000
,
20.0
,
0.0
);
resampler
..
addEvent
(
event0
)
..
addEvent
(
event1
)
..
addEvent
(
event2
)
..
addEvent
(
event3
)
..
addEvent
(
event4
);
final
List
<
PointerEvent
>
result
=
<
PointerEvent
>[];
resampler
.
sample
(
const
Duration
(
microseconds:
500
),
result
.
add
);
// No pointer events should have been returned.
expect
(
result
.
isEmpty
,
true
);
resampler
.
stop
(
result
.
add
);
// All pointer events should have been returned with orignal
// time stamps and positions.
expect
(
result
.
length
,
5
);
expect
(
result
[
0
].
timeStamp
,
const
Duration
(
microseconds:
1000
));
expect
(
result
[
0
]
is
PointerAddedEvent
,
true
);
expect
(
result
[
0
].
position
.
dx
,
0.0
);
expect
(
result
[
0
].
position
.
dy
,
0.0
);
expect
(
result
[
1
].
timeStamp
,
const
Duration
(
microseconds:
2000
));
expect
(
result
[
1
]
is
PointerDownEvent
,
true
);
expect
(
result
[
1
].
position
.
dx
,
0.0
);
expect
(
result
[
1
].
position
.
dy
,
0.0
);
expect
(
result
[
2
].
timeStamp
,
const
Duration
(
microseconds:
3000
));
expect
(
result
[
2
]
is
PointerMoveEvent
,
true
);
expect
(
result
[
2
].
position
.
dx
,
10.0
);
expect
(
result
[
2
].
position
.
dy
,
0.0
);
expect
(
result
[
2
].
delta
.
dx
,
10.0
);
expect
(
result
[
2
].
delta
.
dy
,
0.0
);
expect
(
result
[
3
].
timeStamp
,
const
Duration
(
microseconds:
4000
));
expect
(
result
[
3
]
is
PointerUpEvent
,
true
);
expect
(
result
[
3
].
position
.
dx
,
20.0
);
expect
(
result
[
3
].
position
.
dy
,
0.0
);
expect
(
result
[
4
].
timeStamp
,
const
Duration
(
microseconds:
5000
));
expect
(
result
[
4
]
is
PointerRemovedEvent
,
true
);
expect
(
result
[
4
].
position
.
dx
,
20.0
);
expect
(
result
[
4
].
position
.
dy
,
0.0
);
resampler
.
sample
(
const
Duration
(
microseconds:
10000
),
result
.
add
);
// No pointer events should have been returned.
expect
(
result
.
length
,
5
);
});
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment