这篇博客分析一下拦截拨号的原理及方法。
在介绍具体的方法前,先来看看原理。
以Android 7.0为例,在电话的拨号流程中,当代码运行到packages/services/telephony/src/com/android/phone/OutgoingCallBroadcaster.java中时,
将进行如下操作:
private void processIntent(Intent intent) {...............Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);if (number != null) {broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);}.................// Need to raise foreground in-call UI as soon as possible while allowing 3rd party app// to intercept the outgoing call.// 短暂提升接收者的运行优先级broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);................//以有序广播的方式发送sendOrderedBroadcastAsUser(broadcastIntent, UserHandle.SYSTEM,//指定接收权限android.Manifest.permission.PROCESS_OUTGOING_CALLS,AppOpsManager.OP_PROCESS_OUTGOING_CALLS,//注册一个结果接收器new OutgoingCallReceiver(),null, // schedulerActivity.RESULT_OK, // initialCodenumber, // initialData: initial value for the result datanull); // initialExtras}
我们看一看OutgoingCallReceiver的收到处理结果后的流程:
public class OutgoingCallReceiver extends BroadcastReceiver {............@Overridepublic void onReceive(Context context, Intent intent) {...................final boolean isAttemptingCall = doReceive(context, intent);..................}............}
跟进其中的doReceive函数:
public boolean doReceive(Context context, Intent intent) {..............// Once the NEW_OUTGOING_CALL broadcast is finished, the resultData// is used as the actual number to call. (If null, no call will be// placed.)//得到有序广播的返回结果number = getResultData();..............if (number == null) {if (DBG) Log.v(TAG, "CALL cancelled (null number), returning...");return false;} .................}
从上面的代码流程可以看出,在拨号时,框架将发送一个有序广播,
并根据广播的返回结果决定是否继续拨号及拨号的实际号码(注意进行紧急拨号时,不会发送ACTION_NEW_OUTGOING_CALL)。
根据这部分流程,我们知道只需要在APK中申明对应的权限,然后注册广播监听ACTION_NEW_OUTGOING_CALL就可以拦截拨号了,
代码示例如下:
//申明权限............<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>............
//注册广播接收器监听ACTION_NEW_OUTGOING_CALL,可以动/静态注册//自己测试时,发现静态注册的广播接收器,有时候拦截不成功//主要是:若对应进程未启动,则收不到广播;进程已经启动后,可以收到广播//按代码逻辑,AMS应该会一个一个处理有序广播,若静态广播的进程未启动,则优先启动其进程//个人推测可能由于添加了FLAG_RECEIVER_FOREGROUND,使得超时时间变短了//于是,静态注册的广播对应进程还未完成启动,AMS就认为超时,让下一个接收器处理广播了//这部分代码还没仔细推敲,仅猜测public class CallOutReceiver extends BroadcastReceiver {private static final String HACK_NUMBER = "1008611";@Overridepublic void onReceive(Context context, Intent intent) {Log.d("CallOutReceiver", "onReceive");//从Intent中取出numberString number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);if (number != null && number.equals(HACK_NUMBER)) {..............//设置为null后,就不会进行实际的拨号了//也可以调整为其它值setResultData(null);}}}
如果觉得《通过Intent.ACTION_NEW_OUTGOING_CALL拦截电话拨号》对你有帮助,请点赞、收藏,并留下你的观点哦!