Allow long press on digits in numpad to produce a long sound instead of a short one no matter how long the button was pressed

This commit is contained in:
Sylvain Berfini 2026-03-03 17:50:40 +01:00
parent a2b2b540e8
commit 62f6b5e956
12 changed files with 96 additions and 26 deletions

View file

@ -32,8 +32,6 @@ import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import android.os.PowerManager
import android.provider.Settings
import android.provider.Settings.SettingNotFoundException
import androidx.annotation.AnyThread
import androidx.annotation.UiThread
import androidx.annotation.WorkerThread
@ -1111,23 +1109,6 @@ class CoreContext
keepAliveServiceStarted = false
}
@WorkerThread
fun playDtmf(character: Char, duration: Int = 200, ignoreSystemPolicy: Boolean = false) {
try {
if (ignoreSystemPolicy || Settings.System.getInt(
context.contentResolver,
Settings.System.DTMF_TONE_WHEN_DIALING
) != 0
) {
core.playDtmf(character, duration)
} else {
Log.w("$TAG Numpad DTMF tones are disabled in system settings, not playing them")
}
} catch (snfe: SettingNotFoundException) {
Log.e("$TAG DTMF_TONE_WHEN_DIALING system setting not found: $snfe")
}
}
@WorkerThread
fun computeUserAgent() {
val savedDeviceName = corePreferences.deviceName

View file

@ -304,6 +304,12 @@ class ActiveCallFragment : GenericCallFragment() {
}
}
callViewModel.clearPressedDtmfBarEvent.observe(viewLifecycleOwner) {
it.consume {
binding.callNumpad.digitsHistory.setText("")
}
}
callViewModel.appendDigitToSearchBarEvent.observe(viewLifecycleOwner) {
it.consume { digit ->
binding.callNumpad.digitsHistory.addCharacterAtPosition(digit)

View file

@ -260,6 +260,10 @@ class CurrentCallViewModel
MutableLiveData()
}
val clearPressedDtmfBarEvent: MutableLiveData<Event<Boolean>> by lazy {
MutableLiveData()
}
// Sliding answer/decline button
val isScreenLocked = MutableLiveData<Boolean>()
@ -577,6 +581,7 @@ class CurrentCallViewModel
{ // OnBlindTransferClicked
},
{ // OnClearInput
clearPressedDtmfBarEvent.value = Event(true)
}
)

View file

@ -19,12 +19,16 @@
*/
package org.linphone.ui.main.history.model
import android.provider.Settings
import android.provider.Settings.SettingNotFoundException
import android.view.View
import androidx.annotation.UiThread
import androidx.lifecycle.MutableLiveData
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.LinphoneApplication.Companion.corePreferences
import org.linphone.core.tools.Log
import org.linphone.utils.LinphoneUtils
import org.linphone.utils.TouchListener
open class NumpadModel
@UiThread
@ -47,7 +51,38 @@ open class NumpadModel
val showLetters = MutableLiveData<Boolean>()
val systemPolicyAllowsDtmf: Boolean
val touchListener = object : TouchListener {
override fun onPressed(view: View): Boolean {
Log.i("$TAG Numpad digit [${view.tag}] pressed")
startPlayingDtmf(view.tag.toString())
return false
}
override fun onReleased(view: View): Boolean {
Log.i("$TAG Numpad digit [${view.tag}] released")
stopPlayingDtmf(view.tag.toString())
return false
}
}
init {
var dtmfAllowed = false
try {
dtmfAllowed = Settings.System.getInt(
coreContext.context.contentResolver,
Settings.System.DTMF_TONE_WHEN_DIALING
) != 0
if (!dtmfAllowed) {
Log.w("$TAG Numpad DTMF tones are disabled in system settings, not playing them")
}
} catch (snfe: SettingNotFoundException) {
Log.e("$TAG DTMF_TONE_WHEN_DIALING system setting not found: $snfe")
dtmfAllowed = false
}
systemPolicyAllowsDtmf = dtmfAllowed
coreContext.postOnCoreThread {
showLetters.postValue(corePreferences.showLettersOnDialpad)
@ -61,12 +96,6 @@ open class NumpadModel
fun onDigitClicked(value: String) {
Log.i("$TAG Clicked on digit [$value]")
onDigitClicked.invoke(value)
if (value.isNotEmpty()) {
coreContext.postOnCoreThread {
coreContext.playDtmf(value[0], ignoreSystemPolicy = inCallNumpad)
}
}
}
@UiThread
@ -113,4 +142,24 @@ open class NumpadModel
Log.i("$TAG Transferring call")
onTransferCallClicked.invoke()
}
@UiThread
private fun startPlayingDtmf(dtmf: String) {
if (dtmf.isEmpty() || (!inCallNumpad && !systemPolicyAllowsDtmf)) return
coreContext.postOnCoreThread { core ->
Log.i("$TAG Start playing DTMF [$dtmf]")
core.playDtmf(dtmf[0], -1)
}
}
@UiThread
private fun stopPlayingDtmf(dtmf: String) {
if (dtmf.isEmpty() || (!inCallNumpad && !systemPolicyAllowsDtmf)) return
coreContext.postOnCoreThread { core ->
Log.i("$TAG Stop playing DTMF [$dtmf]")
core.stopDtmf()
}
}
}

View file

@ -26,6 +26,7 @@ import android.graphics.drawable.AnimatedVectorDrawable
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.TextureView
import android.view.View
import android.view.ViewGroup
@ -652,3 +653,21 @@ fun EmojiPickerView.setEmojiPickedListener(listener: EmojiPickedListener) {
interface EmojiPickedListener {
fun onEmojiPicked(item: EmojiViewItem)
}
@SuppressLint("ClickableViewAccessibility")
@BindingAdapter("onTouchListener")
fun View.setTouchListener(listener: TouchListener) {
setOnTouchListener { view, event ->
return@setOnTouchListener when (event.action) {
MotionEvent.ACTION_DOWN -> listener.onPressed(view)
MotionEvent.ACTION_UP -> listener.onReleased(view)
else -> false
}
}
}
interface TouchListener {
fun onPressed(view: View): Boolean
fun onReleased(view: View): Boolean
}

View file

@ -63,6 +63,7 @@
<ImageView
android:id="@+id/backspace"
android:onClick="@{() -> model.onBackspaceClicked()}"
android:onLongClick="@{() -> model.onBackspaceLongClicked()}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"

View file

@ -63,6 +63,7 @@
<ImageView
android:id="@+id/backspace"
android:onClick="@{() -> model.onBackspaceClicked()}"
android:onLongClick="@{() -> model.onBackspaceLongClicked()}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"

View file

@ -13,6 +13,8 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:onClick="@{() -> model.onDigitClicked(digit)}"
android:tag="@{digit}"
onTouchListener="@{model.touchListener}"
android:layout_width="@dimen/call_dtmf_button_size"
android:layout_height="@dimen/call_dtmf_button_size"
android:background="@drawable/in_call_numpad_button_background">

View file

@ -18,6 +18,8 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:onClick="@{() -> model.onDigitClicked(digit)}"
android:onLongClick="@{() -> model.onDigitLongClicked(digit)}"
android:tag="@{digit}"
onTouchListener="@{model.touchListener}"
android:layout_width="@dimen/call_dtmf_button_size"
android:layout_height="@dimen/call_dtmf_button_size"
android:background="@drawable/in_call_numpad_button_background">

View file

@ -16,6 +16,8 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:onClick="@{() -> model.onDigitClicked(digit)}"
android:onLongClick="@{() -> model.onDigitLongClicked(digit)}"
android:tag="@{digit}"
onTouchListener="@{model.touchListener}"
android:layout_width="@dimen/call_dtmf_button_size"
android:layout_height="@dimen/call_dtmf_button_size"
android:background="@drawable/in_call_numpad_button_background">

View file

@ -18,6 +18,8 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:onClick="@{() -> model.onDigitClicked(digit)}"
android:onLongClick="@{() -> model.onVoicemailLongClicked()}"
android:tag="@{digit}"
onTouchListener="@{model.touchListener}"
android:layout_width="@dimen/call_dtmf_button_size"
android:layout_height="@dimen/call_dtmf_button_size"
android:background="@drawable/in_call_numpad_button_background">