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

Android双卡设备中PhoneStateListener适配改造咨询(音乐播放器场景)

嘿,这个双卡设备的通话监听问题我碰过好多次了——你原来的代码只监听了默认SIM卡的状态,副卡来电完全不会触发回调,所以才失效。下面给你两种适配方案,覆盖新老版本系统:

方案1:兼容Android 8.0及以下的多SIM监听

Android 8.0之前没有官方的双卡API,但可以通过反射获取所有SIM卡的subscriptionId,给每个卡单独注册通话状态监听。

首先修正你的监听类(顺便把拼错的CallListner改成CallListener),再添加获取所有SIM卡ID的方法:

class CallListener : PhoneStateListener() {
    // 用计数器跟踪活跃通话数,避免双卡同时通话时误恢复播放
    private var activeCallCount = 0

    override fun onCallStateChanged(state: Int, incomingNumber: String?) {
        super.onCallStateChanged(state, incomingNumber)
        when (state) {
            TelephonyManager.CALL_STATE_IDLE -> {
                // 通话结束,计数器减1,确保所有通话都结束才恢复
                activeCallCount = max(0, activeCallCount - 1)
                if (activeCallCount == 0) {
                    Controls.playPauseControl("play")
                }
            }
            TelephonyManager.CALL_STATE_RINGING, TelephonyManager.CALL_STATE_OFFHOOK -> {
                if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
                    activeCallCount += 1
                }
                Controls.playPauseControl("pause")
            }
        }
    }
}

// 获取所有SIM卡的subscriptionId,兼容旧系统
private fun getAllSubscriptionIds(telephonyManager: TelephonyManager): List<Int> {
    val subscriptionIds = mutableListOf<Int>()
    try {
        // 通过反射调用隐藏的getSubscriptionIds方法
        val method = telephonyManager.javaClass.getMethod("getSubscriptionIds")
        val ids = method.invoke(telephonyManager) as IntArray?
        ids?.let { subscriptionIds.addAll(it.toList()) }
    } catch (e: Exception) {
        e.printStackTrace()
        // 反射失败, fallback到默认卡ID
        subscriptionIds.add(-1)
    }
    return subscriptionIds
}

然后在注册监听时,给每个SIM卡都绑定监听:

val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
val callListener = CallListener()
// 遍历所有SIM卡ID,分别注册监听
getAllSubscriptionIds(telephonyManager).forEach { subId ->
    telephonyManager.listen(callListener, PhoneStateListener.LISTEN_CALL_STATE, subId)
}
方案2:Android 10及以上推荐用TelephonyCallback

从Android 10开始,Google推出了更简洁的TelephonyCallback,自动支持所有SIM卡的监听,不需要手动处理卡ID:

先创建回调实现类:

class CallTelephonyCallback : TelephonyCallback(), TelephonyCallback.CallStateListener {
    private var activeCallCount = 0

    override fun onCallStateChanged(state: Int) {
        when (state) {
            TelephonyManager.CALL_STATE_IDLE -> {
                activeCallCount = max(0, activeCallCount - 1)
                if (activeCallCount == 0) {
                    Controls.playPauseControl("play")
                }
            }
            TelephonyManager.CALL_STATE_RINGING, TelephonyManager.CALL_STATE_OFFHOOK -> {
                if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
                    activeCallCount += 1
                }
                Controls.playPauseControl("pause")
            }
        }
    }
}

然后注册监听(记得判断系统版本):

val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    val callCallback = CallTelephonyCallback()
    // 注册监听,自动覆盖所有SIM卡
    telephonyManager.registerTelephonyCallback(mainExecutor, callCallback)
} else {
    // 旧系统 fallback到方案1的逻辑
    val callListener = CallListener()
    getAllSubscriptionIds(telephonyManager).forEach { subId ->
        telephonyManager.listen(callListener, PhoneStateListener.LISTEN_CALL_STATE, subId)
    }
}
额外必注意的细节
  • 权限:务必在Manifest中声明<uses-permission android:name="android.permission.READ_PHONE_STATE" />,Android 6.0+还要动态申请该权限;Android 13及以上如果需要后台监听,还得申请POST_NOTIFICATIONS权限。
  • 通话计数器:加计数器是为了避免双卡同时通话时,其中一个通话结束就误恢复播放,只有所有通话都结束(计数器归0)才继续播放音乐。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:16:06