From 4e8e355f2713ee5c52fd1b7814d231c6ead58cd6 Mon Sep 17 00:00:00 2001 From: Valere Date: Tue, 9 Sep 2025 09:59:40 +0200 Subject: [PATCH 1/6] Call: RTC decline event support --- .../call/impl/utils/ActiveCallManager.kt | 45 ++++++++ .../utils/DefaultActiveCallManagerTest.kt | 106 ++++++++++++++++++ .../libraries/matrix/api/room/BaseRoom.kt | 7 +- .../matrix/impl/room/RustBaseRoom.kt | 18 +++ .../matrix/test/room/FakeBaseRoom.kt | 17 +++ 5 files changed, 192 insertions(+), 1 deletion(-) diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt index 54a5e567c8..45d6ffedb2 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt @@ -186,6 +186,15 @@ class DefaultActiveCallManager( } Timber.tag(tag).d("Hung up call: $callType") + if (activeCall.value?.callState is CallState.Ringing) { + val ringing = activeCall.value!!.callState as CallState.Ringing + // Decline the call + matrixClientProvider.getOrRestore(ringing.notificationData.sessionId).getOrNull()?.let { client -> + client.getRoom(ringing.notificationData.roomId)?.let { room -> + room.declineCall(ringing.notificationData.eventId) + } + } + } cancelIncomingCallNotification() if (activeWakeLock?.isHeld == true) { @@ -256,6 +265,42 @@ class DefaultActiveCallManager( @OptIn(ExperimentalCoroutinesApi::class) private fun observeRingingCall() { + activeCall + .filterNotNull() + .filter { it.callState is CallState.Ringing && it.callType is CallType.RoomCall } + .flatMapLatest { activeCall -> + val callType = activeCall.callType as CallType.RoomCall + val ringingInfo = activeCall.callState as CallState.Ringing + val client = matrixClientProvider.getOrRestore(callType.sessionId).getOrNull() ?: run { + Timber.tag(tag).d("Couldn't find room for incoming call: $activeCall") + return@flatMapLatest flowOf() + } + val room = client.getRoom(callType.roomId) ?: run { + Timber.tag(tag).d("Couldn't find room for incoming call: $activeCall") + return@flatMapLatest flowOf() + } + + Timber.tag(tag).d("Found room for rining call: ${room.roomId}") + + // If we have declined from another phone we want to stop ringing. + room.subscribeToCallDecline(ringingInfo.notificationData.eventId) + .filter { decliner -> + Timber.tag(tag).d("Call: $activeCall was declined by $decliner") + // only want to listen if the call was declined from another of my sessions, + // (we are ringing for an incoming call in a DM) + decliner == client.sessionId + } + }.onEach { decliner -> + Timber.tag(tag).d("Call: $activeCall was declined by from another session") + // decline + activeCall.value = null + if (activeWakeLock?.isHeld == true) { + Timber.tag(tag).d("Releasing partial wakelock after timeout") + activeWakeLock.release() + } + cancelIncomingCallNotification() + } + .launchIn(coroutineScope) // This will observe ringing calls and ensure they're terminated if the room call is cancelled or if the user // has joined the call from another session. activeCall diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt index 84084c38fe..2b2e4738fa 100644 --- a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt +++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt @@ -22,13 +22,16 @@ import io.element.android.features.call.test.aCallNotificationData import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.test.AN_EVENT_ID +import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID_2 import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClientProvider import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.push.api.notifications.ForegroundServiceType import io.element.android.libraries.push.api.notifications.NotificationIdProvider @@ -38,6 +41,7 @@ import io.element.android.libraries.push.test.notifications.push.FakeNotificatio import io.element.android.services.appnavstate.test.FakeAppForegroundStateService import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value +import io.mockk.coVerify import io.mockk.mockk import io.mockk.verify import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -49,6 +53,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import org.robolectric.Shadows.shadowOf +import timber.log.Timber @RunWith(RobolectricTestRunner::class) class DefaultActiveCallManagerTest { @@ -164,6 +169,107 @@ class DefaultActiveCallManagerTest { verify { notificationManagerCompat.cancel(notificationId) } } + @Test + fun `Decline event - Hangup on a ringing call should send a decline event`() = runTest { + setupShadowPowerManager() + val notificationManagerCompat = mockk(relaxed = true) + + val room = mockk(relaxed = true) + + val matrixClient = FakeMatrixClient().apply { + givenGetRoomResult(A_ROOM_ID, room) + } + val clientProvider = FakeMatrixClientProvider({ Result.success(matrixClient) }) + + val manager = createActiveCallManager( + matrixClientProvider = clientProvider, + notificationManagerCompat = notificationManagerCompat + ) + + val notificationData = aCallNotificationData(roomId = A_ROOM_ID) + manager.registerIncomingCall(notificationData) + + manager.hungUpCall(CallType.RoomCall(notificationData.sessionId, notificationData.roomId)) + + coVerify { + room.declineCall(notificationEventId = notificationData.eventId) + } + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun `Decline event - Declining from another session should stop ringing`() = runTest { + setupShadowPowerManager() + val notificationManagerCompat = mockk(relaxed = true) + + val room = FakeJoinedRoom() + + val matrixClient = FakeMatrixClient().apply { + givenGetRoomResult(A_ROOM_ID, room) + } + val clientProvider = FakeMatrixClientProvider({ Result.success(matrixClient) }) + + val manager = createActiveCallManager( + matrixClientProvider = clientProvider, + notificationManagerCompat = notificationManagerCompat + ) + + val notificationData = aCallNotificationData(roomId = A_ROOM_ID) + manager.registerIncomingCall(notificationData) + + runCurrent() + + // Simulate declined from other session + room.baseRoom.givenDecliner(matrixClient.sessionId, notificationData.eventId) + + runCurrent() + + assertThat(manager.activeCall.value).isNull() + assertThat(manager.activeWakeLock?.isHeld).isFalse() + + verify { notificationManagerCompat.cancel(notificationId) } + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun `Decline event - Should ignore decline for other notification events`() = runTest { + Timber.plant(object : Timber.Tree() { + override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { + println("$tag: $message") + } + }) + + setupShadowPowerManager() + val notificationManagerCompat = mockk(relaxed = true) + + val room = FakeJoinedRoom() + + val matrixClient = FakeMatrixClient().apply { + givenGetRoomResult(A_ROOM_ID, room) + } + val clientProvider = FakeMatrixClientProvider({ Result.success(matrixClient) }) + + val manager = createActiveCallManager( + matrixClientProvider = clientProvider, + notificationManagerCompat = notificationManagerCompat + ) + + val notificationData = aCallNotificationData(roomId = A_ROOM_ID) + manager.registerIncomingCall(notificationData) + + runCurrent() + + // Simulate declined for another notification event + room.baseRoom.givenDecliner(matrixClient.sessionId, AN_EVENT_ID_2) + + runCurrent() + + assertThat(manager.activeCall.value).isNotNull() + assertThat(manager.activeWakeLock?.isHeld).isTrue() + + verify(exactly = 0) { notificationManagerCompat.cancel(notificationId) } + } + @Test fun `hungUpCall - does nothing if the CallType doesn't match`() = runTest { setupShadowPowerManager() diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/BaseRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/BaseRoom.kt index 7e902a66fa..84aae82b66 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/BaseRoom.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/BaseRoom.kt @@ -18,6 +18,7 @@ import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility import io.element.android.libraries.matrix.api.timeline.ReceiptType import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import java.io.Closeable @@ -239,7 +240,11 @@ interface BaseRoom : Closeable { */ suspend fun reportRoom(reason: String?): Result - /** + suspend fun declineCall(notificationEventId: EventId): Result + + suspend fun subscribeToCallDecline(notificationEventId: EventId): Flow + + /** * Destroy the room and release all resources associated to it. */ fun destroy() diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt index 975185242b..37926a59ee 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt @@ -38,10 +38,12 @@ import io.element.android.libraries.matrix.impl.timeline.toRustReceiptType import io.element.android.libraries.matrix.impl.util.mxCallbackFlow import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.withContext +import org.matrix.rustcomponents.sdk.CallDeclineListener import org.matrix.rustcomponents.sdk.RoomInfoListener import org.matrix.rustcomponents.sdk.use import timber.log.Timber @@ -300,4 +302,20 @@ class RustBaseRoom( innerRoom.reportRoom(reason.orEmpty()) } } + + override suspend fun declineCall(notificationEventId: EventId): Result = withContext(roomDispatcher) { + runCatchingExceptions { + innerRoom.declineCall(notificationEventId.toString()) + } + } + + override suspend fun subscribeToCallDecline(notificationEventId: EventId): Flow = withContext(roomDispatcher) { + mxCallbackFlow { + innerRoom.subscribeToCallDeclineEvents(notificationEventId.toString(), object : CallDeclineListener { + override fun call(declinerUserId: String) { + trySend(UserId(declinerUserId)) + } + }) + } + } } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeBaseRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeBaseRoom.kt index 2a61c48e50..3ec9c3f870 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeBaseRoom.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeBaseRoom.kt @@ -29,6 +29,8 @@ import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.simulateLongTask import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.test.TestScope @@ -77,6 +79,12 @@ class FakeBaseRoom( _roomInfoFlow.tryEmit(roomInfo) } + private val declineCallFlowMap: MutableMap> = mutableMapOf() + + suspend fun givenDecliner(userId: UserId, forNotificationEventId: EventId) { + declineCallFlowMap[forNotificationEventId]?.emit(userId) + } + override val membersStateFlow: MutableStateFlow = MutableStateFlow(RoomMembersState.Unknown) override suspend fun updateMembers() = updateMembersResult() @@ -222,6 +230,15 @@ class FakeBaseRoom( override suspend fun reportRoom(reason: String?) = reportRoomResult(reason) + override suspend fun declineCall(notificationEventId: EventId): Result { + return Result.success(Unit) + } + + override suspend fun subscribeToCallDecline(notificationEventId: EventId): Flow { + val flow = declineCallFlowMap.getOrPut(notificationEventId, { MutableSharedFlow() }) + return flow + } + override fun predecessorRoom(): PredecessorRoom? = predecessorRoomResult() fun givenUpdateMembersResult(result: () -> Unit) { From 3ee2e5575bea2017f51eefae129b0f6f470edf87 Mon Sep 17 00:00:00 2001 From: Valere Date: Thu, 11 Sep 2025 13:41:24 +0200 Subject: [PATCH 2/6] fix detekt --- .../android/features/call/impl/utils/ActiveCallManager.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt index 45d6ffedb2..a3591ff945 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt @@ -290,7 +290,8 @@ class DefaultActiveCallManager( // (we are ringing for an incoming call in a DM) decliner == client.sessionId } - }.onEach { decliner -> + } + .onEach { decliner -> Timber.tag(tag).d("Call: $activeCall was declined by from another session") // decline activeCall.value = null From 2db74ce9e59f51be30b5f867a45f3eb5a7f82a4a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 11 Sep 2025 16:21:32 +0200 Subject: [PATCH 3/6] Code cleanup. Avoid usage of !! --- .../call/impl/utils/ActiveCallManager.kt | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt index a3591ff945..6ec35009f9 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt @@ -180,20 +180,21 @@ class DefaultActiveCallManager( } override suspend fun hungUpCall(callType: CallType) = mutex.withLock { - if (activeCall.value?.callType != callType) { + Timber.tag(tag).d("Hung up call: $callType") + val currentActiveCall = activeCall.value ?: run { + Timber.tag(tag).w("No active call, ignoring hang up") + return + } + if (currentActiveCall.callType != callType) { Timber.tag(tag).w("Call type $callType does not match the active call type, ignoring") return } - - Timber.tag(tag).d("Hung up call: $callType") - if (activeCall.value?.callState is CallState.Ringing) { - val ringing = activeCall.value!!.callState as CallState.Ringing + if (currentActiveCall.callState is CallState.Ringing) { // Decline the call - matrixClientProvider.getOrRestore(ringing.notificationData.sessionId).getOrNull()?.let { client -> - client.getRoom(ringing.notificationData.roomId)?.let { room -> - room.declineCall(ringing.notificationData.eventId) - } - } + val notificationData = currentActiveCall.callState.notificationData + matrixClientProvider.getOrRestore(notificationData.sessionId).getOrNull() + ?.getRoom(notificationData.roomId) + ?.declineCall(notificationData.eventId) } cancelIncomingCallNotification() From f1c0ac0b9b63e2f3a858134c445e426dd3ed2827 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 11 Sep 2025 16:37:12 +0200 Subject: [PATCH 4/6] Improve log messages and comment --- .../features/call/impl/utils/ActiveCallManager.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt index 6ec35009f9..0895e6860b 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt @@ -273,7 +273,7 @@ class DefaultActiveCallManager( val callType = activeCall.callType as CallType.RoomCall val ringingInfo = activeCall.callState as CallState.Ringing val client = matrixClientProvider.getOrRestore(callType.sessionId).getOrNull() ?: run { - Timber.tag(tag).d("Couldn't find room for incoming call: $activeCall") + Timber.tag(tag).d("Couldn't find session for incoming call: $activeCall") return@flatMapLatest flowOf() } val room = client.getRoom(callType.roomId) ?: run { @@ -281,7 +281,7 @@ class DefaultActiveCallManager( return@flatMapLatest flowOf() } - Timber.tag(tag).d("Found room for rining call: ${room.roomId}") + Timber.tag(tag).d("Found room for ringing call: ${room.roomId}") // If we have declined from another phone we want to stop ringing. room.subscribeToCallDecline(ringingInfo.notificationData.eventId) @@ -293,11 +293,11 @@ class DefaultActiveCallManager( } } .onEach { decliner -> - Timber.tag(tag).d("Call: $activeCall was declined by from another session") - // decline + Timber.tag(tag).d("Call: $activeCall was declined by user from another session") + // Remove the active call and cancel the notification activeCall.value = null if (activeWakeLock?.isHeld == true) { - Timber.tag(tag).d("Releasing partial wakelock after timeout") + Timber.tag(tag).d("Releasing partial wakelock after call declined from another session") activeWakeLock.release() } cancelIncomingCallNotification() From 1fe2eceb9af00c0621167a52cdfc3b17b479fa39 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 11 Sep 2025 16:58:47 +0200 Subject: [PATCH 5/6] Extract plantTestTimber --- .../call/utils/DefaultActiveCallManagerTest.kt | 9 ++------- .../element/android/tests/testutils/Timber.kt | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 tests/testutils/src/main/kotlin/io/element/android/tests/testutils/Timber.kt diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt index 2b2e4738fa..d842126c67 100644 --- a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt +++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt @@ -41,6 +41,7 @@ import io.element.android.libraries.push.test.notifications.push.FakeNotificatio import io.element.android.services.appnavstate.test.FakeAppForegroundStateService import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value +import io.element.android.tests.testutils.plantTestTimber import io.mockk.coVerify import io.mockk.mockk import io.mockk.verify @@ -53,7 +54,6 @@ import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import org.robolectric.Shadows.shadowOf -import timber.log.Timber @RunWith(RobolectricTestRunner::class) class DefaultActiveCallManagerTest { @@ -233,12 +233,7 @@ class DefaultActiveCallManagerTest { @OptIn(ExperimentalCoroutinesApi::class) @Test fun `Decline event - Should ignore decline for other notification events`() = runTest { - Timber.plant(object : Timber.Tree() { - override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { - println("$tag: $message") - } - }) - + plantTestTimber() setupShadowPowerManager() val notificationManagerCompat = mockk(relaxed = true) diff --git a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/Timber.kt b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/Timber.kt new file mode 100644 index 0000000000..2aad499698 --- /dev/null +++ b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/Timber.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.tests.testutils + +import timber.log.Timber + +fun plantTestTimber() { + Timber.plant(object : Timber.Tree() { + override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { + println("$tag: $message") + } + }) +} From d06c9de08c4ea582928ec74a667c7071fe3041fc Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 11 Sep 2025 17:04:58 +0200 Subject: [PATCH 6/6] Use `.value` instead of `.toString()`. --- .../roommembermoderation/impl/RoomMemberModerationView.kt | 2 +- .../impl/DefaultBaseRoomLastMessageFormatterTest.kt | 2 +- .../android/libraries/matrix/api/core/MatrixPatterns.kt | 2 +- .../android/libraries/matrix/impl/room/RustBaseRoom.kt | 4 ++-- .../android/libraries/matrix/impl/room/join/AllowRule.kt | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationView.kt b/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationView.kt index d4b7a7b69e..248b6cd02b 100644 --- a/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationView.kt +++ b/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationView.kt @@ -242,7 +242,7 @@ private fun RoomMemberActionsBottomSheet( ) } Text( - text = user.userId.toString(), + text = user.userId.value, style = ElementTheme.typography.fontBodyLgRegular, color = ElementTheme.colors.textSecondary, maxLines = 1, diff --git a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultBaseRoomLastMessageFormatterTest.kt b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultBaseRoomLastMessageFormatterTest.kt index ee56fcf2c5..0a7d2c1e73 100644 --- a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultBaseRoomLastMessageFormatterTest.kt +++ b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultBaseRoomLastMessageFormatterTest.kt @@ -102,7 +102,7 @@ class DefaultBaseRoomLastMessageFormatterTest { val info = ImageInfo(null, null, null, null, null, null, null) val message = createRoomEvent(false, null, aStickerContent(body, info, aMediaSource(url = "url"))) val result = formatter.format(message, false) - val expectedBody = someoneElseId.toString() + ": Sticker (a sticker body)" + val expectedBody = someoneElseId.value + ": Sticker (a sticker body)" assertThat(result.toString()).isEqualTo(expectedBody) } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/MatrixPatterns.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/MatrixPatterns.kt index a44e00b664..26a030d361 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/MatrixPatterns.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/core/MatrixPatterns.kt @@ -151,7 +151,7 @@ object MatrixPatterns { val urlMatch = match.groupValues[1] when (val permalink = permalinkParser.parse(urlMatch)) { is PermalinkData.UserLink -> { - add(MatrixPatternResult(MatrixPatternType.USER_ID, permalink.userId.toString(), match.range.first, match.range.last + 1)) + add(MatrixPatternResult(MatrixPatternType.USER_ID, permalink.userId.value, match.range.first, match.range.last + 1)) } is PermalinkData.RoomLink -> { when (permalink.roomIdOrAlias) { diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt index 37926a59ee..1ca5915c71 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt @@ -305,13 +305,13 @@ class RustBaseRoom( override suspend fun declineCall(notificationEventId: EventId): Result = withContext(roomDispatcher) { runCatchingExceptions { - innerRoom.declineCall(notificationEventId.toString()) + innerRoom.declineCall(notificationEventId.value) } } override suspend fun subscribeToCallDecline(notificationEventId: EventId): Flow = withContext(roomDispatcher) { mxCallbackFlow { - innerRoom.subscribeToCallDeclineEvents(notificationEventId.toString(), object : CallDeclineListener { + innerRoom.subscribeToCallDeclineEvents(notificationEventId.value, object : CallDeclineListener { override fun call(declinerUserId: String) { trySend(UserId(declinerUserId)) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/join/AllowRule.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/join/AllowRule.kt index ae74e1edc0..a93ce58236 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/join/AllowRule.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/join/AllowRule.kt @@ -20,7 +20,7 @@ fun RustAllowRule.map(): AllowRule { fun AllowRule.map(): RustAllowRule { return when (this) { - is AllowRule.RoomMembership -> RustAllowRule.RoomMembership(roomId.toString()) + is AllowRule.RoomMembership -> RustAllowRule.RoomMembership(roomId.value) is AllowRule.Custom -> RustAllowRule.Custom(json) } }