From e07743a8b16ac12b360975d467f03394324b0a82 Mon Sep 17 00:00:00 2001 From: luyi Date: Mon, 30 Dec 2024 13:14:36 +0100 Subject: [PATCH] RUM-7332: Add instrumented test for Compose Session Replay --- instrumented/integration/build.gradle.kts | 8 ++ .../sr_compose_button_payload.json | 41 ++++++ .../sr_compose_image_allow_payload.json | 82 +++++++++++ .../sr_compose_image_mask_payload.json | 90 ++++++++++++ .../sr_compose_selectable_allow_payload.json | 54 ++++++++ .../sr_compose_selectable_mask_payload.json | 52 +++++++ .../sr_compose_typography_allow_payload.json | 91 ++++++++++++ .../compose/ComposeButtonTest.kt | 36 +++++ .../compose/ComposeImageAllowTest.kt | 36 +++++ .../compose/ComposeImageMaskTest.kt | 36 +++++ .../compose/ComposeSelectableAllowTest.kt | 36 +++++ .../compose/ComposeSelectableMaskTest.kt | 36 +++++ .../compose/ComposeTypographyAllowTest.kt | 36 +++++ .../integration/src/main/AndroidManifest.xml | 4 + .../android/sdk/integration/RuntimeConfig.kt | 4 + .../compose/ComposeButtonActivity.kt | 46 +++++++ .../compose/ComposeImageActivity.kt | 129 ++++++++++++++++++ .../compose/ComposeSelectableActivity.kt | 40 ++++++ .../compose/ComposeTypographyActivity.kt | 72 ++++++++++ 19 files changed, 929 insertions(+) create mode 100644 instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_button_payload.json create mode 100644 instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_image_allow_payload.json create mode 100644 instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_image_mask_payload.json create mode 100644 instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_selectable_allow_payload.json create mode 100644 instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_selectable_mask_payload.json create mode 100644 instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_typography_allow_payload.json create mode 100644 instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeButtonTest.kt create mode 100644 instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeImageAllowTest.kt create mode 100644 instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeImageMaskTest.kt create mode 100644 instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeSelectableAllowTest.kt create mode 100644 instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeSelectableMaskTest.kt create mode 100644 instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeTypographyAllowTest.kt create mode 100644 instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeButtonActivity.kt create mode 100644 instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeImageActivity.kt create mode 100644 instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeSelectableActivity.kt create mode 100644 instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeTypographyActivity.kt diff --git a/instrumented/integration/build.gradle.kts b/instrumented/integration/build.gradle.kts index 916c1ef86b..6765957f41 100644 --- a/instrumented/integration/build.gradle.kts +++ b/instrumented/integration/build.gradle.kts @@ -27,6 +27,11 @@ android { buildFeatures { buildConfig = true + compose = true + } + + composeOptions { + kotlinCompilerExtensionVersion = libs.versions.androidXComposeRuntime.get() } multiDexEnabled = true @@ -91,6 +96,7 @@ dependencies { coreLibraryDesugaring(libs.androidDesugaringSdk) } implementation(project(":features:dd-sdk-android-session-replay")) + implementation(project(":features:dd-sdk-android-session-replay-compose")) implementation(project(":features:dd-sdk-android-logs")) implementation(project(":features:dd-sdk-android-trace")) implementation(project(":features:dd-sdk-android-rum")) @@ -101,6 +107,8 @@ dependencies { implementation(libs.bundles.androidXSupportBase) implementation(libs.androidXMultidex) implementation(libs.elmyr) + implementation(platform(libs.androidXComposeBom)) + implementation(libs.bundles.androidXCompose) androidTestImplementation(project(":tools:unit")) { attributes { diff --git a/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_button_payload.json b/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_button_payload.json new file mode 100644 index 0000000000..e05075454e --- /dev/null +++ b/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_button_payload.json @@ -0,0 +1,41 @@ +[{ + "type": 4, + "data": { + "width": 320, + "height": 640 + } +}, { + "type": 6, + "data": { + "has_focus": true + } +}, { + "type": 10, + "data": { + "wireframes": [ + { + "type": "shape" + }, + { + "type": "shape" + }, + { + "type": "text", + "text": "Text Button", + "textStyle": { + "family": "Roboto, sans-serif", + "size": 14, + "color": "#ffffffff" + }, + "textPosition": { + "alignment": { + "horizontal": "left" + } + } + }, + { + "type": "shape" + } + ] + } +}] \ No newline at end of file diff --git a/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_image_allow_payload.json b/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_image_allow_payload.json new file mode 100644 index 0000000000..a40d89be71 --- /dev/null +++ b/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_image_allow_payload.json @@ -0,0 +1,82 @@ +[{ + "type": 4, + "data": { + "width": 320, + "height": 640 + } +}, { + "type": 6, + "data": { + "has_focus": true + } +}, { + "type": 10, + "data": { + "wireframes": [ + { + "type": "shape" + }, + { + "type": "image", + "isEmpty": false + }, + { + "type": "text", + "text": "Image", + "textStyle": { + "family": "Roboto, sans-serif", + "size": 20, + "color": "#000000ff" + }, + "textPosition": { + "alignment": { + "horizontal": "left" + } + } + }, + { + "type": "shape" + }, + { + "type": "shape" + }, + { + "type": "text", + "text": "Icon", + "textStyle": { + "family": "Roboto, sans-serif", + "size": 20, + "color": "#000000ff" + }, + "textPosition": { + "alignment": { + "horizontal": "left" + } + } + }, + { + "clip": { + "top": 0, + "bottom": 16, + "left": 0, + "right": 0 + }, + "type": "shape" + }, + { + "type": "text", + "text": "Icon Button", + "textStyle": { + "family": "Roboto, sans-serif", + "size": 20, + "color": "#000000ff" + }, + "textPosition": { + "alignment": { + "horizontal": "left" + } + } + } + ] + } +}] \ No newline at end of file diff --git a/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_image_mask_payload.json b/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_image_mask_payload.json new file mode 100644 index 0000000000..4392853a68 --- /dev/null +++ b/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_image_mask_payload.json @@ -0,0 +1,90 @@ +[{ + "type": 4, + "data": { + "width": 320, + "height": 640 + } +}, { + "type": 6, + "data": { + "has_focus": true + } +}, { + "type": 10, + "data": { + "wireframes": [ + { + "type": "shape" + }, + { + "type": "placeholder", + "label": "Image" + }, + { + "type": "text", + "text": "xxxxx", + "textStyle": { + "family": "Roboto, sans-serif", + "size": 20, + "color": "#000000ff" + }, + "textPosition": { + "alignment": { + "horizontal": "left" + } + } + }, + { + "type": "shape" + }, + { + "type": "shape" + }, + { + "type": "placeholder", + "label": "Image" + }, + { + "type": "text", + "text": "xxxx", + "textStyle": { + "family": "Roboto, sans-serif", + "size": 20, + "color": "#000000ff" + }, + "textPosition": { + "alignment": { + "horizontal": "left" + } + } + }, + { + "clip": { + "top": 0, + "bottom": 16, + "left": 0, + "right": 0 + }, + "type": "shape" + }, + { + "type": "placeholder", + "label": "Image" + }, + { + "type": "text", + "text": "xxxx xxxxxx", + "textStyle": { + "family": "Roboto, sans-serif", + "size": 20, + "color": "#000000ff" + }, + "textPosition": { + "alignment": { + "horizontal": "left" + } + } + } + ] + } +}] \ No newline at end of file diff --git a/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_selectable_allow_payload.json b/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_selectable_allow_payload.json new file mode 100644 index 0000000000..695d263858 --- /dev/null +++ b/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_selectable_allow_payload.json @@ -0,0 +1,54 @@ +[{ + "type": 4, + "data": { + "width": 320, + "height": 640 + } +}, { + "type": 6, + "data": { + "has_focus": true + } +}, { + "type": 10, + "data": { + "wireframes": [ + { + "type": "shape" + }, + { + "border": { + "color": "#03dac6ff", + "width": 2 + }, + "type": "image", + "isEmpty": false + }, + { + "border": { + "color": "#00000099", + "width": 2 + }, + "type": "image", + "isEmpty": false + }, + { + "border": { + "color": "#000000FF", + "width": 1 + }, + "type": "shape" + }, + { + "type": "shape" + }, + { + "border": { + "color": "#000000FF", + "width": 1 + }, + "type": "shape" + } + ] + } +}] \ No newline at end of file diff --git a/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_selectable_mask_payload.json b/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_selectable_mask_payload.json new file mode 100644 index 0000000000..c4cc9678bb --- /dev/null +++ b/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_selectable_mask_payload.json @@ -0,0 +1,52 @@ +[{ + "type": 4, + "data": { + "width": 320, + "height": 640 + } +}, { + "type": 6, + "data": { + "has_focus": true + } +}, { + "type": 10, + "data": { + "wireframes": [ + { + "type": "shape" + }, + { + "border": { + "color": "#000000FF", + "width": 2 + }, + "type": "shape" + }, + { + "border": { + "color": "#000000FF", + "width": 2 + }, + "type": "shape" + }, + { + "border": { + "color": "#000000FF", + "width": 1 + }, + "type": "shape" + }, + { + "type": "shape" + }, + { + "border": { + "color": "#000000FF", + "width": 1 + }, + "type": "shape" + } + ] + } +}] \ No newline at end of file diff --git a/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_typography_allow_payload.json b/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_typography_allow_payload.json new file mode 100644 index 0000000000..27667afef1 --- /dev/null +++ b/instrumented/integration/src/androidTest/assets/session_replay_payloads/sr_compose_typography_allow_payload.json @@ -0,0 +1,91 @@ +[{ + "type": 4, + "data": { + "width": 320, + "height": 640 + } +}, { + "type": 6, + "data": { + "has_focus": true + } +}, { + "type": 10, + "data": { + "wireframes": [ + { + "type": "shape" + }, + { + "type": "text", + "text": "Material H3 - onBackground", + "textStyle": { + "family": "Roboto, sans-serif", + "size": 48, + "color": "#000000ff" + }, + "textPosition": { + "alignment": { + "horizontal": "left" + } + } + }, + { + "type": "text", + "text": "Material H4 - onSurface", + "textStyle": { + "family": "Roboto, sans-serif", + "size": 34, + "color": "#000000ff" + }, + "textPosition": { + "alignment": { + "horizontal": "left" + } + } + }, + { + "type": "text", + "text": "Material H6 - Red", + "textStyle": { + "family": "Roboto, sans-serif", + "size": 20, + "color": "#ff0000ff" + }, + "textPosition": { + "alignment": { + "horizontal": "left" + } + } + }, + { + "type": "text", + "text": "Material Body 1 - Green", + "textStyle": { + "family": "Roboto, sans-serif", + "size": 16, + "color": "#00ff00ff" + }, + "textPosition": { + "alignment": { + "horizontal": "left" + } + } + }, + { + "type": "text", + "text": "Material Caption - Blue", + "textStyle": { + "family": "Roboto, sans-serif", + "size": 12, + "color": "#0000ffff" + }, + "textPosition": { + "alignment": { + "horizontal": "left" + } + } + } + ] + } +}] \ No newline at end of file diff --git a/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeButtonTest.kt b/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeButtonTest.kt new file mode 100644 index 0000000000..e3bb8c2d44 --- /dev/null +++ b/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeButtonTest.kt @@ -0,0 +1,36 @@ +/* + * 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.sdk.integration.sessionreplay.compose + +import com.datadog.android.privacy.TrackingConsent +import com.datadog.android.sdk.integration.sessionreplay.BaseSessionReplayTest +import com.datadog.android.sdk.rules.SessionReplayTestRule +import com.datadog.android.sdk.utils.SR_PRIVACY_LEVEL +import com.datadog.android.sessionreplay.SessionReplayPrivacy +import org.junit.Rule +import org.junit.Test + +internal class ComposeButtonTest : BaseSessionReplayTest() { + + @get:Rule + val rule = SessionReplayTestRule( + ComposeButtonActivity::class.java, + trackingConsent = TrackingConsent.GRANTED, + keepRequests = true, + intentExtras = mapOf(SR_PRIVACY_LEVEL to SessionReplayPrivacy.ALLOW) + ) + + @Test + fun assessRecordedScreenPayload() { + runInstrumentationScenario() + assessSrPayload(EXPECTED_PAYLOAD_FILE_NAME, rule) + } + + companion object { + const val EXPECTED_PAYLOAD_FILE_NAME = "sr_compose_button_payload.json" + } +} diff --git a/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeImageAllowTest.kt b/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeImageAllowTest.kt new file mode 100644 index 0000000000..793c0f379b --- /dev/null +++ b/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeImageAllowTest.kt @@ -0,0 +1,36 @@ +/* + * 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.sdk.integration.sessionreplay.compose + +import com.datadog.android.privacy.TrackingConsent +import com.datadog.android.sdk.integration.sessionreplay.BaseSessionReplayTest +import com.datadog.android.sdk.rules.SessionReplayTestRule +import com.datadog.android.sdk.utils.SR_PRIVACY_LEVEL +import com.datadog.android.sessionreplay.SessionReplayPrivacy +import org.junit.Rule +import org.junit.Test + +internal class ComposeImageAllowTest : BaseSessionReplayTest() { + + @get:Rule + val rule = SessionReplayTestRule( + ComposeImageActivity::class.java, + trackingConsent = TrackingConsent.GRANTED, + keepRequests = true, + intentExtras = mapOf(SR_PRIVACY_LEVEL to SessionReplayPrivacy.ALLOW) + ) + + @Test + fun assessRecordedScreenPayload() { + runInstrumentationScenario() + assessSrPayload(EXPECTED_PAYLOAD_FILE_NAME, rule) + } + + companion object { + const val EXPECTED_PAYLOAD_FILE_NAME = "sr_compose_image_allow_payload.json" + } +} diff --git a/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeImageMaskTest.kt b/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeImageMaskTest.kt new file mode 100644 index 0000000000..a77612298c --- /dev/null +++ b/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeImageMaskTest.kt @@ -0,0 +1,36 @@ +/* + * 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.sdk.integration.sessionreplay.compose + +import com.datadog.android.privacy.TrackingConsent +import com.datadog.android.sdk.integration.sessionreplay.BaseSessionReplayTest +import com.datadog.android.sdk.rules.SessionReplayTestRule +import com.datadog.android.sdk.utils.SR_PRIVACY_LEVEL +import com.datadog.android.sessionreplay.SessionReplayPrivacy +import org.junit.Rule +import org.junit.Test + +internal class ComposeImageMaskTest : BaseSessionReplayTest() { + + @get:Rule + val rule = SessionReplayTestRule( + ComposeImageActivity::class.java, + trackingConsent = TrackingConsent.GRANTED, + keepRequests = true, + intentExtras = mapOf(SR_PRIVACY_LEVEL to SessionReplayPrivacy.MASK) + ) + + @Test + fun assessRecordedScreenPayload() { + runInstrumentationScenario() + assessSrPayload(EXPECTED_PAYLOAD_FILE_NAME, rule) + } + + companion object { + const val EXPECTED_PAYLOAD_FILE_NAME = "sr_compose_image_mask_payload.json" + } +} diff --git a/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeSelectableAllowTest.kt b/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeSelectableAllowTest.kt new file mode 100644 index 0000000000..7f84799d3d --- /dev/null +++ b/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeSelectableAllowTest.kt @@ -0,0 +1,36 @@ +/* + * 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.sdk.integration.sessionreplay.compose + +import com.datadog.android.privacy.TrackingConsent +import com.datadog.android.sdk.integration.sessionreplay.BaseSessionReplayTest +import com.datadog.android.sdk.rules.SessionReplayTestRule +import com.datadog.android.sdk.utils.SR_PRIVACY_LEVEL +import com.datadog.android.sessionreplay.SessionReplayPrivacy +import org.junit.Rule +import org.junit.Test + +internal class ComposeSelectableAllowTest : BaseSessionReplayTest() { + + @get:Rule + val rule = SessionReplayTestRule( + ComposeSelectableActivity::class.java, + trackingConsent = TrackingConsent.GRANTED, + keepRequests = true, + intentExtras = mapOf(SR_PRIVACY_LEVEL to SessionReplayPrivacy.ALLOW) + ) + + @Test + fun assessRecordedScreenPayload() { + runInstrumentationScenario() + assessSrPayload(EXPECTED_PAYLOAD_FILE_NAME, rule) + } + + companion object { + const val EXPECTED_PAYLOAD_FILE_NAME = "sr_compose_selectable_allow_payload.json" + } +} diff --git a/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeSelectableMaskTest.kt b/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeSelectableMaskTest.kt new file mode 100644 index 0000000000..006e6613f1 --- /dev/null +++ b/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeSelectableMaskTest.kt @@ -0,0 +1,36 @@ +/* + * 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.sdk.integration.sessionreplay.compose + +import com.datadog.android.privacy.TrackingConsent +import com.datadog.android.sdk.integration.sessionreplay.BaseSessionReplayTest +import com.datadog.android.sdk.rules.SessionReplayTestRule +import com.datadog.android.sdk.utils.SR_PRIVACY_LEVEL +import com.datadog.android.sessionreplay.SessionReplayPrivacy +import org.junit.Rule +import org.junit.Test + +internal class ComposeSelectableMaskTest : BaseSessionReplayTest() { + + @get:Rule + val rule = SessionReplayTestRule( + ComposeSelectableActivity::class.java, + trackingConsent = TrackingConsent.GRANTED, + keepRequests = true, + intentExtras = mapOf(SR_PRIVACY_LEVEL to SessionReplayPrivacy.MASK) + ) + + @Test + fun assessRecordedScreenPayload() { + runInstrumentationScenario() + assessSrPayload(EXPECTED_PAYLOAD_FILE_NAME, rule) + } + + companion object { + const val EXPECTED_PAYLOAD_FILE_NAME = "sr_compose_selectable_mask_payload.json" + } +} diff --git a/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeTypographyAllowTest.kt b/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeTypographyAllowTest.kt new file mode 100644 index 0000000000..a94113fe0e --- /dev/null +++ b/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeTypographyAllowTest.kt @@ -0,0 +1,36 @@ +/* + * 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.sdk.integration.sessionreplay.compose + +import com.datadog.android.privacy.TrackingConsent +import com.datadog.android.sdk.integration.sessionreplay.BaseSessionReplayTest +import com.datadog.android.sdk.rules.SessionReplayTestRule +import com.datadog.android.sdk.utils.SR_PRIVACY_LEVEL +import com.datadog.android.sessionreplay.SessionReplayPrivacy +import org.junit.Rule +import org.junit.Test + +internal class ComposeTypographyAllowTest : BaseSessionReplayTest() { + + @get:Rule + val rule = SessionReplayTestRule( + ComposeTypographyActivity::class.java, + trackingConsent = TrackingConsent.GRANTED, + keepRequests = true, + intentExtras = mapOf(SR_PRIVACY_LEVEL to SessionReplayPrivacy.ALLOW) + ) + + @Test + fun assessRecordedScreenPayload() { + runInstrumentationScenario() + assessSrPayload(EXPECTED_PAYLOAD_FILE_NAME, rule) + } + + companion object { + const val EXPECTED_PAYLOAD_FILE_NAME = "sr_compose_typography_allow_payload.json" + } +} diff --git a/instrumented/integration/src/main/AndroidManifest.xml b/instrumented/integration/src/main/AndroidManifest.xml index fcf344e525..652f52b4a5 100644 --- a/instrumented/integration/src/main/AndroidManifest.xml +++ b/instrumented/integration/src/main/AndroidManifest.xml @@ -84,6 +84,10 @@ + + + + \ No newline at end of file diff --git a/instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/RuntimeConfig.kt b/instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/RuntimeConfig.kt index 576fcd439a..696d83ad1b 100644 --- a/instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/RuntimeConfig.kt +++ b/instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/RuntimeConfig.kt @@ -15,6 +15,8 @@ import com.datadog.android.log.Logger import com.datadog.android.log.LogsConfiguration import com.datadog.android.rum.RumConfiguration import com.datadog.android.sessionreplay.SessionReplayConfiguration +import com.datadog.android.sessionreplay.compose.ComposeExtensionSupport +import com.datadog.android.sessionreplay.compose.ExperimentalSessionReplayApi import com.datadog.android.trace.AndroidTracer import com.datadog.android.trace.TraceConfiguration import java.util.UUID @@ -73,8 +75,10 @@ internal object RuntimeConfig { .useCustomEndpoint(rumEndpointUrl) } + @OptIn(ExperimentalSessionReplayApi::class) fun sessionReplayConfigBuilder(sampleRate: Float): SessionReplayConfiguration.Builder { return SessionReplayConfiguration.Builder(sampleRate) + .addExtensionSupport(ComposeExtensionSupport()) .useCustomEndpoint(sessionReplayEndpointUrl) } diff --git a/instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeButtonActivity.kt b/instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeButtonActivity.kt new file mode 100644 index 0000000000..d9a86ef21a --- /dev/null +++ b/instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeButtonActivity.kt @@ -0,0 +1,46 @@ +/* + * 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.sdk.integration.sessionreplay.compose + +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.painterResource +import com.datadog.android.sdk.integration.R +import com.datadog.android.sdk.integration.sessionreplay.BaseSessionReplayActivity + +internal class ComposeButtonActivity : BaseSessionReplayActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + ButtonSample() + } + } + + @Composable + private fun ButtonSample() { + Column { + Button(onClick = { + }) { + Text("Text Button") + } + + Button(onClick = { + }) { + Image( + painter = painterResource(R.drawable.ic_dd_icon_red), + contentDescription = "image button" + ) + } + } + } +} diff --git a/instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeImageActivity.kt b/instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeImageActivity.kt new file mode 100644 index 0000000000..d91529916e --- /dev/null +++ b/instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeImageActivity.kt @@ -0,0 +1,129 @@ +/* + * 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.sdk.integration.sessionreplay.compose + +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.datadog.android.sdk.integration.R +import com.datadog.android.sdk.integration.sessionreplay.BaseSessionReplayActivity + +internal class ComposeImageActivity : BaseSessionReplayActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + ImageSample() + } + } + + @Composable + internal fun ImageSample() { + LazyColumn(modifier = Modifier.fillMaxSize()) { + item { + LocalImageNoBackground() + } + + item { + LocalIconDoubleBackground() + } + + item { + IconButtonSingleBackground() + } + } + } + + @Composable + private fun LocalImageNoBackground() { + Row(verticalAlignment = Alignment.CenterVertically) { + Image( + modifier = Modifier.imageModifier(), + painter = painterResource(R.drawable.ic_dd_icon_rgb), + contentDescription = "purple dog" + ) + DescriptionText("Image") + } + } + + @Composable + private fun LocalIconDoubleBackground() { + Row(verticalAlignment = Alignment.CenterVertically) { + Icon( + modifier = Modifier + .padding(16.dp) + .clip(CircleShape) + .background(Color.Green) + .padding(32.dp) + .size(128.dp) + .clip(RoundedCornerShape(8.dp)) + .background(Color.DarkGray) + .padding(4.dp), + painter = painterResource(R.drawable.ic_dd_icon_red), + tint = Color.Red, + contentDescription = "red dog" + ) + DescriptionText("Icon") + } + } + + @Composable + private fun IconButtonSingleBackground() { + Row(verticalAlignment = Alignment.CenterVertically) { + IconButton( + modifier = Modifier + .padding(16.dp) + .clip(RoundedCornerShape(16.dp)) + .background(Color.Black), + onClick = {} + ) { + Icon( + modifier = Modifier + .padding(16.dp) + .size(160.dp), + painter = painterResource(R.drawable.ic_dd_icon_white), + tint = Color.White, + contentDescription = "white dog" + ) + } + DescriptionText("Icon Button") + } + } + + @Composable + private fun DescriptionText(description: String) { + Text( + description, + fontSize = 20.sp + ) + } + + private fun Modifier.imageModifier(): Modifier { + return this + .padding(32.dp) + .size(160.dp) + } +} diff --git a/instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeSelectableActivity.kt b/instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeSelectableActivity.kt new file mode 100644 index 0000000000..e79fb454bd --- /dev/null +++ b/instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeSelectableActivity.kt @@ -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.sdk.integration.sessionreplay.compose + +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.Column +import androidx.compose.material.Checkbox +import androidx.compose.material.RadioButton +import androidx.compose.material.Switch +import androidx.compose.runtime.Composable +import com.datadog.android.sdk.integration.sessionreplay.BaseSessionReplayActivity + +internal class ComposeSelectableActivity : BaseSessionReplayActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + SelectableSample() + } + } + + @Composable + private fun SelectableSample() { + Column { + Checkbox(checked = true, onCheckedChange = {}) + Checkbox(checked = false, onCheckedChange = {}) + + Switch(checked = true, onCheckedChange = {}) + Switch(checked = false, onCheckedChange = {}) + + RadioButton(selected = true, onClick = {}) + RadioButton(selected = false, onClick = {}) + } + } +} diff --git a/instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeTypographyActivity.kt b/instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeTypographyActivity.kt new file mode 100644 index 0000000000..bfabfdda6e --- /dev/null +++ b/instrumented/integration/src/main/kotlin/com/datadog/android/sdk/integration/sessionreplay/compose/ComposeTypographyActivity.kt @@ -0,0 +1,72 @@ +/* + * 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.sdk.integration.sessionreplay.compose + +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import com.datadog.android.sdk.integration.sessionreplay.BaseSessionReplayActivity + +internal class ComposeTypographyActivity : BaseSessionReplayActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + TypographyScreen() + } + } + + @Composable + private fun TypographyScreen() { + Column { + Text( + text = "Material H3 - onBackground", + style = MaterialTheme.typography.h3, + modifier = Modifier.padding(16.dp), + color = MaterialTheme.colors.onBackground + ) + + Text( + text = "Material H4 - onSurface", + style = MaterialTheme.typography.h4, + modifier = Modifier.padding(16.dp), + color = MaterialTheme.colors.onSurface + ) + + Text( + text = "Material H6 - Red", + style = MaterialTheme.typography.h6, + modifier = Modifier.padding(16.dp), + color = Color.Red + ) + + Text( + text = "Material Body 1 - Green", + style = MaterialTheme.typography.body1.copy( + color = Color.Blue + ), + modifier = Modifier.padding(16.dp), + color = Color.Green + ) + + Text( + text = "Material Caption - Blue", + style = MaterialTheme.typography.caption.copy( + color = Color.Blue + ), + modifier = Modifier.padding(16.dp) + ) + } + } +}