Skip to content

Commit abcb38e

Browse files
committed
Merge branch 'develop' into renovate/org.matrix.rustcomponents-sdk-android-25.x
2 parents fe65ba1 + f78c808 commit abcb38e

File tree

27 files changed

+255
-56
lines changed

27 files changed

+255
-56
lines changed

.editorconfig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ ij_smart_tabs = false
1414
ij_visual_guides = none
1515
ij_wrap_on_typing = false
1616

17-
# Ktlint rule, for more information see https://pinterest.github.io/ktlint/1.1.1/faq/#how-do-i-enable-or-disable-a-rule
17+
# Ktlint rule, for more information see https://pinterest.github.io/ktlint/latest/faq/#how-do-i-enable-or-disable-a-rule
1818
ktlint_standard_wrapping = disabled
1919
ktlint_standard_trailing-comma-on-call-site = disabled
2020
ktlint_standard_trailing-comma-on-declaration-site = disabled
@@ -31,6 +31,10 @@ ktlint_function_naming_ignore_when_annotated_with = Composable
3131
ktlint_standard_function-expression-body = disabled
3232
ktlint_standard_chain-method-continuation = disabled
3333
ktlint_standard_class-signature = disabled
34+
# Added when upgrading to 1.8.0
35+
ktlint_standard_when-entry-bracing = disabled
36+
ktlint_standard_blank-line-between-when-conditions = disabled
37+
ktlint_standard_mixed-condition-operators = disabled
3438

3539
[*.java]
3640
ij_java_align_consecutive_assignments = false

appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ import io.element.android.libraries.matrix.api.verification.VerificationRequest
9090
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
9191
import io.element.android.libraries.push.api.notifications.conversations.NotificationConversationService
9292
import io.element.android.libraries.ui.common.nodes.emptyNode
93+
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction
94+
import io.element.android.services.analytics.api.AnalyticsService
9395
import io.element.android.services.appnavstate.api.AppNavigationStateService
9496
import kotlinx.coroutines.CoroutineScope
9597
import kotlinx.coroutines.flow.first
@@ -136,6 +138,7 @@ class LoggedInFlowNode(
136138
private val appPreferencesStore: AppPreferencesStore,
137139
private val buildMeta: BuildMeta,
138140
snackbarDispatcher: SnackbarDispatcher,
141+
private val analyticsService: AnalyticsService,
139142
) : BaseFlowNode<LoggedInFlowNode.NavTarget>(
140143
backstack = BackStack(
141144
initialElement = NavTarget.Placeholder,
@@ -212,6 +215,8 @@ class LoggedInFlowNode(
212215
matrixClient.getMaxFileUploadSize()
213216
}
214217

218+
analyticsService.startLongRunningTransaction(AnalyticsLongRunningTransaction.FirstRoomsDisplayed)
219+
215220
ftueService.state
216221
.onEach { ftueState ->
217222
when (ftueState) {

appnav/src/main/kotlin/io/element/android/appnav/di/SyncOrchestrator.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers
1818
import io.element.android.libraries.core.coroutine.childScope
1919
import io.element.android.libraries.matrix.api.sync.SyncService
2020
import io.element.android.libraries.matrix.api.sync.SyncState
21+
import io.element.android.services.analytics.api.AnalyticsService
22+
import io.element.android.services.analytics.api.recordTransaction
2123
import io.element.android.services.appnavstate.api.AppForegroundStateService
2224
import kotlinx.coroutines.CoroutineScope
2325
import kotlinx.coroutines.FlowPreview
@@ -39,6 +41,7 @@ class SyncOrchestrator(
3941
private val appForegroundStateService: AppForegroundStateService,
4042
private val networkMonitor: NetworkMonitor,
4143
dispatchers: CoroutineDispatchers,
44+
private val analyticsService: AnalyticsService,
4245
) {
4346
@AssistedFactory
4447
interface Factory {
@@ -69,10 +72,13 @@ class SyncOrchestrator(
6972
// Perform an initial sync if the sync service is not running, to check whether the homeserver is accessible
7073
// Otherwise, if the device is offline the sync service will never start and the SyncState will be Idle, not Offline
7174
Timber.tag(tag).d("performing initial sync attempt")
72-
syncService.startSync()
75+
analyticsService.recordTransaction("First sync", "syncService.startSync()") { transaction ->
76+
syncService.startSync()
7377

74-
// Wait until the sync service is not idle, either it will be running or in error/offline state
75-
syncService.syncState.first { it != SyncState.Idle }
78+
// Wait until the sync service is not idle, either it will be running or in error/offline state
79+
val firstState = syncService.syncState.first { it != SyncState.Idle }
80+
transaction.setData("first_sync_state", firstState.name)
81+
}
7682

7783
observeStates()
7884
}

appnav/src/test/kotlin/io/element/android/appnav/SyncOrchestratorTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import io.element.android.features.networkmonitor.api.NetworkStatus
1313
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
1414
import io.element.android.libraries.matrix.api.sync.SyncState
1515
import io.element.android.libraries.matrix.test.sync.FakeSyncService
16+
import io.element.android.services.analytics.test.FakeAnalyticsService
1617
import io.element.android.services.appnavstate.test.FakeAppForegroundStateService
1718
import io.element.android.tests.testutils.WarmUpRule
1819
import io.element.android.tests.testutils.lambda.lambdaRecorder
@@ -390,5 +391,6 @@ class SyncOrchestratorTest {
390391
networkMonitor = networkMonitor,
391392
appForegroundStateService = appForegroundStateService,
392393
dispatchers = testCoroutineDispatchers(),
394+
analyticsService = FakeAnalyticsService(),
393395
)
394396
}

appnav/src/test/kotlin/io/element/android/appnav/di/MatrixSessionCacheTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import io.element.android.libraries.matrix.api.sync.SyncService
1515
import io.element.android.libraries.matrix.test.A_SESSION_ID
1616
import io.element.android.libraries.matrix.test.FakeMatrixClient
1717
import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService
18+
import io.element.android.services.analytics.test.FakeAnalyticsService
1819
import io.element.android.services.appnavstate.test.FakeAppForegroundStateService
1920
import io.element.android.tests.testutils.testCoroutineDispatchers
2021
import kotlinx.coroutines.CoroutineScope
@@ -129,6 +130,7 @@ class MatrixSessionCacheTest {
129130
appForegroundStateService = FakeAppForegroundStateService(),
130131
networkMonitor = FakeNetworkMonitor(),
131132
dispatchers = testCoroutineDispatchers(),
133+
analyticsService = FakeAnalyticsService(),
132134
)
133135
}
134136
}

gradle/libs.versions.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ autoservice = "1.1.1"
6060
# quality
6161
detekt = "1.23.8"
6262
# See https://github.com/pinterest/ktlint/releases/
63-
ktlint = "1.7.1"
63+
ktlint = "1.8.0"
6464
androidx-test-ext-junit = "1.3.0"
6565
kover = "0.9.1"
6666

@@ -141,7 +141,7 @@ accompanist_permission = { module = "com.google.accompanist:accompanist-permissi
141141
squareup_seismic = "com.squareup:seismic:1.0.3"
142142

143143
# network
144-
network_okhttp_bom = "com.squareup.okhttp3:okhttp-bom:5.3.1"
144+
network_okhttp_bom = "com.squareup.okhttp3:okhttp-bom:5.3.2"
145145
network_okhttp_logging = { module = "com.squareup.okhttp3:logging-interceptor" }
146146
network_okhttp_okhttp = { module = "com.squareup.okhttp3:okhttp" }
147147
network_okhttp = { module = "com.squareup.okhttp3:okhttp" }

libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ import io.element.android.libraries.matrix.impl.util.cancelAndDestroy
7676
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
7777
import io.element.android.libraries.matrix.impl.verification.RustSessionVerificationService
7878
import io.element.android.libraries.sessionstorage.api.SessionStore
79+
import io.element.android.services.analytics.api.AnalyticsService
7980
import io.element.android.services.toolbox.api.systemclock.SystemClock
8081
import kotlinx.collections.immutable.ImmutableList
8182
import kotlinx.collections.immutable.persistentListOf
@@ -131,6 +132,7 @@ class RustMatrixClient(
131132
clock: SystemClock,
132133
timelineEventTypeFilterFactory: TimelineEventTypeFilterFactory,
133134
private val featureFlagService: FeatureFlagService,
135+
private val analyticsService: AnalyticsService,
134136
) : MatrixClient {
135137
override val sessionId: UserId = UserId(innerClient.userId())
136138
override val deviceId: DeviceId = DeviceId(innerClient.deviceId())
@@ -178,6 +180,7 @@ class RustMatrixClient(
178180
roomListFactory = RoomListFactory(
179181
innerRoomListService = innerRoomListService,
180182
sessionCoroutineScope = sessionCoroutineScope,
183+
analyticsService = analyticsService,
181184
),
182185
roomSyncSubscriber = roomSyncSubscriber,
183186
)
@@ -212,6 +215,7 @@ class RustMatrixClient(
212215
roomMembershipObserver = roomMembershipObserver,
213216
roomInfoMapper = roomInfoMapper,
214217
featureFlagService = featureFlagService,
218+
analyticsService = analyticsService,
215219
)
216220

217221
override val matrixMediaLoader: MatrixMediaLoader = RustMediaLoader(

libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ class RustMatrixClientFactory(
114114
clock = clock,
115115
timelineEventTypeFilterFactory = timelineEventTypeFilterFactory,
116116
featureFlagService = featureFlagService,
117+
analyticsService = analyticsService,
117118
).also {
118119
Timber.tag(it.toString()).d("Creating Client with access token '$anonymizedAccessToken' and refresh token '$anonymizedRefreshToken'")
119120
}

libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomFactory.kt

Lines changed: 57 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ import io.element.android.libraries.matrix.api.roomlist.RoomListService
2323
import io.element.android.libraries.matrix.api.roomlist.awaitLoaded
2424
import io.element.android.libraries.matrix.impl.room.preview.RoomPreviewInfoMapper
2525
import io.element.android.libraries.matrix.impl.roomlist.roomOrNull
26+
import io.element.android.services.analytics.api.AnalyticsService
27+
import io.element.android.services.analytics.api.recordTransaction
28+
import io.element.android.services.analyticsproviders.api.recordChildTransaction
2629
import io.element.android.services.toolbox.api.systemclock.SystemClock
2730
import kotlinx.coroutines.CoroutineScope
2831
import kotlinx.coroutines.NonCancellable
@@ -54,6 +57,7 @@ class RustRoomFactory(
5457
private val featureFlagService: FeatureFlagService,
5558
private val roomMembershipObserver: RoomMembershipObserver,
5659
private val roomInfoMapper: RoomInfoMapper,
60+
private val analyticsService: AnalyticsService,
5761
) {
5862
private val dispatcher = dispatchers.io.limitedParallelism(1)
5963
private val mutex = Mutex()
@@ -106,48 +110,64 @@ class RustRoomFactory(
106110
Timber.d("Room factory is destroyed, returning null for $roomId")
107111
return@withContext null
108112
}
109-
val sdkRoom = awaitRoomInRoomList(roomId) ?: return@withContext null
113+
114+
val sdkRoom = awaitRoomInRoomList(roomId) ?: return@withLock null
110115

111116
if (sdkRoom.membership() == Membership.JOINED) {
112-
val hideThreadedEvents = featureFlagService.isFeatureEnabled(FeatureFlags.Threads)
113-
// Init the live timeline in the SDK from the Room
114-
val timeline = sdkRoom.timelineWithConfiguration(
115-
TimelineConfiguration(
116-
focus = TimelineFocus.Live(hideThreadedEvents = hideThreadedEvents),
117-
filter = eventFilters?.let(TimelineFilter::EventTypeFilter) ?: TimelineFilter.All,
118-
internalIdPrefix = "live",
119-
dateDividerMode = DateDividerMode.DAILY,
120-
trackReadReceipts = true,
121-
reportUtds = true,
122-
)
123-
)
124-
125-
GetRoomResult.Joined(
126-
JoinedRustRoom(
127-
baseRoom = getBaseRoom(sdkRoom),
128-
notificationSettingsService = notificationSettingsService,
129-
roomContentForwarder = roomContentForwarder,
130-
liveInnerTimeline = timeline,
131-
coroutineDispatchers = dispatchers,
132-
systemClock = systemClock,
133-
featureFlagService = featureFlagService,
117+
analyticsService.recordTransaction(
118+
name = "Get joined room",
119+
operation = "RustRoomFactory.getJoinedRoomOrPreview",
120+
) { transaction ->
121+
val hideThreadedEvents = featureFlagService.isFeatureEnabled(FeatureFlags.Threads)
122+
// Init the live timeline in the SDK from the Room
123+
val timeline = transaction.recordChildTransaction(
124+
operation = "sdkRoom.timelineWithConfiguration",
125+
description = "Get timeline from the SDK",
126+
) {
127+
sdkRoom.timelineWithConfiguration(
128+
TimelineConfiguration(
129+
focus = TimelineFocus.Live(hideThreadedEvents = hideThreadedEvents),
130+
filter = eventFilters?.let(TimelineFilter::EventTypeFilter) ?: TimelineFilter.All,
131+
internalIdPrefix = "live",
132+
dateDividerMode = DateDividerMode.DAILY,
133+
trackReadReceipts = true,
134+
reportUtds = true,
135+
)
136+
)
137+
}
138+
139+
GetRoomResult.Joined(
140+
JoinedRustRoom(
141+
baseRoom = getBaseRoom(sdkRoom),
142+
notificationSettingsService = notificationSettingsService,
143+
roomContentForwarder = roomContentForwarder,
144+
liveInnerTimeline = timeline,
145+
coroutineDispatchers = dispatchers,
146+
systemClock = systemClock,
147+
featureFlagService = featureFlagService,
148+
)
134149
)
135-
)
136-
} else {
137-
val preview = try {
138-
sdkRoom.previewRoom(via = serverNames)
139-
} catch (e: Exception) {
140-
Timber.e(e, "Failed to get room preview for $roomId")
141-
return@withContext null
142150
}
143-
144-
GetRoomResult.NotJoined(
145-
NotJoinedRustRoom(
146-
sessionId = sessionId,
147-
localRoom = getBaseRoom(sdkRoom),
148-
previewInfo = RoomPreviewInfoMapper.map(preview.info()),
151+
} else {
152+
analyticsService.recordTransaction(
153+
name = "Get preview of room",
154+
operation = "RustRoomFactory.getJoinedRoomOrPreview",
155+
) {
156+
val preview = try {
157+
sdkRoom.previewRoom(via = serverNames)
158+
} catch (e: Exception) {
159+
Timber.e(e, "Failed to get room preview for $roomId")
160+
return@recordTransaction null
161+
}
162+
163+
GetRoomResult.NotJoined(
164+
NotJoinedRustRoom(
165+
sessionId = sessionId,
166+
localRoom = getBaseRoom(sdkRoom),
167+
previewInfo = RoomPreviewInfoMapper.map(preview.info()),
168+
)
149169
)
150-
)
170+
}
151171
}
152172
}
153173
}

libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFactory.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import io.element.android.libraries.matrix.api.roomlist.DynamicRoomList
1212
import io.element.android.libraries.matrix.api.roomlist.RoomList
1313
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
1414
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
15+
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction
16+
import io.element.android.services.analytics.api.AnalyticsService
1517
import kotlinx.coroutines.CoroutineScope
1618
import kotlinx.coroutines.flow.MutableSharedFlow
1719
import kotlinx.coroutines.flow.MutableStateFlow
@@ -36,6 +38,7 @@ private val ROOM_LIST_RUST_FILTERS = listOf(
3638
internal class RoomListFactory(
3739
private val innerRoomListService: RoomListService,
3840
private val sessionCoroutineScope: CoroutineScope,
41+
private val analyticsService: AnalyticsService,
3942
) {
4043
private val roomSummaryDetailsFactory: RoomSummaryFactory = RoomSummaryFactory()
4144

@@ -59,6 +62,8 @@ internal class RoomListFactory(
5962
val loadedPages = MutableStateFlow(1)
6063
var innerRoomList: InnerRoomList? = null
6164

65+
val firstRoomsTransaction = analyticsService.startTransaction("Load first set of rooms", "innerRoomList.entriesFlow")
66+
6267
coroutineScope.launch(coroutineContext) {
6368
innerRoomList = innerProvider()
6469
innerRoomList.let { innerRoomList ->
@@ -67,6 +72,10 @@ internal class RoomListFactory(
6772
roomListDynamicEvents = dynamicEvents,
6873
initialFilterKind = RoomListEntriesDynamicFilterKind.All(ROOM_LIST_RUST_FILTERS),
6974
).onEach { update ->
75+
if (!firstRoomsTransaction.isFinished()) {
76+
analyticsService.stopLongRunningTransaction(AnalyticsLongRunningTransaction.FirstRoomsDisplayed)
77+
firstRoomsTransaction.finish()
78+
}
7079
processor.postUpdate(update)
7180
}.launchIn(this)
7281

0 commit comments

Comments
 (0)