You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android自管理ConnectivityService:对方挂断GSM通话时onUnhold未触发

解决自管理Telecom Connection远端挂断GSM通话时无法恢复VoIP通话的问题

问题场景

使用自管理ConnectionService实现VoIP通话管理时,遇到以下异常场景:

  • VoIP通话活跃状态下,接听GSM来电后,Connection会收到onHold()回调,可将VoIP置为保持状态;
  • 本地挂断GSM通话时,Connection能收到onUnhold()回调,正常恢复VoIP通话;但远端挂断GSM通话时,Connection及ConnectionService均无任何回调,导致VoIP通话无法自动恢复;
  • 官方已确认此为预期行为,且常规的PhoneStateListener/TelephonyCallback无法区分状态来自VoIP还是GSM通话。

可行解决方案

方案1:结合自身VoIP状态监听系统通话状态

核心思路是维护自身VoIP通话的状态标记,同时监听系统通话状态变化,当检测到系统无活跃通话且VoIP处于保持状态时,主动触发恢复逻辑。

  1. 维护VoIP状态变量
    在Connection类或通话管理类中添加状态标记,跟踪VoIP是否处于保持状态:
// Java示例
private boolean isVoipOnHold = false;

@Override
public void onHold() {
    super.onHold();
    isVoipOnHold = true;
    // 执行VoIP置为保持的业务逻辑
}

@Override
public void onUnhold() {
    super.onUnhold();
    isVoipOnHold = false;
    // 执行VoIP恢复活跃的业务逻辑
}
  1. 注册TelephonyCallback监听通话状态
    使用Android 12+推荐的TelephonyCallback替代旧的PhoneStateListener,确保兼容性:
// Kotlin示例
val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
val callback = object : TelephonyCallback(), TelephonyCallback.CallStateListener {
    override fun onCallStateChanged(state: Int) {
        // 系统通话变为空闲,且自身VoIP处于保持状态时,主动恢复
        if (state == TelephonyManager.CALL_STATE_IDLE && isVoipOnHold) {
            yourConnection?.setActive()
            isVoipOnHold = false
        }
    }
}
telephonyManager.registerTelephonyCallback(mainExecutor, callback)
  1. 权限要求
    在AndroidManifest中声明权限,并在运行时动态申请(Android 6.0及以上):
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

方案2:通过TelecomManager监听系统通话列表

利用TelecomManager获取系统所有通话的状态,过滤排除自身VoIP通话后,判断是否存在活跃的GSM通话,无活跃通话时恢复自身VoIP。

val telecomManager = getSystemService(Context.TELECOM_SERVICE) as TelecomManager
telecomManager.addListener(object : TelecomManager.TelecomListener() {
    override fun onCallChanged(call: Call) {
        // 过滤出非自管理的活跃系统通话(即GSM通话)
        val activeNonVoipCalls = telecomManager.calls.filter {
            it.state == Call.STATE_ACTIVE && !it.isSelfManaged
        }
        // 无活跃GSM通话且VoIP处于保持状态时,恢复VoIP
        if (activeNonVoipCalls.isEmpty() && isVoipOnHold) {
            yourConnection?.setActive()
            isVoipOnHold = false
        }
    }
})

注意:此方法需申请READ_PHONE_STATE权限,部分高版本Android可能需额外适配MANAGE_CALLS权限。

关键注意事项

  • 状态准确性:仅在收到onHold()回调时标记VoIP为保持状态,避免主动保持等场景误触发恢复逻辑;
  • 权限适配:不同Android版本权限要求有差异,需做好动态申请及兼容性处理;
  • 资源清理:通话结束或应用退后台时,及时注销监听回调,避免内存泄漏。

内容的提问来源于stack exchange,提问作者miecio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 19:35:16