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处于保持状态时,主动触发恢复逻辑。
- 维护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恢复活跃的业务逻辑 }
- 注册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)
- 权限要求
在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
相关产品推荐
相关产品推荐

