mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-22 01:15:54 +03:00
Merge pull request #1993 from vector-im/feature/fix_call_in_background
Don't pause the sync thread if there is an active or pending call.
This commit is contained in:
commit
fbcc7aa211
5 changed files with 94 additions and 13 deletions
|
@ -16,6 +16,7 @@ Bugfix 🐛:
|
|||
- Fix bad color for settings icon on Android < 24 (#1786)
|
||||
- Change user or room avatar: when selecting Gallery, I'm not proposed to crop the selected image (#1590)
|
||||
- Fix uploads still don't work with room v6 (#1879)
|
||||
- Can't handle ongoing call events in background (#1992)
|
||||
|
||||
Translations 🗣:
|
||||
-
|
||||
|
|
|
@ -34,4 +34,6 @@ interface CallSignalingService {
|
|||
fun removeCallListener(listener: CallsListener)
|
||||
|
||||
fun getCallWithId(callId: String) : MxCall?
|
||||
|
||||
fun isThereAnyActiveCall(): Boolean
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.session.call
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import org.matrix.android.sdk.api.session.call.MxCall
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import javax.inject.Inject
|
||||
|
||||
@SessionScope
|
||||
internal class ActiveCallHandler @Inject constructor() {
|
||||
|
||||
private val activeCallListLiveData: MutableLiveData<MutableList<MxCall>> by lazy {
|
||||
MutableLiveData<MutableList<MxCall>>(mutableListOf())
|
||||
}
|
||||
|
||||
fun addCall(call: MxCall) {
|
||||
activeCallListLiveData.postValue(activeCallListLiveData.value?.apply { add(call) })
|
||||
}
|
||||
|
||||
fun removeCall(callId: String) {
|
||||
activeCallListLiveData.postValue(activeCallListLiveData.value?.apply { removeAll { it.callId == callId } })
|
||||
}
|
||||
|
||||
fun getCallWithId(callId: String): MxCall? {
|
||||
return activeCallListLiveData.value?.find { it.callId == callId }
|
||||
}
|
||||
|
||||
fun getActiveCallsLiveData(): LiveData<MutableList<MxCall>> = activeCallListLiveData
|
||||
}
|
|
@ -49,6 +49,7 @@ import javax.inject.Inject
|
|||
internal class DefaultCallSignalingService @Inject constructor(
|
||||
@UserId
|
||||
private val userId: String,
|
||||
private val activeCallHandler: ActiveCallHandler,
|
||||
private val localEchoEventFactory: LocalEchoEventFactory,
|
||||
private val roomEventSender: RoomEventSender,
|
||||
private val taskExecutor: TaskExecutor,
|
||||
|
@ -57,8 +58,6 @@ internal class DefaultCallSignalingService @Inject constructor(
|
|||
|
||||
private val callListeners = mutableSetOf<CallsListener>()
|
||||
|
||||
private val activeCalls = mutableListOf<MxCall>()
|
||||
|
||||
private val cachedTurnServerResponse = object {
|
||||
// Keep one minute safe to avoid considering the data is valid and then actually it is not when effectively using it.
|
||||
private val MIN_TTL = 60
|
||||
|
@ -97,7 +96,7 @@ internal class DefaultCallSignalingService @Inject constructor(
|
|||
}
|
||||
|
||||
override fun createOutgoingCall(roomId: String, otherUserId: String, isVideoCall: Boolean): MxCall {
|
||||
return MxCallImpl(
|
||||
val call = MxCallImpl(
|
||||
callId = UUID.randomUUID().toString(),
|
||||
isOutgoing = true,
|
||||
roomId = roomId,
|
||||
|
@ -106,8 +105,9 @@ internal class DefaultCallSignalingService @Inject constructor(
|
|||
isVideoCall = isVideoCall,
|
||||
localEchoEventFactory = localEchoEventFactory,
|
||||
roomEventSender = roomEventSender
|
||||
).also {
|
||||
activeCalls.add(it)
|
||||
)
|
||||
activeCallHandler.addCall(call).also {
|
||||
return call
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,8 +120,12 @@ internal class DefaultCallSignalingService @Inject constructor(
|
|||
}
|
||||
|
||||
override fun getCallWithId(callId: String): MxCall? {
|
||||
Timber.v("## VOIP getCallWithId $callId all calls ${activeCalls.map { it.callId }}")
|
||||
return activeCalls.find { it.callId == callId }
|
||||
Timber.v("## VOIP getCallWithId $callId all calls ${activeCallHandler.getActiveCallsLiveData().value?.map { it.callId }}")
|
||||
return activeCallHandler.getCallWithId(callId)
|
||||
}
|
||||
|
||||
override fun isThereAnyActiveCall(): Boolean {
|
||||
return activeCallHandler.getActiveCallsLiveData().value?.isNotEmpty() == true
|
||||
}
|
||||
|
||||
internal fun onCallEvent(event: Event) {
|
||||
|
@ -152,6 +156,7 @@ internal class DefaultCallSignalingService @Inject constructor(
|
|||
// Always ignore local echos of invite
|
||||
return
|
||||
}
|
||||
|
||||
event.getClearContent().toModel<CallInviteContent>()?.let { content ->
|
||||
val incomingCall = MxCallImpl(
|
||||
callId = content.callId ?: return@let,
|
||||
|
@ -163,7 +168,7 @@ internal class DefaultCallSignalingService @Inject constructor(
|
|||
localEchoEventFactory = localEchoEventFactory,
|
||||
roomEventSender = roomEventSender
|
||||
)
|
||||
activeCalls.add(incomingCall)
|
||||
activeCallHandler.addCall(incomingCall)
|
||||
onCallInvite(incomingCall, content)
|
||||
}
|
||||
}
|
||||
|
@ -185,8 +190,8 @@ internal class DefaultCallSignalingService @Inject constructor(
|
|||
return
|
||||
}
|
||||
|
||||
activeCallHandler.removeCall(content.callId)
|
||||
onCallHangup(content)
|
||||
activeCalls.removeAll { it.callId == content.callId }
|
||||
}
|
||||
}
|
||||
EventType.CALL_CANDIDATES -> {
|
||||
|
@ -195,7 +200,7 @@ internal class DefaultCallSignalingService @Inject constructor(
|
|||
return
|
||||
}
|
||||
event.getClearContent().toModel<CallCandidatesContent>()?.let { content ->
|
||||
activeCalls.firstOrNull { it.callId == content.callId }?.let {
|
||||
activeCallHandler.getCallWithId(content.callId)?.let {
|
||||
onCallIceCandidate(it, content)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.sync.job
|
|||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import com.squareup.moshi.JsonEncodingException
|
||||
import org.matrix.android.sdk.api.failure.Failure
|
||||
import org.matrix.android.sdk.api.failure.isTokenError
|
||||
|
@ -30,11 +31,14 @@ import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver
|
|||
import org.matrix.android.sdk.internal.util.Debouncer
|
||||
import org.matrix.android.sdk.internal.util.createUIHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.cancelChildren
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.matrix.android.sdk.api.session.call.MxCall
|
||||
import org.matrix.android.sdk.internal.session.call.ActiveCallHandler
|
||||
import timber.log.Timber
|
||||
import java.net.SocketTimeoutException
|
||||
import java.util.Timer
|
||||
|
@ -48,8 +52,9 @@ private const val DEFAULT_LONG_POOL_TIMEOUT = 30_000L
|
|||
internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
|
||||
private val typingUsersTracker: DefaultTypingUsersTracker,
|
||||
private val networkConnectivityChecker: NetworkConnectivityChecker,
|
||||
private val backgroundDetectionObserver: BackgroundDetectionObserver)
|
||||
: Thread(), NetworkConnectivityChecker.Listener, BackgroundDetectionObserver.Listener {
|
||||
private val backgroundDetectionObserver: BackgroundDetectionObserver,
|
||||
private val activeCallHandler: ActiveCallHandler
|
||||
) : Thread(), NetworkConnectivityChecker.Listener, BackgroundDetectionObserver.Listener {
|
||||
|
||||
private var state: SyncState = SyncState.Idle
|
||||
private var liveState = MutableLiveData<SyncState>(state)
|
||||
|
@ -62,6 +67,12 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
|
|||
private var isTokenValid = true
|
||||
private var retryNoNetworkTask: TimerTask? = null
|
||||
|
||||
private val activeCallListObserver = Observer<MutableList<MxCall>> { activeCalls ->
|
||||
if (activeCalls.isEmpty() && backgroundDetectionObserver.isInBackground) {
|
||||
pause()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
updateStateTo(SyncState.Idle)
|
||||
}
|
||||
|
@ -115,9 +126,11 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
|
|||
|
||||
override fun run() {
|
||||
Timber.v("Start syncing...")
|
||||
|
||||
isStarted = true
|
||||
networkConnectivityChecker.register(this)
|
||||
backgroundDetectionObserver.register(this)
|
||||
registerActiveCallsObserver()
|
||||
while (state != SyncState.Killing) {
|
||||
Timber.v("Entering loop, state: $state")
|
||||
if (!isStarted) {
|
||||
|
@ -163,6 +176,19 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
|
|||
updateStateTo(SyncState.Killed)
|
||||
backgroundDetectionObserver.unregister(this)
|
||||
networkConnectivityChecker.unregister(this)
|
||||
unregisterActiveCallsObserver()
|
||||
}
|
||||
|
||||
private fun registerActiveCallsObserver() {
|
||||
syncScope.launch(Dispatchers.Main) {
|
||||
activeCallHandler.getActiveCallsLiveData().observeForever(activeCallListObserver)
|
||||
}
|
||||
}
|
||||
|
||||
private fun unregisterActiveCallsObserver() {
|
||||
syncScope.launch(Dispatchers.Main) {
|
||||
activeCallHandler.getActiveCallsLiveData().removeObserver(activeCallListObserver)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun doSync(params: SyncTask.Params) {
|
||||
|
@ -215,6 +241,8 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
|
|||
}
|
||||
|
||||
override fun onMoveToBackground() {
|
||||
if (activeCallHandler.getActiveCallsLiveData().value.isNullOrEmpty()) {
|
||||
pause()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue