标签:


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);//这里是新增内容}}}
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() {@Overridepublic 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);}}
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 InCallUIPoint touchPoint = TouchPointManager.getInstance().getPoint();//geiPoint(),对应的setPoint()方法,在点击的时候调用if (touchPoint.x != 0 || touchPoint.y != 0) {Bundle extras = new Bundle();extras.putParcelable(TouchPointManager.TOUCH_POINT, touchPoint);//是与动画有关咯,将传至InCallUIintent.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();}}

/*** 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);}}}
/*** @see android.telecom.TelecomManager#placeCall*/@Overridepublic 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);}}}

/*** 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);}}
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);}
/*** 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;}
@Overridepublic void onReceive(Context context, Intent intent) {synchronized (getTelecomSystem().getLock()) {getTelecomSystem().getCallIntentProcessor().processIntent(intent);}}
D/Telecom (11638): UserCallIntentProcessor: processOutgoingCallIntent videoState = 0 //videoState = 0 意为AUDIO_ONLY 1和2为单向视频,3为双向视频D/Telecom (11638): UserCallIntentProcessor: Sending broadcast as user to CallReceiverI/Telecom (11638): CallIntentProcessor: onReceive - isUnknownCall: false
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();}
/*** 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);}}}
/*** 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_ACTIONif (!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;}
V/Telecom (11638): NewOutgoingCallIntentBroadcaster: processIntent isConferenceUri: false isSkipSchemaParsing = false
/*** 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_EMERGENCYLog.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);}}
/*** 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, // schedulerActivity.RESULT_OK, // initialCodenumber, // initialData: initial value for the result data (number to be modified)null); // initialExtras}
/*** Processes the result of the outgoing call broadcast intent, and performs callbacks to* the OutgoingCallIntentBroadcasterListener as necessary.*/private class NewOutgoingCallBroadcastIntentReceiver extends BroadcastReceiver {@Overridepublic 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_SPEAKERPHONEfalse),mIntent.getIntExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,VideoProfile.STATE_AUDIO_ONLY));Trace.endSection();}}
I/Telecom (11638): Event: Call 2: CREATED, nullI/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 bindI/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:10010I/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
Android M MO流程并与Android L MO对比
标签:
原文地址:http://blog.csdn.net/aaa111/article/details/51503295