VoIP: use DialPad bottom sheet to send Dtmf in call

This commit is contained in:
ganfra 2021-01-07 11:17:23 +01:00
parent f5bf774126
commit d09a6714af
8 changed files with 69 additions and 2 deletions

View file

@ -63,6 +63,11 @@ class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetC
dismiss() dismiss()
} }
views.callControlsOpenDialPad.views.itemVerificationClickableZone.debouncedClicks {
callViewModel.handle(VectorCallViewActions.OpenDialPad)
dismiss()
}
callViewModel.observeViewEvents { callViewModel.observeViewEvents {
when (it) { when (it) {
is VectorCallViewEvents.ShowSoundDeviceChooser -> { is VectorCallViewEvents.ShowSoundDeviceChooser -> {

View file

@ -43,6 +43,8 @@ import im.vector.app.core.utils.PERMISSIONS_FOR_VIDEO_IP_CALL
import im.vector.app.core.utils.allGranted import im.vector.app.core.utils.allGranted
import im.vector.app.core.utils.checkPermissions import im.vector.app.core.utils.checkPermissions
import im.vector.app.databinding.ActivityCallBinding import im.vector.app.databinding.ActivityCallBinding
import im.vector.app.features.call.dialpad.CallDialPadBottomSheet
import im.vector.app.features.call.dialpad.DialPadFragment
import im.vector.app.features.call.utils.EglUtils import im.vector.app.features.call.utils.EglUtils
import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.call.webrtc.WebRtcCallManager
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
@ -83,9 +85,14 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
private lateinit var callArgs: CallArgs private lateinit var callArgs: CallArgs
@Inject lateinit var callManager: WebRtcCallManager @Inject lateinit var callManager: WebRtcCallManager
@Inject lateinit var viewModelFactory: VectorCallViewModel.Factory @Inject lateinit var viewModelFactory: VectorCallViewModel.Factory
private val dialPadCallback = object : DialPadFragment.Callback {
override fun onDigitAppended(digit: String) {
callViewModel.handle(VectorCallViewActions.SendDtmfDigit(digit))
}
}
private var rootEglBase: EglBase? = null private var rootEglBase: EglBase? = null
var surfaceRenderersAreInitialized = false var surfaceRenderersAreInitialized = false
@ -114,7 +121,9 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
if (intent.getStringExtra(EXTRA_MODE) == INCOMING_RINGING) { if (intent.getStringExtra(EXTRA_MODE) == INCOMING_RINGING) {
turnScreenOnAndKeyguardOff() turnScreenOnAndKeyguardOff()
} }
if(savedInstanceState != null) {
(supportFragmentManager.findFragmentByTag(FRAGMENT_DIAL_PAD_TAG) as? CallDialPadBottomSheet)?.callback = dialPadCallback
}
configureCallViews() configureCallViews()
callViewModel.subscribe(this) { callViewModel.subscribe(this) {
@ -301,6 +310,11 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
is VectorCallViewEvents.ConnectionTimeout -> { is VectorCallViewEvents.ConnectionTimeout -> {
onErrorTimoutConnect(event.turn) onErrorTimoutConnect(event.turn)
} }
is VectorCallViewEvents.ShowDialPad -> {
CallDialPadBottomSheet.newInstance(false).apply {
callback = dialPadCallback
}.show(supportFragmentManager, FRAGMENT_DIAL_PAD_TAG)
}
null -> { null -> {
} }
} }
@ -323,6 +337,7 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
private const val CAPTURE_PERMISSION_REQUEST_CODE = 1 private const val CAPTURE_PERMISSION_REQUEST_CODE = 1
private const val EXTRA_MODE = "EXTRA_MODE" private const val EXTRA_MODE = "EXTRA_MODE"
private const val FRAGMENT_DIAL_PAD_TAG = "FRAGMENT_DIAL_PAD_TAG"
const val OUTGOING_CREATED = "OUTGOING_CREATED" const val OUTGOING_CREATED = "OUTGOING_CREATED"
const val INCOMING_RINGING = "INCOMING_RINGING" const val INCOMING_RINGING = "INCOMING_RINGING"

View file

@ -25,7 +25,10 @@ sealed class VectorCallViewActions : VectorViewModelAction {
object ToggleMute : VectorCallViewActions() object ToggleMute : VectorCallViewActions()
object ToggleVideo : VectorCallViewActions() object ToggleVideo : VectorCallViewActions()
object ToggleHoldResume: VectorCallViewActions() object ToggleHoldResume: VectorCallViewActions()
object OpenDialPad: VectorCallViewActions()
data class ChangeAudioDevice(val device: CallAudioManager.SoundDevice) : VectorCallViewActions() data class ChangeAudioDevice(val device: CallAudioManager.SoundDevice) : VectorCallViewActions()
data class SendDtmfDigit(val digit: String) : VectorCallViewActions()
object SwitchSoundDevice : VectorCallViewActions() object SwitchSoundDevice : VectorCallViewActions()
object HeadSetButtonPressed : VectorCallViewActions() object HeadSetButtonPressed : VectorCallViewActions()
object ToggleCamera : VectorCallViewActions() object ToggleCamera : VectorCallViewActions()

View file

@ -27,6 +27,7 @@ sealed class VectorCallViewEvents : VectorViewEvents {
val available: List<CallAudioManager.SoundDevice>, val available: List<CallAudioManager.SoundDevice>,
val current: CallAudioManager.SoundDevice val current: CallAudioManager.SoundDevice
) : VectorCallViewEvents() ) : VectorCallViewEvents()
object ShowDialPad: VectorCallViewEvents()
// data class CallAnswered(val content: CallAnswerContent) : VectorCallViewEvents() // data class CallAnswered(val content: CallAnswerContent) : VectorCallViewEvents()
// data class CallHangup(val content: CallHangupContent) : VectorCallViewEvents() // data class CallHangup(val content: CallHangupContent) : VectorCallViewEvents()
// object CallAccepted : VectorCallViewEvents() // object CallAccepted : VectorCallViewEvents()

View file

@ -246,6 +246,12 @@ class VectorCallViewModel @AssistedInject constructor(
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 -> {
_viewEvents.post(VectorCallViewEvents.ShowDialPad)
}
is VectorCallViewActions.SendDtmfDigit -> {
call?.sendDtmfDigit(action.digit)
}
}.exhaustive }.exhaustive
} }

View file

@ -273,6 +273,23 @@ class WebRtcCall(val mxCall: MxCall,
} }
} }
/**
* Sends a DTMF digit to the other party
* @param digit The digit (nb. string - '#' and '*' are dtmf too)
*/
fun sendDtmfDigit(digit: String) {
for (sender in peerConnection?.senders.orEmpty()) {
if (sender.track()?.kind() == "audio" && sender.dtmf()?.canInsertDtmf() == true) {
try {
sender.dtmf()?.insertDtmf(digit, 100, 70)
return
} catch (failure: Throwable) {
Timber.v("Fail to send Dtmf digit")
}
}
}
}
fun detachRenderers(renderers: List<SurfaceViewRenderer>?) { fun detachRenderers(renderers: List<SurfaceViewRenderer>?) {
Timber.v("## VOIP detachRenderers") Timber.v("## VOIP detachRenderers")
// currentCall?.localMediaStream?.let { currentCall?.peerConnection?.removeStream(it) } // currentCall?.localMediaStream?.let { currentCall?.peerConnection?.removeStream(it) }

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="22dp"
android:viewportWidth="16"
android:viewportHeight="22">
<path
android:pathData="M8,18C6.9,18 6,18.9 6,20C6,21.1 6.9,22 8,22C9.1,22 10,21.1 10,20C10,18.9 9.1,18 8,18ZM2,0C0.9,0 0,0.9 0,2C0,3.1 0.9,4 2,4C3.1,4 4,3.1 4,2C4,0.9 3.1,0 2,0ZM2,6C0.9,6 0,6.9 0,8C0,9.1 0.9,10 2,10C3.1,10 4,9.1 4,8C4,6.9 3.1,6 2,6ZM2,12C0.9,12 0,12.9 0,14C0,15.1 0.9,16 2,16C3.1,16 4,15.1 4,14C4,12.9 3.1,12 2,12ZM14,4C15.1,4 16,3.1 16,2C16,0.9 15.1,0 14,0C12.9,0 12,0.9 12,2C12,3.1 12.9,4 14,4ZM8,12C6.9,12 6,12.9 6,14C6,15.1 6.9,16 8,16C9.1,16 10,15.1 10,14C10,12.9 9.1,12 8,12ZM14,12C12.9,12 12,12.9 12,14C12,15.1 12.9,16 14,16C15.1,16 16,15.1 16,14C16,12.9 15.1,12 14,12ZM14,6C12.9,6 12,6.9 12,8C12,9.1 12.9,10 14,10C15.1,10 16,9.1 16,8C16,6.9 15.1,6 14,6ZM8,6C6.9,6 6,6.9 6,8C6,9.1 6.9,10 8,10C9.1,10 10,9.1 10,8C10,6.9 9.1,6 8,6ZM8,0C6.9,0 6,0.9 6,2C6,3.1 6.9,4 8,4C9.1,4 10,3.1 10,2C10,0.9 9.1,0 8,0Z"
android:fillColor="#C1C6CD"/>
</vector>

View file

@ -26,6 +26,15 @@
app:tint="?attr/riotx_text_primary" app:tint="?attr/riotx_text_primary"
tools:actionDescription="Front" /> tools:actionDescription="Front" />
<im.vector.app.core.ui.views.BottomSheetActionButton
android:id="@+id/callControlsOpenDialPad"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:actionTitle="@string/call_dial_pad_title"
app:leftIcon="@drawable/ic_call_dial_pad"
app:tint="?attr/riotx_text_primary"
tools:actionDescription="" />
<im.vector.app.core.ui.views.BottomSheetActionButton <im.vector.app.core.ui.views.BottomSheetActionButton
android:id="@+id/callControlsToggleSDHD" android:id="@+id/callControlsToggleSDHD"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -44,4 +53,6 @@
app:tint="?attr/riotx_text_primary" app:tint="?attr/riotx_text_primary"
tools:actionDescription="" /> tools:actionDescription="" />
</LinearLayout> </LinearLayout>