Browse Source

Bump rust-sdk version to rust-sdk 0.2.57 (#3735)

* Bump rust-sdk version to rust-sdk 0.2.57

* rust sdk update: Support persisted WedgeQueueError

* Trust & Decoration | Support new expected UTD causes

* Room Subscribtion settings not needed anymore (see https://github.com/matrix-org/matrix-rust-sdk/pull/4159)

* File/Attachement upload: update to support `storeInCache`

* feat(knock): update API to use reason and serverNames

* Add another `Konsist` exception

* Update screenshots

---------

Co-authored-by: Jorge Martín <jorgem@element.io>
Co-authored-by: ElementBot <android@element.io>
Co-authored-by: Benoit Marty <benoit@matrix.org>
pull/3740/head
Valere 6 days ago committed by GitHub
parent
commit
9fb68fc58e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 69
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowUtdPreview.kt
  2. 27
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEncryptedView.kt
  3. 14
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEncryptedContentProvider.kt
  4. 4
      gradle/libs.versions.toml
  5. 1
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/LocalEventSendState.kt
  6. 5
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/UtdCause.kt
  7. 2
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt
  8. 7
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/analytics/UtdTracker.kt
  9. 24
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomSyncSubscriber.kt
  10. 6
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt
  11. 40
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt
  12. 5
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt
  13. 48
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/analytics/UtdTrackerTest.kt
  14. 2
      libraries/ui-strings/src/main/res/values/localazy.xml
  15. 1
      tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt
  16. 4
      tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_2_en.png
  17. 3
      tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_3_en.png
  18. 3
      tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_4_en.png
  19. 4
      tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_2_en.png
  20. 3
      tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_3_en.png
  21. 3
      tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_4_en.png
  22. 3
      tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowUtd_Day_0_en.png
  23. 3
      tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowUtd_Night_0_en.png

69
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowUtdPreview.kt

@ -0,0 +1,69 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/
package io.element.android.features.messages.impl.timeline.components
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
import io.element.android.features.messages.impl.timeline.aTimelineItemReactions
import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
import io.element.android.libraries.matrix.api.timeline.item.event.UtdCause
@PreviewsDayNight
@Composable
internal fun TimelineItemEventRowUtdPreview() = ElementPreview {
Column {
ATimelineItemEventRow(
event = aTimelineItemEvent(
senderDisplayName = "Alice",
isMine = false,
content = TimelineItemEncryptedContent(
data = UnableToDecryptContent.Data.MegolmV1AesSha2(
sessionId = "sessionId",
utdCause = UtdCause.UnsignedDevice,
)
),
timelineItemReactions = aTimelineItemReactions(count = 0),
groupPosition = TimelineItemGroupPosition.First,
),
)
ATimelineItemEventRow(
event = aTimelineItemEvent(
senderDisplayName = "Bob",
isMine = false,
content = TimelineItemEncryptedContent(
data = UnableToDecryptContent.Data.MegolmV1AesSha2(
sessionId = "sessionId",
utdCause = UtdCause.VerificationViolation,
)
),
groupPosition = TimelineItemGroupPosition.First,
timelineItemReactions = aTimelineItemReactions(count = 0)
),
)
ATimelineItemEventRow(
event = aTimelineItemEvent(
senderDisplayName = "Bob",
isMine = false,
content = TimelineItemEncryptedContent(
data = UnableToDecryptContent.Data.MegolmV1AesSha2(
sessionId = "sessionId",
utdCause = UtdCause.SentBeforeWeJoined,
)
),
groupPosition = TimelineItemGroupPosition.Last,
timelineItemReactions = aTimelineItemReactions(count = 0)
),
)
}
}

27
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEncryptedView.kt

@ -27,11 +27,28 @@ fun TimelineItemEncryptedView(
onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit, onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val isMembershipUtd = (content.data as? UnableToDecryptContent.Data.MegolmV1AesSha2)?.utdCause == UtdCause.Membership val (textId, iconId) = when (content.data) {
val (textId, iconId) = if (isMembershipUtd) { is UnableToDecryptContent.Data.MegolmV1AesSha2 -> {
CommonStrings.common_unable_to_decrypt_no_access to CompoundDrawables.ic_compound_block when (content.data.utdCause) {
} else { UtdCause.SentBeforeWeJoined -> {
CommonStrings.common_waiting_for_decryption_key to CompoundDrawables.ic_compound_time CommonStrings.common_unable_to_decrypt_no_access to CompoundDrawables.ic_compound_block
}
UtdCause.VerificationViolation -> {
CommonStrings.common_unable_to_decrypt_verification_violation to CompoundDrawables.ic_compound_block
}
UtdCause.UnsignedDevice,
UtdCause.UnknownDevice -> {
CommonStrings.common_unable_to_decrypt_insecure_device to CompoundDrawables.ic_compound_block
}
else -> {
CommonStrings.common_waiting_for_decryption_key to CompoundDrawables.ic_compound_time
}
}
}
else -> {
// Should not happen, we only supports megolm in rooms
CommonStrings.common_waiting_for_decryption_key to CompoundDrawables.ic_compound_time
}
} }
TimelineItemInformativeView( TimelineItemInformativeView(
text = stringResource(id = textId), text = stringResource(id = textId),

14
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemEncryptedContentProvider.kt

@ -18,7 +18,19 @@ open class TimelineItemEncryptedContentProvider : PreviewParameterProvider<Timel
aTimelineItemEncryptedContent( aTimelineItemEncryptedContent(
data = UnableToDecryptContent.Data.MegolmV1AesSha2( data = UnableToDecryptContent.Data.MegolmV1AesSha2(
sessionId = "sessionId", sessionId = "sessionId",
utdCause = UtdCause.Membership, utdCause = UtdCause.SentBeforeWeJoined,
)
),
aTimelineItemEncryptedContent(
data = UnableToDecryptContent.Data.MegolmV1AesSha2(
sessionId = "sessionId",
utdCause = UtdCause.VerificationViolation,
)
),
aTimelineItemEncryptedContent(
data = UnableToDecryptContent.Data.MegolmV1AesSha2(
sessionId = "sessionId",
utdCause = UtdCause.UnsignedDevice,
) )
), ),
aTimelineItemEncryptedContent( aTimelineItemEncryptedContent(

4
gradle/libs.versions.toml

@ -169,7 +169,7 @@ jsoup = "org.jsoup:jsoup:1.18.1"
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
molecule-runtime = "app.cash.molecule:molecule-runtime:2.0.0" molecule-runtime = "app.cash.molecule:molecule-runtime:2.0.0"
timber = "com.jakewharton.timber:timber:5.0.1" timber = "com.jakewharton.timber:timber:5.0.1"
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.56" matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.57"
matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" } matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" } matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" }
sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" } sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
@ -193,7 +193,7 @@ zxing_cpp = "io.github.zxing-cpp:android:2.2.0"
posthog = "com.posthog:posthog-android:3.8.2" posthog = "com.posthog:posthog-android:3.8.2"
sentry = "io.sentry:sentry-android:7.15.0" sentry = "io.sentry:sentry-android:7.15.0"
# main branch can be tested replacing the version with main-SNAPSHOT # main branch can be tested replacing the version with main-SNAPSHOT
matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.25.0" matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.27.0"
# Emojibase # Emojibase
matrix_emojibase_bindings = "io.element.android:emojibase-bindings:1.3.3" matrix_emojibase_bindings = "io.element.android:emojibase-bindings:1.3.3"

1
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/LocalEventSendState.kt

@ -17,7 +17,6 @@ sealed interface LocalEventSendState {
data object Sending : LocalEventSendState data object Sending : LocalEventSendState
sealed interface Failed : LocalEventSendState { sealed interface Failed : LocalEventSendState {
data class Unknown(val error: String) : Failed data class Unknown(val error: String) : Failed
data object CrossSigningNotSetup : Failed
data object SendingFromUnverifiedDevice : Failed data object SendingFromUnverifiedDevice : Failed
sealed interface VerifiedUser : Failed sealed interface VerifiedUser : Failed

5
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/UtdCause.kt

@ -9,5 +9,8 @@ package io.element.android.libraries.matrix.api.timeline.item.event
enum class UtdCause { enum class UtdCause {
Unknown, Unknown,
Membership, SentBeforeWeJoined,
VerificationViolation,
UnsignedDevice,
UnknownDevice
} }

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

@ -398,7 +398,7 @@ class RustMatrixClient(
sessionDispatcher sessionDispatcher
) { ) {
runCatching { runCatching {
client.knock(roomIdOrAlias.identifier).destroy() client.knock(roomIdOrAlias.identifier, message, serverNames).destroy()
try { try {
awaitRoom(roomIdOrAlias, 10.seconds, CurrentUserMembership.KNOCKED) awaitRoom(roomIdOrAlias, 10.seconds, CurrentUserMembership.KNOCKED)
} catch (e: Exception) { } catch (e: Exception) {

7
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/analytics/UtdTracker.kt

@ -21,7 +21,12 @@ class UtdTracker(
Timber.d("onUtd for event ${info.eventId}, timeToDecryptMs: ${info.timeToDecryptMs}") Timber.d("onUtd for event ${info.eventId}, timeToDecryptMs: ${info.timeToDecryptMs}")
val name = when (info.cause) { val name = when (info.cause) {
UtdCause.UNKNOWN -> Error.Name.OlmKeysNotSentError UtdCause.UNKNOWN -> Error.Name.OlmKeysNotSentError
UtdCause.MEMBERSHIP -> Error.Name.ExpectedDueToMembership UtdCause.SENT_BEFORE_WE_JOINED -> Error.Name.ExpectedDueToMembership
UtdCause.VERIFICATION_VIOLATION -> Error.Name.ExpectedVerificationViolation
UtdCause.UNSIGNED_DEVICE,
UtdCause.UNKNOWN_DEVICE -> {
Error.Name.ExpectedSentByInsecureDevice
}
} }
val event = Error( val event = Error(
context = null, context = null,

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

@ -9,18 +9,13 @@ package io.element.android.libraries.matrix.impl.room
import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.timeline.item.event.EventType
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.RequiredState
import org.matrix.rustcomponents.sdk.RoomListService import org.matrix.rustcomponents.sdk.RoomListService
import org.matrix.rustcomponents.sdk.RoomSubscription
import timber.log.Timber import timber.log.Timber
private const val DEFAULT_TIMELINE_LIMIT = 20u
class RoomSyncSubscriber( class RoomSyncSubscriber(
private val roomListService: RoomListService, private val roomListService: RoomListService,
private val dispatchers: CoroutineDispatchers, private val dispatchers: CoroutineDispatchers,
@ -28,28 +23,13 @@ class RoomSyncSubscriber(
private val subscribedRoomIds = mutableSetOf<RoomId>() private val subscribedRoomIds = mutableSetOf<RoomId>()
private val mutex = Mutex() private val mutex = Mutex()
private val settings = RoomSubscription(
requiredState = listOf(
RequiredState(key = EventType.STATE_ROOM_NAME, value = ""),
RequiredState(key = EventType.STATE_ROOM_TOPIC, value = ""),
RequiredState(key = EventType.STATE_ROOM_AVATAR, value = ""),
RequiredState(key = EventType.STATE_ROOM_CANONICAL_ALIAS, value = ""),
RequiredState(key = EventType.STATE_ROOM_JOIN_RULES, value = ""),
RequiredState(key = EventType.STATE_ROOM_POWER_LEVELS, value = ""),
RequiredState(key = EventType.STATE_ROOM_PINNED_EVENT, value = ""),
),
timelineLimit = DEFAULT_TIMELINE_LIMIT,
// We don't need heroes here as they're already included in the `all_rooms` list
includeHeroes = false,
)
suspend fun subscribe(roomId: RoomId) { suspend fun subscribe(roomId: RoomId) {
mutex.withLock { mutex.withLock {
withContext(dispatchers.io) { withContext(dispatchers.io) {
try { try {
if (!isSubscribedTo(roomId)) { if (!isSubscribedTo(roomId)) {
Timber.d("Subscribing to room $roomId}") Timber.d("Subscribing to room $roomId}")
roomListService.subscribeToRooms(listOf(roomId.value), settings) roomListService.subscribeToRooms(listOf(roomId.value))
} }
subscribedRoomIds.add(roomId) subscribedRoomIds.add(roomId)
} catch (exception: Exception) { } catch (exception: Exception) {
@ -65,7 +45,7 @@ class RoomSyncSubscriber(
val roomIdsToSubscribeTo = roomIds.filterNot { isSubscribedTo(it) } val roomIdsToSubscribeTo = roomIds.filterNot { isSubscribedTo(it) }
if (roomIdsToSubscribeTo.isNotEmpty()) { if (roomIdsToSubscribeTo.isNotEmpty()) {
Timber.d("Subscribing to rooms: $roomIds") Timber.d("Subscribing to rooms: $roomIds")
roomListService.subscribeToRooms(roomIdsToSubscribeTo.map { it.value }, settings) roomListService.subscribeToRooms(roomIdsToSubscribeTo.map { it.value })
subscribedRoomIds.addAll(roomIds) subscribedRoomIds.addAll(roomIds)
} }
} catch (cancellationException: CancellationException) { } catch (cancellationException: CancellationException) {

6
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt

@ -339,6 +339,7 @@ class RustTimeline(
formattedCaption = formattedBody?.let { formattedCaption = formattedBody?.let {
FormattedBody(body = it, format = MessageFormat.Html) FormattedBody(body = it, format = MessageFormat.Html)
}, },
storeInCache = true,
progressWatcher = progressCallback?.toProgressWatcher() progressWatcher = progressCallback?.toProgressWatcher()
) )
} }
@ -361,6 +362,7 @@ class RustTimeline(
formattedCaption = formattedBody?.let { formattedCaption = formattedBody?.let {
FormattedBody(body = it, format = MessageFormat.Html) FormattedBody(body = it, format = MessageFormat.Html)
}, },
storeInCache = true,
progressWatcher = progressCallback?.toProgressWatcher() progressWatcher = progressCallback?.toProgressWatcher()
) )
} }
@ -374,6 +376,7 @@ class RustTimeline(
// Maybe allow a caption in the future? // Maybe allow a caption in the future?
caption = null, caption = null,
formattedCaption = null, formattedCaption = null,
storeInCache = true,
progressWatcher = progressCallback?.toProgressWatcher() progressWatcher = progressCallback?.toProgressWatcher()
) )
} }
@ -381,7 +384,7 @@ class RustTimeline(
override suspend fun sendFile(file: File, fileInfo: FileInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler> { override suspend fun sendFile(file: File, fileInfo: FileInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler> {
return sendAttachment(listOf(file)) { return sendAttachment(listOf(file)) {
inner.sendFile(file.path, fileInfo.map(), progressCallback?.toProgressWatcher()) inner.sendFile(file.path, fileInfo.map(), false, progressCallback?.toProgressWatcher())
} }
} }
@ -496,6 +499,7 @@ class RustTimeline(
// Maybe allow a caption in the future? // Maybe allow a caption in the future?
caption = null, caption = null,
formattedCaption = null, formattedCaption = null,
storeInCache = true,
progressWatcher = progressCallback?.toProgressWatcher(), progressWatcher = progressCallback?.toProgressWatcher(),
) )
} }

40
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt

@ -24,7 +24,7 @@ import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import org.matrix.rustcomponents.sdk.EventOrTransactionId import org.matrix.rustcomponents.sdk.EventOrTransactionId
import org.matrix.rustcomponents.sdk.EventSendState import org.matrix.rustcomponents.sdk.QueueWedgeError
import org.matrix.rustcomponents.sdk.Reaction import org.matrix.rustcomponents.sdk.Reaction
import org.matrix.rustcomponents.sdk.ShieldState import org.matrix.rustcomponents.sdk.ShieldState
import uniffi.matrix_sdk_common.ShieldStateCode import uniffi.matrix_sdk_common.ShieldStateCode
@ -78,25 +78,31 @@ fun RustEventSendState?.map(): LocalEventSendState? {
null -> null null -> null
RustEventSendState.NotSentYet -> LocalEventSendState.Sending RustEventSendState.NotSentYet -> LocalEventSendState.Sending
is RustEventSendState.SendingFailed -> { is RustEventSendState.SendingFailed -> {
if (isRecoverable) { when (val queueWedgeError = error) {
LocalEventSendState.Sending QueueWedgeError.CrossVerificationRequired -> {
} else { // The current device is not cross-signed (or cross signing is not setup)
LocalEventSendState.Failed.Unknown(error) LocalEventSendState.Failed.SendingFromUnverifiedDevice
}
is QueueWedgeError.IdentityViolations -> {
LocalEventSendState.Failed.VerifiedUserChangedIdentity(queueWedgeError.users.map { UserId(it) })
}
is QueueWedgeError.InsecureDevices -> {
LocalEventSendState.Failed.VerifiedUserHasUnsignedDevice(
devices = queueWedgeError.userDeviceMap.entries.associate { entry ->
UserId(entry.key) to entry.value.map { DeviceId(it) }
}
)
}
is QueueWedgeError.GenericApiError -> {
if (isRecoverable) {
LocalEventSendState.Sending
} else {
LocalEventSendState.Failed.Unknown(queueWedgeError.msg)
}
}
} }
} }
is RustEventSendState.Sent -> LocalEventSendState.Sent(EventId(eventId)) is RustEventSendState.Sent -> LocalEventSendState.Sent(EventId(eventId))
is RustEventSendState.VerifiedUserChangedIdentity -> {
LocalEventSendState.Failed.VerifiedUserChangedIdentity(users.map { UserId(it) })
}
is RustEventSendState.VerifiedUserHasUnsignedDevice -> {
LocalEventSendState.Failed.VerifiedUserHasUnsignedDevice(
devices = devices.entries.associate { entry ->
UserId(entry.key) to entry.value.map { DeviceId(it) }
}
)
}
EventSendState.CrossSigningNotSetup -> LocalEventSendState.Failed.CrossSigningNotSetup
EventSendState.SendingFromUnverifiedDevice -> LocalEventSendState.Failed.SendingFromUnverifiedDevice
} }
} }

5
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt

@ -140,8 +140,11 @@ private fun RustMembershipChange.map(): MembershipChange {
private fun RustUtdCause.map(): UtdCause { private fun RustUtdCause.map(): UtdCause {
return when (this) { return when (this) {
RustUtdCause.MEMBERSHIP -> UtdCause.Membership RustUtdCause.SENT_BEFORE_WE_JOINED -> UtdCause.SentBeforeWeJoined
RustUtdCause.UNKNOWN -> UtdCause.Unknown RustUtdCause.UNKNOWN -> UtdCause.Unknown
RustUtdCause.VERIFICATION_VIOLATION -> UtdCause.VerificationViolation
RustUtdCause.UNSIGNED_DEVICE -> UtdCause.UnsignedDevice
RustUtdCause.UNKNOWN_DEVICE -> UtdCause.UnknownDevice
} }
} }

48
libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/analytics/UtdTrackerTest.kt

@ -74,7 +74,7 @@ class UtdTrackerTest {
UnableToDecryptInfo( UnableToDecryptInfo(
eventId = AN_EVENT_ID.value, eventId = AN_EVENT_ID.value,
timeToDecryptMs = 123.toULong(), timeToDecryptMs = 123.toULong(),
cause = UtdCause.MEMBERSHIP, cause = UtdCause.SENT_BEFORE_WE_JOINED,
) )
) )
assertThat(fakeAnalyticsService.capturedEvents).containsExactly( assertThat(fakeAnalyticsService.capturedEvents).containsExactly(
@ -90,4 +90,50 @@ class UtdTrackerTest {
assertThat(fakeAnalyticsService.screenEvents).isEmpty() assertThat(fakeAnalyticsService.screenEvents).isEmpty()
assertThat(fakeAnalyticsService.trackedErrors).isEmpty() assertThat(fakeAnalyticsService.trackedErrors).isEmpty()
} }
@Test
fun `when onUtd is called with insecure cause, the expected analytics Event is sent`() {
val fakeAnalyticsService = FakeAnalyticsService()
val sut = UtdTracker(fakeAnalyticsService)
sut.onUtd(
UnableToDecryptInfo(
eventId = AN_EVENT_ID.value,
timeToDecryptMs = 123.toULong(),
cause = UtdCause.UNSIGNED_DEVICE,
)
)
assertThat(fakeAnalyticsService.capturedEvents).containsExactly(
Error(
context = null,
cryptoModule = Error.CryptoModule.Rust,
cryptoSDK = Error.CryptoSDK.Rust,
timeToDecryptMillis = 123,
domain = Error.Domain.E2EE,
name = Error.Name.ExpectedSentByInsecureDevice
)
)
}
@Test
fun `when onUtd is called with verification violation cause, the expected analytics Event is sent`() {
val fakeAnalyticsService = FakeAnalyticsService()
val sut = UtdTracker(fakeAnalyticsService)
sut.onUtd(
UnableToDecryptInfo(
eventId = AN_EVENT_ID.value,
timeToDecryptMs = 123.toULong(),
cause = UtdCause.VERIFICATION_VIOLATION,
)
)
assertThat(fakeAnalyticsService.capturedEvents).containsExactly(
Error(
context = null,
cryptoModule = Error.CryptoModule.Rust,
cryptoSDK = Error.CryptoSDK.Rust,
timeToDecryptMillis = 123,
domain = Error.Domain.E2EE,
name = Error.Name.ExpectedVerificationViolation
)
)
}
} }

2
libraries/ui-strings/src/main/res/values/localazy.xml

@ -238,7 +238,9 @@ Reason: %1$s."</string>
<string name="common_topic">"Topic"</string> <string name="common_topic">"Topic"</string>
<string name="common_topic_placeholder">"What is this room about?"</string> <string name="common_topic_placeholder">"What is this room about?"</string>
<string name="common_unable_to_decrypt">"Unable to decrypt"</string> <string name="common_unable_to_decrypt">"Unable to decrypt"</string>
<string name="common_unable_to_decrypt_insecure_device">"Sent from an insecure device"</string>
<string name="common_unable_to_decrypt_no_access">"You don\'t have access to this message"</string> <string name="common_unable_to_decrypt_no_access">"You don\'t have access to this message"</string>
<string name="common_unable_to_decrypt_verification_violation">"Sender\'s verified identity has changed"</string>
<string name="common_unable_to_invite_message">"Invites couldn\'t be sent to one or more users."</string> <string name="common_unable_to_invite_message">"Invites couldn\'t be sent to one or more users."</string>
<string name="common_unable_to_invite_title">"Unable to send invite(s)"</string> <string name="common_unable_to_invite_title">"Unable to send invite(s)"</string>
<string name="common_unlock">"Unlock"</string> <string name="common_unlock">"Unlock"</string>

1
tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt

@ -113,6 +113,7 @@ class KonsistPreviewTest {
"TimelineItemEventRowForDirectRoomPreview", "TimelineItemEventRowForDirectRoomPreview",
"TimelineItemEventRowShieldPreview", "TimelineItemEventRowShieldPreview",
"TimelineItemEventRowTimestampPreview", "TimelineItemEventRowTimestampPreview",
"TimelineItemEventRowUtdPreview",
"TimelineItemEventRowWithManyReactionsPreview", "TimelineItemEventRowWithManyReactionsPreview",
"TimelineItemEventRowWithRRPreview", "TimelineItemEventRowWithRRPreview",
"TimelineItemEventRowWithReplyPreview", "TimelineItemEventRowWithReplyPreview",

4
tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_2_en.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:fee2af8462597d58274b7168c5cfe1f6d6b0909b048adc0f4fc5b3c12a90b859 oid sha256:cfc3dc1420a58d25b5fd248f0b77c3c336bb03c402c904d0678c35a5abe291f2
size 8861 size 10753

3
tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_3_en.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8beabd7aadf0324e9b66278c49fdd896b1451a805fd15e69aa6c4af37cb7c150
size 9055

3
tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Day_4_en.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fee2af8462597d58274b7168c5cfe1f6d6b0909b048adc0f4fc5b3c12a90b859
size 8861

4
tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_2_en.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:d4f48cd7dc7e2bbf7363d1127e46721c25bb8dd887927dbcffe525f5bb5bae01 oid sha256:d4d9879eda9ffa9c171c5351d9ef8e7b32cad50996717445c9b87cdad8a3d973
size 8781 size 10634

3
tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_3_en.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:077f898ad7822b6a5ff54429bc91e4faef377fb06de28a4cea73483e6adc5ffd
size 9025

3
tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_TimelineItemEncryptedView_Night_4_en.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d4f48cd7dc7e2bbf7363d1127e46721c25bb8dd887927dbcffe525f5bb5bae01
size 8781

3
tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowUtd_Day_0_en.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b1f04171ef894f299b58cc15158daf9655cc04f9ab2418973e7e6e78e22884e8
size 31693

3
tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowUtd_Night_0_en.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8ce15bbbb3bc562f92a7d07a0f2f907d4e351e0b7133a61b7ef49540ef622c15
size 30613
Loading…
Cancel
Save