Skip to content

Commit

Permalink
recording: fix observation on multiple threads in layout/draw is not …
Browse files Browse the repository at this point in the history
…supported for compose
  • Loading branch information
marandaneto committed Nov 11, 2024
1 parent d9052d0 commit 5254218
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 26 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Next

- recording: fix observation on multiple threads in layout/draw is not supported for compose ([#198](https://github.com/PostHog/posthog-android/pull/198))

## 3.9.0 - 2024-10-30

- recording: add replay masking to jetpack compose views ([#198](https://github.com/PostHog/posthog-android/pull/198))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -607,43 +607,59 @@ public class PostHogReplayIntegration(
view: View,
maskableWidgets: MutableList<Rect>,
) {
try {
val semanticsOwner =
(view as? RootForTest)?.semanticsOwner ?: run {
config.logger.log("View is not a RootForTest: $view")
return
}
val semanticsNodes = semanticsOwner.getAllSemanticsNodes(true)
val latch = CountDownLatch(1)

semanticsNodes.forEach { node ->
val hasText = node.config.contains(SemanticsProperties.Text)
val hasEditableText = node.config.contains(SemanticsProperties.EditableText)
val hasPassword = node.config.contains(SemanticsProperties.Password)
val hasImage = node.config.contains(SemanticsProperties.ContentDescription)
// compose requires the handler to be on the main thread
// see https://github.com/PostHog/posthog-android/issues/203
mainHandler.handler.post {
try {
val semanticsOwner =
(view as? RootForTest)?.semanticsOwner ?: run {
config.logger.log("View is not a RootForTest: $view")
return@post
}
val semanticsNodes = semanticsOwner.getAllSemanticsNodes(true)

val hasMaskModifier = node.config.contains(PostHogReplayMask)
val isNoCapture = hasMaskModifier && node.config[PostHogReplayMask]
semanticsNodes.forEach { node ->
val hasText = node.config.contains(SemanticsProperties.Text)
val hasEditableText = node.config.contains(SemanticsProperties.EditableText)
val hasPassword = node.config.contains(SemanticsProperties.Password)
val hasImage = node.config.contains(SemanticsProperties.ContentDescription)

when {
isNoCapture -> {
maskableWidgets.add(node.boundsInWindow.toRect())
}
val hasMaskModifier = node.config.contains(PostHogReplayMask)
val isNoCapture = hasMaskModifier && node.config[PostHogReplayMask]

!hasMaskModifier -> {
when {
(hasText || hasEditableText) && (config.sessionReplayConfig.maskAllTextInputs || hasPassword) -> {
maskableWidgets.add(node.boundsInWindow.toRect())
}
when {
isNoCapture -> {
maskableWidgets.add(node.boundsInWindow.toRect())
}

hasImage && config.sessionReplayConfig.maskAllImages -> {
maskableWidgets.add(node.boundsInWindow.toRect())
!hasMaskModifier -> {
when {
(hasText || hasEditableText) && (config.sessionReplayConfig.maskAllTextInputs || hasPassword) -> {
maskableWidgets.add(node.boundsInWindow.toRect())
}

hasImage && config.sessionReplayConfig.maskAllImages -> {
maskableWidgets.add(node.boundsInWindow.toRect())
}
}
}
}
}
} catch (e: Throwable) {
// swallow possible errors due to compose versioning, etc
config.logger.log("Session Replay findMaskableComposeWidgets (main thread) failed: $e")
} finally {
latch.countDown()
}
}

try {
// await for 1s max
latch.await(1000, TimeUnit.MILLISECONDS)
config.logger.log("test")
} catch (e: Throwable) {
// swallow possible errors due to compose versioning, etc
config.logger.log("Session Replay findMaskableComposeWidgets failed: $e")
}
}
Expand Down

0 comments on commit 5254218

Please sign in to comment.