diff --git a/CHANGELOG.md b/CHANGELOG.md index 35aa59686f..ff12eb68b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ - Remove `AndroidRuntimeManager` StrictMode relaxation to prevent ANRs during SDK init ([#5127](https://github.com/getsentry/sentry-java/pull/5127)) - Fix crash when unregistering `SystemEventsBroadcastReceiver` with try-catch block. ([#5106](https://github.com/getsentry/sentry-java/pull/5106)) +- Use `peekDecorView` instead of `getDecorView` in `SentryGestureListener` to avoid forcing view hierarchy construction ([#5134](https://github.com/getsentry/sentry-java/pull/5134)) - Log an actionable error message when Relay returns HTTP 413 (Content Too Large) ([#5115](https://github.com/getsentry/sentry-java/pull/5115)) - Also switch the client report discard reason for all HTTP 4xx/5xx errors (except 429) from `network_error` to `send_error` - Trim DSN string before parsing to avoid `URISyntaxException` caused by trailing whitespace ([#5113](https://github.com/getsentry/sentry-java/pull/5113)) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/gestures/SentryGestureListener.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/gestures/SentryGestureListener.java index cd89db72f5..8caffedad9 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/gestures/SentryGestureListener.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/gestures/SentryGestureListener.java @@ -347,7 +347,7 @@ void applyScope(final @NotNull IScope scope, final @NotNull ITransaction transac return null; } - final View decorView = window.getDecorView(); + final View decorView = window.peekDecorView(); if (decorView == null) { options .getLogger() diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/internal/gestures/SentryGestureListenerPeekDecorViewTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/internal/gestures/SentryGestureListenerPeekDecorViewTest.kt new file mode 100644 index 0000000000..7b26aa55c7 --- /dev/null +++ b/sentry-android-core/src/test/java/io/sentry/android/core/internal/gestures/SentryGestureListenerPeekDecorViewTest.kt @@ -0,0 +1,48 @@ +package io.sentry.android.core.internal.gestures + +import android.app.Activity +import android.view.MotionEvent +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.sentry.Breadcrumb +import io.sentry.IScopes +import io.sentry.android.core.SentryAndroidOptions +import io.sentry.util.LazyEvaluator +import kotlin.test.Test +import kotlin.test.assertNull +import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.verify +import org.robolectric.Robolectric.buildActivity + +@RunWith(AndroidJUnit4::class) +class SentryGestureListenerPeekDecorViewTest { + + @Test + fun `does not force decor view creation when peekDecorView returns null`() { + // A plain Activity that never calls setContentView — peekDecorView() should return null + val activity = buildActivity(Activity::class.java).create().get() + + // Sanity check: decor view has not been created yet + assertNull(activity.window.peekDecorView()) + + val scopes = mock() + val options = + SentryAndroidOptions().apply { + isEnableUserInteractionBreadcrumbs = true + gestureTargetLocators = listOf(AndroidViewGestureTargetLocator(LazyEvaluator { true })) + dsn = "https://key@sentry.io/proj" + } + + val sut = SentryGestureListener(activity, scopes, options) + sut.onSingleTapUp(mock()) + + // The key assertion: peekDecorView is still null — we did not force view hierarchy creation + assertNull(activity.window.peekDecorView()) + + // And no breadcrumb was captured + verify(scopes, never()).addBreadcrumb(any(), anyOrNull()) + } +} diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/internal/gestures/ViewHelpers.kt b/sentry-android-core/src/test/java/io/sentry/android/core/internal/gestures/ViewHelpers.kt index 86123d0a3a..1a4f28bbe3 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/internal/gestures/ViewHelpers.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/internal/gestures/ViewHelpers.kt @@ -22,7 +22,7 @@ internal inline fun Window.mockDecorView( finalize: (T) -> Unit = {}, ): T { val view = mockView(id, event, touchWithinBounds, clickable, visible, context, finalize) - whenever(decorView).doReturn(view) + whenever(peekDecorView()).doReturn(view) return view }