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 (#204)
  • Loading branch information
marandaneto authored Nov 11, 2024
1 parent d9052d0 commit 2d99605
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 30 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 ([#204](https://github.com/PostHog/posthog-android/pull/204))

## 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
8 changes: 4 additions & 4 deletions posthog-android/lint-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<issue
id="GradleDependency"
message="A newer version of androidx.lifecycle:lifecycle-process than 2.6.2 is available: 2.8.6"
message="A newer version of androidx.lifecycle:lifecycle-process than 2.6.2 is available: 2.8.7"
errorLine1=" implementation(&quot;androidx.lifecycle:lifecycle-process:${PosthogBuildConfig.Dependencies.LIFECYCLE}&quot;)"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
Expand All @@ -14,7 +14,7 @@

<issue
id="GradleDependency"
message="A newer version of androidx.lifecycle:lifecycle-common-java8 than 2.6.2 is available: 2.8.6"
message="A newer version of androidx.lifecycle:lifecycle-common-java8 than 2.6.2 is available: 2.8.7"
errorLine1=" implementation(&quot;androidx.lifecycle:lifecycle-common-java8:${PosthogBuildConfig.Dependencies.LIFECYCLE}&quot;)"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
Expand All @@ -25,7 +25,7 @@

<issue
id="GradleDependency"
message="A newer version of androidx.core:core than 1.5.0 is available: 1.13.1"
message="A newer version of androidx.core:core than 1.5.0 is available: 1.15.0"
errorLine1=" implementation(&quot;androidx.core:core:${PosthogBuildConfig.Dependencies.ANDROIDX_CORE}&quot;)"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
Expand All @@ -36,7 +36,7 @@

<issue
id="GradleDependency"
message="A newer version of androidx.compose.ui:ui than 1.0.0 is available: 1.7.4"
message="A newer version of androidx.compose.ui:ui than 1.0.0 is available: 1.7.5"
errorLine1=" compileOnly(&quot;androidx.compose.ui:ui:${PosthogBuildConfig.Dependencies.ANDROIDX_COMPOSE}&quot;)"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -607,43 +607,58 @@ 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)
} 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 2d99605

Please sign in to comment.