本章部分内容参考自:
Phone ---- OutgoingCallBroadcaster解析
根据Android4.4源码找到OutgoingCallBroadcaster.java,文件位置位于:packages/services/Telephony/src/com/android/phone/OutgoingCallBroadcaster.java
无论从拨号盘输入号码、通话记录、联系人拨打电话等,都会进入OutgoingCallBroadcaster类中。这个类继承自Activity。
源码中是这样描述的:
/**
* OutgoingCallBroadcaster receives CALL and CALL_PRIVILEGED Intents, and
* broadcasts the ACTION_NEW_OUTGOING_CALL intent which allows other
* applications to monitor, redirect, or prevent the outgoing call.
* After the other applications have had a chance to see the
* ACTION_NEW_OUTGOING_CALL intent, it finally reaches the
* {@link OutgoingCallReceiver}, which passes the (possibly modified)
* intent on to the {@link SipCallOptionHandler}, which will
* ultimately start the call using the CallController.placeCall() API.
*
* Emergency calls and calls where no number is present (like for a CDMA
* "empty flash" or a nonexistent voicemail number) are exempt from being
* broadcast.
*/
首先来看看onCreate函数中干了什么(实际上它也没在别的函数中干事情):
/**
* This method is the single point of entry for the CALL intent, which is used (by built-in
* apps like Contacts / Dialer, as well as 3rd-party apps) to initiate an outgoing voice call.
*
*
*/
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.outgoing_call_broadcaster);
mWaitingSpinner = (ProgressBar) findViewById(R.id.spinner);
Intent intent = getIntent();
if (DBG) {
final Configuration configuration = getResources().getConfiguration();
Log.v(TAG, "onCreate: this = " + this + ", icicle = " + icicle);
Log.v(TAG, " - getIntent() = " + intent);
Log.v(TAG, " - configuration = " + configuration);
}
if (icicle != null) {
// A non-null icicle means that this activity is being
// re-initialized after previously being shut down.
//
// In practice this happens very rarely (because the lifetime
// of this activity is so short!), but it *can* happen if the
// framework detects a configuration change at exactly the
// right moment; see bug 2202413.
//
// In this case, do nothing. Our onCreate() method has already
// run once (with icicle==null the first time), which means
// that the NEW_OUTGOING_CALL broadcast for this new call has
// already been sent.
Log.i(TAG, "onCreate: non-null icicle! "
+ "Bailing out, not sending NEW_OUTGOING_CALL broadcast...");
// No need to finish() here, since the OutgoingCallReceiver from
// our original instance will do that. (It'll actually call
// finish() on our original instance, which apparently works fine
// even though the ActivityManager has already shut that instance
// down. And note that if we *do* call finish() here, that just
// results in an "ActivityManager: Duplicate finish request"
// warning when the OutgoingCallReceiver runs.)
return;
}
processIntent(intent);
// isFinishing() return false when 1. broadcast is still ongoing, or 2. dialog is being
// shown. Otherwise finish() is called inside processIntent(), is isFinishing() here will
// return true.
if (DBG) Log.v(TAG, "At the end of onCreate(). isFinishing(): " + isFinishing());
}
注意看Google给的注释,上边清楚的指出这个方法是CALL intent单一的途径,无论你使用联系人、拨号器还是第三方APP向外界发起对话都会经过OutgoingCallBroadcaster 。
Android会在processIntent()中进行一些判断,例如所播号码是否为空号、无效号码或者紧急号码:
final boolean isExactEmergencyNumber =
(number != null) && PhoneNumberUtils.isLocalEmergencyNumber(number, this);
final boolean isPotentialEmergencyNumber =
(number != null) && PhoneNumberUtils.isPotentialLocalEmergencyNumber(number, this);
如果为紧急号码,则发送CALL_EMERGENCY intents
这里我们只分析正常流程。同样,这里Google也给了我们注释:
/**
* Interprets a given Intent and starts something relevant to the Intent.
*
* This method will handle three kinds of actions:
*
* - CALL (action for usual outgoing voice calls)
* - CALL_PRIVILEGED (can come from built-in apps like contacts / voice dialer / bluetooth)
* - CALL_EMERGENCY (from the EmergencyDialer that's reachable from the lockscreen.)
*
* The exact behavior depends on the intent's data:
*
* - The most typical is a tel: URI, which we handle by starting the
* NEW_OUTGOING_CALL broadcast. That broadcast eventually triggers
* the sequence OutgoingCallReceiver -> SipCallOptionHandler ->
* InCallScreen.
*
* - Or, with a sip: URI we skip the NEW_OUTGOING_CALL broadcast and
* go directly to SipCallOptionHandler, which then leads to the
* InCallScreen.
*
* - voicemail: URIs take the same path as regular tel: URIs.
*
* Other special cases:
*
* - Outgoing calls are totally disallowed on non-voice-capable
* devices (see handleNonVoiceCapable()).
*
* - A CALL intent with the EXTRA_SEND_EMPTY_FLASH extra (and
* presumably no data at all) means "send an empty flash" (which
* is only meaningful on CDMA devices while a call is already
* active.)
*
*/
从中我们可以看到大部分情况的流程是发送NEW_OUTGOING_CALL broadcast,在OutgoingCallReceiver内部类中处理做广播,然后通过SipCallOptionHandler,最终调用InCallScreen。
由于我们的项目是在 doReceive()方法中拦截掉URL以及号码并且调用自己实现的蓝牙电话,这样可以保证兼容性。所以后边的流程就没有走。
/**
* Handes receipt of ordered new_outgoing_call intent. Verifies that the return from the
* ordered intent is valid.
* @return true if the call is being attempted; false if we are canceling the call.
*/
public boolean doReceive(Context context, Intent intent)
这里附上一个完整的流程图以供参考: