Android SDK 31中TelephonyManager.getCallState()为何被废弃?
适配方案及问题说明
无权限实现通话状态检测的方案
你完全不需要申请READ_PHONE_STATE权限就能实现需求,以下是通用适配方案:
- 即时查询是否在通话中:调用
AudioManager.getMode(),如果返回值为AudioManager.MODE_IN_CALL(蜂窝通话)或AudioManager.MODE_IN_COMMUNICATION(VOIP通话),即代表用户正处于通话状态,该方法不需要任何权限,可以100%覆盖「避免通话中启动Activity打扰用户」的场景。 - 监听通话状态变更:如果需要实现类似音频应用来电自动暂停的功能,只需要监听系统音频焦点变化即可,Android系统在来电时会主动抢占音频焦点,你只需要实现
AudioManager.OnAudioFocusChangeListener回调就能接收到状态变更,全程不需要申请电话相关权限。
废弃接口调整的背景说明
TelephonyManager.getCallState()被废弃且新增权限要求,属于Android隐私权限收紧的整体迭代内容:旧接口没有做权限拆分,调用时可以同时获取到用户的蜂窝网络信息、通话相关的敏感数据,官方为了避免普通应用滥用权限获取用户隐私,因此对该类接口做了权限限制,未单独在Android 12行为变更文档中提及属于官方文档疏漏。
多场景兼容代码示例
如果你的应用部分变体持有运营商权限或READ_PHONE_STATE权限,可以做分支兼容,覆盖所有场景:
public boolean isDeviceInCall(Context context) { // 有权限场景优先使用官方接口获取精准通话状态 if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // 适配API 31+ 新接口 int callState = telephonyManager.getCallStateForSubscription(SubscriptionManager.getDefaultSubscriptionId()); return callState != TelephonyManager.CALL_STATE_IDLE; } else { int callState = telephonyManager.getCallState(); return callState != TelephonyManager.CALL_STATE_IDLE; } } else { // 无权限场景使用AudioManager通用方案 AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); int audioMode = audioManager.getMode(); return audioMode == AudioManager.MODE_IN_CALL || audioMode == AudioManager.MODE_IN_COMMUNICATION; } }
注:AudioManager的方案同时支持识别蜂窝通话和第三方VOIP通话,覆盖场景比TelephonyManager接口更全面,完全满足普通应用的友好体验设计需求
内容的提问来源于stack exchange,提问作者NathanMDT
相关产品推荐
相关产品推荐

