@@ -23,6 +23,7 @@ import io.sentry.android.replay.ScreenshotRecorderConfig
23
23
import io.sentry.android.replay.capture.CaptureStrategy.Companion.createSegment
24
24
import io.sentry.android.replay.capture.CaptureStrategy.Companion.currentEventsLock
25
25
import io.sentry.android.replay.capture.CaptureStrategy.ReplaySegment
26
+ import io.sentry.android.replay.gestures.ReplayGestureConverter
26
27
import io.sentry.android.replay.util.PersistableLinkedList
27
28
import io.sentry.android.replay.util.gracefullyShutdown
28
29
import io.sentry.android.replay.util.submitSafely
@@ -56,15 +57,12 @@ internal abstract class BaseCaptureStrategy(
56
57
57
58
internal companion object {
58
59
private const val TAG = " CaptureStrategy"
59
-
60
- // rrweb values
61
- private const val TOUCH_MOVE_DEBOUNCE_THRESHOLD = 50
62
- private const val CAPTURE_MOVE_EVENT_THRESHOLD = 500
63
60
}
64
61
65
62
private val persistingExecutor: ScheduledExecutorService by lazy {
66
63
Executors .newSingleThreadScheduledExecutor(ReplayPersistingExecutorServiceThreadFactory ())
67
64
}
65
+ private val gestureConverter = ReplayGestureConverter (dateProvider)
68
66
69
67
protected val isTerminating = AtomicBoolean (false )
70
68
protected var cache: ReplayCache ? = null
@@ -94,9 +92,6 @@ internal abstract class BaseCaptureStrategy(
94
92
persistingExecutor,
95
93
cacheProvider = { cache }
96
94
)
97
- private val currentPositions = LinkedHashMap <Int , ArrayList <Position >>(10 )
98
- private var touchMoveBaseline = 0L
99
- private var lastCapturedMoveEvent = 0L
100
95
101
96
protected val replayExecutor: ScheduledExecutorService by lazy {
102
97
executor ? : Executors .newSingleThreadScheduledExecutor(ReplayExecutorServiceThreadFactory ())
@@ -169,7 +164,7 @@ internal abstract class BaseCaptureStrategy(
169
164
}
170
165
171
166
override fun onTouchEvent (event : MotionEvent ) {
172
- val rrwebEvents = event.toRRWebIncrementalSnapshotEvent( )
167
+ val rrwebEvents = gestureConverter.convert(event, recorderConfig )
173
168
if (rrwebEvents != null ) {
174
169
synchronized(currentEventsLock) {
175
170
currentEvents + = rrwebEvents
@@ -199,126 +194,6 @@ internal abstract class BaseCaptureStrategy(
199
194
}
200
195
}
201
196
202
- private fun MotionEvent.toRRWebIncrementalSnapshotEvent (): List <RRWebIncrementalSnapshotEvent >? {
203
- val event = this
204
- return when (event.actionMasked) {
205
- MotionEvent .ACTION_MOVE -> {
206
- // we only throttle move events as those can be overwhelming
207
- val now = dateProvider.currentTimeMillis
208
- if (lastCapturedMoveEvent != 0L && lastCapturedMoveEvent + TOUCH_MOVE_DEBOUNCE_THRESHOLD > now) {
209
- return null
210
- }
211
- lastCapturedMoveEvent = now
212
-
213
- currentPositions.keys.forEach { pId ->
214
- val pIndex = event.findPointerIndex(pId)
215
-
216
- if (pIndex == - 1 ) {
217
- // no data for this pointer
218
- return @forEach
219
- }
220
-
221
- // idk why but rrweb does it like dis
222
- if (touchMoveBaseline == 0L ) {
223
- touchMoveBaseline = now
224
- }
225
-
226
- currentPositions[pId]!! + = Position ().apply {
227
- x = event.getX(pIndex) * recorderConfig.scaleFactorX
228
- y = event.getY(pIndex) * recorderConfig.scaleFactorY
229
- id = 0 // html node id, but we don't have it, so hardcode to 0 to align with FE
230
- timeOffset = now - touchMoveBaseline
231
- }
232
- }
233
-
234
- val totalOffset = now - touchMoveBaseline
235
- return if (totalOffset > CAPTURE_MOVE_EVENT_THRESHOLD ) {
236
- val moveEvents = mutableListOf<RRWebInteractionMoveEvent >()
237
- for ((pointerId, positions) in currentPositions) {
238
- if (positions.isNotEmpty()) {
239
- moveEvents + = RRWebInteractionMoveEvent ().apply {
240
- this .timestamp = now
241
- this .positions = positions.map { pos ->
242
- pos.timeOffset - = totalOffset
243
- pos
244
- }
245
- this .pointerId = pointerId
246
- }
247
- currentPositions[pointerId]!! .clear()
248
- }
249
- }
250
- touchMoveBaseline = 0L
251
- moveEvents
252
- } else {
253
- null
254
- }
255
- }
256
-
257
- MotionEvent .ACTION_DOWN ,
258
- MotionEvent .ACTION_POINTER_DOWN -> {
259
- val pId = event.getPointerId(event.actionIndex)
260
- val pIndex = event.findPointerIndex(pId)
261
-
262
- if (pIndex == - 1 ) {
263
- // no data for this pointer
264
- return null
265
- }
266
-
267
- // new finger down - add a new pointer for tracking movement
268
- currentPositions[pId] = ArrayList ()
269
- listOf (
270
- RRWebInteractionEvent ().apply {
271
- timestamp = dateProvider.currentTimeMillis
272
- x = event.getX(pIndex) * recorderConfig.scaleFactorX
273
- y = event.getY(pIndex) * recorderConfig.scaleFactorY
274
- id = 0 // html node id, but we don't have it, so hardcode to 0 to align with FE
275
- pointerId = pId
276
- interactionType = InteractionType .TouchStart
277
- }
278
- )
279
- }
280
- MotionEvent .ACTION_UP ,
281
- MotionEvent .ACTION_POINTER_UP -> {
282
- val pId = event.getPointerId(event.actionIndex)
283
- val pIndex = event.findPointerIndex(pId)
284
-
285
- if (pIndex == - 1 ) {
286
- // no data for this pointer
287
- return null
288
- }
289
-
290
- // finger lift up - remove the pointer from tracking
291
- currentPositions.remove(pId)
292
- listOf (
293
- RRWebInteractionEvent ().apply {
294
- timestamp = dateProvider.currentTimeMillis
295
- x = event.getX(pIndex) * recorderConfig.scaleFactorX
296
- y = event.getY(pIndex) * recorderConfig.scaleFactorY
297
- id = 0 // html node id, but we don't have it, so hardcode to 0 to align with FE
298
- pointerId = pId
299
- interactionType = InteractionType .TouchEnd
300
- }
301
- )
302
- }
303
- MotionEvent .ACTION_CANCEL -> {
304
- // gesture cancelled - remove all pointers from tracking
305
- currentPositions.clear()
306
- listOf (
307
- RRWebInteractionEvent ().apply {
308
- timestamp = dateProvider.currentTimeMillis
309
- x = event.x * recorderConfig.scaleFactorX
310
- y = event.y * recorderConfig.scaleFactorY
311
- id = 0 // html node id, but we don't have it, so hardcode to 0 to align with FE
312
- pointerId = 0 // the pointerId is not used for TouchCancel, so just set it to 0
313
- interactionType = InteractionType .TouchCancel
314
- }
315
- )
316
- }
317
-
318
- else -> null
319
- }
320
- }
321
-
322
197
private inline fun <T > persistableAtomicNullable (
323
198
initialValue : T ? = null,
324
199
propertyName : String ,
0 commit comments