Add AnalyticsService.cancelLongRunningTransaction and AnalyticsService.finishLongRunningTransaction

This commit is contained in:
Jorge Martín 2025-11-27 12:27:49 +01:00 committed by Jorge Martin Espinosa
parent 1d77aa447d
commit 1c576fd42d
7 changed files with 37 additions and 9 deletions

View file

@ -49,6 +49,7 @@ import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.LoadMessagesUi import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.LoadMessagesUi
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.OpenRoom import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.OpenRoom
import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.analytics.api.finishLongRunningTransaction
import io.element.android.services.appnavstate.api.ActiveRoomsHolder import io.element.android.services.appnavstate.api.ActiveRoomsHolder
import io.element.android.services.appnavstate.api.AppNavigationStateService import io.element.android.services.appnavstate.api.AppNavigationStateService
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -107,7 +108,7 @@ class JoinedRoomLoadedFlowNode(
trackVisitedRoom() trackVisitedRoom()
}, },
onResume = { onResume = {
analyticsService.removeLongRunningTransaction(LoadJoinedRoomFlow)?.finish() analyticsService.finishLongRunningTransaction(LoadJoinedRoomFlow)
sessionCoroutineScope.launch { sessionCoroutineScope.launch {
inputs.room.subscribeToSync() inputs.room.subscribeToSync()
} }

View file

@ -70,6 +70,7 @@ import io.element.android.libraries.mediaplayer.api.MediaPlayer
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.LoadMessagesUi import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.LoadMessagesUi
import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.analytics.api.finishLongRunningTransaction
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -138,7 +139,7 @@ class MessagesNode(
sessionCoroutineScope.launch { analyticsService.capture(room.toAnalyticsViewRoom()) } sessionCoroutineScope.launch { analyticsService.capture(room.toAnalyticsViewRoom()) }
}, },
onResume = { onResume = {
analyticsService.removeLongRunningTransaction(LoadMessagesUi)?.finish() analyticsService.finishLongRunningTransaction(LoadMessagesUi)
}, },
onDestroy = { onDestroy = {
mediaPlayer.close() mediaPlayer.close()

View file

@ -59,6 +59,7 @@ import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.NotificationTapOpensTimeline import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.NotificationTapOpensTimeline
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.OpenRoom import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.OpenRoom
import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.analytics.api.finishLongRunningTransaction
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -239,9 +240,9 @@ class TimelinePresenter(
timelineItems = newTimelineItems timelineItems = newTimelineItems
analyticsService.run { analyticsService.run {
removeLongRunningTransaction(DisplayFirstTimelineItems)?.finish() finishLongRunningTransaction(DisplayFirstTimelineItems)
removeLongRunningTransaction(OpenRoom)?.finish() finishLongRunningTransaction(OpenRoom)
removeLongRunningTransaction(NotificationTapOpensTimeline)?.finish() finishLongRunningTransaction(NotificationTapOpensTimeline)
} }
} }
.launchIn(this) .launchIn(this)

View file

@ -14,6 +14,7 @@ import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction
import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.analytics.api.finishLongRunningTransaction
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@ -73,7 +74,7 @@ internal class RoomListFactory(
initialFilterKind = RoomListEntriesDynamicFilterKind.All(ROOM_LIST_RUST_FILTERS), initialFilterKind = RoomListEntriesDynamicFilterKind.All(ROOM_LIST_RUST_FILTERS),
).onEach { update -> ).onEach { update ->
if (!firstRoomsTransaction.isFinished()) { if (!firstRoomsTransaction.isFinished()) {
analyticsService.removeLongRunningTransaction(AnalyticsLongRunningTransaction.FirstRoomsDisplayed)?.finish() analyticsService.finishLongRunningTransaction(AnalyticsLongRunningTransaction.FirstRoomsDisplayed)
firstRoomsTransaction.finish() firstRoomsTransaction.finish()
} }
processor.postUpdate(update) processor.postUpdate(update)

View file

@ -89,3 +89,24 @@ inline fun <T> AnalyticsService.recordTransaction(
transaction.finish() transaction.finish()
} }
} }
/**
* Cancels a long running transaction. It behaves the same as [AnalyticsService.removeLongRunningTransaction],
* but it doesn't return the transaction so we can't finish it later.
*/
fun AnalyticsService.cancelLongRunningTransaction(
longRunningTransaction: AnalyticsLongRunningTransaction
) = removeLongRunningTransaction(longRunningTransaction)
/**
* Finishes a long running transaction if it exists. Optionally performs an [action] with the transaction before finishing it.
*/
fun AnalyticsService.finishLongRunningTransaction(
longRunningTransaction: AnalyticsLongRunningTransaction,
action: (AnalyticsTransaction) -> Unit = {},
) {
removeLongRunningTransaction(longRunningTransaction)?.let {
action(it)
it.finish()
}
}

View file

@ -13,6 +13,8 @@ import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.di.annotations.AppCoroutineScope
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction
import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.analytics.api.cancelLongRunningTransaction
import io.element.android.services.analytics.api.finishLongRunningTransaction
import io.element.android.services.analytics.api.watchers.AnalyticsColdStartWatcher import io.element.android.services.analytics.api.watchers.AnalyticsColdStartWatcher
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.catch
@ -47,7 +49,7 @@ class DefaultAnalyticsColdStartWatcher(
override fun whenLoggingIn() { override fun whenLoggingIn() {
if (isColdStart.getAndSet(false)) { if (isColdStart.getAndSet(false)) {
analyticsService.removeLongRunningTransaction(AnalyticsLongRunningTransaction.ColdStartUntilCachedRoomList) analyticsService.cancelLongRunningTransaction(AnalyticsLongRunningTransaction.ColdStartUntilCachedRoomList)
Timber.d("Canceled cold start check: user is logging in") Timber.d("Canceled cold start check: user is logging in")
} }
} }
@ -55,7 +57,7 @@ class DefaultAnalyticsColdStartWatcher(
override fun onRoomListVisible() { override fun onRoomListVisible() {
if (isColdStart.getAndSet(false)) { if (isColdStart.getAndSet(false)) {
Timber.d("Room list is visible, finishing cold start check") Timber.d("Room list is visible, finishing cold start check")
analyticsService.removeLongRunningTransaction(AnalyticsLongRunningTransaction.ColdStartUntilCachedRoomList)?.finish() analyticsService.finishLongRunningTransaction(AnalyticsLongRunningTransaction.ColdStartUntilCachedRoomList)
} }
} }
} }

View file

@ -16,6 +16,7 @@ import io.element.android.libraries.di.annotations.SessionCoroutineScope
import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction
import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.analytics.api.finishLongRunningTransaction
import io.element.android.services.analytics.api.watchers.AnalyticsRoomListStateWatcher import io.element.android.services.analytics.api.watchers.AnalyticsRoomListStateWatcher
import io.element.android.services.appnavstate.api.AppNavigationStateService import io.element.android.services.appnavstate.api.AppNavigationStateService
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -63,7 +64,7 @@ class DefaultAnalyticsRoomListStateWatcher(
roomListService.state roomListService.state
.onEach { state -> .onEach { state ->
if (state == RoomListService.State.Running && isWarmState.get()) { if (state == RoomListService.State.Running && isWarmState.get()) {
analyticsService.removeLongRunningTransaction(AnalyticsLongRunningTransaction.ResumeAppUntilNewRoomsReceived)?.finish() analyticsService.finishLongRunningTransaction(AnalyticsLongRunningTransaction.ResumeAppUntilNewRoomsReceived)
} }
} }
.launchIn(coroutineScope) .launchIn(coroutineScope)