Android电话流程之OutgoingCallBroadcaster

本文分析了Android电话拨打流程中的OutgoingCallBroadcaster类,该类在拨打电话时起关键作用,无论是通过拨号盘、通话记录还是联系人应用。OutgoingCallBroadcaster继承自Activity,所有呼叫请求都会经过它进行判断,如检查号码有效性。文中提到了正常的拨打流程,并提供了一个流程图辅助理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本章部分内容参考自:

Phone ---- OutgoingCallBroadcaster解析 

Android电话拨打流程源码分析


根据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)

这里附上一个完整的流程图以供参考:





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值