Skip to content

Commit 344e07b

Browse files
authored
Cancel ringing call notification on call cancellation (#3047)
* Cancel ringing call notification on call cancellation * Improve implementation, add some comments to clarify how it works. * Make sure the call timeout job is cancelled
1 parent cbad91e commit 344e07b

File tree

3 files changed

+224
-80
lines changed

3 files changed

+224
-80
lines changed

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,25 @@ import io.element.android.features.call.impl.notifications.CallNotificationData
2525
import io.element.android.features.call.impl.notifications.RingingCallNotificationCreator
2626
import io.element.android.libraries.di.AppScope
2727
import io.element.android.libraries.di.SingleIn
28+
import io.element.android.libraries.matrix.api.MatrixClientProvider
2829
import io.element.android.libraries.push.api.notifications.ForegroundServiceType
2930
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
3031
import io.element.android.libraries.push.api.notifications.OnMissedCallNotificationHandler
3132
import kotlinx.coroutines.CoroutineScope
33+
import kotlinx.coroutines.ExperimentalCoroutinesApi
3234
import kotlinx.coroutines.Job
3335
import kotlinx.coroutines.delay
3436
import kotlinx.coroutines.flow.MutableStateFlow
3537
import kotlinx.coroutines.flow.StateFlow
38+
import kotlinx.coroutines.flow.distinctUntilChanged
39+
import kotlinx.coroutines.flow.drop
40+
import kotlinx.coroutines.flow.filter
41+
import kotlinx.coroutines.flow.filterNotNull
42+
import kotlinx.coroutines.flow.flatMapLatest
43+
import kotlinx.coroutines.flow.flowOf
44+
import kotlinx.coroutines.flow.launchIn
45+
import kotlinx.coroutines.flow.map
46+
import kotlinx.coroutines.flow.onEach
3647
import kotlinx.coroutines.launch
3748
import timber.log.Timber
3849
import javax.inject.Inject
@@ -79,11 +90,16 @@ class DefaultActiveCallManager @Inject constructor(
7990
private val onMissedCallNotificationHandler: OnMissedCallNotificationHandler,
8091
private val ringingCallNotificationCreator: RingingCallNotificationCreator,
8192
private val notificationManagerCompat: NotificationManagerCompat,
93+
private val matrixClientProvider: MatrixClientProvider,
8294
) : ActiveCallManager {
8395
private var timedOutCallJob: Job? = null
8496

8597
override val activeCall = MutableStateFlow<ActiveCall?>(null)
8698

99+
init {
100+
observeRingingCall()
101+
}
102+
87103
override fun registerIncomingCall(notificationData: CallNotificationData) {
88104
if (activeCall.value != null) {
89105
displayMissedCallNotification(notificationData)
@@ -173,6 +189,35 @@ class DefaultActiveCallManager @Inject constructor(
173189
)
174190
}
175191
}
192+
193+
@OptIn(ExperimentalCoroutinesApi::class)
194+
private fun observeRingingCall() {
195+
// This will observe ringing calls and ensure they're terminated if the room call is cancelled
196+
activeCall
197+
.filterNotNull()
198+
.filter { it.callState is CallState.Ringing && it.callType is CallType.RoomCall }
199+
.flatMapLatest { activeCall ->
200+
val callType = activeCall.callType as CallType.RoomCall
201+
// Get a flow of updated `hasRoomCall` values for the room
202+
matrixClientProvider.getOrRestore(callType.sessionId).getOrNull()
203+
?.getRoom(callType.roomId)
204+
?.roomInfoFlow
205+
?.map { it.hasRoomCall }
206+
?: flowOf()
207+
}
208+
// We only want to check if the room active call status changes
209+
.distinctUntilChanged()
210+
// Skip the first one, we're not interested in it (if the check below passes, it had to be active anyway)
211+
.drop(1)
212+
.onEach { roomHasActiveCall ->
213+
if (!roomHasActiveCall) {
214+
// The call was cancelled
215+
timedOutCallJob?.cancel()
216+
incomingCallTimedOut()
217+
}
218+
}
219+
.launchIn(coroutineScope)
220+
}
176221
}
177222

178223
/**

0 commit comments

Comments
 (0)