Android M MO流程并与Android L MO对比

此篇介绍Android M上的MO流程,并与Android L上做比较。

先看一下Android M整体的一个流程图:

变化主要在流程的前半部分,下面是一张对比图:

AM_AM_compare

变化集中在红色框内。

下面我们开始跟一下MO的流程。

packages/apps/Dialer

以在拨号盘拨号为入口(当然还有很多其他入口,我们就不挨个跟了),DialpadFragment.java  handleDialButtonPressed(),这个方法内部的代码变少了,也可以看作是多了一步startCall()

packages/apps/Dialer  DialpadFragment.java


   private void handleDialButtonPressed() {

        if (isDigitsEmpty()) { // No number entered.

            handleDialButtonClickWithEmptyDigits();

        } else {

            final String number = mDigits.getText().toString();

 

            // "persist.radio.otaspdial" is a temporary hack needed for one carrier‘s automated

            // test equipment.

            // TODO: clean it up.

            if (number != null

                    && !TextUtils.isEmpty(mProhibitedPhoneNumberRegexp)

                    && number.matches(mProhibitedPhoneNumberRegexp)) {

                Log.i(TAG, "The phone number is prohibited explicitly by a rule.");

                if (getActivity() != null) {

                    DialogFragment dialogFragment = ErrorDialogFragment.newInstance(

                            R.string.dialog_phone_call_prohibited_message);

                    dialogFragment.show(getFragmentManager(), "phone_prohibited_dialog");

                }

 

                // Clear the digits just in case.

                clearDialpad();

            } else {

                startCall(number, OriginCodes.DIALPAD_DIRECT_DIAL);//这里是新增内容

            }

        }

    }

startCall(),这个方法是新增的,其实也可以看作是拆分出来的


    private void startCall(String number, String origin) {

        if (mCurrentCallMethodInfo != null && mCurrentCallMethodInfo.mIsInCallProvider &&

                !PhoneNumberUtils.isEmergencyNumber(number)) {

            mCurrentCallMethodInfo.placeCall(origin, number, getActivity(), false, true,

                    new StartInCallCallReceiver.InCallCallListener() {

                        @Override

                        public void onResult(int resultCode) {

                            if (resultCode == StatusCodes.StartCall.CALL_CONNECTED) {

                                hideAndClearDialpad(false);

                            }

                        }

                    });

        } else {

            // If no sim is selected, or emergency callmethod selected, or number is

            // an emergency number, phone account handle should be null, and will use the

            // default account.

            // Else, create PhoneAccountHandle from selected callmethod components and

            // initial call using that account.

            PhoneAccountHandle handle = CallMethodInfo.getPhoneAccountHandleFromCallMethodInfo(

                    getActivity(), mCurrentCallMethodInfo, number);

            final Intent intent = IntentUtil.getCallIntent(number,//返回的action:android.intent.action.CALL而在5.1上是android.intent.action.CALL_PRIVILEGED

                    (getActivity() instanceof DialtactsActivity ?

                            ((DialtactsActivity) getActivity())

                                    .getCallOrigin() : null),

                    handle);

            DialerUtils.startActivityWithErrorToast(getActivity(), intent, origin);//虽然增加了一步startCall,但这里还是调用了方法

            hideAndClearDialpad(false);

        }

    }

注意这里intent的构造,返回值来自 IntentUtil.getCallIntent(),而Android L的则是返回自CallUtil.getCallIntent()。

这俩有啥区别的?最大的不同是他俩返回的ACTION不一样,一个返回的android.intent.action.CALL一个返回android.intent.action.CALL_PRIVILEGED,暂时还没看到有什么明显的影响,不过既然这个action有变化,肯定会对后面的流程有一点影响,后面会提到。

然后另外还有一个CALL_ACTION:android.intent.action.CALL_EMERGENCY,三者在L上的区别与用法见 Android
5.0 上紧急电话EmergencyCall与普通电话MO流程区别

然后两个文件所在的目录不同:IntentUtil位于Dialer,CallUtil位于ContactCommon,

还有就是起初IntentUtil.java叫做PrivilegedCallUtil,然后改名为CallIntentUtil,后又改名为现在的IntentUtil,

再有就是在早起的Android M版本中返回的也是android.intent.action.CALL_PRIVILEGED,后来改成了android.intent.action.CALL,至于原因和提交在这就不深追了(看IntentUtil的提交历史可知)。

DialerUtils.java


    public static void startActivityWithErrorToast(Context context, Intent intent, int msgId,

                                                   String origin) {

        try {

            if ((IntentUtil.CALL_ACTION.equals(intent.getAction())

                            && context instanceof Activity)) {

                // All dialer-initiated calls should pass the touch point to the InCallUI

                Point touchPoint = TouchPointManager.getInstance().getPoint();//geiPoint(),对应的setPoint()方法,在点击的时候调用

                if (touchPoint.x != 0 || touchPoint.y != 0) {

                    Bundle extras = new Bundle();

                    extras.putParcelable(TouchPointManager.TOUCH_POINT, touchPoint);//是与动画有关咯,将传至InCallUI

                    intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);

                }

                if (origin != null) {

                    intent.putExtra(PhoneConstants.EXTRA_CALL_ORIGIN, origin);

                }

                final TelecomManager tm =

                        (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);

                tm.placeCall(intent.getData(), intent.getExtras());//直接到TelecomManager里去了。在L 5.1上是调用startActivityForResult(),之后再启动CallActivity

            } else {

                context.startActivity(intent);

            }

        } catch (ActivityNotFoundException e) {

            Toast.makeText(context, msgId, Toast.LENGTH_SHORT).show();

        }

    }

从下面开始就是主要变化的地方

framework/telecomm

framework/base/telecomm  TelecomManager.java

TelecomManager.placeCall是新增的api,

其作用注释里面已经写的很清楚了。


 /**

     * Places a new outgoing call to the provided address using the system telecom service with

     * the specified extras.

     *

     * This method is equivalent to placing an outgoing call using {@link Intent#ACTION_CALL},

     * except that the outgoing call will always be sent via the system telecom service. If

     * method-caller is either the user selected default dialer app or preloaded system dialer

     * app, then emergency calls will also be allowed.

     *

     * Requires permission: {@link android.Manifest.permission#CALL_PHONE}

     *

     * Usage example:

     * <pre>

     * Uri uri = Uri.fromParts("tel", "12345", null);//Uri 主要是号码

     * Bundle extras = new Bundle();

     * extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, true);//默认开扬声器

     * telecomManager.placeCall(uri, extras);

     * </pre>

     *

     * The following keys are supported in the supplied extras.

     * <ul>

     *   <li>{@link #EXTRA_OUTGOING_CALL_EXTRAS}</li>

     *   <li>{@link #EXTRA_PHONE_ACCOUNT_HANDLE}</li>

     *   <li>{@link #EXTRA_START_CALL_WITH_SPEAKERPHONE}</li>

     *   <li>{@link #EXTRA_START_CALL_WITH_VIDEO_STATE}</li>

     * </ul>

     *

     * @param address The address to make the call to.

     * @param extras Bundle of extras to use with the call.

     */

    public void placeCall(Uri address, Bundle extras) {

        ITelecomService service = getTelecomService();

        if (service != null) {

            if (address == null) {//检查号码

                Log.w(TAG, "Cannot place call to empty address.");

            }

            try {

                service.placeCall(address, extras == null ? new Bundle() : extras,

                        mContext.getOpPackageName());

            } catch (RemoteException e) {

                Log.e(TAG, "Error calling ITelecomService#placeCall", e);

            }

        }

    }

packages/services/Telecomm

TelecomServiceImpl.java  placeCall


        /**

         * @see android.telecom.TelecomManager#placeCall

         */

        @Override

        public void placeCall(Uri handle, Bundle extras, String callingPackage) {

            enforceCallingPackage(callingPackage);

            if (!canCallPhone(callingPackage, "placeCall")) {

                throw new SecurityException("Package " + callingPackage

                        + " is not allowed to place phone calls");

            }

 

            // Note: we can still get here for the default/system dialer, even if the Phone

            // permission is turned off. This is because the default/system dialer is always

            // allowed to attempt to place a call (regardless of permission state), in case//注释还是要看

            // it turns out to be an emergency call. If the permission is denied and the

            // call is being made to a non-emergency number, the call will be denied later on

            // by {@link UserCallIntentProcessor}.

 

            final boolean hasCallAppOp = mAppOpsManager.noteOp(AppOpsManager.OP_CALL_PHONE,

                    Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED;

 

            final boolean hasCallPermission = mContext.checkCallingPermission(CALL_PHONE) ==

                    PackageManager.PERMISSION_GRANTED;

 

            synchronized (mLock) {

                final UserHandle userHandle = Binder.getCallingUserHandle();

                long token = Binder.clearCallingIdentity();

                try {

                    final Intent intent = new Intent(Intent.ACTION_CALL, handle);

                    intent.putExtras(extras);

                    new UserCallIntentProcessor(mContext, userHandle).processIntent(intent,

                            callingPackage, hasCallAppOp && hasCallPermission);

                } finally {

                    Binder.restoreCallingIdentity(token);

                }

            }

        }

看到UserCallIntentProcessor.java不要又觉得是个新东西,它其实原名CallActivity,就是L版本上那个在onCreate中执行了processIntent()之后直接finish()的没有界面的CallActivity。

另外提一下现在M上有的一个类叫做UserCallActivity.java它的工作其实跟L上的CallActivity是一样的,是一个没有界面的Activity,在AndroidManifest.xml中也配置了过滤的action和别名Activity。

是不是有点晕?L上的CallActivity.java升级到M上改名为UserCallIntentProcessor.java,另外新增一个UserCallActivity.java取代其工作。

好吧这样说的话其实UserCallIntentProcessor.java算个新东西,从内容和功能上来说。

一起改名和移动的的还有:


     /**

     * Processes intents sent to the activity.

     *

     * @param intent The intent.

     */

    public void processIntent(Intent intent, String callingPackageName,

            boolean canCallNonEmergency) {

       

//略过

 

        String action = intent.getAction();

 

        if (Intent.ACTION_CALL.equals(action) || //满足三种CALL_ACTION的任何一种都往外拨打

                Intent.ACTION_CALL_PRIVILEGED.equals(action) ||

                Intent.ACTION_CALL_EMERGENCY.equals(action)) {

            processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency);

        }

    }

ProcessOutgoingCallIntent

处理Intent


   private void processOutgoingCallIntent(Intent intent, String callingPackageName,

            boolean canCallNonEmergency) {

        

//略过不关心的 

        int videoState = intent.getIntExtra(

                TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,

                VideoProfile.STATE_AUDIO_ONLY);

        Log.d(this, "processOutgoingCallIntent videoState = " + videoState);//videoState = 0 意为AUDIO_ONLY 1和2为单向视频,3为双向视频

 

        if (!isEmergencyVideoCallingSupported() && VideoProfile.isVideo(videoState)

                && TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) {

            Log.d(this, "Emergency call...Converting video call to voice...");

            videoState = VideoProfile.STATE_AUDIO_ONLY;

            intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,

                    videoState);

        }

 

        if (VideoProfile.isVideo(videoState) && isTtyModeEnabled() &&

                !TelephonyUtil.shouldProcessAsEmergency(mContext, handle)) {

 

            showErrorDialogForRestrictedOutgoingCall(mContext,

                    R.string.video_call_not_allowed_if_tty_enabled);

            Log.d(this, "Rejecting video calls as tty is enabled");

            return;

        }

 

        intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER,

                isDefaultOrSystemDialer(callingPackageName));

        sendBroadcastToReceiver(intent);

    }

sendBroadcastToReceiver

发送广播


    /**

     * Trampolines the intent to the broadcast receiver that runs only as the primary user.

     */

    private boolean sendBroadcastToReceiver(Intent intent) {

        intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, false);

        intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);

        intent.setClass(mContext, PrimaryCallReceiver.class);//接收者

        Log.d(this, "Sending broadcast as user to CallReceiver");

        mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);//发广播

        return true;

    }

PrimaryCallReceiver,中的onReveiver()很像L版本上CallReceiver.java的onReceiver(),但其实...(看下面)


@Override

    public void onReceive(Context context, Intent intent) {

        synchronized (getTelecomSystem().getLock()) {

            getTelecomSystem().getCallIntentProcessor().processIntent(intent);

        }

    }

log里面也打印了是由CallIntentProcessor接着处理


D/Telecom (11638): UserCallIntentProcessor: processOutgoingCallIntent videoState = 0 //videoState = 0 意为AUDIO_ONLY 1和2为单向视频,3为双向视频

D/Telecom (11638): UserCallIntentProcessor: Sending broadcast as user to CallReceiver

I/Telecom (11638): CallIntentProcessor: onReceive - isUnknownCall: false

CallintentProcessor.java (原名CallReceiver)processIntent


public void processIntent(Intent intent) {

        final boolean isUnknownCall = intent.getBooleanExtra(KEY_IS_UNKNOWN_CALL, false);

        Log.i(this, "onReceive - isUnknownCall: %s", isUnknownCall);

 

        Trace.beginSection("processNewCallCallIntent");

        if (isUnknownCall) {

            processUnknownCallIntent(mCallsManager, intent);

        } else {

            processOutgoingCallIntent(mContext, mCallsManager, intent);

        }

        Trace.endSection();

    }

ProcessOutgongCallIntent


    /**

     * Processes CALL, CALL_PRIVILEGED, and CALL_EMERGENCY intents.

     *

     * @param intent Call intent containing data about the handle to call.

     */

    static void processOutgoingCallIntent(

            Context context,

            CallsManager callsManager,

            Intent intent) {

        Uri handle = intent.getData();

        String scheme = handle.getScheme();

        String uriString = handle.getSchemeSpecificPart();

        Bundle clientExtras = null;

        String origin = null;

//掠过一些本次不关系的

 

        Log.i(CallIntentProcessor.class, " processOutgoingCallIntent handle = " + handle

                + ",scheme = " + scheme + ", uriString = " + uriString

                + ", isSkipSchemaParsing = " + isSkipSchemaParsing

                + ", isAddParticipant = " + isAddParticipant

                + ", isCallPull = " + isCallPull);

 

        // Ensure call subject is passed on to the connection service.

        if (intent.hasExtra(TelecomManager.EXTRA_CALL_SUBJECT)) {

            String callsubject = intent.getStringExtra(TelecomManager.EXTRA_CALL_SUBJECT);

            clientExtras.putString(TelecomManager.EXTRA_CALL_SUBJECT, callsubject);

        }

 

        final boolean isPrivilegedDialer = intent.getBooleanExtra(KEY_IS_PRIVILEGED_DIALER, false);

 

        // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns //先把InCallUI界面起来

        Call call = callsManager.startOutgoingCall(handle, phoneAccountHandle, clientExtras,

                origin);

 

        if (call != null) {

            // Asynchronous calls should not usually be made inside a BroadcastReceiver because once

            // onReceive is complete, the BroadcastReceiver‘s process runs the risk of getting

            // killed if memory is scarce. However, this is OK here because the entire Telecom

            // process will be running throughout the duration of the phone call and should never

            // be killed.

            NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(

                    context, callsManager, call, intent, isPrivilegedDialer);

            final int result = broadcaster.processIntent();

            final boolean success = result == DisconnectCause.NOT_DISCONNECTED;

 

            if (!success && call != null) {

                disconnectCallAndShowErrorDialog(context, call, result);

            }

        }

    }

NewoutgoingCallIntentBroadcaster.java

注意看前面的注释中的三种action介绍,


/**

     * Processes the supplied intent and starts the outgoing call broadcast process relevant to the

     * intent.

     *

     * This method will handle three kinds of actions:

     *

     * - CALL (intent launched by all third party dialers)//第三方的app拨号应用

     * - CALL_PRIVILEGED (intent launched by system apps e.g. system Dialer, voice Dialer)//系统拨号应用,语音拨号应用

     * - CALL_EMERGENCY (intent launched by lock screen emergency dialer)//锁屏界面的紧急拨号器拨打的

     *

     * @return {@link DisconnectCause#NOT_DISCONNECTED} if the call succeeded, and an appropriate

     *         {@link DisconnectCause} if the call did not, describing why it failed.

     */

    int processIntent() {

        Log.v(this, "Processing call intent in OutgoingCallIntentBroadcaster.");

 

        Intent intent = mIntent;

        String action = intent.getAction();

        final Uri handle = intent.getData();

 //略

 

        final boolean isPotentialEmergencyNumber = isPotentialEmergencyNumber(number);

        Log.v(this, "isPotentialEmergencyNumber = %s", isPotentialEmergencyNumber);

 

        rewriteCallIntentAction(intent, isPotentialEmergencyNumber);//这里是重写CALL_ACTION的方法,具体的见下面的插播

        action = intent.getAction();

        // True for certain types of numbers that are not intended to be intercepted or modified

        // by third parties (e.g. emergency numbers).

        boolean callImmediately = false;//一个较为关键的值,赋值受CALL_ACTION影响

 

        if (Intent.ACTION_CALL.equals(action)) {//在目前的版本上默认是这个没啥说的

            if (isPotentialEmergencyNumber) {//是紧急号码的话继续,不是紧急号码的话,那进来就什么都没做。至于紧急号码的判断,在流程中不同的地方可能不一样,请自行了解

                if (!mIsDefaultOrSystemPhoneApp) {

                    Log.w(this, "Cannot call potential emergency number %s with CALL Intent %s "

                            + "unless caller is system or default dialer.", number, intent);

                    launchSystemDialer(intent.getData());//第三方输入紧急号码后点击拨打会调到系统拨号程序(如果不是紧急号码的话会直接跳到系统拨号界面,也就是InCallUI)

                    return DisconnectCause.OUTGOING_CANCELED;

                } else {

                    callImmediately = true;//走到这里的条件是:1.重写后的ACTION是CALL 2.是Potential紧急号码 3.由系统拨号应用发起的拨号

                }

            }

        } else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) {//紧急号码的CALL_ACTION

            if (!isPotentialEmergencyNumber) {

                Log.w(this, "Cannot call non-potential-emergency number %s with EMERGENCY_CALL "

                        + "Intent %s.", number, intent);

                return DisconnectCause.OUTGOING_CANCELED;//用晋级号码的action拨打非紧急号码,是不允许的,返回。

            }

            callImmediately = true;//到这里的条件是:就是action是android.intent.action.CALL_EMERGENCY

        } else {

            Log.w(this, "Unhandled Intent %s. Ignoring and not placing call.", intent);

            return DisconnectCause.INVALID_NUMBER;

        }

 

        if (callImmediately) {//只有在紧急号码的情况下进入

            Log.i(this, "Placing call immediately instead of waiting for "

                    + " OutgoingCallBroadcastReceiver: %s", intent);

            String scheme = isUriNumber ? PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL;

            boolean speakerphoneOn = mIntent.getBooleanExtra(

                    TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);

            int videoState = mIntent.getIntExtra(

                    TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,

                    VideoProfile.STATE_AUDIO_ONLY);

            mCallsManager.placeOutgoingCall(mCall, Uri.fromParts(scheme, number, null), null,//直接开始拨打了,可以说这段代码在一定程度上会加快拨打紧急号码的速度

                    speakerphoneOn, videoState);

 

            // Don‘t return but instead continue and send the ACTION_NEW_OUTGOING_CALL broadcast

            // so that third parties can still inspect (but not intercept) the outgoing call. When

            // the broadcast finally reaches the OutgoingCallBroadcastReceiver, we‘ll know not to

            // initiate the call again because of the presence of the EXTRA_ALREADY_CALLED extra.

        }

 

        Log.i(this, "Sending NewOutgoingCallBroadcast for %s", mCall);

        if (isSkipSchemaParsing) {

            broadcastIntent(intent, handle.toString(), !callImmediately);

        } else {

            broadcastIntent(intent, number, !callImmediately);//又来广播

        }

        return DisconnectCause.NOT_DISCONNECTED;

    }

log


V/Telecom (11638): NewOutgoingCallIntentBroadcaster: processIntent isConferenceUri: false isSkipSchemaParsing = false

插播

这是重写action的方法。主要目的是把CALL_PRIVILEGED的action根据号码类型转换为CALL或者CALL_EMERGENCY,就是转换为普通和紧急号码action类型。

按照Android L上的设计,系统拨号应用intent默认携带android.intent.action.CALL_PRIVILEGED,之后在这个方法内部转换。然而现在默认携带的是android.intent.action.CALL,那么现在这个方法就是废的,从系统拨号应用拨出的紧急号码也不会重写成android.intent.action.CALL_EMERGENCY了,紧急电话的拨打可能会受到一些影响。


/**

     * Given a call intent and whether or not the number to dial is an emergency number, rewrite

     * the call intent action to an appropriate one.

     *

     * @param intent Intent to rewrite the action for

     * @param isPotentialEmergencyNumber Whether or not the number is potentially an emergency

     * number.

     */

    private void rewriteCallIntentAction(Intent intent, boolean isPotentialEmergencyNumber) {

        String action = intent.getAction();

 

        /* Change CALL_PRIVILEGED into CALL or CALL_EMERGENCY as needed. */注释已经很明确了

        if (Intent.ACTION_CALL_PRIVILEGED.equals(action)) {//判断条件是 ACTION_CALL_PRIVILEGED,当前M默认为CALL,所以这个方法基本上也是废的。

            if (isPotentialEmergencyNumber) {//紧急号码的话重写成android.intent.action.CALL_EMERGENCY

                Log.i(this, "ACTION_CALL_PRIVILEGED is used while the number is a potential"

                        + " emergency number. Using ACTION_CALL_EMERGENCY as an action instead.");

                action = Intent.ACTION_CALL_EMERGENCY;

            } else {

                action = Intent.ACTION_CALL;//否则重写成android.intent.action.CALL

            }

            Log.v(this, " - updating action from CALL_PRIVILEGED to %s", action);

            intent.setAction(action);

        }

    }

好,把前面的稍微总结一下,这个aciton变了,但流程上似乎并没什么影响,callImmediately还是被赋值为true了,至于后面啥影响,还没看出来//

继续走

broadcastIntent()


/**

     * Sends a new outgoing call ordered broadcast so that third party apps can cancel the

     * placement of the call or redirect it to a different number.

     *

     * @param originalCallIntent The original call intent.

     * @param number Call number that was stored in the original call intent.

     * @param receiverRequired Whether or not the result from the ordered broadcast should be

     *     processed using a {@link NewOutgoingCallIntentBroadcaster}.

     */

    private void broadcastIntent(

            Intent originalCallIntent,

            String number,

            boolean receiverRequired) {

        Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);

        if (number != null) {

            broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);

        }

 

        // Force receivers of this broadcast intent to run at foreground priority because we

        // want to finish processing the broadcast intent as soon as possible.

        broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);

        Log.v(this, "Broadcasting intent: %s.", broadcastIntent);

 

        checkAndCopyProviderExtras(originalCallIntent, broadcastIntent);

 

        mContext.sendOrderedBroadcastAsUser(

                broadcastIntent,

                UserHandle.CURRENT,

                android.Manifest.permission.PROCESS_OUTGOING_CALLS,

                AppOpsManager.OP_PROCESS_OUTGOING_CALLS,

                receiverRequired ? new NewOutgoingCallBroadcastIntentReceiver() : null,

                null,  // scheduler

                Activity.RESULT_OK,  // initialCode

                number,  // initialData: initial value for the result data (number to be modified)

                null);  // initialExtras

    }

NewOutgoingCallBroadcastIntentReceiver


    /**

     * Processes the result of the outgoing call broadcast intent, and performs callbacks to

     * the OutgoingCallIntentBroadcasterListener as necessary.

     */

    private class NewOutgoingCallBroadcastIntentReceiver extends BroadcastReceiver {

 

        @Override

        public void onReceive(Context context, Intent intent) {

            Trace.beginSection("onReceiveNewOutgoingCallBroadcast");

            Log.v(this, "onReceive: %s", 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.)

            String resultNumber = getResultData();

            Log.i(this, "Received new-outgoing-call-broadcast for %s with data %s", mCall,

                    Log.pii(resultNumber));

 

           

//略 

            GatewayInfo gatewayInfo = getGateWayInfoFromIntent(intent, resultHandleUri);

            mCallsManager.placeOutgoingCall(mCall, resultHandleUri, gatewayInfo,

                    mIntent.getBooleanExtra(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE,??EXTRA_START_CALL_WITH_SPEAKERPHONE

                            false),

                    mIntent.getIntExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,

                            VideoProfile.STATE_AUDIO_ONLY));

            Trace.endSection();

        }

    }

后面与L上的流程几乎都是一样的了,暂时就不细说了,

关键log

Event 开头的是新增log


I/Telecom (11638): Event: Call 2: CREATED, null

I/Telecom (11638): Event: Call 2: SET_CONNECTING, ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}, [356a192b7913b04c54574d18c28d46e6395428ab], UserHandle{0}

I/Telecom (11638): Event: Call 2: AUDIO_ROUTE, EARPIECE//audio变化

I/Telecom (11638): Event: Call 2: BIND_CS, ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}//CS call bind

I/Telecom (11638): Event: Call 2: CS_BOUND, ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}

I/Telecom (11638): Event: Call 2: START_CONNECTION, tel:10010

I/Telecom (11638): Event: Call 2: SET_DIALING, successful outgoing call//拨号

I/Telecom (11638): Event: Call 2: SET_ACTIVE, active set explicitly//接通

I/Telecom (11638): Event: Call 2: REQUEST_DISCONNECT, null//主动断开

I/Telecom (11638): Event: Call 2: SET_DISCONNECTED, disconnected set explicitly> DisconnectCause [ Code: (LOCAL) Label: () Description: () Reason: (LOCAL) Tone: (27) ]//断开原因

I/Telecom (11638): Event: Call 2: DESTROYED, null
时间: 2024-08-11 03:00:29

Android M MO流程并与Android L MO对比的相关文章

Android View measure流程详解

Android View measure流程详解 Android中View绘制的流程包括:measure(测量)->layout(布局)->draw(绘制). 因为Android中每个View都占据了一块矩形的空间,当我们要在屏幕上显示这个矩形的View的时候 首先我们需要知道这个矩形的大小(宽和高)这就对应了View的measure流程. 有了View的宽和高,我们还需要知道View左上角的起点在哪里,右下角的终点在哪里,这就对应了View的layout流程. 当矩形的区域在屏幕上确定之后,

android事件分发流程

1.描述 说到android事件的分发机制,真的是感觉既熟悉又陌生,因为每次需要用到的时候查看相关的源码,总能找到一些所以然来,但是要根据自己理解从头到尾说一遍,却一点都说不上.总结原因吧,感觉是自己不善于总结,过目就忘,并没有把心思放在上面,自然也就没有一点概念咯~~所以在这里主要是把自己理解的一些东西记录下来,不涉及源代码. 好吧,接下来简单说说android事件分发流程吧,说到事件分发,首先应该想到的是两个类,View和ViewGroup,ViewGroup是继承自View实现的,View

React Native Android Gradle 编译流程浅析

[工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果.私信联系我] 1 背景 前面已经发车了一篇<React Native Android 从学车到补胎和成功发车经历>,接着就该好好琢磨一下 React Native 周边了,没看第一篇的可以先去看看:这里我们先从 React Native 的 Android 编译来简单揭晓一下 React Native 在集成的过程中到底干了哪些不可告人的坏事:由于我们项目准备以 Gradle 形式接入

Android -- Wifi连接流程分析

Android -- Wifi连接流程分析 当我们在Android手机上连接一个AP时,间接调用WifiManager的connect()方法: /** * Connect to a network with the given configuration. The network also * gets added to the supplicant configuration. * * For a new network, this function is used instead of a

Android技术20:Android的初始化流程

Android系统是如何启动的呢,应用程序是如何启动.下面简要介绍下初始化流程. 1.Android系统的初始化 1.1Android系统会首先启动Linux基础系统,然后引导加载Linux内核并启动初始化进程Init Linux Kernel---->Init(pid=1) 1.2启动守护进程Daemons 启动Usb守护进程,管理USB连接 启动Android Debug Bridge守护进程管理ADB连接 启动Debuggerd Debug守护进程 启动无线接口守护进程管理无线通信 1.3

Android WIFI 启动流程(TIP^^)

前几天因为解决一堆Bug,没时间写.我不会每天都写,就是为了存档一些资料. 内容来源:工作中接触到的+高手博客+文档(Books)=自己理解 仅限参考^^ 此博客是上一个<<Android WIFI 启动流程>>的附加项. 参考博客:http://blog.csdn.net/eoeandroida/article/details/40583353 配置AP: 当用户在WifiSettings界面上选择了一个AP后,会显示配置AP参数的一个对话框. showAccessPointDi

Android Day01-电话拨号器案例&Android开发流程

电话拨号器开发步骤: 1.在清单文件中添加打电话的权限 <?xml version="1.0"encoding="utf-8"?>       <manifestxmlns:android="http://schemas.android.com/apk/res/android"             package="cn.itcast.action"             android:version

Android 之MediaScanner流程解析

MediaScanner详解 OK, 我们现在开始来大概分析一下android framework中MediaScanner部分的流程,若大家发现分析过程中有错误,欢迎拍砖指正. 分析流程之前,我们先给自己定个要用MediaScanner解决的问题,这样我们才会有目标感,才知道我们要干什么.否则,干巴巴的分析流程,一般都会很容易的迷失在各种code的迷雾中. 我们这里要定的目标是:获取某个MP3文件的artist & album. 我们可以假定,现在有个媒体播放器,在播放music的时候,需要在

android 电池(二):android关机充电流程、充电画面显示【转】

本文转载自:http://blog.csdn.net/xubin341719/article/details/8498580 上一篇我们讲了锂电池的充放电的流程和电池的一些特性,这一节我们重点说一下android关机充电是怎么.充电画面显示是怎么实现的,这个在工作中也比较有用,我们开始做这一块的时候也走了不少的弯路.我记得我们做adnroid2.3的时候,关机状态和充电logo显示是在uboot中做的.应该是有两种做法,回头我再看下uboot中做画面显示那一块是怎么做的,这一节我们重点说系统中的