diff --git a/features/callnative/impl/src/main/kotlin/io/element/android/features/callnative/impl/DefaultNativeCallEntryPoint.kt b/features/callnative/impl/src/main/kotlin/io/element/android/features/callnative/impl/DefaultNativeCallEntryPoint.kt index 2210663376..6b40e72dbf 100644 --- a/features/callnative/impl/src/main/kotlin/io/element/android/features/callnative/impl/DefaultNativeCallEntryPoint.kt +++ b/features/callnative/impl/src/main/kotlin/io/element/android/features/callnative/impl/DefaultNativeCallEntryPoint.kt @@ -42,6 +42,8 @@ class DefaultNativeCallEntryPoint( ElementCallData( roomId = RoomId(callData.roomId.value), isAudioCall = callData.isAudioCall, + // Temporary, to be removed from the library soon: the core already skips the ring when anyone else is in the call. + isStartingCall = true, ) ) // The call screen asks for the microphone itself, and is where the answer normally comes diff --git a/features/callnative/impl/src/main/kotlin/io/element/android/features/callnative/impl/ElementXCallLifecycleListener.kt b/features/callnative/impl/src/main/kotlin/io/element/android/features/callnative/impl/ElementXCallLifecycleListener.kt index 83ec22b392..b64617639d 100644 --- a/features/callnative/impl/src/main/kotlin/io/element/android/features/callnative/impl/ElementXCallLifecycleListener.kt +++ b/features/callnative/impl/src/main/kotlin/io/element/android/features/callnative/impl/ElementXCallLifecycleListener.kt @@ -8,6 +8,7 @@ package io.element.android.features.callnative.impl import io.element.android.call.api.ElementCallData +import io.element.android.call.api.ElementCallEndReason import io.element.android.call.api.ElementCallLifecycleListener import io.element.android.features.call.api.CallData import io.element.android.features.call.api.CurrentCall @@ -19,6 +20,7 @@ import io.element.android.services.appnavstate.api.AppForegroundStateService import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch +import timber.log.Timber /** * Reports a native call back to the parts of Element X that already track calls. @@ -47,7 +49,8 @@ class ElementXCallLifecycleListener( sessionCoroutineScope.launch { ringingCallTracker.onCallJoined(callData.toCallData()) } } - override fun onCallEnded(callData: ElementCallData?) { + override fun onCallEnded(callData: ElementCallData?, reason: ElementCallEndReason) { + Timber.i("Native call ended: $reason") currentCallTracker.onCallEnded() callData?.let { sessionCoroutineScope.launch { ringingCallTracker.onCallEnded(it.toCallData()) } } } diff --git a/features/callnative/impl/src/test/kotlin/io/element/android/features/callnative/impl/ElementXCallLifecycleListenerTest.kt b/features/callnative/impl/src/test/kotlin/io/element/android/features/callnative/impl/ElementXCallLifecycleListenerTest.kt index 6ef057e512..1e7cc0df92 100644 --- a/features/callnative/impl/src/test/kotlin/io/element/android/features/callnative/impl/ElementXCallLifecycleListenerTest.kt +++ b/features/callnative/impl/src/test/kotlin/io/element/android/features/callnative/impl/ElementXCallLifecycleListenerTest.kt @@ -9,6 +9,7 @@ package io.element.android.features.callnative.impl import com.google.common.truth.Truth.assertThat import io.element.android.call.api.ElementCallData +import io.element.android.call.api.ElementCallEndReason import io.element.android.call.api.rtc.id.RoomId import io.element.android.features.call.api.CurrentCall import io.element.android.features.call.test.FakeCurrentCallTracker @@ -30,7 +31,7 @@ class ElementXCallLifecycleListenerTest { val listener = createListener(currentCallTracker = currentCallTracker) listener.onCallStarted(A_CALL) - listener.onCallEnded(A_CALL) + listener.onCallEnded(A_CALL, ElementCallEndReason.LEFT) assertThat(currentCallTracker.calls).containsExactly( CurrentCall.RoomCall(A_ROOM_ID), @@ -59,7 +60,7 @@ class ElementXCallLifecycleListenerTest { ringingCallTracker = ringingCallTracker, ) - listener.onCallEnded(null) + listener.onCallEnded(null, ElementCallEndReason.LEFT) runCurrent() // The current call is always cleared; only the ring needs to know which call it was. @@ -79,6 +80,6 @@ class ElementXCallLifecycleListenerTest { ) private companion object { - val A_CALL = ElementCallData(roomId = RoomId(A_ROOM_ID.value), isAudioCall = true) + val A_CALL = ElementCallData(roomId = RoomId(A_ROOM_ID.value), isAudioCall = true, isStartingCall = true) } } diff --git a/features/roomcall/impl/src/main/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenter.kt b/features/roomcall/impl/src/main/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenter.kt index 7763933a29..d507f2c9e3 100644 --- a/features/roomcall/impl/src/main/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenter.kt +++ b/features/roomcall/impl/src/main/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenter.kt @@ -61,7 +61,7 @@ class RoomCallStatePresenter( isAudioCall = roomInfo.activeCallIntentConsensus.isAudio(), ) else -> { - val isEmptyDm = roomInfo.isDm && roomInfo.activeMembersCount <= 1 + val isEmptyDm = roomInfo.isDm && roomInfo.joinedMembersCount <= 1 RoomCallState.StandBy( canStartCall = canJoinCall && !isEmptyDm, isDM = roomInfo.isDm diff --git a/features/roomcall/impl/src/test/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenterTest.kt b/features/roomcall/impl/src/test/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenterTest.kt index 9a4c3b0af0..5b0626279f 100644 --- a/features/roomcall/impl/src/test/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenterTest.kt +++ b/features/roomcall/impl/src/test/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenterTest.kt @@ -85,6 +85,21 @@ class RoomCallStatePresenterTest { } } + @Test + fun `present - a DM whose other member is only invited cannot be called`() = runTest { + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + initialRoomInfo = aRoomInfo(isDm = true, activeMembersCount = 2, joinedMembersCount = 1), + roomPermissions = roomPermissions(true), + ) + ) + val presenter = createRoomCallStatePresenter(joinedRoom = room) + presenter.test { + skipItems(1) + assertThat(awaitItem()).isEqualTo(RoomCallState.StandBy(canStartCall = false, isDM = true)) + } + } + @Test fun `present - element call not available`() = runTest { val room = FakeJoinedRoom( @@ -128,7 +143,7 @@ class RoomCallStatePresenterTest { fun `present - initial state - when is DM room`() = runTest { val room = FakeJoinedRoom( baseRoom = FakeBaseRoom( - initialRoomInfo = aRoomInfo(isDm = true), + initialRoomInfo = aRoomInfo(isDm = true, joinedMembersCount = 2), roomPermissions = roomPermissions(true), ) ) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f7cd3df6e8..bcb3d50090 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -64,7 +64,7 @@ ktlint = "1.8.0" androidx-test-ext-junit = "1.3.0" kover = "0.9.11" # The native MatrixRTC call component, https://github.com/element-hq/element-call-android -element_call = "0.1.0-rc.7" +element_call = "0.1.0-rc.8" [libraries] # Project @@ -186,7 +186,7 @@ test_detekt_test = { module = "io.gitlab.arturbosch.detekt:detekt-test", version # it as a plain `require`: without this, a library built against a newer SDK would silently drag this app # onto it. With it, this pin always wins, and a library that needs something newer fails at configuration # time naming both versions instead of at runtime with NoSuchMethodError. -matrix_sdk = { module = "org.matrix.rustcomponents:sdk-android", version = { strictly = "26.10.14-nightly" } } +matrix_sdk = { module = "org.matrix.rustcomponents:sdk-android", version = { strictly = "26.10.15" } } rustls_platform_verifier = "org.rustls:rustls-platform-verifier:0.2.0" # Others