@@ -22,10 +22,7 @@ import io.sentry.protocol.TransactionNameSource
2222import io.sentry.util.IntegrationUtils.addIntegrationToSdkVersion
2323import java.lang.ref.WeakReference
2424
25- private const val BACKSTACK_KEY = " backstack"
26- private const val NAVIGATION_CONTEXT_KEY = " navigation"
2725private const val NAVIGATION_OP : String = " navigation"
28- private const val TRANSACTION_ORIGIN = " auto.navigation.nav3"
2926
3027/* *
3128 * Observes the back stack managed by a single [SentryNavEffect] and records Sentry state as the
@@ -61,7 +58,7 @@ internal class BackStackObserver<T : Any>(
6158
6259 private val routeTranslator = RouteTranslator (extractors, scopes.options.logger)
6360
64- private val navTransaction = NavTransaction (scopes, NAVIGATION_OP , TRANSACTION_ORIGIN )
61+ private val navTransaction = NavTransaction (scopes)
6562 private val navContext = NavContext (scopes, options)
6663 private val navScreen = NavScreen ()
6764 private val navBreadcrumbs = NavBreadcrumbs (scopes)
@@ -127,7 +124,7 @@ internal class BackStackObserver<T : Any>(
127124 // replaces one observer with another, there may be a brief gap where events lack nav
128125 // context. Apps should keep the observer at the nav root so cleanup only runs when the
129126 // navigation session is ending, not during normal destination changes.
130- navContext.update (scope, emptyList() )
127+ navContext.clear (scope)
131128 }
132129 }
133130 }
@@ -147,15 +144,8 @@ internal class BackStackObserver<T : Any>(
147144 when (change) {
148145 is BackStackIsEmpty -> handleEmptyBackStack(scope)
149146
150- is BackStackHasNewTop -> {
151- handleNewTop(scope, change.previousTop, change.backStack)
152- storeAsPreviousTop(change.backStack.topEntry, change.backStack.topRoute)
153- }
154-
155- is BackStackHasSameTop -> {
156- handleSameTop(scope, change.backStack)
157- storeAsPreviousTop(change.backStack.topEntry, change.backStack.topRoute)
158- }
147+ is BackStackHasNewTop -> handleNewTop(scope, change.previousTop, change.backStack)
148+ is BackStackHasSameTop -> handleSameTop(scope, change.backStack)
159149 }
160150 }
161151
@@ -230,24 +220,31 @@ internal class BackStackObserver<T : Any>(
230220 // Rotate the propagation context.
231221 scope.withPropagationContext { scope.setPropagationContext(PropagationContext ()) }
232222 }
223+
224+ storeAsPreviousTop(currentBackStack.topEntry, currentBackStack.topRoute)
233225 }
234226
235227 private fun handleSameTop (scope : IScope , backStack : BackStackData <T >) {
236228 navContext.update(scope, backStack.capturedRoutes)
229+ storeAsPreviousTop(backStack.topEntry, backStack.topRoute)
237230 }
238231
239232 private fun handleEmptyBackStack (scope : IScope ) {
240233 navTransaction.stop(scope)
234+ navContext.clear(scope)
241235 navScreen.clear(scope)
242- navContext.update(scope, emptyList())
243- previousTopEntry = null
244- previousTopRoute = null
236+ clearPreviousTop()
245237 }
246238
247239 private fun storeAsPreviousTop (topEntry : T , topRoute : Route ) {
248240 previousTopEntry = WeakReference (topEntry)
249241 previousTopRoute = topRoute
250242 }
243+
244+ private fun clearPreviousTop () {
245+ previousTopEntry = null
246+ previousTopRoute = null
247+ }
251248}
252249
253250/* *
@@ -287,27 +284,27 @@ private data class BackStackData<T>(
287284)
288285
289286/* * A helper class for managing nav transactions. */
290- private class NavTransaction (
291- private val scopes : IScopes ,
292- private val navigationOp : String ,
293- private val transactionOrigin : String ,
294- ) {
287+ private class NavTransaction (private val scopes : IScopes ) {
288+
289+ private companion object {
290+ private const val TRANSACTION_ORIGIN = " auto.navigation.nav3 "
291+ }
295292
296293 private var activeNavTransaction: ITransaction ? = null
297294
298295 /* * Starts an idle navigation transaction, or no-ops if another transaction is already active. */
299296 fun start (
300297 scope : IScope ,
301- routeName : String ,
298+ name : String ,
302299 arguments : Map <String , Any ?>,
303300 ): ITransaction ? {
304- clearFinishedScopeTransaction (scope)
301+ clearTransactionIfFinished (scope)
305302
306303 if (scope.transaction != null ) {
307304 scopes.options.logger.log(
308305 DEBUG ,
309306 " Nav3 transaction for route %s won't be created because another transaction is active." ,
310- routeName ,
307+ name ,
311308 )
312309
313310 return null
@@ -320,12 +317,12 @@ private class NavTransaction(
320317 val deadlineTimeoutMillis = scopes.options.deadlineTimeout
321318 it.deadlineTimeout = if (deadlineTimeoutMillis <= 0 ) null else deadlineTimeoutMillis
322319 it.isTrimEnd = true
323- it.origin = transactionOrigin
320+ it.origin = TRANSACTION_ORIGIN
324321 }
325322
326323 val transaction =
327324 scopes.startTransaction(
328- TransactionContext (routeName , TransactionNameSource .ROUTE , navigationOp ),
325+ TransactionContext (name , TransactionNameSource .ROUTE , NAVIGATION_OP ),
329326 transactionOptions,
330327 )
331328
@@ -362,7 +359,7 @@ private class NavTransaction(
362359 }
363360
364361 /* * Clears a stale finished transaction that's still bound to the default scope. */
365- private fun clearFinishedScopeTransaction (scope : IScope ) {
362+ private fun clearTransactionIfFinished (scope : IScope ) {
366363 scope.withTransaction { tx ->
367364 if (tx?.isFinished == true ) {
368365 scope.clearTransaction()
@@ -374,12 +371,24 @@ private class NavTransaction(
374371/* * A helper class for updating [nav context][NAVIGATION_CONTEXT_KEY]. */
375372private class NavContext (private val scopes : IScopes , private val options : SentryNavOptions ) {
376373
374+ private companion object {
375+ private const val BACKSTACK_KEY = " backstack"
376+ private const val NAVIGATION_CONTEXT_KEY = " navigation"
377+ }
378+
377379 fun update (scope : IScope , backStackRoutes : List <Route >) {
378380 if (backStackRoutes.isEmpty()) {
379- removeNavContext(scope)
380- } else {
381- scope.setContexts(NAVIGATION_CONTEXT_KEY , backStackRoutes.toNavigationContext())
381+ clear(scope)
382+ return
382383 }
384+
385+ scope.setContexts(NAVIGATION_CONTEXT_KEY , backStackRoutes.toBackStackMap())
386+ }
387+
388+ fun clear (scope : IScope ) {
389+ // We purposefully don't call IScope.removeContexts(), as it doesn't notify IScopeObserver and
390+ // therefore doesn't write its updates to disk ¯\_ (ツ)_/¯.
391+ scope.setContexts(NAVIGATION_CONTEXT_KEY , null as Any? )
383392 }
384393
385394 /* *
@@ -405,19 +414,12 @@ private class NavContext(private val scopes: IScopes, private val options: Sentr
405414 }
406415
407416 if (options.captureBackStack && backStack.capturedRoutes.isNotEmpty()) {
408- transaction.setContext(NAVIGATION_CONTEXT_KEY , backStack.capturedRoutes.toNavigationContext ())
417+ transaction.setContext(NAVIGATION_CONTEXT_KEY , backStack.capturedRoutes.toBackStackMap ())
409418 }
410419 }
411420
412- private fun removeNavContext (scope : IScope ) {
413- // We purposefully don't call IScope.removeContexts(), as it doesn't notify IScopeObserver and
414- // therefore doesn't write its updates to disk ¯\_ (ツ)_/¯.
415- scope.setContexts(NAVIGATION_CONTEXT_KEY , null as Any? )
416- }
417-
418421 /* * Builds the `{"backstack": [...]}` map bound under [NAVIGATION_CONTEXT_KEY]. */
419- private fun List<Route>.toNavigationContext (): Map <String , Any ?> =
420- mapOf (BACKSTACK_KEY to serialize())
422+ private fun List<Route>.toBackStackMap (): Map <String , Any ?> = mapOf (BACKSTACK_KEY to serialize())
421423}
422424
423425/* * A helper class for updating the tracked screen name. */
0 commit comments