@@ -25,14 +25,25 @@ import io.element.android.features.call.impl.notifications.CallNotificationData
25
25
import io.element.android.features.call.impl.notifications.RingingCallNotificationCreator
26
26
import io.element.android.libraries.di.AppScope
27
27
import io.element.android.libraries.di.SingleIn
28
+ import io.element.android.libraries.matrix.api.MatrixClientProvider
28
29
import io.element.android.libraries.push.api.notifications.ForegroundServiceType
29
30
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
30
31
import io.element.android.libraries.push.api.notifications.OnMissedCallNotificationHandler
31
32
import kotlinx.coroutines.CoroutineScope
33
+ import kotlinx.coroutines.ExperimentalCoroutinesApi
32
34
import kotlinx.coroutines.Job
33
35
import kotlinx.coroutines.delay
34
36
import kotlinx.coroutines.flow.MutableStateFlow
35
37
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
36
47
import kotlinx.coroutines.launch
37
48
import timber.log.Timber
38
49
import javax.inject.Inject
@@ -79,11 +90,16 @@ class DefaultActiveCallManager @Inject constructor(
79
90
private val onMissedCallNotificationHandler : OnMissedCallNotificationHandler ,
80
91
private val ringingCallNotificationCreator : RingingCallNotificationCreator ,
81
92
private val notificationManagerCompat : NotificationManagerCompat ,
93
+ private val matrixClientProvider : MatrixClientProvider ,
82
94
) : ActiveCallManager {
83
95
private var timedOutCallJob: Job ? = null
84
96
85
97
override val activeCall = MutableStateFlow <ActiveCall ?>(null )
86
98
99
+ init {
100
+ observeRingingCall()
101
+ }
102
+
87
103
override fun registerIncomingCall (notificationData : CallNotificationData ) {
88
104
if (activeCall.value != null ) {
89
105
displayMissedCallNotification(notificationData)
@@ -173,6 +189,35 @@ class DefaultActiveCallManager @Inject constructor(
173
189
)
174
190
}
175
191
}
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
+ }
176
221
}
177
222
178
223
/* *
0 commit comments