Android拨号应用:通话中编程检测新来电并显示的方法
解决通话中检测新来电并展示的问题
核心问题分析
你当前的BroadcastReceiver方案失效,主要有两个关键原因:
- 实例状态无法持久:静态注册的BroadcastReceiver每次触发
onReceive时都会创建新实例,成员变量lastState无法保存上一次的通话状态,导致无法判断「当前通话中+新来电」的场景。 - 系统版本限制:Android 10(API 29)及以上系统对
ACTION_PHONE_STATE_CHANGED广播做了权限和行为限制,静态广播的可靠性大幅降低。
推荐解决方案:使用TelephonyCallback(API 29+)
从Android 10开始,官方推荐用TelephonyCallback替代广播监听通话状态,它能更可靠地获取实时通话状态,包括等待来电。
步骤1:申请必要权限
在AndroidManifest.xml中添加权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_CALL_LOG" /> <!-- Android 12+ 需要通知权限才能在通话界面弹出提示 --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- 如果需要处理接听/挂断等待来电,需添加 --> <uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
注意:这些权限属于危险权限,需要在运行时动态申请。
步骤2:实现TelephonyCallback监听通话状态
在通话管理类或Activity中注册TelephonyCallback.CallStateListener:
class CallManager(private val context: Context) { private val telephonyManager = context.getSystemService(TelephonyManager::class.java) private val callStateListener = object : TelephonyCallback.CallStateListener() { override fun onCallStateChanged(state: Int) { when (state) { TelephonyManager.CALL_STATE_RINGING -> { // 检查当前是否有活跃通话 val activeCalls = telephonyManager.activeCalls if (activeCalls.isNotEmpty() && activeCalls.any { it.state == Call.STATE_ACTIVE }) { // 存在活跃通话,触发新来电等待逻辑 notifyIncomingWaitingCall() } } } } } // 注册监听 fun registerCallStateListener() { if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED ) { telephonyManager.registerTelephonyCallback(context.mainExecutor, callStateListener) } } // 注销监听 fun unregisterCallStateListener() { telephonyManager.unregisterTelephonyCallback(callStateListener) } private fun notifyIncomingWaitingCall() { // 通过本地广播通知通话界面展示新来电 val intent = Intent("ACTION_INCOMING_WAITING_CALL") intent.putExtra("PHONE_NUMBER", telephonyManager.line1Number) LocalBroadcastManager.getInstance(context).sendBroadcast(intent) } }
步骤3:在通话界面接收通知并展示
在通话Activity中注册本地广播接收器,处理等待来电事件:
class CallingActivity : AppCompatActivity() { private val waitingCallReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { intent?.getStringExtra("PHONE_NUMBER")?.let { phoneNumber -> showWaitingCallDialog(phoneNumber) } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_calling) // 注册本地广播 LocalBroadcastManager.getInstance(this).registerReceiver( waitingCallReceiver, IntentFilter("ACTION_INCOMING_WAITING_CALL") ) // 注册TelephonyCallback监听 CallManager(this).registerCallStateListener() } override fun onDestroy() { super.onDestroy() LocalBroadcastManager.getInstance(this).unregisterReceiver(waitingCallReceiver) CallManager(this).unregisterCallStateListener() } private fun showWaitingCallDialog(phoneNumber: String) { AlertDialog.Builder(this) .setTitle("新来电等待") .setMessage("来电号码:$phoneNumber") .setPositiveButton("接听") { _, _ -> acceptWaitingCall() } .setNegativeButton("挂断") { _, _ -> rejectWaitingCall() } .show() } private fun acceptWaitingCall() { val telecomManager = getSystemService(TelecomManager::class.java) if (ContextCompat.checkSelfPermission(this, Manifest.permission.ANSWER_PHONE_CALLS) == PackageManager.PERMISSION_GRANTED ) { telecomManager.acceptRingingCall() } } private fun rejectWaitingCall() { val telecomManager = getSystemService(TelecomManager::class.java) telecomManager.endCall() } }
兼容API 29以下的方案
如果需要支持Android 9及以下,需动态注册ACTION_PHONE_STATE_CHANGED广播,同时用Application全局变量保存通话状态:
class MyApp : Application() { var lastCallState = TelephonyManager.CALL_STATE_IDLE }
修改BroadcastReceiver:
class CallActionReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val app = context.applicationContext as MyApp val stateStr = intent.getStringExtra(TelephonyManager.EXTRA_STATE) val currentState = when (stateStr) { TelephonyManager.EXTRA_STATE_IDLE -> TelephonyManager.CALL_STATE_IDLE TelephonyManager.EXTRA_STATE_RINGING -> TelephonyManager.CALL_STATE_RINGING TelephonyManager.EXTRA_STATE_OFFHOOK -> TelephonyManager.CALL_STATE_OFFHOOK else -> TelephonyManager.CALL_STATE_IDLE } if (app.lastCallState != currentState) { when (currentState) { TelephonyManager.CALL_STATE_RINGING -> { val telephonyManager = context.getSystemService(TelephonyManager::class.java) if (app.lastCallState == TelephonyManager.CALL_STATE_OFFHOOK || telephonyManager.activeCalls.isNotEmpty()) { LocalBroadcastManager.getInstance(context) .sendBroadcast(Intent("ACTION_INCOMING_WAITING_CALL")) } } } } app.lastCallState = currentState // 处理接听/挂断逻辑... } }
在Activity中动态注册广播:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val filter = IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED) registerReceiver(CallActionReceiver(), filter) }
内容的提问来源于stack exchange,提问作者Hamza Sheikh
相关产品推荐
相关产品推荐

