Added 30 secs timeout to call update dialog

This commit is contained in:
Sylvain Berfini 2020-08-20 11:40:12 +02:00
parent 74cd0f1bf8
commit 932a3a7265
5 changed files with 71 additions and 19 deletions

View file

@ -29,6 +29,7 @@ import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import java.util.*
import org.linphone.R
import org.linphone.activities.call.viewmodels.CallsViewModel
import org.linphone.activities.call.viewmodels.ControlsViewModel
@ -47,6 +48,8 @@ class ControlsFragment : Fragment() {
private lateinit var controlsViewModel: ControlsViewModel
private lateinit var sharedViewModel: SharedCallViewModel
private var dialog: Dialog? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@ -87,7 +90,11 @@ class ControlsFragment : Fragment() {
callsViewModel.callUpdateEvent.observe(viewLifecycleOwner, Observer {
it.consume { call ->
showCallUpdateDialog(call)
if (call.state == Call.State.StreamsRunning) {
dialog?.dismiss()
} else if (call.state == Call.State.UpdatedByRemote) {
showCallUpdateDialog(call)
}
}
})
@ -132,18 +139,18 @@ class ControlsFragment : Fragment() {
private fun showCallUpdateDialog(call: Call) {
val viewModel = DialogViewModel(AppUtils.getString(R.string.call_video_update_requested_dialog))
val dialog: Dialog = DialogUtils.getDialog(requireContext(), viewModel)
dialog = DialogUtils.getDialog(requireContext(), viewModel)
viewModel.showCancelButton({
callsViewModel.answerCallUpdateRequest(call, false)
dialog.dismiss()
dialog?.dismiss()
}, getString(R.string.dialog_decline))
viewModel.showOkButton({
callsViewModel.answerCallUpdateRequest(call, true)
dialog.dismiss()
dialog?.dismiss()
}, getString(R.string.dialog_accept))
dialog.show()
dialog?.show()
}
}

View file

@ -22,6 +22,11 @@ package org.linphone.activities.call.viewmodels
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import java.util.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.contact.GenericContactViewModel
import org.linphone.core.Call
@ -54,6 +59,8 @@ open class CallViewModel(val call: Call) : GenericContactViewModel(call.remoteAd
MutableLiveData<Event<Boolean>>()
}
private var timer: Timer? = null
private val listener = object : CallListenerStub() {
override fun onStateChanged(call: Call, state: Call.State, message: String) {
if (call != this@CallViewModel.call) return
@ -61,6 +68,7 @@ open class CallViewModel(val call: Call) : GenericContactViewModel(call.remoteAd
isPaused.value = state == Call.State.Paused
if (state == Call.State.End || state == Call.State.Released || state == Call.State.Error) {
timer?.cancel()
callEndedEvent.value = Event(true)
if (state == Call.State.Error) {
@ -68,6 +76,13 @@ open class CallViewModel(val call: Call) : GenericContactViewModel(call.remoteAd
}
} else if (call.state == Call.State.Connected) {
callConnectedEvent.value = Event(true)
} else if (call.state == Call.State.StreamsRunning) {
// Stop call update timer once user has accepted or declined call update
timer?.cancel()
} else if (call.state == Call.State.UpdatedByRemote) {
// User has 30 secs to accept or decline call update
// Dialog to accept or decline is handled by CallsViewModel & ControlsFragment
startTimer(call)
}
}
}
@ -103,4 +118,20 @@ open class CallViewModel(val call: Call) : GenericContactViewModel(call.remoteAd
if (call.core.conferenceSize <= 1) call.core.leaveConference()
}
}
private fun startTimer(call: Call) {
timer?.cancel()
timer = Timer("Call update timeout")
timer?.schedule(object : TimerTask() {
override fun run() {
// Decline call update
viewModelScope.launch {
withContext(Dispatchers.Main) {
coreContext.answerCallUpdateRequest(call, false)
}
}
}
}, 30000)
}
}

View file

@ -76,17 +76,20 @@ class CallsViewModel : ViewModel() {
} else if (state == Call.State.Resuming) {
removeCallFromPausedListIfPresent(call)
} else if (call.state == Call.State.UpdatedByRemote) {
// If the correspondent proposes video while audio call,
// If the correspondent asks to turn on video while audio call,
// defer update until user has chosen whether to accept it or not
val remoteVideo = call.remoteParams?.videoEnabled() ?: false
val localVideo = call.currentParams.videoEnabled()
val autoAccept = call.core.videoActivationPolicy.automaticallyAccept
if (remoteVideo && !localVideo && !autoAccept) {
call.deferUpdate()
// TODO: start 30 secs timer and decline update if no answer when it triggers
callUpdateEvent.value = Event(call)
}
} else {
if (state == Call.State.StreamsRunning) {
callUpdateEvent.value = Event(call)
}
if (call.conference != null) {
addCallToConferenceListIfNotAlreadyInIt(call)
} else {
@ -126,16 +129,7 @@ class CallsViewModel : ViewModel() {
}
fun answerCallUpdateRequest(call: Call, accept: Boolean) {
val core = call.core
val params = core.createCallParams(call)
if (accept) {
params?.enableVideo(true)
core.enableVideoCapture(true)
core.enableVideoDisplay(true)
}
call.acceptUpdate(params)
coreContext.answerCallUpdateRequest(call, accept)
}
fun pauseConference() {

View file

@ -22,6 +22,10 @@ package org.linphone.activities.call.viewmodels
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.*
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.core.AudioDevice
@ -119,8 +123,12 @@ class ControlsFadingViewModel : ViewModel() {
timer = Timer("Hide UI controls scheduler")
timer?.schedule(object : TimerTask() {
override fun run() {
val videoEnabled = coreContext.isVideoCallOrConferenceActive()
areControlsHidden.postValue(videoEnabled)
viewModelScope.launch {
withContext(Dispatchers.Main) {
val videoEnabled = coreContext.isVideoCallOrConferenceActive()
areControlsHidden.postValue(videoEnabled)
}
}
}
}, 3000)
}

View file

@ -299,6 +299,18 @@ class CoreContext(val context: Context, coreConfig: Config) {
/* Call related functions */
fun answerCallUpdateRequest(call: Call, accept: Boolean) {
val params = core.createCallParams(call)
if (accept) {
params?.enableVideo(true)
core.enableVideoCapture(true)
core.enableVideoDisplay(true)
}
call.acceptUpdate(params)
}
fun answerCall(call: Call) {
Log.i("[Context] Answering call $call")
val params = core.createCallParams(call)