diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/nav3/Nav3Activity.kt b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/nav3/Nav3Activity.kt index e90e27573a..449ac2b299 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/nav3/Nav3Activity.kt +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/nav3/Nav3Activity.kt @@ -92,11 +92,10 @@ class Nav3Activity : ComponentActivity() { configuration.applyToCurrentOptions() showActivityUiLoadTransactionDelayMessage = configuration.hasOnlyActivityUiLoadTransactions - if (!configuration.enableActivityUiLoadTransaction) { - // Cancel the already-started Activity transaction before Compose installs SentryNavEffect, - // otherwise the initial /Landing route transaction gets preempted by the lingering ui.load. - cancelCurrentActivityUiLoadTransaction() - } + // When the toggle is off, cancel the already-started Activity transaction before Compose + // installs SentryNavEffect, otherwise the lingering ui.load preempts the initial /Landing route + // transaction. + applyActivityUiLoadTransactionSetting(this, configuration.enableActivityUiLoadTransaction) NavigationTransactionHistory.install() diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/nav3/Nav3MultiActivity.kt b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/nav3/Nav3MultiActivity.kt index 5e6ca0b9d0..e3c92bf8d7 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/nav3/Nav3MultiActivity.kt +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/nav3/Nav3MultiActivity.kt @@ -89,9 +89,7 @@ class Nav3ProductsActivity : ComponentActivity() { super.onCreate(savedInstanceState) val configuration = (intent.extras ?: Bundle()).nav3SampleConfiguration() NavigationTransactionHistory.install() - if (!configuration.enableActivityUiLoadTransaction) { - cancelCurrentActivityUiLoadTransaction() - } + applyActivityUiLoadTransactionSetting(this, configuration.enableActivityUiLoadTransaction) setContent { val stack = rememberSaveableNav3BackStack(Nav3Route.ProductList) SideEffect { @@ -174,9 +172,7 @@ open class Nav3CheckoutActivity : ComponentActivity() { val crashOnFirstComposition = savedInstanceState == null && intent.getBooleanExtra(EXTRA_CRASH_ON_FIRST_COMPOSITION, false) NavigationTransactionHistory.install() - if (!configuration.enableActivityUiLoadTransaction) { - cancelCurrentActivityUiLoadTransaction() - } + applyActivityUiLoadTransactionSetting(this, configuration.enableActivityUiLoadTransaction) setContent { Nav3SampleTheme { if (showAsSheet) { diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/nav3/Nav3MultiFragment.kt b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/nav3/Nav3MultiFragment.kt index 846344103c..d95be37b4a 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/nav3/Nav3MultiFragment.kt +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/nav3/Nav3MultiFragment.kt @@ -76,9 +76,7 @@ class Nav3FragmentsActivity : FragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) NavigationTransactionHistory.install() - if (!configuration.enableActivityUiLoadTransaction) { - cancelCurrentActivityUiLoadTransaction() - } + applyActivityUiLoadTransactionSetting(this, configuration.enableActivityUiLoadTransaction) val controls = ComposeView(this).apply { diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/nav3/Nav3SampleTracing.kt b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/nav3/Nav3SampleTracing.kt index a23ed37c3f..9b266f52b9 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/nav3/Nav3SampleTracing.kt +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/navigation/nav3/Nav3SampleTracing.kt @@ -1,8 +1,12 @@ package io.sentry.samples.android.navigation.nav3 +import android.app.Activity +import io.sentry.EventProcessor +import io.sentry.Hint import io.sentry.Sentry import io.sentry.SpanStatus import io.sentry.protocol.SentryTransaction +import java.util.concurrent.ConcurrentHashMap import kotlin.coroutines.resume import kotlinx.coroutines.suspendCancellableCoroutine @@ -21,6 +25,50 @@ internal fun SentryTransaction.navigationSampleScenarioLabel(): String = ?: getTag(NAV3_SCENARIO_TAG) ?: UNKNOWN_NAVIGATION_SCENARIO_LABEL +/** + * Applies the sample's "Activity ui.load transaction" toggle to [activity]. + * + * Call from `onCreate` after `super.onCreate`, once the SDK has started the Activity's ui.load + * transaction. When [enabled] is false, the transaction is cancelled if it's bound to the scope. + * It's also dropped before sending, because the SDK doesn't bind it when another transaction (such + * as the previous Activity's nav transaction) is already bound, and the sample can't reach an + * unbound ui.load transaction to cancel it. + */ +internal fun applyActivityUiLoadTransactionSetting(activity: Activity, enabled: Boolean) { + // Matches the transaction name ActivityLifecycleIntegration uses. + val activityName = activity.javaClass.simpleName + if (enabled) { + SuppressedActivityUiLoadTransactions.activityNames.remove(activityName) + return + } + SuppressedActivityUiLoadTransactions.install() + SuppressedActivityUiLoadTransactions.activityNames.add(activityName) + cancelCurrentActivityUiLoadTransaction() +} + +/** Drops ui.load transactions for sample Activities created with the ui.load toggle off. */ +private object SuppressedActivityUiLoadTransactions : EventProcessor { + val activityNames: MutableSet = ConcurrentHashMap.newKeySet() + + @Volatile private var installed = false + + fun install() { + if (installed) return + synchronized(this) { + if (installed) return + Sentry.getCurrentScopes().options.addEventProcessor(this) + installed = true + } + } + + override fun process(transaction: SentryTransaction, hint: Hint): SentryTransaction? { + val isSuppressed = + transaction.contexts.trace?.operation == ACTIVITY_UI_LOAD_OP && + transaction.transaction in activityNames + return if (isSuppressed) null else transaction + } +} + internal fun cancelCurrentActivityUiLoadTransaction() { Sentry.configureScope { scope -> scope.withTransaction { transaction ->