From c7f4c96f70791a3e04d2d77a8cd0ffd4208e9c79 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 22:04:39 +0000 Subject: [PATCH 01/10] Update dependency androidx.sqlite:sqlite-ktx to v2.7.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ef95884507..d3cb11cdc5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -209,7 +209,7 @@ sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", ver sqldelight-driver-jvm = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqldelight" } sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqldelight" } sqlcipher = "net.zetetic:sqlcipher-android:4.16.0" -sqlite = "androidx.sqlite:sqlite-ktx:2.6.2" +sqlite = "androidx.sqlite:sqlite-ktx:2.7.0" unifiedpush = "org.unifiedpush.android:connector:3.3.3" vanniktech_blurhash = "com.vanniktech:blurhash:0.3.0" telephoto_zoomableimage = { module = "me.saket.telephoto:zoomable-image-coil3", version.ref = "telephoto" } From b0c9947a11baf3bfb41ec1fa1b8bd8d7132831d9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Jul 2026 08:06:26 +0000 Subject: [PATCH 02/10] Update dependency org.matrix.rustcomponents:sdk-android to v26.07.13 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 90dd5c39bc..edf63b0fb9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -185,7 +185,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.06.30" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:26.07.13" # Others coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" } From 09b7732c1b1c278a40de03084a0c8403ab8ba4d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Tue, 14 Jul 2026 15:45:26 +0200 Subject: [PATCH 03/10] Fix API breaks: - Add `Beacon` variants for `NotificationData`. - Add `call` and `status` to `UserProfile`. --- .../libraries/matrix/api/notification/NotificationData.kt | 3 +++ .../TimelineEventToNotificationContentMapper.kt | 2 ++ .../android/libraries/matrix/impl/RustMatrixClientTest.kt | 2 ++ .../matrix/impl/fixtures/factories/UserProfile.kt | 6 ++++++ .../libraries/matrix/impl/fixtures/fakes/FakeFfiClient.kt | 3 ++- .../impl/notifications/DefaultNotifiableEventResolver.kt | 7 ++++++- 6 files changed, 21 insertions(+), 2 deletions(-) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationData.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationData.kt index c58a458865..8a4891a5bf 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationData.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationData.kt @@ -89,6 +89,8 @@ sealed interface NotificationContent { val senderId: UserId, val question: String, ) : MessageLike + + data object Beacon : MessageLike } sealed interface StateEvent : NotificationContent { @@ -116,6 +118,7 @@ sealed interface NotificationContent { data class RoomTopic(val topic: String) : StateEvent data object SpaceChild : StateEvent data object SpaceParent : StateEvent + data object BeaconInfo : StateEvent } data class Invite( diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/TimelineEventToNotificationContentMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/TimelineEventToNotificationContentMapper.kt index 84fd2e80e8..e4914019ea 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/TimelineEventToNotificationContentMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/TimelineEventToNotificationContentMapper.kt @@ -71,6 +71,7 @@ private fun StateEventContent.toContent(): NotificationContent.StateEvent { is StateEventContent.RoomTopic -> NotificationContent.StateEvent.RoomTopic(topic) StateEventContent.SpaceChild -> NotificationContent.StateEvent.SpaceChild StateEventContent.SpaceParent -> NotificationContent.StateEvent.SpaceParent + StateEventContent.BeaconInfo -> NotificationContent.StateEvent.BeaconInfo } } @@ -108,6 +109,7 @@ private fun MessageLikeEventContent.toContent(senderId: UserId): NotificationCon ) MessageLikeEventContent.Sticker -> NotificationContent.MessageLike.Sticker is MessageLikeEventContent.Poll -> NotificationContent.MessageLike.Poll(senderId, question) + MessageLikeEventContent.Beacon -> NotificationContent.MessageLike.Beacon } } } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientTest.kt index 745fbf02d5..49cf59a954 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientTest.kt @@ -90,6 +90,8 @@ class RustMatrixClientTest { userId = userId, displayName = A_USER_NAME, avatarUrl = AN_AVATAR_URL, + status = null, + call = null, ) }, ), diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/UserProfile.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/UserProfile.kt index 8713e08f1c..947e6e7aa1 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/UserProfile.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/UserProfile.kt @@ -9,14 +9,20 @@ package io.element.android.libraries.matrix.impl.fixtures.factories import io.element.android.libraries.matrix.test.A_USER_ID +import org.matrix.rustcomponents.sdk.UserCall import org.matrix.rustcomponents.sdk.UserProfile +import org.matrix.rustcomponents.sdk.UserStatus internal fun aRustUserProfile( userId: String = A_USER_ID.value, displayName: String = "displayName", avatarUrl: String = "avatarUrl", + status: UserStatus? = null, + call: UserCall? = null, ) = UserProfile( userId = userId, displayName = displayName, avatarUrl = avatarUrl, + status = status, + call = call, ) diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiClient.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiClient.kt index 4c23744d53..efae379415 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiClient.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiClient.kt @@ -9,6 +9,7 @@ package io.element.android.libraries.matrix.impl.fixtures.fakes import io.element.android.libraries.matrix.impl.fixtures.factories.aRustSession +import io.element.android.libraries.matrix.impl.fixtures.factories.aRustUserProfile import io.element.android.libraries.matrix.test.A_DEVICE_ID import io.element.android.libraries.matrix.test.A_HOMESERVER_URL import io.element.android.libraries.matrix.test.A_USER_ID @@ -49,7 +50,7 @@ class FakeFfiClient( private val session: Session = aRustSession(), private val clearCachesResult: () -> Unit = { lambdaError() }, private val withUtdHook: (UnableToDecryptDelegate) -> Unit = { lambdaError() }, - private val getProfileResult: (String) -> UserProfile = { UserProfile(userId = userId, displayName = null, avatarUrl = null) }, + private val getProfileResult: (String) -> UserProfile = { aRustUserProfile() }, private val homeserverLoginDetailsResult: () -> HomeserverLoginDetails = { lambdaError() }, private val getStoreSizesResult: () -> StoreSizes = { lambdaError() }, private val createRoomResult: (CreateRoomParameters) -> String = { lambdaError() }, diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolver.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolver.kt index 2f3fa9b0b7..0b2ae5be2c 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolver.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolver.kt @@ -299,6 +299,10 @@ class DefaultNotifiableEventResolver( Timber.tag(loggerTag.value).d("Ignoring notification for sticker") throw NotificationResolverException.EventFilteredOut } + NotificationContent.MessageLike.Beacon -> { + Timber.tag(loggerTag.value).d("Ignoring notification for beacon") + throw NotificationResolverException.EventFilteredOut + } is NotificationContent.StateEvent.RoomMemberContent, NotificationContent.StateEvent.PolicyRuleRoom, NotificationContent.StateEvent.PolicyRuleServer, @@ -318,7 +322,8 @@ class DefaultNotifiableEventResolver( NotificationContent.StateEvent.RoomTombstone, is NotificationContent.StateEvent.RoomTopic, NotificationContent.StateEvent.SpaceChild, - NotificationContent.StateEvent.SpaceParent -> { + NotificationContent.StateEvent.SpaceParent, + NotificationContent.StateEvent.BeaconInfo -> { Timber.tag(loggerTag.value).d("Ignoring notification for state event ${content.javaClass.simpleName}") throw NotificationResolverException.EventFilteredOut } From 1619155b87407812caa133485ce3a0fdf250cf30 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 15:48:26 +0200 Subject: [PATCH 04/10] Update dependency io.github.sergio-sastre.ComposablePreviewScanner:android to v0.9.1 (#7201) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 90dd5c39bc..80b428bf8f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -175,7 +175,7 @@ test_truth = "com.google.truth:truth:1.4.5" test_parameter_injector = "com.google.testparameterinjector:test-parameter-injector:1.22" test_robolectric = "org.robolectric:robolectric:4.16.1" test_appyx_junit = { module = "com.bumble.appyx:testing-junit4", version.ref = "appyx" } -test_composable_preview_scanner = "io.github.sergio-sastre.ComposablePreviewScanner:android:0.9.0" +test_composable_preview_scanner = "io.github.sergio-sastre.ComposablePreviewScanner:android:0.9.1" test_detekt_api = { module = "io.gitlab.arturbosch.detekt:detekt-api", version.ref = "detekt" } test_detekt_test = { module = "io.gitlab.arturbosch.detekt:detekt-test", version.ref = "detekt" } From 3bb7fe97e651bed2daa541d4887ba3bbf1bebf64 Mon Sep 17 00:00:00 2001 From: Timo <16718859+toger5@users.noreply.github.com> Date: Tue, 14 Jul 2026 17:49:40 +0200 Subject: [PATCH 05/10] Default to dark theme for EC (#7162) * Default to dark theme for EC (this is the intended design on light and dark system configuration) * Use `theme=dark` url param for element call * Update CallScreenPresenter.kt --- .../call/impl/ui/CallScreenPresenter.kt | 3 +- .../call/impl/ui/ElementCallActivity.kt | 37 +++++++++++-------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt index 7d8e20967f..cc3468a845 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt @@ -22,7 +22,6 @@ import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedFactory import dev.zacsweers.metro.AssistedInject import im.vector.app.features.analytics.plan.MobileScreen -import io.element.android.compound.theme.ElementTheme import io.element.android.features.call.api.CallData import io.element.android.features.call.impl.data.WidgetMessage import io.element.android.features.call.impl.utils.ActiveCallManager @@ -84,7 +83,7 @@ class CallScreenPresenter( var ignoreWebViewError by rememberSaveable { mutableStateOf(false) } var webViewError by remember { mutableStateOf(null) } val languageTag = languageTagProvider.provideLanguageTag() - val theme = if (ElementTheme.isLightTheme) "light" else "dark" + val theme = "dark" DisposableEffect(Unit) { coroutineScope.launch { diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/ElementCallActivity.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/ElementCallActivity.kt index 26df7c160c..9a093ff5a6 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/ElementCallActivity.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/ElementCallActivity.kt @@ -38,6 +38,7 @@ import androidx.core.view.WindowInsetsControllerCompat import androidx.lifecycle.Lifecycle import dev.zacsweers.metro.Inject import io.element.android.compound.colors.SemanticColorsLightDark +import io.element.android.compound.theme.ForcedDarkElementTheme import io.element.android.features.call.api.CallData import io.element.android.features.call.impl.DefaultElementCallEntryPoint import io.element.android.features.call.impl.di.CallBindings @@ -143,24 +144,28 @@ class ElementCallActivity : compoundDark = colors.dark, buildMeta = buildMeta, ) { - val state = presenter.present() - eventSink = state.eventSink - LaunchedEffect(state.isCallActive) { - if (state.isCallActive) { - setCallIsActive() + ForcedDarkElementTheme( + colors = colors, + ) { + val state = presenter.present() + eventSink = state.eventSink + LaunchedEffect(state.isCallActive) { + if (state.isCallActive) { + setCallIsActive() + } } + CallScreenView( + state = state, + pipState = pipState, + onConsoleMessage = { + consoleMessageLogger.log("ElementCall", it) + }, + requestPermissions = { permissions, callback -> + requestPermissionCallback = callback + requestPermissionsLauncher.launch(permissions) + } + ) } - CallScreenView( - state = state, - pipState = pipState, - onConsoleMessage = { - consoleMessageLogger.log("ElementCall", it) - }, - requestPermissions = { permissions, callback -> - requestPermissionCallback = callback - requestPermissionsLauncher.launch(permissions) - } - ) } } } From afdf07b23e1ca829c758b315fd9e4ffcb2eb8e2a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 15 Jul 2026 08:36:59 +0200 Subject: [PATCH 06/10] Update dependency io.github.zxing-cpp:android to v3.1.0 (#7206) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 80b428bf8f..027fe03526 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -220,7 +220,7 @@ maplibre_ktx = "org.maplibre.gl:android-sdk-ktx-v7:3.0.2" maplibre_compose = "org.maplibre.compose:maplibre-compose:0.13.0" maplibre_annotation = "org.maplibre.gl:android-plugin-annotation-v9:3.0.2" opusencoder = "io.element.android:opusencoder:1.2.0" -zxing_cpp = "io.github.zxing-cpp:android:3.0.2" +zxing_cpp = "io.github.zxing-cpp:android:3.1.0" google_zxing = "com.google.zxing:core:3.5.4" google_guava = "com.google.guava:guava:33.6.0-android" From e915cd242ba0b18a474fceb92584342711544eb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Wischer?= <33184634+unclejay80@users.noreply.github.com> Date: Wed, 15 Jul 2026 09:23:54 +0200 Subject: [PATCH 07/10] Expose current/max progress values to accessibility services (#7209) --- .../theme/components/LinearProgressIndicator.kt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/LinearProgressIndicator.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/LinearProgressIndicator.kt index 04f08166b7..77946dd5ab 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/LinearProgressIndicator.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/LinearProgressIndicator.kt @@ -16,6 +16,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.semantics.ProgressBarRangeInfo +import androidx.compose.ui.semantics.progressBarRangeInfo +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -32,7 +35,9 @@ fun LinearProgressIndicator( strokeCap: StrokeCap = ProgressIndicatorDefaults.LinearStrokeCap, ) { androidx.compose.material3.LinearProgressIndicator( - modifier = modifier, + modifier = modifier.semantics { + progressBarRangeInfo = ProgressBarRangeInfo(progress(), 0f..1f) + }, progress = progress, gapSize = gapSize, color = color, @@ -63,7 +68,9 @@ fun LinearProgressIndicator( ) } else { androidx.compose.material3.LinearProgressIndicator( - modifier = modifier, + modifier = modifier.semantics { + progressBarRangeInfo = ProgressBarRangeInfo.Indeterminate + }, color = color, gapSize = gapSize, trackColor = trackColor, From f794cb9f063cbc0dede429b593967fe1b6814c20 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 15 Jul 2026 09:49:06 +0200 Subject: [PATCH 08/10] Revert "Expose current/max progress values to accessibility services (#7209)" This reverts commit e915cd242ba0b18a474fceb92584342711544eb1. --- .../theme/components/LinearProgressIndicator.kt | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/LinearProgressIndicator.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/LinearProgressIndicator.kt index 77946dd5ab..04f08166b7 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/LinearProgressIndicator.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/LinearProgressIndicator.kt @@ -16,9 +16,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.platform.LocalInspectionMode -import androidx.compose.ui.semantics.ProgressBarRangeInfo -import androidx.compose.ui.semantics.progressBarRangeInfo -import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -35,9 +32,7 @@ fun LinearProgressIndicator( strokeCap: StrokeCap = ProgressIndicatorDefaults.LinearStrokeCap, ) { androidx.compose.material3.LinearProgressIndicator( - modifier = modifier.semantics { - progressBarRangeInfo = ProgressBarRangeInfo(progress(), 0f..1f) - }, + modifier = modifier, progress = progress, gapSize = gapSize, color = color, @@ -68,9 +63,7 @@ fun LinearProgressIndicator( ) } else { androidx.compose.material3.LinearProgressIndicator( - modifier = modifier.semantics { - progressBarRangeInfo = ProgressBarRangeInfo.Indeterminate - }, + modifier = modifier, color = color, gapSize = gapSize, trackColor = trackColor, From 03f3e8b3e08f7987686c2a59ddc821dde5c4d556 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Wed, 15 Jul 2026 10:56:50 +0200 Subject: [PATCH 09/10] Try fixing DM creation in Maestro (#7204) * Try fixing DM creation in Maestro * Also handle 'invite new people to this room' with first invite to aRoomName * Try adding a room list clean up sub-flow * No need to press back button after successful invites * Looks like 'hideKeyboard' works as 'back' and messes up with the navigation. Try using the workaround described in https://docs.maestro.dev/reference/commands-available/hidekeyboard#workarounds --- .maestro/tests/roomList/cleanUpRoomList.yaml | 21 +++++++++++++++++++ .../tests/roomList/createAndDeleteDM.yaml | 11 +++++++++- .../tests/roomList/createAndDeleteRoom.yaml | 14 +++++++++---- .maestro/tests/roomList/roomList.yaml | 1 + .../invitepeople/impl/InvitePeopleView.kt | 4 ++-- 5 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 .maestro/tests/roomList/cleanUpRoomList.yaml diff --git a/.maestro/tests/roomList/cleanUpRoomList.yaml b/.maestro/tests/roomList/cleanUpRoomList.yaml new file mode 100644 index 0000000000..3d9fb3d6e4 --- /dev/null +++ b/.maestro/tests/roomList/cleanUpRoomList.yaml @@ -0,0 +1,21 @@ +appId: ${MAESTRO_APP_ID} +--- +# Clean up the room list if it was left in a bad state by previous tests +- runFlow: + when: + visible: 'aRoomName' + commands: + - longPressOn: 'aRoomName' + - tapOn: + text: "Leave room" + index: 0 + - tapOn: "Leave" +- runFlow: + when: + visible: ${MAESTRO_INVITEE1_MXID} + commands: + - longPressOn: ${MAESTRO_INVITEE1_MXID} + - tapOn: + text: "Leave room" + index: 0 + - tapOn: "Leave" diff --git a/.maestro/tests/roomList/createAndDeleteDM.yaml b/.maestro/tests/roomList/createAndDeleteDM.yaml index eed576c04f..8372d6dbc9 100644 --- a/.maestro/tests/roomList/createAndDeleteDM.yaml +++ b/.maestro/tests/roomList/createAndDeleteDM.yaml @@ -7,7 +7,16 @@ appId: ${MAESTRO_APP_ID} - tapOn: text: ${MAESTRO_INVITEE1_MXID} index: 1 -- tapOn: "Continue" +- runFlow: + when: + visible: 'Start a chat with this new contact?' + commands: + - tapOn: 'Continue' +- runFlow: + when: + visible: 'Send invite?' + commands: + - tapOn: 'Send invite' - takeScreenshot: build/maestro/330-createAndDeleteDM - tapOn: "maestroelement2" - scroll diff --git a/.maestro/tests/roomList/createAndDeleteRoom.yaml b/.maestro/tests/roomList/createAndDeleteRoom.yaml index adf9d7cf29..6b4d745fae 100644 --- a/.maestro/tests/roomList/createAndDeleteRoom.yaml +++ b/.maestro/tests/roomList/createAndDeleteRoom.yaml @@ -15,6 +15,12 @@ appId: ${MAESTRO_APP_ID} text: ${MAESTRO_INVITEE1_MXID} index: 1 - tapOn: "Finish" +- runFlow: + when: + visible: 'Invite new contact to this room?' + commands: + - tapOn: + id: "confirm_invite_unknown" - tapOn: "aRoomName" - tapOn: "Invite" # assert there's 1 member and 1 invitee @@ -23,6 +29,10 @@ appId: ${MAESTRO_APP_ID} - tapOn: text: ${MAESTRO_INVITEE2_MXID} index: 1 +# Hide keyboard by tapping on an external element in case it's displayed, otherwise it will 'eat' the back button press +- tapOn: + # Navigation title + text: "Invite people" - tapOn: "Invite" - runFlow: when: @@ -30,10 +40,6 @@ appId: ${MAESTRO_APP_ID} commands: - tapOn: id: "confirm_invite_unknown" -# Close the keyboard if it's still open -- tapOn: "Back" -# Go back to the room details screen -- tapOn: "Back" - scrollUntilVisible: direction: DOWN element: diff --git a/.maestro/tests/roomList/roomList.yaml b/.maestro/tests/roomList/roomList.yaml index 5cc9e269c5..704d983b7d 100644 --- a/.maestro/tests/roomList/roomList.yaml +++ b/.maestro/tests/roomList/roomList.yaml @@ -1,5 +1,6 @@ appId: ${MAESTRO_APP_ID} --- +- runFlow: cleanUpRoomList.yaml - runFlow: searchRoomList.yaml - takeScreenshot: build/maestro/300-RoomList - runFlow: timeline/timeline.yaml diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt index 2bbd64c977..0ee3559aa3 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt @@ -302,13 +302,13 @@ private fun InvitePeopleConfirmModal( text = stringResource(CommonStrings.action_remove), onClick = onRemove, leadingIcon = IconSource.Vector(CompoundIcons.Close()), - modifier = Modifier.weight(1f).testTag(TestTags.confirmInviteUnknown), + modifier = Modifier.weight(1f), ) Button( text = stringResource(CommonStrings.action_invite), onClick = onInvite, leadingIcon = IconSource.Vector(CompoundIcons.Check()), - modifier = Modifier.weight(1f) + modifier = Modifier.weight(1f).testTag(TestTags.confirmInviteUnknown), ) } } From 62cc7e0505e461722548ee79882bc72693c724a9 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Wed, 15 Jul 2026 13:29:16 +0200 Subject: [PATCH 10/10] Allow homeserver to disable encryption in Element Pro (#7198) * Allow HS to disable encryption in Element Pro Add `force_disable_e2ee` support in the Element well known retriever and cache to allow a homeserver to disable encrypted room creation and enabling encryption in an existing room in Element Pro clients * Bump enterprise repo back to `main` branch --- enterprise | 2 +- features/createroom/impl/build.gradle.kts | 2 ++ .../configureroom/ConfigureRoomPresenter.kt | 4 ++- .../impl/ConfigureRoomPresenterTest.kt | 29 +++++++++++++++++++ .../api/SessionEnterpriseService.kt | 2 ++ .../impl/DefaultSessionEnterpriseService.kt | 1 + .../test/FakeSessionEnterpriseService.kt | 5 ++++ .../securityandprivacy/impl/build.gradle.kts | 2 ++ .../impl/root/SecurityAndPrivacyPresenter.kt | 7 +++++ .../impl/root/SecurityAndPrivacyState.kt | 3 +- .../root/SecurityAndPrivacyStateProvider.kt | 2 ++ .../root/SecurityAndPrivacyPresenterTest.kt | 19 ++++++++++++ .../libraries/matrix/test/FakeMatrixClient.kt | 8 ++--- .../wellknown/api/ElementWellKnown.kt | 1 + .../impl/InternalElementWellKnown.kt | 2 ++ .../libraries/wellknown/impl/Mapper.kt | 1 + .../DefaultSessionWellknownRetrieverTest.kt | 8 ++++- .../impl/DefaultWellknownRetrieverTest.kt | 6 +++- .../features/wellknown/test/Fixtures.kt | 2 ++ 19 files changed, 97 insertions(+), 9 deletions(-) diff --git a/enterprise b/enterprise index bc38a11f95..cca96c4fc2 160000 --- a/enterprise +++ b/enterprise @@ -1 +1 @@ -Subproject commit bc38a11f95988cc1bbc209decb998f21c465ded0 +Subproject commit cca96c4fc24b6e2fd1ccf9265c8283ac9bf63dc0 diff --git a/features/createroom/impl/build.gradle.kts b/features/createroom/impl/build.gradle.kts index 13a195e940..2cd3961ead 100644 --- a/features/createroom/impl/build.gradle.kts +++ b/features/createroom/impl/build.gradle.kts @@ -43,6 +43,7 @@ dependencies { implementation(libs.coil.compose) implementation(projects.libraries.featureflag.api) implementation(projects.features.invitepeople.api) + implementation(projects.features.enterprise.api) api(projects.features.createroom.api) testCommonDependencies(libs, true) @@ -53,4 +54,5 @@ dependencies { testImplementation(projects.libraries.permissions.test) testImplementation(projects.features.startchat.test) testImplementation(projects.libraries.featureflag.test) + testImplementation(projects.features.enterprise.test) } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt index 0d74ca05bf..abedc2bd49 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt @@ -24,6 +24,7 @@ import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedFactory import dev.zacsweers.metro.AssistedInject import im.vector.app.features.analytics.plan.CreatedRoom +import io.element.android.features.enterprise.api.SessionEnterpriseService import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runCatchingUpdatingState @@ -73,6 +74,7 @@ class ConfigureRoomPresenter( private val featureFlagService: FeatureFlagService, private val roomAliasHelper: RoomAliasHelper, private val mediaOptimizationConfigProvider: MediaOptimizationConfigProvider, + private val sessionEnterpriseService: SessionEnterpriseService, ) : Presenter { @AssistedFactory interface Factory { @@ -256,7 +258,7 @@ class ConfigureRoomPresenter( CreateRoomParameters( name = config.roomName, topic = config.topic, - isEncrypted = true, + isEncrypted = !sessionEnterpriseService.isEncryptionDisabledByHomeserver(), isDirect = false, visibility = RoomVisibility.Private, historyVisibilityOverride = RoomHistoryVisibility.Invited, diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/ConfigureRoomPresenterTest.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/ConfigureRoomPresenterTest.kt index c0c4a8a5fe..046d00a5c6 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/ConfigureRoomPresenterTest.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/ConfigureRoomPresenterTest.kt @@ -20,11 +20,13 @@ import io.element.android.features.createroom.impl.configureroom.CreateRoomConfi import io.element.android.features.createroom.impl.configureroom.JoinRuleItem import io.element.android.features.createroom.impl.configureroom.RoomAddress import io.element.android.features.createroom.impl.configureroom.RoomVisibilityState +import io.element.android.features.enterprise.test.FakeSessionEnterpriseService import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters import io.element.android.libraries.matrix.api.room.RoomInfo import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper @@ -56,6 +58,7 @@ import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.lambda.matching import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.test import io.mockk.mockk @@ -517,6 +520,30 @@ class ConfigureRoomPresenterTest : RobolectricTest() { } } + @Test + fun `present - creating a private room when encryption is disabled by the HS creates it unencrypted`() = runTest { + val sessionEnterpriseService = FakeSessionEnterpriseService(isEncryptionDisabledResult = { true }) + val createRoomLambda = lambdaRecorder> { Result.success(A_ROOM_ID) } + val matrixClient = createMatrixClient().apply { + createRoomResult = createRoomLambda + } + val presenter = createConfigureRoomPresenter( + matrixClient = matrixClient, + sessionEnterpriseService = sessionEnterpriseService, + ) + presenter.test { + val initialState = initialState() + + initialState.eventSink(ConfigureRoomEvents.JoinRuleChanged(JoinRuleItem.PrivateVisibility.Private)) + initialState.eventSink(ConfigureRoomEvents.CreateRoom) + + assertThat(awaitItem().createRoomAction.isLoading()).isTrue() + assertThat(awaitItem().createRoomAction.isSuccess()).isTrue() + + createRoomLambda.assertions().isCalledOnce().with(matching { !it.isEncrypted }) + } + } + private suspend fun TurbineTestContext.initialState(): ConfigureRoomState { skipItems(1) return awaitItem() @@ -552,6 +579,7 @@ class ConfigureRoomPresenterTest : RobolectricTest() { permissionsPresenter: PermissionsPresenter = FakePermissionsPresenter(), isKnockFeatureEnabled: Boolean = true, mediaOptimizationConfigProvider: FakeMediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider(), + sessionEnterpriseService: FakeSessionEnterpriseService = FakeSessionEnterpriseService(isEncryptionDisabledResult = { false }), ) = ConfigureRoomPresenter( isSpace = isSpace, initialParentSpaceId = initialParenSpaceId, @@ -566,5 +594,6 @@ class ConfigureRoomPresenterTest : RobolectricTest() { mapOf(FeatureFlags.Knock.key to isKnockFeatureEnabled) ), mediaOptimizationConfigProvider = mediaOptimizationConfigProvider, + sessionEnterpriseService = sessionEnterpriseService, ) } diff --git a/features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/SessionEnterpriseService.kt b/features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/SessionEnterpriseService.kt index f87dc743e8..ee005a0b6b 100644 --- a/features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/SessionEnterpriseService.kt +++ b/features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/SessionEnterpriseService.kt @@ -12,5 +12,7 @@ interface SessionEnterpriseService { suspend fun isElementCallAvailable(): Boolean suspend fun tweakMasUrl(url: String): String + suspend fun isEncryptionDisabledByHomeserver(): Boolean + suspend fun init() } diff --git a/features/enterprise/impl-foss/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultSessionEnterpriseService.kt b/features/enterprise/impl-foss/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultSessionEnterpriseService.kt index 9aafcd343c..3ac10d8a08 100644 --- a/features/enterprise/impl-foss/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultSessionEnterpriseService.kt +++ b/features/enterprise/impl-foss/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultSessionEnterpriseService.kt @@ -17,4 +17,5 @@ class DefaultSessionEnterpriseService : SessionEnterpriseService { override suspend fun init() = Unit override suspend fun tweakMasUrl(url: String): String = url override suspend fun isElementCallAvailable(): Boolean = true + override suspend fun isEncryptionDisabledByHomeserver(): Boolean = false } diff --git a/features/enterprise/test/src/main/kotlin/io/element/android/features/enterprise/test/FakeSessionEnterpriseService.kt b/features/enterprise/test/src/main/kotlin/io/element/android/features/enterprise/test/FakeSessionEnterpriseService.kt index 0bcad13033..e198fca867 100644 --- a/features/enterprise/test/src/main/kotlin/io/element/android/features/enterprise/test/FakeSessionEnterpriseService.kt +++ b/features/enterprise/test/src/main/kotlin/io/element/android/features/enterprise/test/FakeSessionEnterpriseService.kt @@ -15,6 +15,7 @@ import io.element.android.tests.testutils.simulateLongTask class FakeSessionEnterpriseService( private val isElementCallAvailableResult: () -> Boolean = { lambdaError() }, private val tweakMasUrlResult: (String) -> String = { lambdaError() }, + private val isEncryptionDisabledResult: () -> Boolean = { lambdaError() }, ) : SessionEnterpriseService { override suspend fun init() { } @@ -26,4 +27,8 @@ class FakeSessionEnterpriseService( override suspend fun isElementCallAvailable(): Boolean = simulateLongTask { isElementCallAvailableResult() } + + override suspend fun isEncryptionDisabledByHomeserver(): Boolean { + return isEncryptionDisabledResult() + } } diff --git a/features/securityandprivacy/impl/build.gradle.kts b/features/securityandprivacy/impl/build.gradle.kts index bb9764eb60..d42bdef883 100644 --- a/features/securityandprivacy/impl/build.gradle.kts +++ b/features/securityandprivacy/impl/build.gradle.kts @@ -41,10 +41,12 @@ dependencies { implementation(projects.libraries.uiStrings) implementation(projects.services.analytics.api) implementation(projects.libraries.featureflag.api) + implementation(projects.features.enterprise.api) testCommonDependencies(libs, true) testImplementation(projects.services.analytics.test) testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.featureflag.test) testImplementation(projects.libraries.testtags) + testImplementation(projects.features.enterprise.test) } diff --git a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyPresenter.kt b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyPresenter.kt index 48ab41a820..32517cd18d 100644 --- a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyPresenter.kt +++ b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyPresenter.kt @@ -22,6 +22,7 @@ import androidx.compose.runtime.setValue import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedFactory import dev.zacsweers.metro.AssistedInject +import io.element.android.features.enterprise.api.SessionEnterpriseService import io.element.android.features.securityandprivacy.api.SecurityAndPrivacyPermissions import io.element.android.features.securityandprivacy.api.securityAndPrivacyPermissions import io.element.android.features.securityandprivacy.impl.SecurityAndPrivacyNavigator @@ -63,6 +64,7 @@ class SecurityAndPrivacyPresenter( private val matrixClient: MatrixClient, private val room: JoinedRoom, private val featureFlagService: FeatureFlagService, + private val sessionEnterpriseService: SessionEnterpriseService, ) : Presenter { @AssistedFactory interface Factory { @@ -83,6 +85,10 @@ class SecurityAndPrivacyPresenter( val homeserverName = remember { matrixClient.userIdServerName() } val roomInfo by room.roomInfoFlow.collectAsState() + val isEncryptionDisabledByHomeserver by produceState(false) { + value = sessionEnterpriseService.isEncryptionDisabledByHomeserver() + } + val savedIsVisibleInRoomDirectory = remember { mutableStateOf>(AsyncData.Uninitialized) } LaunchedEffect(Unit) { isRoomVisibleInRoomDirectory(savedIsVisibleInRoomDirectory) @@ -247,6 +253,7 @@ class SecurityAndPrivacyPresenter( isSpace = roomInfo.isSpace, selectableJoinedSpaces = selectableJoinedSpaces, spaceSelectionMode = spaceSelectionMode, + isEncryptionDisabledByHomeserver = isEncryptionDisabledByHomeserver, eventSink = ::handleEvent, ) diff --git a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyState.kt b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyState.kt index 26e77b3c70..ddba5d0caa 100644 --- a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyState.kt +++ b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyState.kt @@ -27,6 +27,7 @@ data class SecurityAndPrivacyState( // the settings the user wants to apply. val editedSettings: SecurityAndPrivacySettings, val homeserverName: String, + val isEncryptionDisabledByHomeserver: Boolean, val showEnableEncryptionConfirmation: Boolean, private val isKnockEnabled: Boolean, val saveAction: AsyncAction, @@ -84,7 +85,7 @@ data class SecurityAndPrivacyState( editedSettings.roomAccess.canConfigureRoomVisibility() val showHistoryVisibilitySection = permissions.canChangeHistoryVisibility && !isSpace - val showEncryptionSection = permissions.canChangeEncryption && !isSpace + val showEncryptionSection = !isEncryptionDisabledByHomeserver && permissions.canChangeEncryption && !isSpace @Composable fun spaceMemberDescription(): String { diff --git a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyStateProvider.kt b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyStateProvider.kt index 19124302e3..998d61b564 100644 --- a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyStateProvider.kt +++ b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyStateProvider.kt @@ -138,6 +138,7 @@ fun aSecurityAndPrivacyState( isSpace: Boolean = false, selectableJoinedSpaces: Set = emptySet(), spaceSelectionMode: SpaceSelectionMode = SpaceSelectionMode.None, + isEncryptionDisabledByHomeserver: Boolean = false, eventSink: (SecurityAndPrivacyEvent) -> Unit = {} ) = SecurityAndPrivacyState( editedSettings = editedSettings, @@ -150,5 +151,6 @@ fun aSecurityAndPrivacyState( isSpace = isSpace, selectableJoinedSpaces = selectableJoinedSpaces.toImmutableSet(), spaceSelectionMode = spaceSelectionMode, + isEncryptionDisabledByHomeserver = isEncryptionDisabledByHomeserver, eventSink = eventSink, ) diff --git a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyPresenterTest.kt b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyPresenterTest.kt index 34b4222053..0b5133fe6a 100644 --- a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyPresenterTest.kt +++ b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyPresenterTest.kt @@ -8,6 +8,7 @@ package io.element.android.features.securityandprivacy.impl.root import com.google.common.truth.Truth.assertThat +import io.element.android.features.enterprise.test.FakeSessionEnterpriseService import io.element.android.features.securityandprivacy.impl.FakeSecurityAndPrivacyNavigator import io.element.android.features.securityandprivacy.impl.SecurityAndPrivacyNavigator import io.element.android.features.securityandprivacy.impl.manageauthorizedspaces.SpaceSelectionStateHolder @@ -1046,6 +1047,20 @@ class SecurityAndPrivacyPresenterTest { } } + @Test + fun `present - showEncryptionSection is false if the HS disabled encryption`() = runTest { + val sessionEnterpriseService = FakeSessionEnterpriseService(isEncryptionDisabledResult = { true }) + val presenter = createSecurityAndPrivacyPresenter( + sessionEnterpriseService = sessionEnterpriseService, + ) + presenter.test { + skipItems(1) + + // The HS has disabled encryption, so the encryption section should not be shown + assertThat(awaitItem().showEncryptionSection).isFalse() + } + } + private fun roomPermissions( canChangeRoomAccess: Boolean = true, canChangeHistoryVisibility: Boolean = true, @@ -1084,6 +1099,9 @@ class SecurityAndPrivacyPresenterTest { ), ), spaceSelectionStateHolder: SpaceSelectionStateHolder = SpaceSelectionStateHolder(), + sessionEnterpriseService: FakeSessionEnterpriseService = FakeSessionEnterpriseService( + isEncryptionDisabledResult = { false }, + ) ): SecurityAndPrivacyPresenter { return SecurityAndPrivacyPresenter( room = room, @@ -1091,6 +1109,7 @@ class SecurityAndPrivacyPresenterTest { navigator = navigator, featureFlagService = featureFlagService, spaceSelectionStateHolder = spaceSelectionStateHolder, + sessionEnterpriseService = sessionEnterpriseService, ) } } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt index dc7593904d..1c9fcfa482 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt @@ -126,7 +126,7 @@ class FakeMatrixClient( private val getMapStyleUrlResult: () -> Result = { lambdaError() }, private val getDatabaseSizesLambda: () -> Result = { lambdaError() }, private val resetWellKnownConfigLambda: () -> Result = { lambdaError() }, - override val contentScanner: ContentScanner? = null + override val contentScanner: ContentScanner? = null, ) : MatrixClient { var setDisplayNameCalled: Boolean = false private set @@ -144,7 +144,7 @@ class FakeMatrixClient( private val _userProfile: MutableStateFlow = MutableStateFlow(MatrixUser(sessionId, userDisplayName, userAvatarUrl)) override val userProfile: StateFlow = _userProfile - private var createRoomResult: Result = Result.success(A_ROOM_ID) + var createRoomResult: (CreateRoomParameters) -> Result = { Result.success(A_ROOM_ID) } private var createDmResult: Result = Result.success(A_ROOM_ID) private var findDmResult: Result = Result.success(A_ROOM_ID) private val getRoomResults = mutableMapOf() @@ -193,7 +193,7 @@ class FakeMatrixClient( } override suspend fun createRoom(createRoomParams: CreateRoomParameters): Result = simulateLongTask { - return createRoomResult + return createRoomResult(createRoomParams) } override suspend fun createDM(userId: UserId): Result = simulateLongTask { @@ -297,7 +297,7 @@ class FakeMatrixClient( // Mocks fun givenCreateRoomResult(result: Result) { - createRoomResult = result + createRoomResult = { result } } fun givenCreateDmResult(result: Result) { diff --git a/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/ElementWellKnown.kt b/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/ElementWellKnown.kt index 45448f66c2..a9c42b7121 100644 --- a/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/ElementWellKnown.kt +++ b/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/ElementWellKnown.kt @@ -17,4 +17,5 @@ data class ElementWellKnown( val identityProviderAppScheme: String?, val customRecoveryPassphrase: CustomRecoveryPassphrase?, val contentScannerUrl: String?, + val forceDisableE2EE: Boolean?, ) diff --git a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/InternalElementWellKnown.kt b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/InternalElementWellKnown.kt index ad60caefa5..c585264f55 100644 --- a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/InternalElementWellKnown.kt +++ b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/InternalElementWellKnown.kt @@ -46,6 +46,8 @@ data class InternalElementWellKnown( val customRecoveryPassphrase: InternalCustomRecoveryPassphrase? = null, @SerialName("content_scanner_url") val contentScannerUrl: String? = null, + @SerialName("force_disable_e2ee") + val forceDisableE2EE: Boolean? = null, ) @Serializable diff --git a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/Mapper.kt b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/Mapper.kt index 420dea2bae..c4d15e7325 100644 --- a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/Mapper.kt +++ b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/Mapper.kt @@ -31,6 +31,7 @@ fun InternalElementWellKnown.map() = ElementWellKnown( identityProviderAppScheme = identityProviderAppScheme, customRecoveryPassphrase = customRecoveryPassphrase?.toPublic(), contentScannerUrl = contentScannerUrl, + forceDisableE2EE = forceDisableE2EE, ) private fun InternalCustomRecoveryPassphrase.toPublic(): CustomRecoveryPassphrase { diff --git a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt index ec939b9988..6a2a12774b 100644 --- a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt +++ b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt @@ -50,6 +50,7 @@ class DefaultSessionWellknownRetrieverTest { identityProviderAppScheme = null, customRecoveryPassphrase = null, contentScannerUrl = null, + forceDisableE2EE = null, ) ) ) @@ -77,6 +78,7 @@ class DefaultSessionWellknownRetrieverTest { identityProviderAppScheme = "an_app_scheme", customRecoveryPassphrase = null, contentScannerUrl = "https://content-scanner.example.com", + forceDisableE2EE = false, ) ) ) @@ -108,6 +110,7 @@ class DefaultSessionWellknownRetrieverTest { identityProviderAppScheme = null, contentScannerUrl = null, customRecoveryPassphrase = null, + forceDisableE2EE = null, ) ) ) @@ -255,6 +258,7 @@ class DefaultSessionWellknownRetrieverTest { identityProviderAppScheme = "an_app_scheme", customRecoveryPassphrase = null, contentScannerUrl = "https://content-scanner.example.com", + forceDisableE2EE = false, ) ) ) @@ -303,6 +307,7 @@ class DefaultSessionWellknownRetrieverTest { identityProviderAppScheme = "an_app_scheme", customRecoveryPassphrase = null, contentScannerUrl = "https://content-scanner.example.com", + forceDisableE2EE = false, ) ) ) @@ -340,7 +345,8 @@ class DefaultSessionWellknownRetrieverTest { "brand_color": "#FF0000", "notification_sound": "a_notification_sound.flac", "idp_app_scheme": "an_app_scheme", - "content_scanner_url": "https://content-scanner.example.com" + "content_scanner_url": "https://content-scanner.example.com", + "force_disable_e2ee": false, }""" } } diff --git a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellknownRetrieverTest.kt b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellknownRetrieverTest.kt index 0e9288f658..3ee5b2b91f 100644 --- a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellknownRetrieverTest.kt +++ b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellknownRetrieverTest.kt @@ -50,6 +50,7 @@ class DefaultWellknownRetrieverTest { identityProviderAppScheme = null, customRecoveryPassphrase = null, contentScannerUrl = null, + forceDisableE2EE = null, ) ) ) @@ -72,6 +73,7 @@ class DefaultWellknownRetrieverTest { identityProviderAppScheme = "an_app_scheme", customRecoveryPassphrase = null, contentScannerUrl = "https://content-scanner.example.com", + forceDisableE2EE = false, ) ) ) @@ -101,6 +103,7 @@ class DefaultWellknownRetrieverTest { identityProviderAppScheme = null, contentScannerUrl = null, customRecoveryPassphrase = null, + forceDisableE2EE = null, ) ) ) @@ -266,7 +269,8 @@ class DefaultWellknownRetrieverTest { "brand_color": "#FF0000", "notification_sound": "a_notification_sound.flac", "idp_app_scheme": "an_app_scheme", - "content_scanner_url": "https://content-scanner.example.com" + "content_scanner_url": "https://content-scanner.example.com", + "force_disable_e2ee": false }""" } } diff --git a/libraries/wellknown/test/src/main/kotlin/io/element/android/features/wellknown/test/Fixtures.kt b/libraries/wellknown/test/src/main/kotlin/io/element/android/features/wellknown/test/Fixtures.kt index 8ec8874ad9..941e5f4cc7 100644 --- a/libraries/wellknown/test/src/main/kotlin/io/element/android/features/wellknown/test/Fixtures.kt +++ b/libraries/wellknown/test/src/main/kotlin/io/element/android/features/wellknown/test/Fixtures.kt @@ -20,6 +20,7 @@ fun anElementWellKnown( identityProviderAppScheme: String? = null, customRecoveryPassphrase: CustomRecoveryPassphrase? = null, contentScannerUrl: String? = null, + forceDisableE2EE: Boolean? = null, ) = ElementWellKnown( registrationHelperUrl = registrationHelperUrl, enforceElementPro = enforceElementPro, @@ -29,6 +30,7 @@ fun anElementWellKnown( identityProviderAppScheme = identityProviderAppScheme, customRecoveryPassphrase = customRecoveryPassphrase, contentScannerUrl = contentScannerUrl, + forceDisableE2EE = forceDisableE2EE, ) fun aCustomRecoveryPassphrase(