diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/receivers/DeclineCallBroadcastReceiver.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/receivers/DeclineCallBroadcastReceiver.kt index 902c4d7d8d..b9775892c3 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/receivers/DeclineCallBroadcastReceiver.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/receivers/DeclineCallBroadcastReceiver.kt @@ -29,6 +29,7 @@ class DeclineCallBroadcastReceiver : BroadcastReceiver() { companion object { const val EXTRA_NOTIFICATION_DATA = "EXTRA_NOTIFICATION_DATA" } + @Inject lateinit var activeCallManager: ActiveCallManager @@ -40,7 +41,13 @@ class DeclineCallBroadcastReceiver : BroadcastReceiver() { ?: return context.bindings().inject(this) appCoroutineScope.launch { - activeCallManager.hangUpCall(callType = CallType.RoomCall(notificationData.sessionId, notificationData.roomId)) + activeCallManager.hangUpCall( + callType = CallType.RoomCall( + sessionId = notificationData.sessionId, + roomId = notificationData.roomId, + ), + notificationData = notificationData, + ) } } } 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 2c0e2e7742..e85b101112 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 @@ -75,7 +75,10 @@ interface ActiveCallManager { * Called to hang up the active call. It will hang up the call and remove any existing UI and the active call. * @param callType The type of call that the user hangs up, either an external url one or a room one. */ - suspend fun hangUpCall(callType: CallType) + suspend fun hangUpCall( + callType: CallType, + notificationData: CallNotificationData? = null, + ) /** * Called after the user joined a call. It will remove any existing UI and set the call state as [CallState.InCall]. @@ -192,13 +195,30 @@ class DefaultActiveCallManager( } } - override suspend fun hangUpCall(callType: CallType) = mutex.withLock { - Timber.tag(tag).d("Hung up call: $callType") + override suspend fun hangUpCall( + callType: CallType, + notificationData: CallNotificationData?, + ) = mutex.withLock { Timber.tag(tag).d("Hang up call: $callType") + cancelIncomingCallNotification() val currentActiveCall = activeCall.value ?: run { + // activeCall.value can be null if the application has been killed while the call was ringing + // Build a currentActiveCall with the provided parameters. + if (notificationData != null) { + ActiveCall( + callType = callType, + callState = CallState.Ringing( + notificationData = notificationData, + ) + ) + } else { + null + } + } ?: run { Timber.tag(tag).w("No active call, ignoring hang up") return@withLock } + if (currentActiveCall.callType != callType) { Timber.tag(tag).w("Call type $callType does not match the active call type, ignoring") return@withLock @@ -209,9 +229,13 @@ class DefaultActiveCallManager( matrixClientProvider.getOrRestore(notificationData.sessionId).getOrNull() ?.getRoom(notificationData.roomId) ?.declineCall(notificationData.eventId) + ?.onFailure { + Timber.e(it, "Failed to decline incoming call") + } + ?: run { + Timber.tag(tag).d("Couldn't find session or room to decline call for incoming call") + } } - - cancelIncomingCallNotification() if (activeWakeLock?.isHeld == true) { Timber.tag(tag).d("Releasing partial wakelock after hang up") activeWakeLock.release() @@ -222,7 +246,6 @@ class DefaultActiveCallManager( override suspend fun joinedCall(callType: CallType) = mutex.withLock { Timber.tag(tag).d("Joined call: $callType") - cancelIncomingCallNotification() if (activeWakeLock?.isHeld == true) { Timber.tag(tag).d("Releasing partial wakelock after joining call") diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/FakeActiveCallManager.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/FakeActiveCallManager.kt index 14b252e572..2d0e126ab5 100644 --- a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/FakeActiveCallManager.kt +++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/FakeActiveCallManager.kt @@ -17,7 +17,7 @@ import kotlinx.coroutines.flow.MutableStateFlow class FakeActiveCallManager( var registerIncomingCallResult: (CallNotificationData) -> Unit = {}, - var hangUpCallResult: (CallType) -> Unit = {}, + var hangUpCallResult: (CallType, CallNotificationData?) -> Unit = { _, _ -> }, var joinedCallResult: (CallType) -> Unit = {}, ) : ActiveCallManager { override val activeCall = MutableStateFlow(null) @@ -26,8 +26,8 @@ class FakeActiveCallManager( registerIncomingCallResult(notificationData) } - override suspend fun hangUpCall(callType: CallType) = simulateLongTask { - hangUpCallResult(callType) + override suspend fun hangUpCall(callType: CallType, notificationData: CallNotificationData?) = simulateLongTask { + hangUpCallResult(callType, notificationData) } override suspend fun joinedCall(callType: CallType) = simulateLongTask {