@@ -30,6 +30,7 @@ import io.sentry.transport.ICurrentDateProvider
3030import io.sentry.util.FileUtils
3131import java.io.File
3232import java.util.Date
33+ import java.util.concurrent.CopyOnWriteArrayList
3334import java.util.concurrent.Executors
3435import java.util.concurrent.ScheduledExecutorService
3536import java.util.concurrent.ThreadFactory
@@ -48,7 +49,6 @@ internal abstract class BaseCaptureStrategy(
4849
4950 internal companion object {
5051 private const val TAG = " CaptureStrategy"
51- private const val DEBOUNCE_TIMEOUT = 200
5252 private val snakecasePattern = " _[a-z]" .toRegex()
5353 private val supportedNetworkData = setOf (
5454 " status_code" ,
@@ -58,6 +58,9 @@ internal abstract class BaseCaptureStrategy(
5858 " http.response_content_length" ,
5959 " http.request_content_length"
6060 )
61+ // rrweb values
62+ private const val TOUCH_MOVE_DEBOUNCE_THRESHOLD = 50
63+ private const val CAPTURE_MOVE_EVENT_THRESHOLD = 500
6164 }
6265
6366 protected var cache: ReplayCache ? = null
@@ -66,8 +69,11 @@ internal abstract class BaseCaptureStrategy(
6669 override val currentReplayId = AtomicReference (SentryId .EMPTY_ID )
6770 override val currentSegment = AtomicInteger (0 )
6871 override val replayCacheDir: File ? get() = cache?.replayCacheDir
69- private val currentEvents = mutableListOf<RRWebEvent >()
70- private val lastExecutionTime = AtomicLong (0 )
72+
73+ private val currentEvents = CopyOnWriteArrayList <RRWebEvent >()
74+ private val currentPositions = mutableListOf<Position >()
75+ private var touchMoveBaseline = 0L
76+ private var lastCapturedMoveEvent = 0L
7177
7278 protected val replayExecutor: ScheduledExecutorService by lazy {
7379 executor ? : Executors .newSingleThreadScheduledExecutor(ReplayExecutorServiceThreadFactory ())
@@ -281,6 +287,7 @@ internal abstract class BaseCaptureStrategy(
281287 }
282288
283289 override fun onTouchEvent (event : MotionEvent ) {
290+ // TODO: rotate in buffer mode
284291 val rrwebEvent = event.toRRWebIncrementalSnapshotEvent()
285292 if (rrwebEvent != null ) {
286293 currentEvents + = rrwebEvent
@@ -363,30 +370,47 @@ internal abstract class BaseCaptureStrategy(
363370 return when (val action = event.actionMasked) {
364371 MotionEvent .ACTION_MOVE -> {
365372 // we only throttle move events as those can be overwhelming
366- val now = dateProvider.getCurrentTimeMillis()
367- if (lastExecutionTime.get() != 0L && lastExecutionTime.get() + DEBOUNCE_TIMEOUT > now) {
373+ val now = dateProvider.currentTimeMillis
374+ if (lastCapturedMoveEvent != 0L && lastCapturedMoveEvent + TOUCH_MOVE_DEBOUNCE_THRESHOLD > now) {
368375 return null
369376 }
370- lastExecutionTime.set( now)
377+ lastCapturedMoveEvent = now
371378
372- RRWebInteractionMoveEvent ().apply {
373- timestamp = dateProvider.currentTimeMillis
374- positions = listOf (
375- Position ().apply {
376- x = event.x * recorderConfig.scaleFactorX
377- y = event.y * recorderConfig.scaleFactorY
378- id = event.getPointerId(event.actionIndex)
379- timeOffset = 0 // TODO: is this needed?
379+ // idk why but rrweb does it like dis
380+ if (touchMoveBaseline == 0L ) {
381+ touchMoveBaseline = now
382+ }
383+
384+ currentPositions + = Position ().apply {
385+ x = event.x * recorderConfig.scaleFactorX
386+ y = event.y * recorderConfig.scaleFactorY
387+ id = 0 // html node id, but we don't have it, so hardcode to 0 to align with FE
388+ timeOffset = now - touchMoveBaseline
389+ }
390+
391+ val totalOffset = now - touchMoveBaseline
392+ return if (totalOffset > CAPTURE_MOVE_EVENT_THRESHOLD ) {
393+ RRWebInteractionMoveEvent ().apply {
394+ timestamp = now
395+ positions = currentPositions.map { pos ->
396+ pos.timeOffset - = totalOffset
397+ pos
380398 }
381- ) // TODO: support multiple pointers
399+ }.also {
400+ currentPositions.clear()
401+ touchMoveBaseline = 0L
402+ }
403+ } else {
404+ null
382405 }
383406 }
407+
384408 MotionEvent .ACTION_DOWN , MotionEvent .ACTION_UP , MotionEvent .ACTION_CANCEL -> {
385409 RRWebInteractionEvent ().apply {
386410 timestamp = dateProvider.currentTimeMillis
387411 x = event.x * recorderConfig.scaleFactorX
388412 y = event.y * recorderConfig.scaleFactorY
389- id = event.getPointerId(event.actionIndex)
413+ id = 0 // html node id, but we don't have it, so hardcode to 0 to align with FE
390414 interactionType = when (action) {
391415 MotionEvent .ACTION_UP -> InteractionType .TouchEnd
392416 MotionEvent .ACTION_DOWN -> InteractionType .TouchStart
@@ -395,6 +419,7 @@ internal abstract class BaseCaptureStrategy(
395419 }
396420 }
397421 }
422+
398423 else -> null
399424 }
400425 }
0 commit comments