@@ -73,37 +73,50 @@ typedef FrameTimingCallback = void Function(
73
73
DateTime startTimestamp, DateTime endTimestamp);
74
74
75
75
mixin SentryWidgetsBindingMixin on WidgetsBinding {
76
- DateTime ? _startTimestamp;
77
- FrameTimingCallback ? _frameTimingCallback;
78
- ClockProvider ? _clock;
79
-
80
- SentryOptions get _options => Sentry .currentHub.options;
76
+ FrameTimingCallback ? _onDelayedFrame;
77
+ FrameTimingCallback ? get onDelayedFrame => _onDelayedFrame;
78
+ Duration ? _expectedFrameDuration;
79
+ Duration ? get expectedFrameDuration => _expectedFrameDuration;
80
+ bool _isTrackingActive = false ;
81
+ SentryOptions ? _options;
82
+ SentryOptions ? get options => _options;
83
+ final Stopwatch _stopwatch = Stopwatch ();
81
84
82
85
@internal
83
- void registerFramesTracking (
84
- FrameTimingCallback callback, ClockProvider clock) {
85
- _frameTimingCallback ?? = callback;
86
- _clock ?? = clock;
86
+ void initializeFramesTracking (FrameTimingCallback onDelayedFrame,
87
+ SentryOptions options, Duration expectedFrameDuration) {
88
+ _onDelayedFrame ?? = onDelayedFrame;
89
+ _options ?? = options;
90
+ _expectedFrameDuration ?? = expectedFrameDuration;
91
+ }
92
+
93
+ void resumeTrackingFrames () {
94
+ _isTrackingActive = true ;
87
95
}
88
96
89
- @visibleForTesting
90
- bool isFramesTrackingInitialized () {
91
- return _frameTimingCallback != null && _clock != null ;
97
+ void pauseTrackingFrames () {
98
+ // Stopwatch could continue running if we pause tracking in between a frame
99
+ _stopwatch.stop ();
100
+ _stopwatch.reset ();
101
+ _isTrackingActive = false ;
92
102
}
93
103
94
104
@internal
95
105
void removeFramesTracking () {
96
- _frameTimingCallback = null ;
97
- _clock = null ;
106
+ _onDelayedFrame = null ;
107
+ _expectedFrameDuration = null ;
108
+ _options = null ;
98
109
}
99
110
100
111
@override
101
112
void handleBeginFrame (Duration ? rawTimeStamp) {
102
- try {
103
- _startTimestamp = _clock? .call ();
104
- } catch (_) {
105
- if (_options.automatedTestMode) {
106
- rethrow ;
113
+ if (_isTrackingActive) {
114
+ try {
115
+ _stopwatch.start ();
116
+ } catch (_) {
117
+ if (_options? .automatedTestMode == true ) {
118
+ rethrow ;
119
+ }
107
120
}
108
121
}
109
122
@@ -114,15 +127,25 @@ mixin SentryWidgetsBindingMixin on WidgetsBinding {
114
127
void handleDrawFrame () {
115
128
super .handleDrawFrame ();
116
129
130
+ if (! _isTrackingActive) {
131
+ return ;
132
+ }
133
+ final expectedFrameDuration = _expectedFrameDuration;
134
+ final options = _options;
117
135
try {
118
- final endTimestamp = _clock? .call ();
119
- if (_startTimestamp != null &&
120
- endTimestamp != null &&
121
- _startTimestamp! .isBefore (endTimestamp)) {
122
- _frameTimingCallback? .call (_startTimestamp! , endTimestamp);
136
+ _stopwatch.stop ();
137
+ if (options != null &&
138
+ expectedFrameDuration != null &&
139
+ _stopwatch.elapsedMilliseconds >
140
+ expectedFrameDuration.inMilliseconds) {
141
+ final endTimestamp = options.clock ();
142
+ final startTimestamp = endTimestamp
143
+ .subtract (Duration (milliseconds: _stopwatch.elapsedMilliseconds));
144
+ _onDelayedFrame? .call (startTimestamp, endTimestamp);
123
145
}
146
+ _stopwatch.reset ();
124
147
} catch (_) {
125
- if (_options.automatedTestMode) {
148
+ if (_options? .automatedTestMode == true ) {
126
149
rethrow ;
127
150
}
128
151
}
0 commit comments