@@ -23,6 +23,7 @@ import io.sentry.android.replay.ScreenshotRecorderConfig
2323import io.sentry.android.replay.capture.CaptureStrategy.Companion.createSegment
2424import io.sentry.android.replay.capture.CaptureStrategy.Companion.currentEventsLock
2525import io.sentry.android.replay.capture.CaptureStrategy.ReplaySegment
26+ import io.sentry.android.replay.gestures.ReplayGestureConverter
2627import io.sentry.android.replay.util.PersistableLinkedList
2728import io.sentry.android.replay.util.gracefullyShutdown
2829import io.sentry.android.replay.util.submitSafely
@@ -56,15 +57,12 @@ internal abstract class BaseCaptureStrategy(
5657
5758 internal companion object {
5859 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
6360 }
6461
6562 private val persistingExecutor: ScheduledExecutorService by lazy {
6663 Executors .newSingleThreadScheduledExecutor(ReplayPersistingExecutorServiceThreadFactory ())
6764 }
65+ private val gestureConverter = ReplayGestureConverter (dateProvider)
6866
6967 protected val isTerminating = AtomicBoolean (false )
7068 protected var cache: ReplayCache ? = null
@@ -94,9 +92,6 @@ internal abstract class BaseCaptureStrategy(
9492 persistingExecutor,
9593 cacheProvider = { cache }
9694 )
97- private val currentPositions = LinkedHashMap <Int , ArrayList <Position >>(10 )
98- private var touchMoveBaseline = 0L
99- private var lastCapturedMoveEvent = 0L
10095
10196 protected val replayExecutor: ScheduledExecutorService by lazy {
10297 executor ? : Executors .newSingleThreadScheduledExecutor(ReplayExecutorServiceThreadFactory ())
@@ -169,7 +164,7 @@ internal abstract class BaseCaptureStrategy(
169164 }
170165
171166 override fun onTouchEvent (event : MotionEvent ) {
172- val rrwebEvents = event.toRRWebIncrementalSnapshotEvent( )
167+ val rrwebEvents = gestureConverter.convert(event, recorderConfig )
173168 if (rrwebEvents != null ) {
174169 synchronized(currentEventsLock) {
175170 currentEvents + = rrwebEvents
@@ -199,126 +194,6 @@ internal abstract class BaseCaptureStrategy(
199194 }
200195 }
201196
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-
322197 private inline fun <T > persistableAtomicNullable (
323198 initialValue : T ? = null,
324199 propertyName : String ,
0 commit comments