diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt index 52e93d4992..79a476ff04 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt @@ -189,9 +189,13 @@ class LinkNewDeviceFlowNode( is ErrorType.InvalidCheckCode -> ErrorScreenType.InsecureChannelDetected is ErrorType.MissingSecretsBackup -> ErrorScreenType.UnknownError is ErrorType.NotFound -> ErrorScreenType.Expired - is ErrorType.UnableToCreateDevice -> ErrorScreenType.UnknownError + is ErrorType.DeviceNotFound -> ErrorScreenType.UnknownError is ErrorType.Unknown -> ErrorScreenType.UnknownError is ErrorType.UnsupportedProtocol -> ErrorScreenType.UnknownError + is ErrorType.Cancelled -> ErrorScreenType.UnknownError + is ErrorType.ConnectionInsecure -> ErrorScreenType.InsecureChannelDetected + is ErrorType.Expired -> ErrorScreenType.Expired + is ErrorType.OtherDeviceAlreadySignedIn -> ErrorScreenType.UnknownError } // It is OK to push on backstack, since when user leaves the error screen, a new root will be set, // or the whole flow will be popped. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 80977f3483..1f5f7f4bcb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -178,7 +178,7 @@ test_detekt_test = { module = "io.gitlab.arturbosch.detekt:detekt-test", version # https://github.com/matrix-org/matrix-rust-components-kotlin/commits/main/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt # All new features should not be implemented in the pull request that upgrades the version, developers should # only fix API breaks and may add some TODOs. -matrix_sdk = "org.matrix.rustcomponents:sdk-android:26.03.0" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:26.03.1" # Others coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/NotificationResolverException.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/NotificationResolverException.kt index fd3adf2592..a83fbd1e23 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/NotificationResolverException.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/exception/NotificationResolverException.kt @@ -22,6 +22,11 @@ sealed class NotificationResolverException : Exception() { */ data object EventFilteredOut : NotificationResolverException() + /** + * The event was found but it has been redacted. + */ + data object EventRedacted : NotificationResolverException() + /** * An unexpected error occurred while trying to resolve the event. */ diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/linknewdevice/ErrorType.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/linknewdevice/ErrorType.kt index 0f61007d47..21c0d521c9 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/linknewdevice/ErrorType.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/linknewdevice/ErrorType.kt @@ -33,13 +33,33 @@ sealed class ErrorType(message: String) : Exception(message) { */ class NotFound(message: String) : ErrorType(message) - /** - * The device could not be created. - */ - class UnableToCreateDevice(message: String) : ErrorType(message) - /** * An unknown error has happened. */ class Unknown(message: String) : ErrorType(message) + + /** + * The requested device was not returned by the homeserver. + */ + class DeviceNotFound(message: String) : ErrorType(message) + + /** + * The other device is already signed in and so does not need to sign in. + */ + class OtherDeviceAlreadySignedIn(message: String) : ErrorType(message) + + /** + * The sign in was cancelled. + */ + class Cancelled(message: String) : ErrorType(message) + + /** + * The sign in was not completed in the required time. + */ + class Expired(message: String) : ErrorType(message) + + /** + * A secure connection could not have been established between the two devices. + */ + class ConnectionInsecure(message: String) : ErrorType(message) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/HumanQrGrantLoginExceptionExtension.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/HumanQrGrantLoginExceptionExtension.kt index 2d47b60def..4027ee507b 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/HumanQrGrantLoginExceptionExtension.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/HumanQrGrantLoginExceptionExtension.kt @@ -15,7 +15,11 @@ internal fun HumanQrGrantLoginException.map() = when (this) { is HumanQrGrantLoginException.InvalidCheckCode -> ErrorType.InvalidCheckCode(message.orEmpty()) is HumanQrGrantLoginException.MissingSecretsBackup -> ErrorType.MissingSecretsBackup(message.orEmpty()) is HumanQrGrantLoginException.NotFound -> ErrorType.NotFound(message.orEmpty()) - is HumanQrGrantLoginException.UnableToCreateDevice -> ErrorType.UnableToCreateDevice(message.orEmpty()) + is HumanQrGrantLoginException.Cancelled -> ErrorType.Cancelled(message.orEmpty()) + is HumanQrGrantLoginException.ConnectionInsecure -> ErrorType.ConnectionInsecure(message.orEmpty()) + is HumanQrGrantLoginException.DeviceNotFound -> ErrorType.DeviceNotFound(message.orEmpty()) + is HumanQrGrantLoginException.Expired -> ErrorType.Expired(message.orEmpty()) + is HumanQrGrantLoginException.OtherDeviceAlreadySignedIn -> ErrorType.OtherDeviceAlreadySignedIn(message.orEmpty()) is HumanQrGrantLoginException.Unknown -> ErrorType.Unknown(message.orEmpty()) is HumanQrGrantLoginException.UnsupportedProtocol -> ErrorType.UnsupportedProtocol(message.orEmpty()) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/RustNotificationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/RustNotificationService.kt index 59d95af05b..238a8d988c 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/RustNotificationService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/RustNotificationService.kt @@ -66,6 +66,10 @@ class RustNotificationService( Timber.d("Could not retrieve event for notification with $eventId - event filtered out") put(eventId, Result.failure(NotificationResolverException.EventFilteredOut)) } + NotificationStatus.EventRedacted -> { + Timber.d("Could not retrieve event for notification with $eventId - event redacted") + put(eventId, Result.failure(NotificationResolverException.EventRedacted)) + } } } is BatchNotificationResult.Error -> { diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RoomTimelineExtensions.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RoomTimelineExtensions.kt index bc0e5eed99..c932230217 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RoomTimelineExtensions.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RoomTimelineExtensions.kt @@ -21,11 +21,11 @@ import org.matrix.rustcomponents.sdk.TimelineDiff import org.matrix.rustcomponents.sdk.TimelineInterface import org.matrix.rustcomponents.sdk.TimelineListener import timber.log.Timber -import uniffi.matrix_sdk.RoomPaginationStatus +import uniffi.matrix_sdk.PaginationStatus -internal fun TimelineInterface.liveBackPaginationStatus(): Flow = callbackFlow { +internal fun TimelineInterface.liveBackPaginationStatus(): Flow = callbackFlow { val listener = object : PaginationStatusListener { - override fun onUpdate(status: RoomPaginationStatus) { + override fun onUpdate(status: PaginationStatus) { trySend(status) } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt index 391349b52d..0ee7239933 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt @@ -71,7 +71,7 @@ import org.matrix.rustcomponents.sdk.UploadParameters import org.matrix.rustcomponents.sdk.UploadSource import org.matrix.rustcomponents.sdk.use import timber.log.Timber -import uniffi.matrix_sdk.RoomPaginationStatus +import uniffi.matrix_sdk.PaginationStatus import java.io.File import org.matrix.rustcomponents.sdk.EventOrTransactionId as RustEventOrTransactionId import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline @@ -147,8 +147,8 @@ class RustTimeline( .onEach { backPaginationStatus -> updatePaginationStatus(Timeline.PaginationDirection.BACKWARDS) { when (backPaginationStatus) { - is RoomPaginationStatus.Idle -> it.copy(isPaginating = false, hasMoreToLoad = !backPaginationStatus.hitTimelineStart) - is RoomPaginationStatus.Paginating -> it.copy(isPaginating = true, hasMoreToLoad = true) + is PaginationStatus.Idle -> it.copy(isPaginating = false, hasMoreToLoad = !backPaginationStatus.hitTimelineStart) + is PaginationStatus.Paginating -> it.copy(isPaginating = true, hasMoreToLoad = true) } } } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiTimeline.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiTimeline.kt index d45330bd3f..1c65ab00f2 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiTimeline.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiTimeline.kt @@ -14,7 +14,7 @@ import org.matrix.rustcomponents.sdk.TaskHandle import org.matrix.rustcomponents.sdk.Timeline import org.matrix.rustcomponents.sdk.TimelineDiff import org.matrix.rustcomponents.sdk.TimelineListener -import uniffi.matrix_sdk.RoomPaginationStatus +import uniffi.matrix_sdk.PaginationStatus class FakeFfiTimeline : Timeline(NoHandle) { private var listener: TimelineListener? = null @@ -33,7 +33,7 @@ class FakeFfiTimeline : Timeline(NoHandle) { return FakeFfiTaskHandle() } - fun emitPaginationStatus(status: RoomPaginationStatus) { + fun emitPaginationStatus(status: PaginationStatus) { paginationStatusListener!!.onUpdate(status) } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimelineTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimelineTest.kt index ab46e8aa5f..4c96800cd0 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimelineTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimelineTest.kt @@ -32,7 +32,7 @@ import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test import org.matrix.rustcomponents.sdk.TimelineDiff -import uniffi.matrix_sdk.RoomPaginationStatus +import uniffi.matrix_sdk.PaginationStatus import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline class RustTimelineTest { @@ -68,10 +68,10 @@ class RustTimelineTest { // Start pagination sut.paginate(Timeline.PaginationDirection.BACKWARDS) // Simulate SDK starting pagination - inner.emitPaginationStatus(RoomPaginationStatus.Paginating) + inner.emitPaginationStatus(PaginationStatus.Paginating) // No new events received // Simulate SDK stopping pagination, more event to load - inner.emitPaginationStatus(RoomPaginationStatus.Idle(hitTimelineStart = false)) + inner.emitPaginationStatus(PaginationStatus.Idle(hitTimelineStart = false)) // expect an item to be emitted, with an updated timestamp with(awaitItem()) { assertThat(size).isEqualTo(2) diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt index 3f13f33818..0053a18838 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt @@ -124,6 +124,14 @@ class DefaultPushHandler( sessionId = request.sessionId, comment = "Push handled successfully but notification was filtered out", ) + } else if (exception is NotificationResolverException.EventRedacted) { + pushHistoryService.onSuccess( + providerInfo = request.providerInfo, + eventId = request.eventId, + roomId = request.roomId, + sessionId = request.sessionId, + comment = "Push handled successfully but event has been redacted", + ) } else { val reason = when (exception) { is NotificationResolverException.EventNotFound -> "Event not found" @@ -155,6 +163,10 @@ class DefaultPushHandler( // Do nothing, we don't want to show a notification for filtered out events null } + is NotificationResolverException.EventRedacted -> { + // Do nothing, we don't want to show a notification for redacted events + null + } else -> { Timber.tag(loggerTag.value).e(exception, "Failed to resolve push event") ResolvedPushEvent.Event(