Android 7.0 去电流程
来源:互联网 发布:身份证登记软件下载 编辑:程序博客网 时间:2024/05/02 11:18
拨号的入口在TelecomManager的placeCall的方法,该方法实际调用TelecomServiceImpl的placeCall(),接着调用UserCallIntentProcessor的processIntent()方法
TelecomServiceImpl->placeCall()
public void placeCall(Uri handle, Bundle extras, String callingPackage) { try { ... synchronized (mLock) { final UserHandle userHandle = Binder.getCallingUserHandle(); long token = Binder.clearCallingIdentity(); try { final Intent intent = new Intent(Intent.ACTION_CALL, handle); if (extras != null) { extras.setDefusable(true); intent.putExtras(extras); } mUserCallIntentProcessorFactory.create(mContext, userHandle) .processIntent( intent, callingPackage, hasCallAppOp && hasCallPermission);//mUserCallIntentProcessorFactory是在TelecomSystem中初始化的 } finally { Binder.restoreCallingIdentity(token); } } } finally { Log.endSession(); } }
UserCallIntentProcessor又在process(),UserCallIntentProcessor中方执行顺序为
process()->processOutgoingCallIntent()->sendBroadcastToReceiver():
UserCallIntentProcessor->process():
public void processIntent(Intent intent, String callingPackageName, boolean canCallNonEmergency) { // Ensure call intents are not processed on devices that are not capable of calling. if (!isVoiceCapable()) { return; } String action = intent.getAction(); if (Intent.ACTION_CALL.equals(action) || Intent.ACTION_CALL_PRIVILEGED.equals(action) || Intent.ACTION_CALL_EMERGENCY.equals(action)) { processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency); } }
UserCallIntentProcessor->processOutgoingCallIntent()
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); intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER, isDefaultOrSystemDialer(callingPackageName)); // Save the user handle of current user before forwarding the intent to primary user. intent.putExtra(CallIntentProcessor.KEY_INITIATING_USER, mUserHandle); sendBroadcastToReceiver(intent); }
UserCallIntentProcessor->sendBroadcastToReceiver():
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.SYSTEM); return true; }
UserCallIntentProcessor给PrimaryCallReceiver发送广播后, PrimaryCallReceiver在onReceive()实际上就了调用CallIntentProcessor的processIntent的方法,接着调用CallsManager的startOutgoingCall 初始化Call,然后NewOutgoingCallIntentBroadcaster的processIntent()方法:
public void onReceive(Context context, Intent intent) { synchronized (getTelecomSystem().getLock()) { getTelecomSystem().getCallIntentProcessor().processIntent(intent); } }
在CallIntentProcessor的processIntent方法中调用processOutgoingCallIntent()方法。
CallIntentProcessor->processOutgoingCallIntent():
static void processOutgoingCallIntent( Context context, CallsManager callsManager, Intent intent) { ... Call call = callsManager .startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser);//初始化call及启动InCallUI 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, callsManager.getPhoneNumberUtilsAdapter(), isPrivilegedDialer); final int result = broadcaster.processIntent(); final boolean success = result == DisconnectCause.NOT_DISCONNECTED; if (!success && call != null) { callsManager.clearPendingMOEmergencyCall(); disconnectCallAndShowErrorDialog(context, call, result); } }}
NewOutgoingCallIntentBroadcaster ->processIntent():
public int processIntent() { ... if (callImmediately) { 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); // Since we will not start NewOutgoingCallBroadcastIntentReceiver in case of // callImmediately is true, make sure to mark it as ready, so that when user // selects account, call can go ahead in case of numbers which are potential emergency // but not actual emergeny. mCall.setNewOutgoingCallIntentBroadcastIsDone(); mCallsManager.placeOutgoingCall(mCall, Uri.fromParts(scheme, number, null), null, speakerphoneOn, videoState); } }
CallsManager->placeOutgoingCall():
... if (call.getTargetPhoneAccount() != null || call.isEmergencyCall()) { if (!call.isEmergencyCall()) { updateLchStatus(call.getTargetPhoneAccount().getId()); } call.startCreateConnection(mPhoneAccountRegistrar); } } ...
Call->startCreateConnection():
void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) { ... mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this, phoneAccountRegistrar, mContext); mCreateConnectionProcessor.process(); }
CreateConnectionProcessor->process():
public void process() { clearTimeout(); mAttemptRecords = new ArrayList<>(); if (mCall.getTargetPhoneAccount() != null) { mAttemptRecords.add(new CallAttemptRecord( mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount())); } adjustAttemptsForConnectionManager(); adjustAttemptsForEmergency(mCall.getTargetPhoneAccount()); mAttemptRecordIterator = mAttemptRecords.iterator(); attemptNextPhoneAccount(); }
CreateConnectionProcessor->attemptNextPhoneAccount()
private void attemptNextPhoneAccount() { ... if (mCallResponse != null && attempt != null) { Log.i(this, "Trying attempt %s", attempt); PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount; mService = mRepository.getService(phoneAccount.getComponentName(), phoneAccount.getUserHandle()); if (mService == null) { Log.i(this, "Found no connection service for attempt %s", attempt); attemptNextPhoneAccount();//递归 } else { mConnectionAttempt++; mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount); mCall.setTargetPhoneAccount(attempt.targetPhoneAccount); mCall.setConnectionService(mService); setTimeoutIfNeeded(mService, attempt); mService.createConnection(mCall, this); } } }
ConnectionServiceWrapper->createConnection():
public void createConnection(final Call call, final CreateConnectionResponse response) { Log.d(this, "createConnection(%s) via %s.", call, getComponentName()); BindCallback callback = new BindCallback() { @Override public void onSuccess() { String callId = mCallIdMapper.getCallId(call); mPendingResponses.put(callId, response); GatewayInfo gatewayInfo = call.getGatewayInfo(); Bundle extras = call.getIntentExtras(); if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null && gatewayInfo.getOriginalAddress() != null) { extras = (Bundle) extras.clone(); extras.putString( TelecomManager.GATEWAY_PROVIDER_PACKAGE, gatewayInfo.getGatewayProviderPackageName()); extras.putParcelable( TelecomManager.GATEWAY_ORIGINAL_ADDRESS, gatewayInfo.getOriginalAddress()); } Log.event(call, Log.Events.START_CONNECTION, Log.piiHandle(call.getHandle())); try { mServiceInterface.createConnection( call.getConnectionManagerPhoneAccount(), callId, new ConnectionRequest( call.getTargetPhoneAccount(), call.getHandle(), extras, call.getVideoState(), callId), call.shouldAttachToExistingConnection(), call.isUnknown()); } catch (RemoteException e) { Log.e(this, e, "Failure to createConnection -- %s", getComponentName()); mPendingResponses.remove(callId).handleCreateConnectionFailure( new DisconnectCause(DisconnectCause.ERROR, e.toString())); } } @Override public void onFailure() { Log.e(this, new Exception(), "Failure to call %s", getComponentName()); response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR)); } }; mBinder.bind(callback, call);//回调 }
ConnetctionService->createConnection():
private void createConnection( final PhoneAccountHandle callManagerAccount, final String callId, final ConnectionRequest request, boolean isIncoming, boolean isUnknown) { Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request) : isIncoming ? onCreateIncomingConnection(callManagerAccount, request) : onCreateOutgoingConnection(callManagerAccount, request); ... }
onCreateOutgoingConnection是在ConnetctionService的子类TelephonyConnectionService中实现的
TelephonyConnectionService->onCreateOutgoingConnection():
public Connection onCreateOutgoingConnection( PhoneAccountHandle connectionManagerPhoneAccount, final ConnectionRequest request) { ... final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber); Connection resultConnection = getTelephonyConnection(request, numberToDial, isEmergencyNumber, handle, phone); // If there was a failure, the resulting connection will not be a TelephonyConnection, // so don't place the call! if(resultConnection instanceof TelephonyConnection) { placeOutgoingConnection((TelephonyConnection) resultConnection, phone, request); } return resultConnection; }
TelephonyConnectionService->placeOutgoingConnection():
private void placeOutgoingConnection( TelephonyConnection connection, Phone phone, int videoState, Bundle extras, ConnectionRequest request) { ... String number = connection.getAddress().getSchemeSpecificPart();com.android.internal.telephony.Connection originalConnection = null; try { if (phone != null) { if (isAddParticipant) { phone.addParticipant(number); return; } else { originalConnection = phone.dial(number, null, request.getVideoState(), bundle); } } } catch (CallStateException e) { Log.e(this, e, "placeOutgoingConnection, phone.dial exception: " + e); int cause = android.telephony.DisconnectCause.OUTGOING_FAILURE; if (e.getError() == CallStateException.ERROR_DISCONNECTED) { cause = android.telephony.DisconnectCause.OUT_OF_SERVICE; } else if (e.getError() == CallStateException.ERROR_POWER_OFF) { cause = android.telephony.DisconnectCause.POWER_OFF; } connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause( cause, e.getMessage())); return; } }
GsmCdmaPhone->dial():
public Connection dial(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras) throws CallStateException { ... if (isPhoneTypeGsm()) { return dialInternal(dialString, null, VideoProfile.STATE_AUDIO_ONLY, intentExtras); } else { return dialInternal(dialString, null, videoState, intentExtras); } }
GsmCdmaPhone->dialInternal():
protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras) throws CallStateException { // Need to make sure dialString gets parsed properly String newDialString = PhoneNumberUtils.stripSeparators(dialString); if (isPhoneTypeGsm()) { // handle in-call MMI first if applicable if (handleInCallMmiCommands(newDialString)) { return null; } // Only look at the Network portion for mmi String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString); GsmMmiCode mmi = GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get()); if (DBG) logd("dialing w/ mmi '" + mmi + "'..."); if (mmi == null) { return mCT.dial(newDialString, uusInfo, intentExtras); } else if (mmi.isTemporaryModeCLIR()) { return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras); } else { mPendingMMIs.add(mmi); mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); try { mmi.processCode(); } catch (CallStateException e) { //do nothing } // FIXME should this return null or something else? return null; } } else { return mCT.dial(newDialString); } }
GsmCdmaCallTracker->dial():
public synchronized Connection dial(String dialString, int clirMode, UUSInfo uusInfo, Bundle intentExtras) throws CallStateException { ... if ( mPendingMO.getAddress() == null || mPendingMO.getAddress().length() == 0 || mPendingMO.getAddress().indexOf(PhoneNumberUtils.WILD) >= 0) { // Phone number is invalid mPendingMO.mCause = DisconnectCause.INVALID_NUMBER; // handlePollCalls() will notice this call not present // and will mark it as dropped. pollCallsWhenSafe(); } else { // Always unmute when initiating a new call setMute(false); mCi.dial(mPendingMO.getAddress(), clirMode, uusInfo, obtainCompleteMessage()); } if (mNumberConverted) { mPendingMO.setConverted(origNumber); mNumberConverted = false; } updatePhoneState(); mPhone.notifyPreciseCallStateChanged(); return mPendingMO; }
- Android 7.0 去电流程
- android 去电流程
- android -- phone (二) 去电流程
- android -- phone (二) 去电流程
- android -- phone (二) 去电流程
- Android 5.1 Phone MO(去电)流程分析(Framework层)
- Android 6.0 Phone MO(去电)流程分析(应用层)
- Android6.0去电流程
- 去电流程分析---之一
- android拦截去电
- Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析
- 转(Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析)
- Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析
- Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析
- Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析
- Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析
- 去电流程分析---之二
- (学习笔记)android 5.0 系统去电流程状态判断(上)
- Kotlin Reference (十一) Visibility Modifiers
- ethercat状态机
- java 备份(转存)数据库到云服务器或本地磁盘
- Swift Router 页面跳转路由,组件解耦
- 小程序怎么打断点
- Android 7.0 去电流程
- 代码干货 | H5和NA(WebView)的交互
- 敌兵布阵
- 部门递归处理
- Which should we choice between javax.faces.bean.XScoped and javax.enterprise.context.XScoped
- 数据结构实验之链表七:单链表中重复元素的删除
- 79. Word Search
- Servlet 监听器----ServletRequest
- 五大常用算法之三:贪心算法