diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt index c3a79acb81..5006218bda 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -60,7 +60,6 @@ import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.MAIN_SPACE import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.api.sync.StartSyncReason import io.element.android.libraries.matrix.api.sync.SyncState import io.element.android.libraries.push.api.notifications.NotificationDrawerManager import io.element.android.services.appnavstate.api.AppNavigationStateService @@ -125,7 +124,7 @@ class LoggedInFlowNode @AssistedInject constructor( onStop = { //Counterpart startSync is done in observeSyncStateAndNetworkStatus method. coroutineScope.launch { - syncService.stopSync(StartSyncReason.AppInForeground) + syncService.stopSync() } }, onDestroy = { @@ -151,7 +150,7 @@ class LoggedInFlowNode @AssistedInject constructor( .collect { (syncState, networkStatus) -> Timber.d("Sync state: $syncState, network status: $networkStatus") if (syncState != SyncState.Running && networkStatus == NetworkStatus.Online) { - syncService.startSync(StartSyncReason.AppInForeground) + syncService.startSync() } } } diff --git a/build.gradle.kts b/build.gradle.kts index b48ef70ce7..69f5676e72 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -261,6 +261,8 @@ koverMerged { includes += "*Presenter" excludes += "*Fake*Presenter" excludes += "io.element.android.appnav.loggedin.LoggedInPresenter$*" + // Some options can't be tested at the moment + excludes += "io.element.android.features.preferences.impl.developer.DeveloperSettingsPresenter$*" } bound { minValue = 85 diff --git a/changelog.d/+sdk_bump.feature b/changelog.d/+sdk_bump.feature new file mode 100644 index 0000000000..4f92120f84 --- /dev/null +++ b/changelog.d/+sdk_bump.feature @@ -0,0 +1 @@ +Bump Rust SDK to `v0.1.49` \ No newline at end of file diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenter.kt index 5f50fde309..ebcd44b4db 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenter.kt @@ -124,16 +124,12 @@ class DeveloperSettingsPresenter @Inject constructor( enabledFeatures: SnapshotStateMap, featureUiModel: FeatureUiModel, enabled: Boolean, - triggerClearCache: () -> Unit, + @Suppress("UNUSED_PARAMETER") triggerClearCache: () -> Unit, ) = launch { val feature = features[featureUiModel.key] ?: return@launch if (featureFlagService.setFeatureEnabled(feature, enabled)) { enabledFeatures[featureUiModel.key] = enabled } - - if (featureUiModel.key == FeatureFlags.UseEncryptionSync.key) { - triggerClearCache() - } } private fun CoroutineScope.computeCacheSize(cacheSize: MutableState>) = launch { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7a722301fd..f42532ac1b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -146,7 +146,7 @@ jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" } appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } molecule-runtime = { module = "app.cash.molecule:molecule-runtime", version.ref = "molecule" } timber = "com.jakewharton.timber:timber:5.0.1" -matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.48" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.49" sqldelight-driver-android = { module = "com.squareup.sqldelight:android-driver", version.ref = "sqldelight" } sqldelight-driver-jvm = { module = "com.squareup.sqldelight:sqlite-driver", version.ref = "sqldelight" } sqldelight-coroutines = { module = "com.squareup.sqldelight:coroutines-extensions", version.ref = "sqldelight" } diff --git a/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt index 312745a4df..c28dc28144 100644 --- a/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt +++ b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt @@ -31,10 +31,4 @@ enum class FeatureFlags( title = "Polls", description = "Create poll and render poll events in the timeline", ), - UseEncryptionSync( - key = "feature.useencryptionsync", - title = "Use encryption sync", - description = "Use the encryption sync API for decrypting notifications.", - defaultValue = true, - ) } diff --git a/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/BuildtimeFeatureFlagProvider.kt b/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/BuildtimeFeatureFlagProvider.kt index 5640d108a6..83913cbac5 100644 --- a/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/BuildtimeFeatureFlagProvider.kt +++ b/libraries/featureflag/impl/src/main/kotlin/io/element/android/libraries/featureflag/impl/BuildtimeFeatureFlagProvider.kt @@ -31,7 +31,6 @@ class BuildtimeFeatureFlagProvider @Inject constructor() : when (feature) { FeatureFlags.LocationSharing -> true FeatureFlags.Polls -> false - FeatureFlags.UseEncryptionSync -> true } } else { false diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/sync/StartSyncReason.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/sync/StartSyncReason.kt deleted file mode 100644 index 4a6b44949e..0000000000 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/sync/StartSyncReason.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2023 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.element.android.libraries.matrix.api.sync - -import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.api.core.RoomId - -sealed interface StartSyncReason { - data object AppInForeground : StartSyncReason - data class Notification(val roomId: RoomId, val eventId: EventId) : StartSyncReason -} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/sync/SyncService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/sync/SyncService.kt index 03a8402b32..994b35edc4 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/sync/SyncService.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/sync/SyncService.kt @@ -22,12 +22,12 @@ interface SyncService { /** * Tries to start the sync. If already syncing it has no effect. */ - suspend fun startSync(reason: StartSyncReason): Result + suspend fun startSync(): Result /** * Tries to stop the sync. If service is not syncing it has no effect. */ - suspend fun stopSync(reason: StartSyncReason): Result + suspend fun stopSync(): Result /** * Flow of [SyncState]. Will be updated as soon as the current [SyncState] changes. diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index 4b0afb0b4f..54641f785b 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -65,6 +65,7 @@ import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeout import org.matrix.rustcomponents.sdk.Client import org.matrix.rustcomponents.sdk.ClientDelegate +import org.matrix.rustcomponents.sdk.NotificationProcessSetup import org.matrix.rustcomponents.sdk.Room import org.matrix.rustcomponents.sdk.RoomListItem import org.matrix.rustcomponents.sdk.use @@ -98,9 +99,13 @@ class RustMatrixClient constructor( client = client, dispatchers = dispatchers, ) - private val notificationClient = client.notificationClient().use { builder -> - builder.filterByPushRules().finish() - } + private val notificationProcessSetup = NotificationProcessSetup.SingleProcess(syncService) + private val notificationClient = client.notificationClient(notificationProcessSetup) + .use { builder -> + builder + .filterByPushRules() + .finish() + } private val notificationService = RustNotificationService(sessionId, notificationClient, dispatchers, clock) @@ -279,6 +284,7 @@ class RustMatrixClient constructor( syncService.destroy() innerRoomListService.destroy() notificationClient.destroy() + notificationProcessSetup.destroy() client.destroy() } @@ -316,6 +322,7 @@ class RustMatrixClient constructor( client.accountUrl() } } + override suspend fun loadUserDisplayName(): Result = withContext(sessionDispatcher) { runCatching { client.displayName() diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt index 3615115bb4..b37266342e 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt @@ -19,8 +19,6 @@ package io.element.android.libraries.matrix.impl import android.content.Context import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.di.ApplicationContext -import io.element.android.libraries.featureflag.api.FeatureFlagService -import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.network.useragent.UserAgentProvider import io.element.android.libraries.sessionstorage.api.SessionData import io.element.android.libraries.sessionstorage.api.SessionStore @@ -41,7 +39,6 @@ class RustMatrixClientFactory @Inject constructor( private val sessionStore: SessionStore, private val userAgentProvider: UserAgentProvider, private val clock: SystemClock, - private val featureFlagsService: FeatureFlagService, ) { suspend fun create(sessionData: SessionData): RustMatrixClient = withContext(coroutineDispatchers.io) { @@ -56,11 +53,7 @@ class RustMatrixClientFactory @Inject constructor( client.restoreSession(sessionData.toSession()) - val syncService = client.syncService().apply { - if (featureFlagsService.isFeatureEnabled(FeatureFlags.UseEncryptionSync)) { - withEncryptionSync(withCrossProcessLock = false, appIdentifier = null) - } - } + val syncService = client.syncService() .finish() RustMatrixClient( diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListService.kt index f56e55d759..655c634502 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListService.kt @@ -126,6 +126,7 @@ private fun RoomListLoadingState.toLoadingState(): RoomList.LoadingState { private fun RoomListServiceState.toRoomListState(): RoomListService.State { return when (this) { RoomListServiceState.INITIAL, + RoomListServiceState.RECOVERING, RoomListServiceState.SETTING_UP -> RoomListService.State.Idle RoomListServiceState.RUNNING -> RoomListService.State.Running RoomListServiceState.ERROR -> RoomListService.State.Error diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/sync/RustSyncService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/sync/RustSyncService.kt index b0a9fb31ec..932da42afb 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/sync/RustSyncService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/sync/RustSyncService.kt @@ -16,7 +16,6 @@ package io.element.android.libraries.matrix.impl.sync -import io.element.android.libraries.matrix.api.sync.StartSyncReason import io.element.android.libraries.matrix.api.sync.SyncService import io.element.android.libraries.matrix.api.sync.SyncState import kotlinx.coroutines.CoroutineScope @@ -26,8 +25,6 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock import org.matrix.rustcomponents.sdk.SyncServiceInterface import org.matrix.rustcomponents.sdk.SyncServiceState import timber.log.Timber @@ -36,36 +33,19 @@ class RustSyncService( private val innerSyncService: SyncServiceInterface, sessionCoroutineScope: CoroutineScope ) : SyncService { - private val mutex = Mutex() - private val startSyncReasonSet = mutableSetOf() - override suspend fun startSync(reason: StartSyncReason): Result { - return mutex.withLock { - startSyncReasonSet.add(reason) - runCatching { - Timber.d("Start sync") - innerSyncService.start() - }.onFailure { - Timber.e("Start sync failed: $it") - } - } + override suspend fun startSync() = runCatching { + Timber.i("Start sync") + innerSyncService.start() + }.onFailure { + Timber.d("Start sync failed: $it") } - override suspend fun stopSync(reason: StartSyncReason): Result { - return mutex.withLock { - startSyncReasonSet.remove(reason) - if (startSyncReasonSet.isEmpty()) { - runCatching { - Timber.d("Stop sync") - innerSyncService.stop() - }.onFailure { - Timber.e("Stop sync failed: $it") - } - } else { - Timber.d("Stop sync skipped, still $startSyncReasonSet") - Result.success(Unit) - } - } + override suspend fun stopSync() = runCatching { + Timber.i("Stop sync") + innerSyncService.stop() + }.onFailure { + Timber.d("Stop sync failed: $it") } override val syncState: StateFlow = diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/sync/FakeSyncService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/sync/FakeSyncService.kt index 87a54a2571..4e618deb9a 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/sync/FakeSyncService.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/sync/FakeSyncService.kt @@ -16,7 +16,6 @@ package io.element.android.libraries.matrix.test.sync -import io.element.android.libraries.matrix.api.sync.StartSyncReason import io.element.android.libraries.matrix.api.sync.SyncService import io.element.android.libraries.matrix.api.sync.SyncState import kotlinx.coroutines.flow.MutableStateFlow @@ -30,12 +29,12 @@ class FakeSyncService : SyncService { syncStateFlow.value = SyncState.Error } - override suspend fun startSync(reason: StartSyncReason): Result { + override suspend fun startSync(): Result { syncStateFlow.value = SyncState.Running return Result.success(Unit) } - override suspend fun stopSync(reason: StartSyncReason): Result { + override suspend fun stopSync(): Result { syncStateFlow.value = SyncState.Terminated return Result.success(Unit) } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolver.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolver.kt index ce3d09f013..e5af7785db 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolver.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventResolver.kt @@ -26,7 +26,6 @@ import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.notification.NotificationContent import io.element.android.libraries.matrix.api.notification.NotificationData import io.element.android.libraries.matrix.api.room.RoomMembershipState -import io.element.android.libraries.matrix.api.sync.StartSyncReason import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType @@ -45,7 +44,6 @@ import io.element.android.libraries.push.impl.notifications.model.NotifiableMess import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.services.toolbox.api.strings.StringProvider import io.element.android.services.toolbox.api.systemclock.SystemClock -import kotlinx.coroutines.delay import timber.log.Timber import javax.inject.Inject @@ -67,14 +65,6 @@ class NotifiableEventResolver @Inject constructor( // Restore session val client = matrixClientProvider.getOrRestore(sessionId).getOrNull() ?: return null val notificationService = client.notificationService() - - // Restart the sync service to ensure that the crypto sync handle the toDevice Events. - client.syncService().startSync(StartSyncReason.Notification(roomId, eventId)) - // Wait for toDevice Event to be processed - // FIXME This delay can be removed when the Rust SDK will handle internal retry to get - // clear notification content. - delay(300) - val notificationData = notificationService.getNotification( userId = sessionId, roomId = roomId, @@ -83,8 +73,6 @@ class NotifiableEventResolver @Inject constructor( Timber.tag(loggerTag.value).e(it, "Unable to resolve event: $eventId.") }.getOrNull() - client.syncService().stopSync(StartSyncReason.Notification(roomId, eventId)) - // TODO this notificationData is not always valid at the moment, sometimes the Rust SDK can't fetch the matching event return notificationData?.asNotifiableEvent(sessionId) } diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt index 94cd28f021..d0309ebec7 100644 --- a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt @@ -26,7 +26,6 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.core.view.WindowCompat -import io.element.android.libraries.featureflag.impl.DefaultFeatureFlagService import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService import io.element.android.libraries.matrix.impl.RustMatrixClientFactory import io.element.android.libraries.matrix.impl.auth.RustMatrixAuthenticationService @@ -56,7 +55,6 @@ class MainActivity : ComponentActivity() { sessionStore = sessionStore, userAgentProvider = userAgentProvider, clock = DefaultSystemClock(), - featureFlagsService = DefaultFeatureFlagService(emptySet()) ) ) } diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt index bb90425a48..faaccc9b8e 100644 --- a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt @@ -39,7 +39,6 @@ import io.element.android.libraries.eventformatter.impl.StateContentFormatter import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.room.RoomMembershipObserver -import io.element.android.libraries.matrix.api.sync.StartSyncReason import io.element.android.services.toolbox.impl.strings.AndroidStringProvider import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking @@ -110,12 +109,12 @@ class RoomListScreen( DisposableEffect(Unit) { Timber.w("Start sync!") runBlocking { - matrixClient.syncService().startSync(StartSyncReason.AppInForeground) + matrixClient.syncService().startSync() } onDispose { Timber.w("Stop sync!") runBlocking { - matrixClient.syncService().stopSync(StartSyncReason.AppInForeground) + matrixClient.syncService().stopSync() } } }