Call transfer: handle unknown person correctly
This commit is contained in:
parent
8e8bc0055d
commit
34b012732e
|
@ -175,7 +175,7 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
|
||||||
when (callState) {
|
when (callState) {
|
||||||
is CallState.Idle,
|
is CallState.Idle,
|
||||||
is CallState.CreateOffer,
|
is CallState.CreateOffer,
|
||||||
is CallState.Dialing -> {
|
is CallState.Dialing -> {
|
||||||
views.callVideoGroup.isInvisible = true
|
views.callVideoGroup.isInvisible = true
|
||||||
views.callInfoGroup.isVisible = true
|
views.callInfoGroup.isVisible = true
|
||||||
views.callStatusText.setText(R.string.call_ring)
|
views.callStatusText.setText(R.string.call_ring)
|
||||||
|
@ -189,17 +189,22 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
|
||||||
configureCallInfo(state)
|
configureCallInfo(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
is CallState.Answering -> {
|
is CallState.Answering -> {
|
||||||
views.callVideoGroup.isInvisible = true
|
views.callVideoGroup.isInvisible = true
|
||||||
views.callInfoGroup.isVisible = true
|
views.callInfoGroup.isVisible = true
|
||||||
views.callStatusText.setText(R.string.call_connecting)
|
views.callStatusText.setText(R.string.call_connecting)
|
||||||
views.callConnectingProgress.isVisible = true
|
views.callConnectingProgress.isVisible = true
|
||||||
configureCallInfo(state)
|
configureCallInfo(state)
|
||||||
}
|
}
|
||||||
is CallState.Connected -> {
|
is CallState.Connected -> {
|
||||||
if (callState.iceConnectionState == MxPeerConnectionState.CONNECTED) {
|
if (callState.iceConnectionState == MxPeerConnectionState.CONNECTED) {
|
||||||
if (state.transfereeName.hasValue()) {
|
if (state.transferee !is VectorCallViewState.TransfereeState.NoTransferee) {
|
||||||
views.callActionText.text = getString(R.string.call_transfer_transfer_to_title, state.transfereeName.get())
|
val transfereeName = if (state.transferee is VectorCallViewState.TransfereeState.KnownTransferee) {
|
||||||
|
state.transferee.name
|
||||||
|
} else {
|
||||||
|
getString(R.string.call_transfer_unknown_person)
|
||||||
|
}
|
||||||
|
views.callActionText.text = getString(R.string.call_transfer_transfer_to_title, transfereeName)
|
||||||
views.callActionText.isVisible = true
|
views.callActionText.isVisible = true
|
||||||
views.callActionText.setOnClickListener { callViewModel.handle(VectorCallViewActions.TransferCall) }
|
views.callActionText.setOnClickListener { callViewModel.handle(VectorCallViewActions.TransferCall) }
|
||||||
views.callStatusText.text = state.formattedDuration
|
views.callStatusText.text = state.formattedDuration
|
||||||
|
@ -226,7 +231,7 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
|
||||||
if (callArgs.isVideoCall) {
|
if (callArgs.isVideoCall) {
|
||||||
views.callVideoGroup.isVisible = true
|
views.callVideoGroup.isVisible = true
|
||||||
views.callInfoGroup.isVisible = false
|
views.callInfoGroup.isVisible = false
|
||||||
views.pipRenderer.isVisible = !state.isVideoCaptureInError && state.otherKnownCallInfo == null
|
views.pipRenderer.isVisible = !state.isVideoCaptureInError && state.otherKnownCallInfo == null
|
||||||
} else {
|
} else {
|
||||||
views.callVideoGroup.isInvisible = true
|
views.callVideoGroup.isInvisible = true
|
||||||
views.callInfoGroup.isVisible = true
|
views.callInfoGroup.isVisible = true
|
||||||
|
@ -241,10 +246,10 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
|
||||||
views.callConnectingProgress.isVisible = true
|
views.callConnectingProgress.isVisible = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is CallState.Terminated -> {
|
is CallState.Terminated -> {
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
null -> {
|
null -> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,10 +258,10 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
|
||||||
state.callInfo.otherUserItem?.let {
|
state.callInfo.otherUserItem?.let {
|
||||||
val colorFilter = ContextCompat.getColor(this, R.color.bg_call_screen)
|
val colorFilter = ContextCompat.getColor(this, R.color.bg_call_screen)
|
||||||
avatarRenderer.renderBlur(it, views.bgCallView, sampling = 20, rounded = false, colorFilter = colorFilter)
|
avatarRenderer.renderBlur(it, views.bgCallView, sampling = 20, rounded = false, colorFilter = colorFilter)
|
||||||
if (state.transfereeName.hasValue()) {
|
if (state.transferee is VectorCallViewState.TransfereeState.NoTransferee) {
|
||||||
views.participantNameText.text = getString(R.string.call_transfer_consulting_with, it.getBestName())
|
|
||||||
} else {
|
|
||||||
views.participantNameText.text = it.getBestName()
|
views.participantNameText.text = it.getBestName()
|
||||||
|
} else {
|
||||||
|
views.participantNameText.text = getString(R.string.call_transfer_consulting_with, it.getBestName())
|
||||||
}
|
}
|
||||||
if (blurAvatar) {
|
if (blurAvatar) {
|
||||||
avatarRenderer.renderBlur(it, views.otherMemberAvatar, sampling = 2, rounded = true, colorFilter = colorFilter)
|
avatarRenderer.renderBlur(it, views.otherMemberAvatar, sampling = 2, rounded = true, colorFilter = colorFilter)
|
||||||
|
@ -332,13 +337,13 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
|
||||||
private fun handleViewEvents(event: VectorCallViewEvents?) {
|
private fun handleViewEvents(event: VectorCallViewEvents?) {
|
||||||
Timber.v("## VOIP handleViewEvents $event")
|
Timber.v("## VOIP handleViewEvents $event")
|
||||||
when (event) {
|
when (event) {
|
||||||
VectorCallViewEvents.DismissNoCall -> {
|
VectorCallViewEvents.DismissNoCall -> {
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
is VectorCallViewEvents.ConnectionTimeout -> {
|
is VectorCallViewEvents.ConnectionTimeout -> {
|
||||||
onErrorTimoutConnect(event.turn)
|
onErrorTimoutConnect(event.turn)
|
||||||
}
|
}
|
||||||
is VectorCallViewEvents.ShowDialPad -> {
|
is VectorCallViewEvents.ShowDialPad -> {
|
||||||
CallDialPadBottomSheet.newInstance(false).apply {
|
CallDialPadBottomSheet.newInstance(false).apply {
|
||||||
callback = dialPadCallback
|
callback = dialPadCallback
|
||||||
}.show(supportFragmentManager, FRAGMENT_DIAL_PAD_TAG)
|
}.show(supportFragmentManager, FRAGMENT_DIAL_PAD_TAG)
|
||||||
|
@ -346,7 +351,7 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
|
||||||
is VectorCallViewEvents.ShowCallTransferScreen -> {
|
is VectorCallViewEvents.ShowCallTransferScreen -> {
|
||||||
navigator.openCallTransfer(this, callArgs.callId)
|
navigator.openCallTransfer(this, callArgs.callId)
|
||||||
}
|
}
|
||||||
null -> {
|
null -> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,8 @@ import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
import im.vector.app.core.extensions.exhaustive
|
import im.vector.app.core.extensions.exhaustive
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
import im.vector.app.features.call.audio.CallAudioManager
|
import im.vector.app.features.call.audio.CallAudioManager
|
||||||
|
@ -39,7 +39,6 @@ import org.matrix.android.sdk.api.session.call.CallState
|
||||||
import org.matrix.android.sdk.api.session.call.MxCall
|
import org.matrix.android.sdk.api.session.call.MxCall
|
||||||
import org.matrix.android.sdk.api.session.call.MxPeerConnectionState
|
import org.matrix.android.sdk.api.session.call.MxPeerConnectionState
|
||||||
import org.matrix.android.sdk.api.session.room.model.call.supportCallTransfer
|
import org.matrix.android.sdk.api.session.room.model.call.supportCallTransfer
|
||||||
import org.matrix.android.sdk.api.util.Optional
|
|
||||||
|
|
||||||
class VectorCallViewModel @AssistedInject constructor(
|
class VectorCallViewModel @AssistedInject constructor(
|
||||||
@Assisted initialState: VectorCallViewState,
|
@Assisted initialState: VectorCallViewState,
|
||||||
|
@ -109,22 +108,22 @@ class VectorCallViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val transfereeName = computeTransfereeNameIfAny(call)
|
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
callState = Success(callState),
|
callState = Success(callState),
|
||||||
canOpponentBeTransferred = call.capabilities.supportCallTransfer(),
|
canOpponentBeTransferred = call.capabilities.supportCallTransfer(),
|
||||||
transfereeName = transfereeName
|
transferee = computeTransfereeState(call)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun computeTransfereeNameIfAny(call: MxCall): Optional<String> {
|
private fun computeTransfereeState(call: MxCall): VectorCallViewState.TransfereeState {
|
||||||
val transfereeCall = callManager.getTransfereeForCallId(call.callId) ?: return Optional.empty()
|
val transfereeCall = callManager.getTransfereeForCallId(call.callId) ?: return VectorCallViewState.TransfereeState.NoTransferee
|
||||||
val transfereeRoom = session.getRoomSummary(transfereeCall.nativeRoomId)
|
val transfereeRoom = session.getRoomSummary(transfereeCall.nativeRoomId)
|
||||||
val transfereeName = transfereeRoom?.displayName ?: "Unknown person"
|
return transfereeRoom?.displayName?.let {
|
||||||
return Optional.from(transfereeName)
|
VectorCallViewState.TransfereeState.KnownTransferee(it)
|
||||||
|
} ?: VectorCallViewState.TransfereeState.UnknownTransferee
|
||||||
}
|
}
|
||||||
|
|
||||||
private val currentCallListener = object : WebRtcCallManager.CurrentCallListener {
|
private val currentCallListener = object : WebRtcCallManager.CurrentCallListener {
|
||||||
|
@ -176,7 +175,7 @@ class VectorCallViewModel @AssistedInject constructor(
|
||||||
} else {
|
} else {
|
||||||
call = webRtcCall
|
call = webRtcCall
|
||||||
callManager.addCurrentCallListener(currentCallListener)
|
callManager.addCurrentCallListener(currentCallListener)
|
||||||
val item = webRtcCall.getOpponentAsMatrixItem(session)
|
val item = webRtcCall.getOpponentAsMatrixItem(session)
|
||||||
webRtcCall.addListener(callListener)
|
webRtcCall.addListener(callListener)
|
||||||
val currentSoundDevice = callManager.audioManager.selectedDevice
|
val currentSoundDevice = callManager.audioManager.selectedDevice
|
||||||
if (currentSoundDevice == CallAudioManager.Device.PHONE) {
|
if (currentSoundDevice == CallAudioManager.Device.PHONE) {
|
||||||
|
@ -196,7 +195,7 @@ class VectorCallViewModel @AssistedInject constructor(
|
||||||
formattedDuration = webRtcCall.formattedDuration(),
|
formattedDuration = webRtcCall.formattedDuration(),
|
||||||
isHD = webRtcCall.mxCall.isVideoCall && webRtcCall.currentCaptureFormat() is CaptureFormat.HD,
|
isHD = webRtcCall.mxCall.isVideoCall && webRtcCall.currentCaptureFormat() is CaptureFormat.HD,
|
||||||
canOpponentBeTransferred = webRtcCall.mxCall.capabilities.supportCallTransfer(),
|
canOpponentBeTransferred = webRtcCall.mxCall.capabilities.supportCallTransfer(),
|
||||||
transfereeName = computeTransfereeNameIfAny(webRtcCall.mxCall)
|
transferee = computeTransfereeState(webRtcCall.mxCall)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
updateOtherKnownCall(webRtcCall)
|
updateOtherKnownCall(webRtcCall)
|
||||||
|
@ -212,27 +211,27 @@ class VectorCallViewModel @AssistedInject constructor(
|
||||||
|
|
||||||
override fun handle(action: VectorCallViewActions) = withState { state ->
|
override fun handle(action: VectorCallViewActions) = withState { state ->
|
||||||
when (action) {
|
when (action) {
|
||||||
VectorCallViewActions.EndCall -> call?.endCall()
|
VectorCallViewActions.EndCall -> call?.endCall()
|
||||||
VectorCallViewActions.AcceptCall -> {
|
VectorCallViewActions.AcceptCall -> {
|
||||||
setState {
|
setState {
|
||||||
copy(callState = Loading())
|
copy(callState = Loading())
|
||||||
}
|
}
|
||||||
call?.acceptIncomingCall()
|
call?.acceptIncomingCall()
|
||||||
}
|
}
|
||||||
VectorCallViewActions.DeclineCall -> {
|
VectorCallViewActions.DeclineCall -> {
|
||||||
setState {
|
setState {
|
||||||
copy(callState = Loading())
|
copy(callState = Loading())
|
||||||
}
|
}
|
||||||
call?.endCall()
|
call?.endCall()
|
||||||
}
|
}
|
||||||
VectorCallViewActions.ToggleMute -> {
|
VectorCallViewActions.ToggleMute -> {
|
||||||
val muted = state.isAudioMuted
|
val muted = state.isAudioMuted
|
||||||
call?.muteCall(!muted)
|
call?.muteCall(!muted)
|
||||||
setState {
|
setState {
|
||||||
copy(isAudioMuted = !muted)
|
copy(isAudioMuted = !muted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VectorCallViewActions.ToggleVideo -> {
|
VectorCallViewActions.ToggleVideo -> {
|
||||||
if (state.isVideoCall) {
|
if (state.isVideoCall) {
|
||||||
val videoEnabled = state.isVideoEnabled
|
val videoEnabled = state.isVideoEnabled
|
||||||
call?.enableVideo(!videoEnabled)
|
call?.enableVideo(!videoEnabled)
|
||||||
|
@ -242,14 +241,14 @@ class VectorCallViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
Unit
|
Unit
|
||||||
}
|
}
|
||||||
VectorCallViewActions.ToggleHoldResume -> {
|
VectorCallViewActions.ToggleHoldResume -> {
|
||||||
val isRemoteOnHold = state.isRemoteOnHold
|
val isRemoteOnHold = state.isRemoteOnHold
|
||||||
call?.updateRemoteOnHold(!isRemoteOnHold)
|
call?.updateRemoteOnHold(!isRemoteOnHold)
|
||||||
}
|
}
|
||||||
is VectorCallViewActions.ChangeAudioDevice -> {
|
is VectorCallViewActions.ChangeAudioDevice -> {
|
||||||
callManager.audioManager.setAudioDevice(action.device)
|
callManager.audioManager.setAudioDevice(action.device)
|
||||||
}
|
}
|
||||||
VectorCallViewActions.SwitchSoundDevice -> {
|
VectorCallViewActions.SwitchSoundDevice -> {
|
||||||
_viewEvents.post(
|
_viewEvents.post(
|
||||||
VectorCallViewEvents.ShowSoundDeviceChooser(state.availableDevices, state.device)
|
VectorCallViewEvents.ShowSoundDeviceChooser(state.availableDevices, state.device)
|
||||||
)
|
)
|
||||||
|
@ -265,17 +264,17 @@ class VectorCallViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
Unit
|
Unit
|
||||||
}
|
}
|
||||||
VectorCallViewActions.ToggleCamera -> {
|
VectorCallViewActions.ToggleCamera -> {
|
||||||
call?.switchCamera()
|
call?.switchCamera()
|
||||||
}
|
}
|
||||||
VectorCallViewActions.ToggleHDSD -> {
|
VectorCallViewActions.ToggleHDSD -> {
|
||||||
if (!state.isVideoCall) return@withState
|
if (!state.isVideoCall) return@withState
|
||||||
call?.setCaptureFormat(if (state.isHD) CaptureFormat.SD else CaptureFormat.HD)
|
call?.setCaptureFormat(if (state.isHD) CaptureFormat.SD else CaptureFormat.HD)
|
||||||
}
|
}
|
||||||
VectorCallViewActions.OpenDialPad -> {
|
VectorCallViewActions.OpenDialPad -> {
|
||||||
_viewEvents.post(VectorCallViewEvents.ShowDialPad)
|
_viewEvents.post(VectorCallViewEvents.ShowDialPad)
|
||||||
}
|
}
|
||||||
is VectorCallViewActions.SendDtmfDigit -> {
|
is VectorCallViewActions.SendDtmfDigit -> {
|
||||||
call?.sendDtmfDigit(action.digit)
|
call?.sendDtmfDigit(action.digit)
|
||||||
}
|
}
|
||||||
VectorCallViewActions.InitiateCallTransfer -> {
|
VectorCallViewActions.InitiateCallTransfer -> {
|
||||||
|
@ -283,7 +282,7 @@ class VectorCallViewModel @AssistedInject constructor(
|
||||||
VectorCallViewEvents.ShowCallTransferScreen
|
VectorCallViewEvents.ShowCallTransferScreen
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
VectorCallViewActions.TransferCall -> {
|
VectorCallViewActions.TransferCall -> {
|
||||||
handleCallTransfer()
|
handleCallTransfer()
|
||||||
}
|
}
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
|
|
|
@ -22,7 +22,6 @@ import com.airbnb.mvrx.Uninitialized
|
||||||
import im.vector.app.features.call.audio.CallAudioManager
|
import im.vector.app.features.call.audio.CallAudioManager
|
||||||
import org.matrix.android.sdk.api.session.call.CallState
|
import org.matrix.android.sdk.api.session.call.CallState
|
||||||
import org.matrix.android.sdk.api.util.MatrixItem
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
import org.matrix.android.sdk.api.util.Optional
|
|
||||||
|
|
||||||
data class VectorCallViewState(
|
data class VectorCallViewState(
|
||||||
val callId: String,
|
val callId: String,
|
||||||
|
@ -43,9 +42,15 @@ data class VectorCallViewState(
|
||||||
val callInfo: CallInfo = CallInfo(callId),
|
val callInfo: CallInfo = CallInfo(callId),
|
||||||
val formattedDuration: String = "",
|
val formattedDuration: String = "",
|
||||||
val canOpponentBeTransferred: Boolean = false,
|
val canOpponentBeTransferred: Boolean = false,
|
||||||
val transfereeName: Optional<String> = Optional.empty()
|
val transferee: TransfereeState = TransfereeState.NoTransferee
|
||||||
) : MvRxState {
|
) : MvRxState {
|
||||||
|
|
||||||
|
sealed class TransfereeState {
|
||||||
|
object NoTransferee: TransfereeState()
|
||||||
|
data class KnownTransferee(val name:String): TransfereeState()
|
||||||
|
object UnknownTransferee: TransfereeState()
|
||||||
|
}
|
||||||
|
|
||||||
data class CallInfo(
|
data class CallInfo(
|
||||||
val callId: String,
|
val callId: String,
|
||||||
val otherUserItem: MatrixItem? = null
|
val otherUserItem: MatrixItem? = null
|
||||||
|
|
|
@ -3234,6 +3234,7 @@
|
||||||
<string name="call_transfer_users_tab_title">Users</string>
|
<string name="call_transfer_users_tab_title">Users</string>
|
||||||
<string name="call_transfer_consulting_with">Consulting with %1$s</string>
|
<string name="call_transfer_consulting_with">Consulting with %1$s</string>
|
||||||
<string name="call_transfer_transfer_to_title">Transfer to %1$s</string>
|
<string name="call_transfer_transfer_to_title">Transfer to %1$s</string>
|
||||||
|
<string name="call_transfer_unknown_person">Unknown person</string>
|
||||||
|
|
||||||
<string name="re_authentication_activity_title">Re-Authentication Needed</string>
|
<string name="re_authentication_activity_title">Re-Authentication Needed</string>
|
||||||
<!-- Note to translators: the translation MUST contain the string "${app_name}", which will be replaced by the application name -->
|
<!-- Note to translators: the translation MUST contain the string "${app_name}", which will be replaced by the application name -->
|
||||||
|
|
Loading…
Reference in New Issue