From 5f709b77679f0f050edc84ee5a398fa2751504dd Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Fri, 25 Oct 2024 09:47:00 +0200 Subject: [PATCH 1/3] recording: fix crash when calling view.isVisible --- CHANGELOG.md | 5 ++ .../replay/PostHogReplayIntegration.kt | 52 ++++++++++++++----- .../replay/PostHogSessionReplayConfig.kt | 5 +- 3 files changed, 46 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 165fffd4..ab3e7b1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## Next +## 3.8.3 - 2024-10-25 + +- recording: fix crash when calling view.isVisible ([#197](https://github.com/PostHog/posthog-android/pull/197)) +- recording: change debouncerDelayMs default from 500ms to 1000ms (1s) ([#197](https://github.com/PostHog/posthog-android/pull/197)) + ## 3.8.2 - 2024-10-14 - recording: session replay respect feature flag variants ([#197](https://github.com/PostHog/posthog-android/pull/197)) diff --git a/posthog-android/src/main/java/com/posthog/android/replay/PostHogReplayIntegration.kt b/posthog-android/src/main/java/com/posthog/android/replay/PostHogReplayIntegration.kt index 70488127..93aa559c 100644 --- a/posthog-android/src/main/java/com/posthog/android/replay/PostHogReplayIntegration.kt +++ b/posthog-android/src/main/java/com/posthog/android/replay/PostHogReplayIntegration.kt @@ -7,6 +7,7 @@ import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint +import android.graphics.Point import android.graphics.PorterDuff import android.graphics.Rect import android.graphics.RectF @@ -30,9 +31,7 @@ import android.view.MotionEvent import android.view.PixelCopy import android.view.View import android.view.ViewGroup -import android.view.ViewStub import android.view.Window -import android.view.accessibility.AccessibilityNodeInfo import android.webkit.WebView import android.widget.Button import android.widget.CheckBox @@ -460,20 +459,45 @@ public class PostHogReplayIntegration( status.lastSnapshot = wireframe } + /** + * Adapted from https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/core/java/android/view/View.java;l=11620;bpv=0;bpt=1 + */ private fun View.isVisible(): Boolean { - // TODO: also check for getGlobalVisibleRect intersects the display - val visible = isShown && width >= 0 && height >= 0 && this !is ViewStub - - // Between API 16 and API 29, this method may incorrectly return false when magnification - // is enabled. On other versions, a node is considered visible even if it is not on - // the screen because magnification is active. - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) { - return visible - } + try { + if (isAttachedToWindow) { + // Attached to invisible window means this view is not visible. + if (windowVisibility != View.VISIBLE) { + return false + } + // An invisible predecessor or one with alpha zero means + // that this view is not visible to the user. + var current: Any? = this + while (current is View) { + val view = current + val transitionAlpha = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) view.transitionAlpha else 1f + // We have attach info so this view is attached and there is no + // need to check whether we reach to ViewRootImpl on the way up. + if (view.alpha <= 0 || transitionAlpha <= 0 || view.visibility != View.VISIBLE) { + return false + } + current = view.parent + } + // Check if the view is entirely covered by its predecessors. + val visibleRect = Rect() + val offset = Point() - val nodeInfo = AccessibilityNodeInfo() - onInitializeAccessibilityNodeInfo(nodeInfo) - return visible && nodeInfo.isVisibleToUser + return getGlobalVisibleRect(visibleRect, offset) + + // TODO: also check for getGlobalVisibleRect intersects the display +// if (boundInView != null) { +// visibleRect.offset(-offset.x, -offset.y) +// return boundInView.intersect(visibleRect) +// } + } + } catch (e: Throwable) { + config.logger.log("Session Replay isVisible failed: $e.") + } + return false } private fun Drawable.shouldMaskDrawable(): Boolean { diff --git a/posthog-android/src/main/java/com/posthog/android/replay/PostHogSessionReplayConfig.kt b/posthog-android/src/main/java/com/posthog/android/replay/PostHogSessionReplayConfig.kt index a94ea35f..a6d113b0 100644 --- a/posthog-android/src/main/java/com/posthog/android/replay/PostHogSessionReplayConfig.kt +++ b/posthog-android/src/main/java/com/posthog/android/replay/PostHogSessionReplayConfig.kt @@ -44,8 +44,9 @@ public class PostHogSessionReplayConfig * Deboucer delay used to reduce the number of snapshots captured and reduce performance impact * This is used for capturing the view as a wireframe or screenshot * The lower the number more snapshots will be captured but higher the performance impact - * Defaults to 500ms + * Defaults to 1000ms = 1s + * Ps: it was 500ms by default until version 3.8.2 */ @PostHogExperimental - public var debouncerDelayMs: Long = 500, + public var debouncerDelayMs: Long = 1000, ) From 1105b5259ac70d801f7e0c64301eb7bcf8cdca35 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Fri, 25 Oct 2024 09:48:13 +0200 Subject: [PATCH 2/3] fix --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab3e7b1e..995fe2f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,8 @@ ## 3.8.3 - 2024-10-25 -- recording: fix crash when calling view.isVisible ([#197](https://github.com/PostHog/posthog-android/pull/197)) -- recording: change debouncerDelayMs default from 500ms to 1000ms (1s) ([#197](https://github.com/PostHog/posthog-android/pull/197)) +- recording: fix crash when calling view.isVisible ([#201](https://github.com/PostHog/posthog-android/pull/201)) +- recording: change debouncerDelayMs default from 500ms to 1000ms (1s) ([#201](https://github.com/PostHog/posthog-android/pull/201)) ## 3.8.2 - 2024-10-14 From 5de905e47c396abb332926992d04816876bbc67d Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Fri, 25 Oct 2024 10:03:50 +0200 Subject: [PATCH 3/3] fix --- .../java/com/posthog/android/replay/PostHogReplayIntegration.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/posthog-android/src/main/java/com/posthog/android/replay/PostHogReplayIntegration.kt b/posthog-android/src/main/java/com/posthog/android/replay/PostHogReplayIntegration.kt index 93aa559c..bee459c7 100644 --- a/posthog-android/src/main/java/com/posthog/android/replay/PostHogReplayIntegration.kt +++ b/posthog-android/src/main/java/com/posthog/android/replay/PostHogReplayIntegration.kt @@ -496,6 +496,8 @@ public class PostHogReplayIntegration( } } catch (e: Throwable) { config.logger.log("Session Replay isVisible failed: $e.") + // if there's an exception, we just return true otherwise we might miss some views + return true } return false }