Skip to content

Commit

Permalink
RUM-8652: add customCallbacks option to SessionReplayConfiguration …
Browse files Browse the repository at this point in the history
…builder

- have the option to override `getCurrentWindows` in order to improve
cross-platform support
- make `setCustomCallbacks`to be available only through internal proxy
  • Loading branch information
cdn34dd committed Mar 3, 2025
1 parent 9068c03 commit fdb1b74
Show file tree
Hide file tree
Showing 11 changed files with 124 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ public final class com/datadog/android/sessionreplay/SessionReplay {
}

public final class com/datadog/android/sessionreplay/SessionReplayConfiguration {
public final fun copy (Ljava/lang/String;Lcom/datadog/android/sessionreplay/SessionReplayPrivacy;Ljava/util/List;Ljava/util/List;Ljava/util/List;FLcom/datadog/android/sessionreplay/ImagePrivacy;ZLcom/datadog/android/sessionreplay/TouchPrivacy;Lcom/datadog/android/sessionreplay/TextAndInputPrivacy;ZLcom/datadog/android/sessionreplay/SystemRequirementsConfiguration;)Lcom/datadog/android/sessionreplay/SessionReplayConfiguration;
public static synthetic fun copy$default (Lcom/datadog/android/sessionreplay/SessionReplayConfiguration;Ljava/lang/String;Lcom/datadog/android/sessionreplay/SessionReplayPrivacy;Ljava/util/List;Ljava/util/List;Ljava/util/List;FLcom/datadog/android/sessionreplay/ImagePrivacy;ZLcom/datadog/android/sessionreplay/TouchPrivacy;Lcom/datadog/android/sessionreplay/TextAndInputPrivacy;ZLcom/datadog/android/sessionreplay/SystemRequirementsConfiguration;ILjava/lang/Object;)Lcom/datadog/android/sessionreplay/SessionReplayConfiguration;
public final fun copy (Ljava/lang/String;Lcom/datadog/android/sessionreplay/SessionReplayPrivacy;Ljava/util/List;Ljava/util/List;Ljava/util/List;FLcom/datadog/android/sessionreplay/ImagePrivacy;ZLcom/datadog/android/sessionreplay/TouchPrivacy;Lcom/datadog/android/sessionreplay/TextAndInputPrivacy;ZLcom/datadog/android/sessionreplay/SystemRequirementsConfiguration;Lcom/datadog/android/sessionreplay/internal/recorder/SessionReplayCustomCallbacks;)Lcom/datadog/android/sessionreplay/SessionReplayConfiguration;
public static synthetic fun copy$default (Lcom/datadog/android/sessionreplay/SessionReplayConfiguration;Ljava/lang/String;Lcom/datadog/android/sessionreplay/SessionReplayPrivacy;Ljava/util/List;Ljava/util/List;Ljava/util/List;FLcom/datadog/android/sessionreplay/ImagePrivacy;ZLcom/datadog/android/sessionreplay/TouchPrivacy;Lcom/datadog/android/sessionreplay/TextAndInputPrivacy;ZLcom/datadog/android/sessionreplay/SystemRequirementsConfiguration;Lcom/datadog/android/sessionreplay/internal/recorder/SessionReplayCustomCallbacks;ILjava/lang/Object;)Lcom/datadog/android/sessionreplay/SessionReplayConfiguration;
public fun equals (Ljava/lang/Object;)Z
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
Expand Down Expand Up @@ -108,11 +108,33 @@ public final class com/datadog/android/sessionreplay/TouchPrivacy : java/lang/En
public static fun values ()[Lcom/datadog/android/sessionreplay/TouchPrivacy;
}

public final class com/datadog/android/sessionreplay/_SessionReplayInternalProxy {
public static final field Companion Lcom/datadog/android/sessionreplay/_SessionReplayInternalProxy$Companion;
public fun <init> ()V
}

public final class com/datadog/android/sessionreplay/_SessionReplayInternalProxy$Companion {
public final fun setCustomCallbacks (Lcom/datadog/android/sessionreplay/SessionReplayConfiguration$Builder;Lcom/datadog/android/sessionreplay/internal/recorder/SessionReplayCustomCallbacks;)Lcom/datadog/android/sessionreplay/SessionReplayConfiguration$Builder;
}

public final class com/datadog/android/sessionreplay/internal/TouchPrivacyManager {
public fun <init> (Lcom/datadog/android/sessionreplay/TouchPrivacy;)V
public final fun addTouchOverrideArea (Landroid/graphics/Rect;Lcom/datadog/android/sessionreplay/TouchPrivacy;)V
}

public final class com/datadog/android/sessionreplay/internal/recorder/SessionReplayCustomCallbacks {
public fun <init> ()V
public fun <init> (Lkotlin/jvm/functions/Function0;)V
public synthetic fun <init> (Lkotlin/jvm/functions/Function0;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Lkotlin/jvm/functions/Function0;
public final fun copy (Lkotlin/jvm/functions/Function0;)Lcom/datadog/android/sessionreplay/internal/recorder/SessionReplayCustomCallbacks;
public static synthetic fun copy$default (Lcom/datadog/android/sessionreplay/internal/recorder/SessionReplayCustomCallbacks;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lcom/datadog/android/sessionreplay/internal/recorder/SessionReplayCustomCallbacks;
public fun equals (Ljava/lang/Object;)Z
public final fun getGetCurrentWindows ()Lkotlin/jvm/functions/Function0;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public abstract interface class com/datadog/android/sessionreplay/internal/recorder/obfuscator/StringObfuscator {
public static final field Companion Lcom/datadog/android/sessionreplay/internal/recorder/obfuscator/StringObfuscator$Companion;
public abstract fun obfuscate (Ljava/lang/String;)Ljava/lang/String;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ object SessionReplay {
customDrawableMappers = sessionReplayConfiguration.customDrawableMappers,
sampleRate = sessionReplayConfiguration.sampleRate,
startRecordingImmediately = sessionReplayConfiguration.startRecordingImmediately,
dynamicOptimizationEnabled = sessionReplayConfiguration.dynamicOptimizationEnabled
dynamicOptimizationEnabled = sessionReplayConfiguration.dynamicOptimizationEnabled,
customCallbacks = sessionReplayConfiguration.customCallbacks
)

if (isAlreadyRegistered()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package com.datadog.android.sessionreplay

import androidx.annotation.FloatRange
import com.datadog.android.api.InternalLogger
import com.datadog.android.sessionreplay.internal.recorder.SessionReplayCustomCallbacks
import com.datadog.android.sessionreplay.recorder.OptionSelectorDetector
import com.datadog.android.sessionreplay.utils.DrawableToColorMapper
import java.util.Locale
Expand All @@ -27,7 +28,8 @@ data class SessionReplayConfiguration internal constructor(
internal val touchPrivacy: TouchPrivacy,
internal val textAndInputPrivacy: TextAndInputPrivacy,
internal val dynamicOptimizationEnabled: Boolean,
internal val systemRequirementsConfiguration: SystemRequirementsConfiguration
internal val systemRequirementsConfiguration: SystemRequirementsConfiguration,
internal val customCallbacks: SessionReplayCustomCallbacks
) {

/**
Expand Down Expand Up @@ -73,6 +75,7 @@ data class SessionReplayConfiguration internal constructor(
private var extensionSupportSet: MutableSet<ExtensionSupport> = mutableSetOf()
private var dynamicOptimizationEnabled = true
private var systemRequirementsConfiguration = SystemRequirementsConfiguration.NONE
private var customCallbacks: SessionReplayCustomCallbacks = SessionReplayCustomCallbacks()

/**
* Adds an extension support implementation. This is mostly used when you want to provide
Expand Down Expand Up @@ -210,6 +213,15 @@ data class SessionReplayConfiguration internal constructor(
return this
}

/**
* Specifies callbacks functions to override standard behaviours in Session Replay
* that need to behave differently depending on the platform.
*/
internal fun setCustomCallbacks(customCallbacks: SessionReplayCustomCallbacks): Builder {
this.customCallbacks = customCallbacks
return this
}

/**
* Builds a [SessionReplayConfiguration] based on the current state of this Builder.
*/
Expand All @@ -226,7 +238,8 @@ data class SessionReplayConfiguration internal constructor(
sampleRate = sampleRate,
startRecordingImmediately = startRecordingImmediately,
dynamicOptimizationEnabled = dynamicOptimizationEnabled,
systemRequirementsConfiguration = systemRequirementsConfiguration
systemRequirementsConfiguration = systemRequirementsConfiguration,
customCallbacks = customCallbacks
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.sessionreplay

import com.datadog.android.lint.InternalApi
import com.datadog.android.sessionreplay.internal.recorder.SessionReplayCustomCallbacks

/**
* This class exposes internal methods that are used by other Datadog modules and cross platform
* frameworks. It is not meant for public use.
*
* DO NOT USE this class or its methods if you are not working on the internals of the Datadog SDK
* or one of the cross platform frameworks.
*
* Methods, members, and functionality of this class are subject to change without notice, as they
* are not considered part of the public interface of the Datadog SDK.
*/
@InternalApi
@Suppress(
"UndocumentedPublicClass",
"UndocumentedPublicFunction",
"UndocumentedPublicProperty",
"ClassName",
"ClassNaming",
"VariableNaming"
)
class _SessionReplayInternalProxy {
companion object {
fun setCustomCallbacks(
builder: SessionReplayConfiguration.Builder,
customCallbacks: SessionReplayCustomCallbacks
): SessionReplayConfiguration.Builder {
return builder.setCustomCallbacks(customCallbacks)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import com.datadog.android.sessionreplay.ImagePrivacy
import com.datadog.android.sessionreplay.MapperTypeWrapper
import com.datadog.android.sessionreplay.TextAndInputPrivacy
import com.datadog.android.sessionreplay.internal.recorder.Recorder
import com.datadog.android.sessionreplay.internal.recorder.SessionReplayCustomCallbacks
import com.datadog.android.sessionreplay.internal.recorder.SessionReplayRecorder
import com.datadog.android.sessionreplay.internal.recorder.mapper.ActionBarContainerMapper
import com.datadog.android.sessionreplay.internal.recorder.mapper.ButtonMapper
Expand Down Expand Up @@ -64,7 +65,8 @@ internal class DefaultRecorderProvider(
private val customMappers: List<MapperTypeWrapper<*>>,
private val customOptionSelectorDetectors: List<OptionSelectorDetector>,
private val customDrawableMappers: List<DrawableToColorMapper>,
private val dynamicOptimizationEnabled: Boolean
private val dynamicOptimizationEnabled: Boolean,
private val customCallbacks: SessionReplayCustomCallbacks
) : RecorderProvider {

override fun provideSessionReplayRecorder(
Expand All @@ -87,7 +89,8 @@ internal class DefaultRecorderProvider(
customOptionSelectorDetectors = customOptionSelectorDetectors,
customDrawableMappers = customDrawableMappers,
sdkCore = sdkCore,
dynamicOptimizationEnabled = dynamicOptimizationEnabled
dynamicOptimizationEnabled = dynamicOptimizationEnabled,
customCallbacks = customCallbacks
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import com.datadog.android.sessionreplay.internal.net.BatchesToSegmentsMapper
import com.datadog.android.sessionreplay.internal.net.SegmentRequestFactory
import com.datadog.android.sessionreplay.internal.recorder.NoOpRecorder
import com.datadog.android.sessionreplay.internal.recorder.Recorder
import com.datadog.android.sessionreplay.internal.recorder.SessionReplayCustomCallbacks
import com.datadog.android.sessionreplay.internal.resources.ResourceDataStoreManager
import com.datadog.android.sessionreplay.internal.resources.ResourceHashesEntryDeserializer
import com.datadog.android.sessionreplay.internal.resources.ResourceHashesEntrySerializer
Expand Down Expand Up @@ -71,7 +72,8 @@ internal class SessionReplayFeature(
customDrawableMappers: List<DrawableToColorMapper>,
sampleRate: Float,
startRecordingImmediately: Boolean,
dynamicOptimizationEnabled: Boolean
dynamicOptimizationEnabled: Boolean,
customCallbacks: SessionReplayCustomCallbacks
) : this(
sdkCore,
customEndpointUrl,
Expand All @@ -89,7 +91,8 @@ internal class SessionReplayFeature(
customMappers,
customOptionSelectorDetectors,
customDrawableMappers,
dynamicOptimizationEnabled
dynamicOptimizationEnabled,
customCallbacks
)
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.sessionreplay.internal.recorder

import android.view.Window

data class SessionReplayCustomCallbacks(
val getCurrentWindows: (() -> List<Window>)? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ internal class SessionReplayRecorder : OnWindowRefreshedCallback, Recorder {
private val viewOnDrawInterceptor: ViewOnDrawInterceptor
private val internalLogger: InternalLogger
private val resourceDataStoreManager: ResourceDataStoreManager
private val customCallbacks: SessionReplayCustomCallbacks

private val uiHandler: Handler
private var shouldRecord = false
Expand All @@ -91,7 +92,8 @@ internal class SessionReplayRecorder : OnWindowRefreshedCallback, Recorder {
windowInspector: WindowInspector = WindowInspector,
sdkCore: FeatureSdkCore,
resourceDataStoreManager: ResourceDataStoreManager,
dynamicOptimizationEnabled: Boolean
dynamicOptimizationEnabled: Boolean,
customCallbacks: SessionReplayCustomCallbacks
) {
val internalLogger = sdkCore.internalLogger
val rumContextDataHandler = RumContextDataHandler(
Expand Down Expand Up @@ -129,6 +131,7 @@ internal class SessionReplayRecorder : OnWindowRefreshedCallback, Recorder {
recordedDataQueue = ConcurrentLinkedQueue()
)
this.resourceDataStoreManager = resourceDataStoreManager
this.customCallbacks = customCallbacks

val viewIdentifierResolver: ViewIdentifierResolver = DefaultViewIdentifierResolver
val colorStringFormatter: ColorStringFormatter = DefaultColorStringFormatter
Expand Down Expand Up @@ -169,8 +172,7 @@ internal class SessionReplayRecorder : OnWindowRefreshedCallback, Recorder {
onDrawListenerProducer = DefaultOnDrawListenerProducer(
snapshotProducer = SnapshotProducer(
DefaultImageWireframeHelper(
logger = internalLogger,
resourceResolver = resourceResolver,
logger = internalLogger, resourceResolver = resourceResolver,
viewIdentifierResolver = viewIdentifierResolver,
viewUtilsInternal = ViewUtilsInternal(),
imageTypeResolver = ImageTypeResolver()
Expand Down Expand Up @@ -231,7 +233,8 @@ internal class SessionReplayRecorder : OnWindowRefreshedCallback, Recorder {
recordedDataQueueHandler: RecordedDataQueueHandler,
resourceDataStoreManager: ResourceDataStoreManager,
uiHandler: Handler,
internalLogger: InternalLogger
internalLogger: InternalLogger,
customCallbacks: SessionReplayCustomCallbacks
) {
this.appContext = appContext
this.rumContextProvider = rumContextProvider
Expand All @@ -250,6 +253,7 @@ internal class SessionReplayRecorder : OnWindowRefreshedCallback, Recorder {
this.uiHandler = uiHandler
this.internalLogger = internalLogger
this.resourceDataStoreManager = resourceDataStoreManager
this.customCallbacks = customCallbacks
}

override fun stopProcessingRecords() {
Expand All @@ -267,7 +271,8 @@ internal class SessionReplayRecorder : OnWindowRefreshedCallback, Recorder {
override fun resumeRecorders() {
uiHandler.post {
shouldRecord = true
val windows = sessionReplayLifecycleCallback.getCurrentWindows()
val windows = this.customCallbacks.getCurrentWindows?.let { it() }
?: sessionReplayLifecycleCallback.getCurrentWindows()
val decorViews = windowInspector.getGlobalWindowViews(internalLogger)
windowCallbackInterceptor.intercept(windows, appContext)
viewOnDrawInterceptor.intercept(decorViews, textAndInputPrivacy, imagePrivacy)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.datadog.android.api.InternalLogger
import com.datadog.android.sessionreplay.internal.LifecycleCallback
import com.datadog.android.sessionreplay.internal.TouchPrivacyManager
import com.datadog.android.sessionreplay.internal.async.RecordedDataQueueHandler
import com.datadog.android.sessionreplay.internal.recorder.SessionReplayCustomCallbacks
import com.datadog.android.sessionreplay.internal.recorder.SessionReplayRecorder
import com.datadog.android.sessionreplay.internal.recorder.ViewOnDrawInterceptor
import com.datadog.android.sessionreplay.internal.recorder.WindowCallbackInterceptor
Expand Down Expand Up @@ -125,7 +126,8 @@ internal class SessionReplayRecorderTest {
recordedDataQueueHandler = mockRecordedDataQueueHandler,
uiHandler = mockUiHandler,
internalLogger = mockInternalLogger,
resourceDataStoreManager = mockDataStoreManager
resourceDataStoreManager = mockDataStoreManager,
customCallbacks = SessionReplayCustomCallbacks()
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.datadog.android.sessionreplay.SessionReplayPrivacy
import com.datadog.android.sessionreplay.SystemRequirementsConfiguration
import com.datadog.android.sessionreplay.TextAndInputPrivacy
import com.datadog.android.sessionreplay.TouchPrivacy
import com.datadog.android.sessionreplay.internal.recorder.SessionReplayCustomCallbacks
import fr.xgouchet.elmyr.Forge
import fr.xgouchet.elmyr.ForgeryFactory
import org.mockito.kotlin.mock
Expand All @@ -30,6 +31,7 @@ class SessionReplayConfigurationForgeryFactory : ForgeryFactory<SessionReplayCon
startRecordingImmediately = forge.aBool(),
sampleRate = forge.aFloat(min = 0f, max = 100f),
dynamicOptimizationEnabled = forge.aBool(),
customCallbacks = SessionReplayCustomCallbacks(),
systemRequirementsConfiguration = SystemRequirementsConfiguration.Builder()
.setMinRAMSizeMb(forge.aSmallInt())
.setMinCPUCoreNumber(forge.aSmallInt())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.datadog.android.sessionreplay.forge.ForgeConfigurator
import com.datadog.android.sessionreplay.internal.net.SegmentRequestFactory
import com.datadog.android.sessionreplay.internal.recorder.NoOpRecorder
import com.datadog.android.sessionreplay.internal.recorder.Recorder
import com.datadog.android.sessionreplay.internal.recorder.SessionReplayCustomCallbacks
import com.datadog.android.sessionreplay.internal.recorder.SessionReplayRecorder
import com.datadog.android.sessionreplay.internal.storage.NoOpRecordWriter
import com.datadog.android.sessionreplay.internal.storage.SessionReplayRecordWriter
Expand Down Expand Up @@ -142,7 +143,8 @@ internal class SessionReplayFeatureTest {
customDrawableMappers = emptyList(),
startRecordingImmediately = true,
sampleRate = fakeConfiguration.sampleRate,
dynamicOptimizationEnabled = fakeConfiguration.dynamicOptimizationEnabled
dynamicOptimizationEnabled = fakeConfiguration.dynamicOptimizationEnabled,
customCallbacks = SessionReplayCustomCallbacks()
)

// When
Expand All @@ -169,7 +171,8 @@ internal class SessionReplayFeatureTest {
customDrawableMappers = emptyList(),
sampleRate = fakeConfiguration.sampleRate,
startRecordingImmediately = true,
dynamicOptimizationEnabled = fakeConfiguration.dynamicOptimizationEnabled
dynamicOptimizationEnabled = fakeConfiguration.dynamicOptimizationEnabled,
customCallbacks = SessionReplayCustomCallbacks()
)

// When
Expand Down

0 comments on commit fdb1b74

Please sign in to comment.