Skip to content
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c7737c4
Fruta xml
abelonogov-ld Nov 18, 2025
1c35019
Rotate user address
abelonogov-ld Nov 19, 2025
4f6a6f9
XML Credit Card Editor
abelonogov-ld Nov 19, 2025
e7cab04
ldMask for Compose and XML views
abelonogov-ld Nov 19, 2025
7b48b46
delete artifacts
abelonogov-ld Nov 19, 2025
1e78c1c
Code clean up
abelonogov-ld Nov 19, 2025
f9008c1
Some renaming
abelonogov-ld Nov 19, 2025
917929a
Small to check only ldMask flag
abelonogov-ld Nov 19, 2025
89596e6
renaming file
abelonogov-ld Nov 19, 2025
63d9734
missed
abelonogov-ld Nov 19, 2025
e162025
fix child extending beyond parent view case
abelonogov-ld Nov 19, 2025
9baa92b
To maskviewinfo
abelonogov-ld Nov 20, 2025
7a188b6
rename to target
abelonogov-ld Nov 20, 2025
4341bad
Split on 2 files
abelonogov-ld Nov 20, 2025
50b48f2
missed deleted files
abelonogov-ld Nov 20, 2025
ee23ad2
move func into targets
abelonogov-ld Nov 20, 2025
a93deaf
rect methods
abelonogov-ld Nov 20, 2025
8fc24d4
move root
abelonogov-ld Nov 21, 2025
494a0fd
clean up code
abelonogov-ld Nov 21, 2025
82a6c2e
Merge branch 'main' into andrey/mask-native-input-text
abelonogov-ld Nov 21, 2025
c9475ba
move smoothie files
abelonogov-ld Nov 21, 2025
3bbed5a
fix compilation
abelonogov-ld Nov 21, 2025
2fe53bc
Delete copy
abelonogov-ld Nov 21, 2025
71c36bf
start using logger
abelonogov-ld Nov 21, 2025
882d67e
missed imports
abelonogov-ld Nov 21, 2025
8ede685
Merge branch 'andrey/compilation-fix' into andrey/mask-native-input-text
abelonogov-ld Nov 21, 2025
6a92056
delete local properties
abelonogov-ld Nov 22, 2025
78eda10
reverse test code
abelonogov-ld Nov 22, 2025
11aa544
remove key
abelonogov-ld Nov 22, 2025
60a4713
Merge branch 'main' into andrey/mask-native-input-text
abelonogov-ld Nov 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion e2e/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
android:exported="false"
android:theme="@style/Theme.AndroidObservability" />
<activity
android:name="com.smoothie.SmoothieListActivity"
android:name=".smoothie.SmoothieListActivity"
android:exported="false"
android:theme="@style/Theme.AndroidObservability" />
<service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.example.androidobservability.smoothie.SmoothieListActivity
import com.example.androidobservability.ui.theme.AndroidObservabilityTheme

class MainActivity : ComponentActivity() {
Expand Down Expand Up @@ -86,7 +87,7 @@ class MainActivity : ComponentActivity() {
[email protected](
Intent(
this@MainActivity,
com.smoothie.SmoothieListActivity::class.java
SmoothieListActivity::class.java
)
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.smoothie
package com.example.androidobservability.smoothie

import android.graphics.Bitmap
import android.view.LayoutInflater
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.smoothie
package com.example.androidobservability.smoothie

import android.graphics.BitmapFactory
import android.os.Bundle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ import android.os.Looper
import android.util.Base64
import android.view.Choreographer
import android.view.PixelCopy
import com.launchdarkly.logging.LDLogger
import com.launchdarkly.observability.coroutines.DispatcherProviderHolder
import com.launchdarkly.observability.replay.masking.MaskMatcher
import com.launchdarkly.observability.replay.masking.SensitiveAreasCollector
import io.opentelemetry.android.session.SessionManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableSharedFlow
Expand All @@ -37,6 +40,7 @@ import androidx.compose.ui.geometry.Rect as ComposeRect
class CaptureSource(
private val sessionManager: SessionManager,
private val maskMatchers: List<MaskMatcher>,
private val logger: LDLogger,
// TODO: O11Y-628 - add captureQuality options
) :
Application.ActivityLifecycleCallbacks {
Expand All @@ -46,7 +50,7 @@ class CaptureSource(
private val _captureEventFlow = MutableSharedFlow<CaptureEvent>()
val captureFlow: SharedFlow<CaptureEvent> = _captureEventFlow.asSharedFlow()

private val sensitiveAreasCollector = SensitiveAreasCollector()
private val sensitiveAreasCollector = SensitiveAreasCollector(logger)

/**
* Attaches the [CaptureSource] to the [Application] whose [Activity]s will be captured.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package com.launchdarkly.observability.replay

import android.app.Activity
import android.app.Application
import android.os.Build
import android.os.Bundle
import android.os.SystemClock
import android.view.KeyboardShortcutGroup
import android.view.Menu
import android.view.MotionEvent
import android.view.Window
import androidx.annotation.RequiresApi
import io.opentelemetry.android.session.SessionManager
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package com.launchdarkly.observability.replay

import androidx.compose.ui.semantics.SemanticsActions
import androidx.compose.ui.semantics.SemanticsNode
import androidx.compose.ui.semantics.SemanticsProperties
import androidx.compose.ui.semantics.getOrNull
import com.launchdarkly.observability.replay.masking.MaskMatcher
import com.launchdarkly.observability.replay.masking.MaskTarget

/**
* [PrivacyProfile] encapsulates options and functionality related to privacy of session
Expand All @@ -15,7 +13,7 @@ import androidx.compose.ui.semantics.getOrNull
* @param maskTextInputs set to false to turn off masking text inputs
* @param maskText set to false to turn off masking text
* @param maskSensitive set to false to turn off masking sensitive views
* @param maskAdditionalMatchers list of additional [MaskMatcher]s that will be masked when they match
* @param maskAdditionalMatchers list of additional [com.launchdarkly.observability.replay.masking.MaskMatcher]s that will be masked when they match
**/
data class PrivacyProfile(
val maskTextInputs: Boolean = true,
Expand All @@ -40,12 +38,8 @@ data class PrivacyProfile(
* miss as we can't account for all possible future semantic properties.
*/
val textInputMatcher: MaskMatcher = object : MaskMatcher {
override fun isMatch(node: SemanticsNode): Boolean {
val config = node.config
return config.contains(SemanticsProperties.EditableText) ||
config.contains(SemanticsActions.SetText) ||
config.contains(SemanticsActions.PasteText) ||
config.contains(SemanticsActions.InsertTextAtCursor)
override fun isMatch(target: MaskTarget): Boolean {
return target.isTextInput()
}
}

Expand All @@ -54,8 +48,8 @@ data class PrivacyProfile(
* miss as we can't account for all possible future semantic properties.
*/
val textMatcher: MaskMatcher = object : MaskMatcher {
override fun isMatch(node: SemanticsNode): Boolean {
return node.config.contains(SemanticsProperties.Text)
override fun isMatch(target: MaskTarget): Boolean {
return target.isText()
}
}

Expand All @@ -64,39 +58,8 @@ data class PrivacyProfile(
* and all text or context descriptions that have substring matches with any of the [sensitiveKeywords]
*/
val sensitiveMatcher: MaskMatcher = object : MaskMatcher {
override fun isMatch(node: SemanticsNode): Boolean {/**/
if (node.config.contains(SemanticsProperties.Password)) {
return true
}

// check text first for performance, more likely to get a match here than in description below
val textValues = node.config.getOrNull(SemanticsProperties.Text)
if (textValues != null) {
if (textValues.any { annotated ->
val lowerText = annotated.text.lowercase()
sensitiveKeywords.any { keyword ->
// could use ignoreCase = true here, but that is less
// performant than lower casing desc once above
lowerText.contains(keyword)
}
}) return true
}

// check content description
val contentDescriptions =
node.config.getOrNull(SemanticsProperties.ContentDescription)
if (contentDescriptions != null) {
if (contentDescriptions.any { desc ->
val lowerDesc = desc.lowercase()
sensitiveKeywords.any { keyword ->
// could use ignoreCase = true here, but that is less
// performant than lower casing desc once above
lowerDesc.contains(keyword)
}
}) return true
}

return false
override fun isMatch(target: MaskTarget): Boolean {
return target.isSensitive(sensitiveKeywords)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.launchdarkly.observability.replay

import com.launchdarkly.logging.LDLogger
import com.launchdarkly.observability.coroutines.DispatcherProviderHolder
import com.launchdarkly.observability.interfaces.LDExtendedInstrumentation
import io.opentelemetry.android.instrumentation.InstallationContext
Expand Down Expand Up @@ -68,7 +69,6 @@ class ReplayInstrumentation(
private lateinit var _otelLogger: Logger
private lateinit var _captureSource: CaptureSource
private lateinit var _interactionSource: InteractionSource

private var _captureJob: Job? = null
private var _isPaused: Boolean = false
private val _captureMutex = Mutex()
Expand All @@ -77,7 +77,8 @@ class ReplayInstrumentation(

override fun install(ctx: InstallationContext) {
_otelLogger = ctx.openTelemetry.logsBridge.get(INSTRUMENTATION_SCOPE_NAME)
_captureSource = CaptureSource(ctx.sessionManager, options.privacyProfile.asMatchersList())
val logger = LDLogger()
_captureSource = CaptureSource(ctx.sessionManager, options.privacyProfile.asMatchersList(), logger)
_interactionSource = InteractionSource(ctx.sessionManager)

// TODO: O11Y-621 - don't use global scope
Expand Down
Loading
Loading