diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt index 4244df2614..d41e2aa11f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/CryptoService.kt @@ -64,7 +64,7 @@ interface CryptoService { fun setDeviceVerification(trustLevel: DeviceTrustLevel, userId: String, deviceId: String) - fun getUserDevices(userId: String): MutableList + suspend fun getUserDevices(userId: String): MutableList fun getMyDevice(): CryptoDeviceInfo @@ -84,7 +84,7 @@ interface CryptoService { fun setRoomBlacklistUnverifiedDevices(roomId: String) - fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? + suspend fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? fun reRequestRoomKeyForEvent(event: Event) @@ -92,7 +92,7 @@ interface CryptoService { fun removeRoomKeysRequestListener(listener: GossipingRequestListener) - fun fetchDevicesList(callback: MatrixCallback) + suspend fun fetchDevicesList(): List fun getMyDevicesInfo(): List @@ -112,7 +112,7 @@ interface CryptoService { fun discardOutboundSession(roomId: String) @Throws(MXCryptoError::class) - fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult + suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback) @@ -122,7 +122,7 @@ interface CryptoService { suspend fun downloadKeys(userIds: List, forceDownload: Boolean = false): MXUsersDevicesMap - fun getCryptoDeviceInfo(userId: String): List + suspend fun getCryptoDeviceInfo(userId: String): List fun getLiveCryptoDeviceInfo(userId: String): Flow> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt index 611f657010..e4c0e90f6d 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt @@ -66,7 +66,6 @@ import org.matrix.android.sdk.internal.crypto.model.event.RoomKeyContent import org.matrix.android.sdk.internal.crypto.model.event.RoomKeyWithHeldContent import org.matrix.android.sdk.internal.crypto.model.event.SecretSendEventContent import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo -import org.matrix.android.sdk.internal.crypto.model.rest.DevicesListResponse import org.matrix.android.sdk.internal.crypto.model.rest.ForwardedRoomKeyContent import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore @@ -224,23 +223,12 @@ internal class DefaultCryptoService @Inject constructor( return runBlocking { olmMachine.ownDevice() } } - override fun fetchDevicesList(callback: MatrixCallback) { - getDevicesTask - .configureWith { - // this.executionThread = TaskThread.CRYPTO - this.callback = object : MatrixCallback { - override fun onFailure(failure: Throwable) { - callback.onFailure(failure) - } - - override fun onSuccess(data: DevicesListResponse) { - // Save in local DB - cryptoStore.saveMyDevicesInfo(data.devices.orEmpty()) - callback.onSuccess(data) - } - } - } - .executeBy(taskExecutor) + override suspend fun fetchDevicesList(): List { + val devicesList = tryOrNull { + getDevicesTask.execute(Unit).devices + }.orEmpty() + cryptoStore.saveMyDevicesInfo(devicesList) + return devicesList } override fun getLiveMyDevicesInfo(): LiveData> { @@ -301,10 +289,9 @@ internal class DefaultCryptoService @Inject constructor( */ fun start() { internalStart() - // Just update - fetchDevicesList(NoOpMatrixCallback()) - cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { + // Just update + fetchDevicesList() cryptoStore.tidyUpDataBase() } } @@ -412,20 +399,13 @@ internal class DefaultCryptoService @Inject constructor( * @param userId the user id * @param deviceId the device id */ - override fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? { - return if (userId.isNotEmpty() && !deviceId.isNullOrEmpty()) { - runBlocking { - this@DefaultCryptoService.olmMachine.getCryptoDeviceInfo(userId, deviceId) - } - } else { - null - } + override suspend fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? { + if (userId.isEmpty() || deviceId.isNullOrEmpty()) return null + return olmMachine.getCryptoDeviceInfo(userId, deviceId) } - override fun getCryptoDeviceInfo(userId: String): List { - return runBlocking { - this@DefaultCryptoService.olmMachine.getCryptoDeviceInfo(userId) - } + override suspend fun getCryptoDeviceInfo(userId: String): List { + return olmMachine.getCryptoDeviceInfo(userId) } override fun getLiveCryptoDeviceInfo(userId: String): Flow> { @@ -503,7 +483,7 @@ internal class DefaultCryptoService @Inject constructor( /** * @return the stored device keys for a user. */ - override fun getUserDevices(userId: String): MutableList { + override suspend fun getUserDevices(userId: String): MutableList { return this.getCryptoDeviceInfo(userId).toMutableList() } @@ -577,10 +557,8 @@ internal class DefaultCryptoService @Inject constructor( * @return the MXEventDecryptionResult data, or throw in case of error */ @Throws(MXCryptoError::class) - override fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult { - return runBlocking { - olmMachine.decryptRoomEvent(event) - } + override suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult { + return olmMachine.decryptRoomEvent(event) } /** diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt index 1555f8a04a..42aed8e38f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt @@ -362,11 +362,11 @@ internal class OlmMachine( suspend fun decryptRoomEvent(event: Event): MXEventDecryptionResult = withContext(Dispatchers.IO) { val adapter = MoshiProvider.providesMoshi().adapter(Event::class.java) - val serializedEvent = adapter.toJson(event) try { if (event.roomId.isNullOrBlank()) { throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_FIELDS, MXCryptoError.MISSING_FIELDS_REASON) } + val serializedEvent = adapter.toJson(event) val decrypted = inner.decryptRoomEvent(serializedEvent, event.roomId) val deserializationAdapter = diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt index e0d501c515..cd06d47f05 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt @@ -156,7 +156,7 @@ internal class DefaultFetchThreadTimelineTask @Inject constructor( * Invoke the event decryption mechanism for a specific event */ - private fun decryptIfNeeded(event: Event, roomId: String) { + private suspend fun decryptIfNeeded(event: Event, roomId: String) { try { // Event from sync does not have roomId, so add it to the event first val result = cryptoService.decryptEvent(event.copy(roomId = roomId), "") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/SendingEventsDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/SendingEventsDataSource.kt index b7a2cf2fce..9e1b33037f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/SendingEventsDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/SendingEventsDataSource.kt @@ -43,6 +43,7 @@ internal class RealmSendingEventsDataSource( private var roomEntity: RoomEntity? = null private var sendingTimelineEvents: RealmList? = null private var frozenSendingTimelineEvents: RealmList? = null + private val builtEvents = ArrayList() private val sendingTimelineEventsListener = RealmChangeListener> { events -> uiEchoManager.onSentEventsInDatabase(events.map { it.eventId }) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDecryptor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDecryptor.kt index 8d62c6e8ec..7c52aa1b9b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDecryptor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineEventDecryptor.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.session.room.timeline import io.realm.Realm import io.realm.RealmConfiguration +import kotlinx.coroutines.runBlocking import org.matrix.android.sdk.api.session.crypto.CryptoService import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.events.model.Event @@ -126,7 +127,9 @@ internal class TimelineEventDecryptor @Inject constructor( return } try { - val result = cryptoService.decryptEvent(request.event, timelineId) + val result = runBlocking { + cryptoService.decryptEvent(request.event, timelineId) + } Timber.v("Successfully decrypted event ${event.eventId}") realm.executeTransaction { val eventId = event.eventId ?: return@executeTransaction diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt index 8be342c6d1..7b5c08ebd6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/RoomSyncHandler.kt @@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.sync.handler.room import dagger.Lazy import io.realm.Realm import io.realm.kotlin.createObject +import kotlinx.coroutines.runBlocking import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType @@ -343,7 +344,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle return roomEntity } - private suspend fun handleTimelineEvents(realm: Realm, + private fun handleTimelineEvents(realm: Realm, roomId: String, roomEntity: RoomEntity, eventList: List, @@ -458,7 +459,9 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle private fun decryptIfNeeded(event: Event, roomId: String) { try { // Event from sync does not have roomId, so add it to the event first - val result = cryptoService.decryptEvent(event.copy(roomId = roomId), "") + val result = runBlocking { + cryptoService.decryptEvent(event.copy(roomId = roomId), "") + } event.mxDecryptionResult = OlmDecryptionResult( payload = result.clearEvent, senderKey = result.senderCurve25519Key, diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt index 03c87bbaff..f3a272c3e8 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheetViewModel.kt @@ -131,28 +131,29 @@ class VerificationBottomSheetViewModel @AssistedInject constructor( session.cryptoService().verificationService().getExistingTransaction(initialState.otherUserId, it) as? QrCodeVerificationTransaction } - val hasAnyOtherSession = session.cryptoService() - .getCryptoDeviceInfo(session.myUserId) - .any { - it.deviceId != session.sessionParams.deviceId - } + viewModelScope.launch { - setState { - copy( - otherUserMxItem = userItem?.toMatrixItem(), - sasTransactionState = sasTx?.state, - qrTransactionState = qrTx?.state, - transactionId = pr?.transactionId ?: initialState.verificationId, - pendingRequest = if (pr != null) Success(pr) else Uninitialized, - isMe = initialState.otherUserId == session.myUserId, - currentDeviceCanCrossSign = session.cryptoService().crossSigningService().canCrossSign(), - quadSContainsSecrets = session.sharedSecretStorageService.isRecoverySetup(), - hasAnyOtherSession = hasAnyOtherSession - ) - } + val hasAnyOtherSession = session.cryptoService() + .getCryptoDeviceInfo(session.myUserId) + .any { + it.deviceId != session.sessionParams.deviceId + } - if (autoReady) { - viewModelScope.launch { + setState { + copy( + otherUserMxItem = userItem?.toMatrixItem(), + sasTransactionState = sasTx?.state, + qrTransactionState = qrTx?.state, + transactionId = pr?.transactionId ?: initialState.verificationId, + pendingRequest = if (pr != null) Success(pr) else Uninitialized, + isMe = initialState.otherUserId == session.myUserId, + currentDeviceCanCrossSign = session.cryptoService().crossSigningService().canCrossSign(), + quadSContainsSecrets = session.sharedSecretStorageService.isRecoverySetup(), + hasAnyOtherSession = hasAnyOtherSession + ) + } + + if (autoReady) { // TODO, can I be here in DM mode? in this case should test if roomID is null? session.cryptoService().verificationService() .readyPendingVerification( @@ -480,7 +481,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor( } } - private fun handleTransactionUpdate(state: VerificationBottomSheetViewState, tx: VerificationTransaction){ + private fun handleTransactionUpdate(state: VerificationBottomSheetViewState, tx: VerificationTransaction) { viewModelScope.launch { if (state.selfVerificationMode && state.transactionId == null) { // is this an incoming with that user diff --git a/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt index 8a36a4c19e..537adcf00d 100644 --- a/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt @@ -32,10 +32,11 @@ import im.vector.app.core.platform.VectorViewModelAction import im.vector.app.features.settings.VectorPreferences import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.sample -import org.matrix.android.sdk.api.NoOpMatrixCallback +import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.util.MatrixItem @@ -58,7 +59,7 @@ data class DeviceDetectionInfo( class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted initialState: UnknownDevicesState, session: Session, private val vectorPreferences: VectorPreferences) : - VectorViewModel(initialState) { + VectorViewModel(initialState) { sealed class Action : VectorViewModelAction { data class IgnoreDevice(val deviceIds: List) : Action() @@ -75,12 +76,6 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted init { - val currentSessionTs = session.cryptoService().getCryptoDeviceInfo(session.myUserId) - .firstOrNull { it.deviceId == session.sessionParams.deviceId } - ?.firstTimeSeenLocalTs - ?: System.currentTimeMillis() - Timber.v("## Detector - Current Session first time seen $currentSessionTs") - ignoredDeviceList.addAll( vectorPreferences.getUnknownDeviceDismissedList().also { Timber.v("## Detector - Remembered ignored list $it") @@ -90,10 +85,12 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted combine( session.flow().liveUserCryptoDevices(session.myUserId), session.flow().liveMyDevicesInfo(), - session.flow().liveCrossSigningPrivateKeys() - ) { cryptoList, infoList, pInfo -> + session.flow().liveCrossSigningPrivateKeys(), + session.firstTimeDeviceSeen(), + ) { cryptoList, infoList, pInfo, firstTimeDeviceSeen -> // Timber.v("## Detector trigger ${cryptoList.map { "${it.deviceId} ${it.trustLevel}" }}") // Timber.v("## Detector trigger canCrossSign ${pInfo.get().selfSigned != null}") + Timber.v("## Detector - Current Session first time seen $firstTimeDeviceSeen") infoList .filter { info -> // filter verified session, by checking the crypto device info @@ -106,7 +103,7 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted val deviceKnownSince = cryptoList.firstOrNull { it.deviceId == deviceInfo.deviceId }?.firstTimeSeenLocalTs ?: 0 DeviceDetectionInfo( deviceInfo, - deviceKnownSince > currentSessionTs + 60_000, // short window to avoid false positive, + deviceKnownSince > firstTimeDeviceSeen + 60_000, // short window to avoid false positive, pInfo.getOrNull()?.selfSigned != null // adding this to pass distinct when cross sign change ) } @@ -125,12 +122,14 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted .sample(5_000) .onEach { // If we have a new crypto device change, we might want to trigger refresh of device info - session.cryptoService().fetchDevicesList(NoOpMatrixCallback()) + session.cryptoService().fetchDevicesList() } .launchIn(viewModelScope) // trigger a refresh of lastSeen / last Ip - session.cryptoService().fetchDevicesList(NoOpMatrixCallback()) + viewModelScope.launch { + session.cryptoService().fetchDevicesList() + } } override fun handle(action: Action) { @@ -154,4 +153,13 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted vectorPreferences.storeUnknownDeviceDismissedList(ignoredDeviceList) super.onCleared() } + + private fun Session.firstTimeDeviceSeen() = flow { + val value = cryptoService().getCryptoDeviceInfo(myUserId) + .firstOrNull { it.deviceId == sessionParams.deviceId } + ?.firstTimeSeenLocalTs + ?: System.currentTimeMillis() + emit(value) + } + } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt index 5575d9b7f6..db8629defb 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt @@ -164,11 +164,12 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted onEach(MessageActionState::timelineEvent, MessageActionState::actionPermissions) { timelineEvent, permissions -> val nonNullTimelineEvent = timelineEvent() ?: return@onEach eventIdFlow.tryEmit(nonNullTimelineEvent.eventId) + val events = actionsForEvent(nonNullTimelineEvent, permissions) setState { copy( eventId = nonNullTimelineEvent.eventId, messageBody = computeMessageBody(nonNullTimelineEvent), - actions = actionsForEvent(nonNullTimelineEvent, permissions) + actions = events ) } } @@ -246,7 +247,7 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted } } - private fun actionsForEvent(timelineEvent: TimelineEvent, actionPermissions: ActionPermissions): List { + private suspend fun actionsForEvent(timelineEvent: TimelineEvent, actionPermissions: ActionPermissions): List { val messageContent = timelineEvent.getLastMessageContent() val msgType = messageContent?.msgType @@ -317,7 +318,7 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted // TODO sent by me or sufficient power level } - private fun ArrayList.addActionsForSyncedState(timelineEvent: TimelineEvent, + private suspend fun ArrayList.addActionsForSyncedState(timelineEvent: TimelineEvent, actionPermissions: ActionPermissions, messageContent: MessageContent?, msgType: String?) { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt index bd0ba075a5..e2283fef81 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt @@ -139,20 +139,18 @@ class MessageInformationDataFactory @Inject constructor(private val session: Ses } } - private fun getE2EDecoration(roomSummary: RoomSummary?, event: TimelineEvent): E2EDecoration { + private fun getE2EDecoration(roomSummary: RoomSummary?, event: TimelineEvent): E2EDecoration = runBlocking{ if (event.root.sendState != SendState.SYNCED) - return E2EDecoration.NONE + return@runBlocking E2EDecoration.NONE if (!roomSummary?.isEncrypted.orFalse()) - return E2EDecoration.NONE - val isUserVerified = runBlocking { - session.cryptoService().crossSigningService().getUserCrossSigningKeys(event.root.senderId ?: "")?.isTrusted().orFalse() - } + return@runBlocking E2EDecoration.NONE + val isUserVerified = session.cryptoService().crossSigningService().getUserCrossSigningKeys(event.root.senderId ?: "")?.isTrusted().orFalse() if (!isUserVerified) { - return E2EDecoration.NONE + return@runBlocking E2EDecoration.NONE } val ts = roomSummary?.encryptionEventTs ?: 0 val eventTs = event.root.originServerTs ?: 0 - return if (event.isEncrypted()) { + return@runBlocking if (event.isEncrypted()) { // Do not decorate failed to decrypt, or redaction (we lost sender device info) if (event.root.getClearType() == EventType.ENCRYPTED || event.root.isRedacted()) { E2EDecoration.NONE diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt index ec034173fc..3cdc9e8c76 100644 --- a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt @@ -190,7 +190,7 @@ class NotifiableEventResolver @Inject constructor( } } - private fun TimelineEvent.attemptToDecryptIfNeeded(session: Session) { + private suspend fun TimelineEvent.attemptToDecryptIfNeeded(session: Session) { if (root.isEncrypted() && root.mxDecryptionResult == null) { // TODO use a global event decryptor? attache to session and that listen to new sessionId? // for now decrypt sync diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt index 95a7213b35..67cca1a083 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt @@ -70,12 +70,10 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import me.gujun.android.span.span -import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.extensions.getFingerprintHumanReadable import org.matrix.android.sdk.api.raw.RawService import org.matrix.android.sdk.internal.crypto.crosssigning.isVerified import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo -import org.matrix.android.sdk.internal.crypto.model.rest.DevicesListResponse import javax.inject.Inject class VectorSettingsSecurityPrivacyFragment @Inject constructor( @@ -524,7 +522,7 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( /** * Build the cryptography preference section. */ - private fun refreshCryptographyPreference(devices: List) { + private suspend fun refreshCryptographyPreference(devices: List) { showDeviceListPref.isEnabled = devices.isNotEmpty() showDeviceListPref.summary = resources.getQuantityString(R.plurals.settings_active_sessions_count, devices.size, devices.size) @@ -580,28 +578,19 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( // ============================================================================================================== private fun refreshMyDevice() { - session.cryptoService().getUserDevices(session.myUserId).map { - DeviceInfo( - userId = session.myUserId, - deviceId = it.deviceId, - displayName = it.displayName() - ) - }.let { - refreshCryptographyPreference(it) + viewLifecycleOwner.lifecycleScope.launchWhenResumed { + session.cryptoService().getUserDevices(session.myUserId).map { + DeviceInfo( + userId = session.myUserId, + deviceId = it.deviceId, + displayName = it.displayName() + ) + }.let { + refreshCryptographyPreference(it) + } + // TODO Move to a ViewModel... + val devicesList = session.cryptoService().fetchDevicesList() + refreshCryptographyPreference(devicesList) } - // TODO Move to a ViewModel... - session.cryptoService().fetchDevicesList(object : MatrixCallback { - override fun onSuccess(data: DevicesListResponse) { - if (isAdded) { - refreshCryptographyPreference(data.devices.orEmpty()) - } - } - - override fun onFailure(failure: Throwable) { - if (isAdded) { - refreshCryptographyPreference(emptyList()) - } - } - }) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt index 10cda3ad44..871109210a 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt @@ -147,7 +147,7 @@ class DevicesViewModel @AssistedInject constructor( .sample(5_000) .onEach { // If we have a new crypto device change, we might want to trigger refresh of device info - session.cryptoService().fetchDevicesList(NoOpMatrixCallback()) + session.cryptoService().fetchDevicesList() } .launchIn(viewModelScope) @@ -160,7 +160,7 @@ class DevicesViewModel @AssistedInject constructor( refreshSource.stream().throttleFirst(4_000) .onEach { - session.cryptoService().fetchDevicesList(NoOpMatrixCallback()) + session.cryptoService().fetchDevicesList() session.cryptoService().downloadKeys(listOf(session.myUserId), true) } .launchIn(viewModelScope)