Browse Source

Improve how active calls work (#3029)

* Improve how active calls work:

- Sending the `m.call.notify` event is now done in `CallScreenPresenter` once we know the sync is running.
- You can mark a call of both external url or room type as joined.
- Hanging up checks the current active call type and will only remove it if it matches.
pull/3046/head
Jorge Martin Espinosa 3 months ago committed by GitHub
parent
commit
2e32adf1f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      changelog.d/3029.misc
  2. 20
      features/call/impl/src/main/kotlin/io/element/android/features/call/impl/notifications/RingingCallNotificationCreator.kt
  3. 10
      features/call/impl/src/main/kotlin/io/element/android/features/call/impl/receivers/DeclineCallBroadcastReceiver.kt
  4. 45
      features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt
  5. 3
      features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallActivity.kt
  6. 46
      features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt
  7. 26
      features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt
  8. 48
      features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt
  9. 15
      features/call/impl/src/test/kotlin/io/element/android/features/call/utils/FakeActiveCallManager.kt

1
changelog.d/3029.misc

@ -0,0 +1 @@ @@ -0,0 +1 @@
Improve how active calls work by also taking into account external url calls and waiting for the sync process to start before sending the `m.call.notify` event.

20
features/call/impl/src/main/kotlin/io/element/android/features/call/impl/notifications/RingingCallNotificationCreator.kt

@ -84,11 +84,24 @@ class RingingCallNotificationCreator @Inject constructor( @@ -84,11 +84,24 @@ class RingingCallNotificationCreator @Inject constructor(
.build()
val answerIntent = IntentProvider.getPendingIntent(context, CallType.RoomCall(sessionId, roomId))
val notificationData = CallNotificationData(
sessionId = sessionId,
roomId = roomId,
eventId = eventId,
senderId = senderId,
roomName = roomName,
senderName = senderDisplayName,
avatarUrl = roomAvatarUrl,
notificationChannelId = notificationChannelId,
timestamp = timestamp
)
val declineIntent = PendingIntentCompat.getBroadcast(
context,
DECLINE_REQUEST_CODE,
Intent(context, DeclineCallBroadcastReceiver::class.java),
Intent(context, DeclineCallBroadcastReceiver::class.java).apply {
putExtra(DeclineCallBroadcastReceiver.EXTRA_NOTIFICATION_DATA, notificationData)
},
PendingIntent.FLAG_CANCEL_CURRENT,
false,
)!!
@ -97,10 +110,7 @@ class RingingCallNotificationCreator @Inject constructor( @@ -97,10 +110,7 @@ class RingingCallNotificationCreator @Inject constructor(
context,
FULL_SCREEN_INTENT_REQUEST_CODE,
Intent(context, IncomingCallActivity::class.java).apply {
putExtra(
IncomingCallActivity.EXTRA_NOTIFICATION_DATA,
CallNotificationData(sessionId, roomId, eventId, senderId, roomName, senderDisplayName, roomAvatarUrl, notificationChannelId, timestamp)
)
putExtra(IncomingCallActivity.EXTRA_NOTIFICATION_DATA, notificationData)
},
PendingIntent.FLAG_CANCEL_CURRENT,
false

10
features/call/impl/src/main/kotlin/io/element/android/features/call/impl/receivers/DeclineCallBroadcastReceiver.kt

@ -19,7 +19,10 @@ package io.element.android.features.call.impl.receivers @@ -19,7 +19,10 @@ package io.element.android.features.call.impl.receivers
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.core.content.IntentCompat
import io.element.android.features.call.api.CallType
import io.element.android.features.call.impl.di.CallBindings
import io.element.android.features.call.impl.notifications.CallNotificationData
import io.element.android.features.call.impl.utils.ActiveCallManager
import io.element.android.libraries.architecture.bindings
import javax.inject.Inject
@ -28,10 +31,15 @@ import javax.inject.Inject @@ -28,10 +31,15 @@ import javax.inject.Inject
* Broadcast receiver to decline the incoming call.
*/
class DeclineCallBroadcastReceiver : BroadcastReceiver() {
companion object {
const val EXTRA_NOTIFICATION_DATA = "EXTRA_NOTIFICATION_DATA"
}
@Inject
lateinit var activeCallManager: ActiveCallManager
override fun onReceive(context: Context, intent: Intent?) {
val notificationData = intent?.let { IntentCompat.getParcelableExtra(it, EXTRA_NOTIFICATION_DATA, CallNotificationData::class.java) }
?: return
context.bindings<CallBindings>().inject(this)
activeCallManager.hungUpCall()
activeCallManager.hungUpCall(callType = CallType.RoomCall(notificationData.sessionId, notificationData.roomId))
}
}

45
features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt

@ -40,14 +40,15 @@ import io.element.android.libraries.architecture.AsyncData @@ -40,14 +40,15 @@ import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runCatchingUpdatingState
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.MatrixClientProvider
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.sync.SyncState
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
import io.element.android.libraries.network.useragent.UserAgentProvider
import io.element.android.services.analytics.api.ScreenTracker
import io.element.android.services.toolbox.api.systemclock.SystemClock
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
@ -75,6 +76,7 @@ class CallScreenPresenter @AssistedInject constructor( @@ -75,6 +76,7 @@ class CallScreenPresenter @AssistedInject constructor(
private val isInWidgetMode = callType is CallType.RoomCall
private val userAgent = userAgentProvider.provide()
private var notifiedCallStart = false
@Composable
override fun present(): CallScreenState {
@ -84,11 +86,14 @@ class CallScreenPresenter @AssistedInject constructor( @@ -84,11 +86,14 @@ class CallScreenPresenter @AssistedInject constructor(
val messageInterceptor = remember { mutableStateOf<WidgetMessageInterceptor?>(null) }
var isJoinedCall by rememberSaveable { mutableStateOf(false) }
LaunchedEffect(Unit) {
loadUrl(callType, urlState, callWidgetDriver)
if (callType is CallType.RoomCall) {
activeCallManager.joinedCall(callType.sessionId, callType.roomId)
DisposableEffect(Unit) {
coroutineScope.launch {
// Sets the call as joined
activeCallManager.joinedCall(callType)
loadUrl(callType, urlState, callWidgetDriver)
}
onDispose {
activeCallManager.hungUpCall(callType)
}
}
@ -140,14 +145,6 @@ class CallScreenPresenter @AssistedInject constructor( @@ -140,14 +145,6 @@ class CallScreenPresenter @AssistedInject constructor(
}
}
DisposableEffect(Unit) {
onDispose {
if (callType is CallType.RoomCall) {
activeCallManager.hungUpCall()
}
}
}
fun handleEvents(event: CallScreenEvents) {
when (event) {
is CallScreenEvents.Hangup -> {
@ -173,15 +170,15 @@ class CallScreenPresenter @AssistedInject constructor( @@ -173,15 +170,15 @@ class CallScreenPresenter @AssistedInject constructor(
urlState = urlState.value,
userAgent = userAgent,
isInWidgetMode = isInWidgetMode,
eventSink = ::handleEvents,
eventSink = { handleEvents(it) },
)
}
private fun CoroutineScope.loadUrl(
private suspend fun loadUrl(
inputs: CallType,
urlState: MutableState<AsyncData<String>>,
callWidgetDriver: MutableState<MatrixWidgetDriver?>,
) = launch {
) {
urlState.runCatchingUpdatingState {
when (inputs) {
is CallType.ExternalUrl -> {
@ -209,12 +206,13 @@ class CallScreenPresenter @AssistedInject constructor( @@ -209,12 +206,13 @@ class CallScreenPresenter @AssistedInject constructor(
} ?: return@DisposableEffect onDispose { }
coroutineScope.launch {
client.syncService().syncState
.onEach { state ->
if (state != SyncState.Running) {
.collect { state ->
if (state == SyncState.Running) {
client.notifyCallStartIfNeeded(callType.roomId)
} else {
client.syncService().startSync()
}
}
.collect()
}
onDispose {
// We can't use the local coroutine scope here because it will be disposed before this effect
@ -229,6 +227,13 @@ class CallScreenPresenter @AssistedInject constructor( @@ -229,6 +227,13 @@ class CallScreenPresenter @AssistedInject constructor(
}
}
private suspend fun MatrixClient.notifyCallStartIfNeeded(roomId: RoomId) {
if (!notifiedCallStart) {
getRoom(roomId)?.sendCallNotificationIfNeeded()
?.onSuccess { notifiedCallStart = true }
}
}
private fun parseMessage(message: String): WidgetMessage? {
return WidgetMessageSerializer.deserialize(message).getOrNull()
}

3
features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallActivity.kt

@ -91,6 +91,7 @@ class IncomingCallActivity : AppCompatActivity() { @@ -91,6 +91,7 @@ class IncomingCallActivity : AppCompatActivity() {
}
private fun onCancel() {
activeCallManager.hungUpCall()
val activeCall = activeCallManager.activeCall.value ?: return
activeCallManager.hungUpCall(callType = activeCall.callType)
}
}

46
features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt

@ -20,13 +20,11 @@ import android.annotation.SuppressLint @@ -20,13 +20,11 @@ import android.annotation.SuppressLint
import androidx.core.app.NotificationManagerCompat
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.appconfig.ElementCallConfig
import io.element.android.features.call.api.CallType
import io.element.android.features.call.impl.notifications.CallNotificationData
import io.element.android.features.call.impl.notifications.RingingCallNotificationCreator
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.SingleIn
import io.element.android.libraries.matrix.api.MatrixClientProvider
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.push.api.notifications.ForegroundServiceType
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
import io.element.android.libraries.push.api.notifications.OnMissedCallNotificationHandler
@ -61,24 +59,23 @@ interface ActiveCallManager { @@ -61,24 +59,23 @@ interface ActiveCallManager {
fun incomingCallTimedOut()
/**
* Hangs up the active call and removes any associated UI.
* Called when the active call has been hung up. It will remove any existing UI and the active call.
* @param callType The type of call that the user hung up, either an external url one or a room one.
*/
fun hungUpCall()
fun hungUpCall(callType: CallType)
/**
* Called when the user joins a call. It will remove any existing UI and set the call state as [CallState.InCall].
* Called after the user joined a call. It will remove any existing UI and set the call state as [CallState.InCall].
*
* @param sessionId The session ID of the user joining the call.
* @param roomId The room ID of the call.
* @param callType The type of call that the user joined, either an external url one or a room one.
*/
fun joinedCall(sessionId: SessionId, roomId: RoomId)
fun joinedCall(callType: CallType)
}
@SingleIn(AppScope::class)
@ContributesBinding(AppScope::class)
class DefaultActiveCallManager @Inject constructor(
private val coroutineScope: CoroutineScope,
private val matrixClientProvider: MatrixClientProvider,
private val onMissedCallNotificationHandler: OnMissedCallNotificationHandler,
private val ringingCallNotificationCreator: RingingCallNotificationCreator,
private val notificationManagerCompat: NotificationManagerCompat,
@ -94,15 +91,17 @@ class DefaultActiveCallManager @Inject constructor( @@ -94,15 +91,17 @@ class DefaultActiveCallManager @Inject constructor(
return
}
activeCall.value = ActiveCall(
sessionId = notificationData.sessionId,
roomId = notificationData.roomId,
callType = CallType.RoomCall(
sessionId = notificationData.sessionId,
roomId = notificationData.roomId,
),
callState = CallState.Ringing(notificationData),
)
timedOutCallJob = coroutineScope.launch {
showIncomingCallNotification(notificationData)
// Wait for the call to end
// Wait for the ringing call to time out
delay(ElementCallConfig.RINGING_CALL_DURATION_SECONDS.seconds)
incomingCallTimedOut()
}
@ -118,28 +117,24 @@ class DefaultActiveCallManager @Inject constructor( @@ -118,28 +117,24 @@ class DefaultActiveCallManager @Inject constructor(
displayMissedCallNotification(notificationData)
}
override fun hungUpCall() {
override fun hungUpCall(callType: CallType) {
if (activeCall.value?.callType != callType) {
Timber.w("Call type $callType does not match the active call type, ignoring")
return
}
cancelIncomingCallNotification()
timedOutCallJob?.cancel()
activeCall.value = null
}
override fun joinedCall(sessionId: SessionId, roomId: RoomId) {
override fun joinedCall(callType: CallType) {
cancelIncomingCallNotification()
timedOutCallJob?.cancel()
activeCall.value = ActiveCall(
sessionId = sessionId,
roomId = roomId,
callType = callType,
callState = CallState.InCall,
)
// Send call notification to the room
coroutineScope.launch {
matrixClientProvider.getOrRestore(sessionId)
.getOrNull()
?.getRoom(roomId)
?.sendCallNotificationIfNeeded()
}
}
@SuppressLint("MissingPermission")
@ -184,8 +179,7 @@ class DefaultActiveCallManager @Inject constructor( @@ -184,8 +179,7 @@ class DefaultActiveCallManager @Inject constructor(
* Represents an active call.
*/
data class ActiveCall(
val sessionId: SessionId,
val roomId: RoomId,
val callType: CallType,
val callState: CallState,
)

26
features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt

@ -35,6 +35,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID @@ -35,6 +35,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
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.FakeMatrixRoom
import io.element.android.libraries.matrix.test.widget.FakeMatrixWidgetDriver
import io.element.android.libraries.network.useragent.UserAgentProvider
import io.element.android.services.analytics.api.ScreenTracker
@ -61,11 +62,13 @@ class CallScreenPresenterTest { @@ -61,11 +62,13 @@ class CallScreenPresenterTest {
val warmUpRule = WarmUpRule()
@Test
fun `present - with CallType ExternalUrl just loads the URL`() = runTest {
val analyticsLambda = lambdaRecorder<MobileScreen.ScreenName, Unit> { }
fun `present - with CallType ExternalUrl just loads the URL and sets the call as active`() = runTest {
val analyticsLambda = lambdaRecorder<MobileScreen.ScreenName, Unit> {}
val joinedCallLambda = lambdaRecorder<CallType, Unit> {}
val presenter = createCallScreenPresenter(
callType = CallType.ExternalUrl("https://call.element.io"),
screenTracker = FakeScreenTracker(analyticsLambda)
screenTracker = FakeScreenTracker(analyticsLambda),
activeCallManager = FakeActiveCallManager(joinedCallResult = joinedCallLambda),
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
@ -76,25 +79,35 @@ class CallScreenPresenterTest { @@ -76,25 +79,35 @@ class CallScreenPresenterTest {
assertThat(initialState.urlState).isEqualTo(AsyncData.Success("https://call.element.io"))
assertThat(initialState.isInWidgetMode).isFalse()
analyticsLambda.assertions().isNeverCalled()
joinedCallLambda.assertions().isCalledOnce()
}
}
@Test
fun `present - with CallType RoomCall loads URL and runs WidgetDriver`() = runTest {
fun `present - with CallType RoomCall sets call as active, loads URL, runs WidgetDriver and notifies the other clients a call started`() = runTest {
val sendCallNotificationIfNeededLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
val fakeRoom = FakeMatrixRoom(sendCallNotificationIfNeededResult = sendCallNotificationIfNeededLambda)
val client = FakeMatrixClient().apply {
givenGetRoomResult(A_ROOM_ID, fakeRoom)
}
val widgetDriver = FakeMatrixWidgetDriver()
val widgetProvider = FakeCallWidgetProvider(widgetDriver)
val analyticsLambda = lambdaRecorder<MobileScreen.ScreenName, Unit> { }
val analyticsLambda = lambdaRecorder<MobileScreen.ScreenName, Unit> {}
val joinedCallLambda = lambdaRecorder<CallType, Unit> {}
val presenter = createCallScreenPresenter(
matrixClientsProvider = FakeMatrixClientProvider(getClient = { Result.success(client) }),
callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID),
widgetDriver = widgetDriver,
widgetProvider = widgetProvider,
screenTracker = FakeScreenTracker(analyticsLambda)
screenTracker = FakeScreenTracker(analyticsLambda),
activeCallManager = FakeActiveCallManager(joinedCallResult = joinedCallLambda),
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
// Wait until the URL is loaded
skipItems(1)
joinedCallLambda.assertions().isCalledOnce()
val initialState = awaitItem()
assertThat(initialState.urlState).isInstanceOf(AsyncData.Success::class.java)
assertThat(initialState.isInWidgetMode).isTrue()
@ -106,6 +119,7 @@ class CallScreenPresenterTest { @@ -106,6 +119,7 @@ class CallScreenPresenterTest {
listOf(value(MobileScreen.ScreenName.RoomCall)),
listOf(value(MobileScreen.ScreenName.RoomCall))
)
sendCallNotificationIfNeededLambda.assertions().isCalledOnce()
}
}

48
features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt

@ -19,6 +19,7 @@ package io.element.android.features.call.utils @@ -19,6 +19,7 @@ package io.element.android.features.call.utils
import androidx.core.app.NotificationManagerCompat
import androidx.test.platform.app.InstrumentationRegistry
import com.google.common.truth.Truth.assertThat
import io.element.android.features.call.api.CallType
import io.element.android.features.call.impl.notifications.RingingCallNotificationCreator
import io.element.android.features.call.impl.utils.ActiveCall
import io.element.android.features.call.impl.utils.CallState
@ -31,9 +32,7 @@ import io.element.android.libraries.matrix.test.AN_EVENT_ID @@ -31,9 +32,7 @@ import io.element.android.libraries.matrix.test.AN_EVENT_ID
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.FakeMatrixRoom
import io.element.android.libraries.push.api.notifications.ForegroundServiceType
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
import io.element.android.libraries.push.test.notifications.FakeImageLoaderHolder
@ -69,8 +68,10 @@ class DefaultActiveCallManagerTest { @@ -69,8 +68,10 @@ class DefaultActiveCallManagerTest {
assertThat(manager.activeCall.value).isEqualTo(
ActiveCall(
sessionId = callNotificationData.sessionId,
roomId = callNotificationData.roomId,
callType = CallType.RoomCall(
sessionId = callNotificationData.sessionId,
roomId = callNotificationData.roomId,
),
callState = CallState.Ringing(callNotificationData)
)
)
@ -98,7 +99,7 @@ class DefaultActiveCallManagerTest { @@ -98,7 +99,7 @@ class DefaultActiveCallManagerTest {
manager.registerIncomingCall(aCallNotificationData(roomId = A_ROOM_ID_2))
assertThat(manager.activeCall.value).isEqualTo(activeCall)
assertThat(manager.activeCall.value?.roomId).isNotEqualTo(A_ROOM_ID_2)
assertThat((manager.activeCall.value?.callType as? CallType.RoomCall)?.roomId).isNotEqualTo(A_ROOM_ID_2)
advanceTimeBy(1)
@ -141,46 +142,56 @@ class DefaultActiveCallManagerTest { @@ -141,46 +142,56 @@ class DefaultActiveCallManagerTest {
}
@Test
fun `hungUpCall - removes existing call`() = runTest {
fun `hungUpCall - removes existing call if the CallType matches`() = runTest {
val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true)
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
manager.registerIncomingCall(aCallNotificationData())
val notificationData = aCallNotificationData()
manager.registerIncomingCall(notificationData)
assertThat(manager.activeCall.value).isNotNull()
manager.hungUpCall()
manager.hungUpCall(CallType.RoomCall(notificationData.sessionId, notificationData.roomId))
assertThat(manager.activeCall.value).isNull()
verify { notificationManagerCompat.cancel(notificationId) }
}
@Test
fun `hungUpCall - does nothing if the CallType doesn't match`() = runTest {
val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true)
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
manager.registerIncomingCall(aCallNotificationData())
assertThat(manager.activeCall.value).isNotNull()
manager.hungUpCall(CallType.ExternalUrl("https://example.com"))
assertThat(manager.activeCall.value).isNotNull()
verify(exactly = 0) { notificationManagerCompat.cancel(notificationId) }
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun `joinedCall - register an ongoing call and tries sending the call notify event`() = runTest {
val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true)
val sendCallNotifyLambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
val room = FakeMatrixRoom(sendCallNotificationIfNeededResult = sendCallNotifyLambda)
val client = FakeMatrixClient().apply {
givenGetRoomResult(A_ROOM_ID, room)
}
val manager = createActiveCallManager(
matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.success(client) }),
notificationManagerCompat = notificationManagerCompat,
)
assertThat(manager.activeCall.value).isNull()
manager.joinedCall(A_SESSION_ID, A_ROOM_ID)
manager.joinedCall(CallType.RoomCall(A_SESSION_ID, A_ROOM_ID))
assertThat(manager.activeCall.value).isEqualTo(
ActiveCall(
sessionId = A_SESSION_ID,
roomId = A_ROOM_ID,
callType = CallType.RoomCall(
sessionId = A_SESSION_ID,
roomId = A_ROOM_ID,
),
callState = CallState.InCall,
)
)
runCurrent()
sendCallNotifyLambda.assertions().isCalledOnce()
verify { notificationManagerCompat.cancel(notificationId) }
}
@ -190,7 +201,6 @@ class DefaultActiveCallManagerTest { @@ -190,7 +201,6 @@ class DefaultActiveCallManagerTest {
notificationManagerCompat: NotificationManagerCompat = mockk(relaxed = true),
) = DefaultActiveCallManager(
coroutineScope = this,
matrixClientProvider = matrixClientProvider,
onMissedCallNotificationHandler = onMissedCallNotificationHandler,
ringingCallNotificationCreator = RingingCallNotificationCreator(
context = InstrumentationRegistry.getInstrumentation().targetContext,

15
features/call/impl/src/test/kotlin/io/element/android/features/call/utils/FakeActiveCallManager.kt

@ -16,18 +16,17 @@ @@ -16,18 +16,17 @@
package io.element.android.features.call.utils
import io.element.android.features.call.api.CallType
import io.element.android.features.call.impl.notifications.CallNotificationData
import io.element.android.features.call.impl.utils.ActiveCall
import io.element.android.features.call.impl.utils.ActiveCallManager
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId
import kotlinx.coroutines.flow.MutableStateFlow
class FakeActiveCallManager(
var registerIncomingCallResult: (CallNotificationData) -> Unit = {},
var incomingCallTimedOutResult: () -> Unit = {},
var hungUpCallResult: () -> Unit = {},
var joinedCallResult: (SessionId, RoomId) -> Unit = { _, _ -> },
var hungUpCallResult: (CallType) -> Unit = {},
var joinedCallResult: (CallType) -> Unit = {},
) : ActiveCallManager {
override val activeCall = MutableStateFlow<ActiveCall?>(null)
@ -39,12 +38,12 @@ class FakeActiveCallManager( @@ -39,12 +38,12 @@ class FakeActiveCallManager(
incomingCallTimedOutResult()
}
override fun hungUpCall() {
hungUpCallResult()
override fun hungUpCall(callType: CallType) {
hungUpCallResult(callType)
}
override fun joinedCall(sessionId: SessionId, roomId: RoomId) {
joinedCallResult(sessionId, roomId)
override fun joinedCall(callType: CallType) {
joinedCallResult(callType)
}
fun setActiveCall(value: ActiveCall?) {

Loading…
Cancel
Save