本流程图基于MTK平台 Android 7.0,拨打的普通电话,本流程只作为沟通学习使用

整体流程图

流程中部分重点知识

packages-apps目录

  • dialer应用的DialpadFragment.onClick中,通过用户输入号码并点击拨号按钮(R.id.dialpad_floating_action_button)发起MO
  • 在handleDialButtonPressed方法里面会判断输入框中是否含有号码,然后通过IntentUtil构造一个intent,并通过startActivityWithErrorToast启动intent,这里会判断 mProhibitedPhoneNumberRegexp = getResources().getString(R.string.config_prohibited_phone_number_regexp);`是否含有默认拒绝拨打的号码,如果含有弹出含有“Can\’t call this number”字符串的DialogFragment提示用户。
  • 在startActivityWithErrorToast中,会获取当前触摸屏幕的位置信息,并存入intent中,后续启动incallUI的时候可能会使用Point touchPoint = TouchPointManager.getInstance().getPoint(); 
    if (touchPoint.x != 0 || touchPoint.y != 0) { 
    Bundle extras; 
    // Make sure to not accidentally clobber any existing extras 
    if (intent.hasExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS)) { 
    extras = intent.getParcelableExtra( 
    TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS); 
    } else { 
    extras = new Bundle(); 

    extras.putParcelable(TouchPointManager.TOUCH_POINT, touchPoint); 
    intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras); 
    }
  • 在TelecomUtil的这个方法中判断是否有权限拨打号码,包括判断是否是默认的dialer,和是否有”android.permission.CALL_PHONE”;这个权限public static boolean hasCallPhonePermission(Context context) { 
    return isDefaultDialer(context) 
    || hasPermission(context, Manifest.permission.CALL_PHONE); 
    }

packages-services-Telecomm目录

TelecomServiceImpl.placeCall

  • 这里会做一些检查,比如:权限检查和包检查,即使call 的权限是关闭的也会走这里,因为一些特殊的通话,比如:紧急通话,在后面的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;
  • 1
  • 2
  • 3
  • 4
  • 5

UserCallIntentProcessor

processIntent

    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()) {//通过com.android.internal.R.bool.config_voice_capable判断是否支持通话,比如:流量卡就不支持通话,并不会启动incallUIreturn;}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);}}public static final String ACTION_DIAL = "android.intent.action.DIAL";//普通电话进入dialer界面的拨号盘public static final String ACTION_CALL = "android.intent.action.CALL";//只能拨打普通电话不能拨打紧急号码,M即以上必须有android.Manifest.permission#CALL_PHONE权限public static final String ACTION_CALL_EMERGENCY = "android.intent.action.CALL_EMERGENCY"; //只能拨打紧急号码的actionpublic static final String ACTION_CALL_PRIVILEGED = "android.intent.action.CALL_PRIVILEGED";//可以拨打任意类型电话的action
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

processOutgoingCallIntent

  • 判断是正常的通话类型是否是SIP phone
        if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(uriString) ?PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, uriString, null);//构造intent的data}public static boolean isUriNumber(String number) {// Note we allow either "@" or "%40" to indicate a URI, in case// the passed-in string is URI-escaped.  (Neither "@" nor "%40"// will ever be found in a legal PSTN number.)return number != null && (number.contains("@") || number.contains("%40"));}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 判断是否有DISALLOW_OUTGOING_CALLS的限制,如果拨打的是emergency call则忽略这个限制,如果拨打的正常号码且具有这个限制,或者权限没有通过,不允许打正常的电话,则弹出错误的对话框 like:“Only emergency calls are allowed.”or “This application cannot make outgoing calls without the Phone permission.”
  • 如果是video_call并且打的是emergency_call则需要将video的状态改成voice来打emergency_call
 intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER,isDefaultOrSystemDialer(callingPackageName));//判断是否是默认或者系统的dialer应用,如果是才可以打emergency_call
  • 1
  • 2

PrimaryCallReceiver

    public void onReceive(Context context, Intent intent) {Log.startSession("PCR.oR");synchronized (getTelecomSystem().getLock()) {if (!ExtensionManager.getCallMgrExt().shouldPreventVideoCallIfLowBattery(context, intent)) {//如果是video_call的话,判断当前的电量是否处于低电模式,现在默认是返回false,后续会根据不同项目要求做定制getTelecomSystem().getCallIntentProcessor().processIntent(intent);}}Log.endSession();}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

CallIntentProcessor

processOutgoingCallIntent

  • 这个方法里面主要还是重新拿出intent里面的数据,并判断当前是否是主要的dialer,是否sip_phone,是否有phone账户,是否是video状态,用哪一张卡打,是否是IMS通话请求,是否是会议通话请求,根据这些判断再重新构造intent的Extras,然后通过前面得到的状态创建一个call,如果是conference的话直接创建链接,如果不是则继续往下执行
        if (intent.hasExtra(TelecomUtils.EXTRA_SLOT)) {int slotId = intent.getIntExtra(TelecomUtils.EXTRA_SLOT, -1);phoneAccountHandle = TelecomUtils.getPhoneAccountHandleWithSlotId(context, slotId, phoneAccountHandle);//如果有多张卡的话会拿到重那张卡拨打号码}
  • 1
  • 2
  • 3
  • 4
  • 5
        // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returnsCall call = callsManager.startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser);//通过这里来启动incallUI
  • 1
  • 2
  • 3

NewOutgoingCallIntentBroadcaster

processIntent

  • 先判断是否是VoicemailNumber,然后再得到格式化号码包括大小写转换成数字,分隔符的分离,判断是否是潜在的紧急号码,再将action为ACTION_CALL_PRIVILEGED类型的通话变成ACTION_CALL_EMERGENCY或者ACTION_CALL, 
    * - CALL (intent launched by all third party dialers) 
    * - CALL_PRIVILEGED (intent launched by system apps e.g. system Dialer, voice Dialer) 
    * - CALL_EMERGENCY (intent launched by lock screen emergency dialer) 如果是拨打紧急号码的话会直接调用placeOutgoingCall,否则会执行后面的流程发送广播。
        boolean isUriNumber = mPhoneNumberUtilsAdapter.isUriNumber(number);//判断通话类型,是否是sip_phoneif (!isUriNumber) {number = mPhoneNumberUtilsAdapter.convertKeypadLettersToDigits(number);//将号码字符串的字母转换成数字number = mPhoneNumberUtilsAdapter.stripSeparators(number);//将号码中的分割符分离}final boolean isPotentialEmergencyNumber = isPotentialEmergencyNumber(number);//判断是否是潜在的紧急号码Log.v(this, "isPotentialEmergencyNumber = %s", isPotentialEmergencyNumber);rewriteCallIntentAction(intent, isPotentialEmergencyNumber);//将ACTION_CALL_PRIVILEGED变成ACTION_CALL_EMERGENCY或者ACTION_CALL
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

CallsManager

placeOutgoingCall

  • 这里主要是对CDMA模式的call的广播,然后就是根据一些状态判断speaker的开关,是否是紧急号码的判断,然后就是开始创建链接

CreateConnectionProcessor

attemptNextPhoneAccount

        if (mCallResponse != null && attempt != null) {Log.i(this, "Trying attempt %s", attempt);PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;mService = mRepository.getService(phoneAccount.getComponentName(),phoneAccount.getUserHandle());//得到创建链接的serviceif (mService == null) {Log.i(this, "Found no connection service for attempt %s", attempt);attemptNextPhoneAccount();} else {mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);//设置phoneaccount的ConnectionManagermCall.setTargetPhoneAccount(attempt.targetPhoneAccount);mCall.setConnectionService(mService);//设置servicesetTimeoutIfNeeded(mService, attempt);mService.createConnection(mCall, this);//创建链接}} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

ConnectionServiceWrapper

createConnection

  • 通过binder创建链接,如果创建成功,先会判断callid是否为null以应对某些特定情况下链接创建成功前呼叫就已经断开了,这种情况下会打印错误log和DisconnectCause.ERROR的response返回,然后继续往下执行创建链接。
try {/// M: For VoLTE @{boolean isConferenceDial = call.isConferenceDial();if (isConferenceDial) {logOutgoing("createConference(%s) via %s.", call, getComponentName());mServiceInterface.createConference(//会议链接call.getConnectionManagerPhoneAccount(),callId,new ConnectionRequest(call.getTargetPhoneAccount(),call.getHandle(),extras,call.getVideoState(),callId),call.getConferenceParticipants(),call.isIncoming());} else {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()));}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

packages-services-Telephony目录

TelephonyConnectionService

onCreateOutgoingConnection

这里会做一系列的判断:

  • 拨打号码是否为null,拨打电话的账户是否存在
  • 判断是否是ECC重连(紧急号码相关),如果是将voiceemail的通话类型转换成tel,否则判断当前号码是否和*228正则表达式匹配,如果匹配就拒绝此次链接,因为这些特殊的数字用于OTASP,如果不禁用可能将LTE锁定到3G网络下。
  • 判断phone是否为null,如果为null并且config_checkSimStateBeforeOutgoingCall值为true就会去检查当前SIM卡的状态,并确定是否弹出PIN码的输入框
  • 判断飞行模式是否打开
  • 判断如果是拨打紧急号码且当前处于4G only数据链接状态,者取消这次链接
  • 判断当前网络是否注册成功
  • 判断当前是否是紧急号码并处于isInEcm模式,如果拨打的不是紧急号码,但是当前处于ECM模式,则KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL这个bool值觉得是否结束当前链接(ECM模式是指紧急呼叫回拨模式,一般GSM网络不支持,CDMA网络支持)
  • 对service状态的判断,处理不部分异常信息
  • 如果是videocall则判断TTY是否开启,如果开启则断开链接(TTY聋哑人专用模式)
  • 链接的初始化,number,video状态这些的配置
    // If configured, reject attempts to dial numbers matching this pattern.private static final Pattern CDMA_ACTIVATION_CODE_REGEX_PATTERN =Pattern.compile("\\*228[0-9]{0,2}");/// M: For ECC change feature @{if (isEmergencyNumber) {if (mSwitchPhoneHelper == null) {mSwitchPhoneHelper = new SwitchPhoneHelper(this, number);}if (mSwitchPhoneHelper.needToPrepareForDial()) {mSwitchPhoneHelper.prepareForDial(new SwitchPhoneHelper.Callback() {@Overridepublic void onComplete(boolean success) {if (connection.getState() == Connection.STATE_DISCONNECTED) {Log.d(this, "prepareForDial, connection disconnect");} else if (success) {Log.d(this, "startTurnOnRadio");startTurnOnRadio(connection, request, number);} else {/// M: CC: ECC Retry @{// Assume only one ECC exists// Not trigger retry since Modem fails to// power on should be a bugif (TelephonyConnectionServiceUtil.getInstance().isEccRetryOn()) {Log.d(this, "ECC Retry : clear ECC param");TelephonyConnectionServiceUtil.getInstance().clearEccRetryParams();}/// @}Log.d(this, "prepareForDial, failed to turn on radio");connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(android.telephony.DisconnectCause.POWER_OFF,"Failed to turn on radio."));connection.destroy();}}});/// @}} else {/// M: CC: ECC Retry @{if (!TelephonyConnectionServiceUtil.getInstance().isEccRetryOn()) {Log.d(this, "ECC Retry : set param with Intial ECC.");TelephonyConnectionServiceUtil.getInstance().setEccRetryParams(request,phone.getPhoneId());}/// @}if (useEmergencyCallHelper) {if (mEmergencyCallHelper == null) {mEmergencyCallHelper = new EmergencyCallHelper(this);}final Phone eccPhone = phone;mEmergencyCallHelper.startTurnOnRadioSequence(eccPhone,new EmergencyCallHelper.Callback() {@Overridepublic void onComplete(boolean isRadioReady) {if (connection.getState() == Connection.STATE_DISCONNECTED) {Log.d(this, "onCreateOutgoingConnection,"+ " connection disconnected");// If the connection has already been disconnected,// do nothing.} else if (isRadioReady) {///M: 4G data only @{if (TelephonyConnectionServiceUtil.getInstance().isDataOnlyMode(eccPhone)) {Log.d(this, "startTurnOnRadioSequence, 4G data only");/// M: CC: ECC Retry @{// Assume only one ECC existsif (TelephonyConnectionServiceUtil.getInstance().isEccRetryOn()) {Log.d(this, "ECC Retry : clear ECC param");TelephonyConnectionServiceUtil.getInstance().clearEccRetryParams();}/// @}connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(android.telephony.DisconnectCause.OUTGOING_CANCELED, null));connection.destroy();return;}/// @}connection.setInitialized();placeOutgoingConnection(connection, eccPhone, request);} else {/// M: CC: ECC Retry @{// Assume only one ECC exists// Not trigger retry since Modem fails to// power on should be a bugif (TelephonyConnectionServiceUtil.getInstance().isEccRetryOn()) {Log.d(this, "ECC Retry : clear ECC param");TelephonyConnectionServiceUtil.getInstance().clearEccRetryParams();}/// @}Log.d(this, "onCreateOutgoingConnection,"+ " failed to turn on radio");connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(android.telephony.DisconnectCause.POWER_OFF,"Failed to turn on radio."));connection.destroy();}}});} else {placeOutgoingConnection(connection, phone, request);}}} else {placeOutgoingConnection(connection, phone, request);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117

frameworks-opt-telephony目录

dial

  • 这里会判断是否是IMScall,GSMcall,WiFicall,紧急通话,然后通过不同的phone继续下发dial指令
    public Connection dial(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)throws CallStateException {if (!isPhoneTypeGsm() && uusInfo != null) {throw new CallStateException("Sending UUS information NOT supported in CDMA!");}boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(dialString);Phone imsPhone = mImsPhone;CarrierConfigManager configManager =(CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);boolean alwaysTryImsForEmergencyCarrierConfig = configManager.getConfigForSubId(getSubId()).getBoolean(CarrierConfigManager.KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL);boolean imsUseEnabled = isImsUseEnabled()&& imsPhone != null&& (imsPhone.isVolteEnabled() || imsPhone.isWifiCallingEnabled() ||(imsPhone.isVideoEnabled() && VideoProfile.isVideo(videoState)))&& (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE);boolean useImsForEmergency = imsPhone != null&& isEmergency&& alwaysTryImsForEmergencyCarrierConfig&& ImsManager.isNonTtyOrTtyOnVolteEnabled(mContext)&& (imsPhone.getServiceState().getState() != ServiceState.STATE_POWER_OFF);/// M: @{if (!isPhoneTypeGsm()) {useImsForEmergency = false;     //TODO: remove this workaround for ECC fail}/// @}String dialPart = PhoneNumberUtils.extractNetworkPortionAlt(PhoneNumberUtils.stripSeparators(dialString));boolean isUt = (dialPart.startsWith("*") || dialPart.startsWith("#"))&& dialPart.endsWith("#");boolean useImsForUt = imsPhone != null && imsPhone.isUtEnabled();if (DBG) {logd("imsUseEnabled=" + imsUseEnabled+ ", useImsForEmergency=" + useImsForEmergency+ ", useImsForUt=" + useImsForUt+ ", isUt=" + isUt+ ", imsPhone=" + imsPhone+ ", imsPhone.isVolteEnabled()="+ ((imsPhone != null) ? imsPhone.isVolteEnabled() : "N/A")+ ", imsPhone.isVowifiEnabled()="+ ((imsPhone != null) ? imsPhone.isWifiCallingEnabled() : "N/A")+ ", imsPhone.isVideoEnabled()="+ ((imsPhone != null) ? imsPhone.isVideoEnabled() : "N/A")+ ", imsPhone.getServiceState().getState()="+ ((imsPhone != null) ? imsPhone.getServiceState().getState() : "N/A"));}Phone.checkWfcWifiOnlyModeBeforeDial(mImsPhone, mContext);/// M: should be removed later, just for debug @{Rlog.w(LOG_TAG, "IMS: imsphone = " + imsPhone + "isEmergencyNumber = "+ PhoneNumberUtils.isEmergencyNumber(dialString));if (imsPhone != null) {Rlog.w(LOG_TAG, "service state = " + imsPhone.getServiceState().getState());}/// @}if ((imsUseEnabled && (!isUt || useImsForUt)) || useImsForEmergency) {/// M: CC: Check GSM call state to avoid InCallMMI dispatching to IMS @{// [ALPS02516173],[ALPS02615800]if (isInCSCall()) {if (DBG) Rlog.d(LOG_TAG, "has CS Call. Don't try IMS PS Call!");} else {/// @}try {/// M: ALPS02137073 3G VT Refactoryif (videoState == VideoProfile.STATE_AUDIO_ONLY) {if (DBG) Rlog.d(LOG_TAG, "Trying IMS PS call");return imsPhone.dial(dialString, uusInfo, videoState, intentExtras);} else {if (SystemProperties.get("persist.mtk_vilte_support").equals("1")) {if (DBG) {Rlog.d(LOG_TAG, "Trying IMS PS video call");}return imsPhone.dial(dialString, uusInfo, videoState, intentExtras);} else {/// M: CC: For 3G VT only @{if (DBG) {Rlog.d(LOG_TAG, "Trying (non-IMS) CS video call");}return dialInternal(dialString, uusInfo, videoState, intentExtras);/// @}}}} catch (CallStateException e) {if (DBG) logd("IMS PS call exception " + e +"imsUseEnabled =" + imsUseEnabled + ", imsPhone =" + imsPhone);if (!Phone.CS_FALLBACK.equals(e.getMessage())) {CallStateException ce = new CallStateException(e.getMessage());ce.setStackTrace(e.getStackTrace());throw ce;}}/// M: CC: Check GSM call state to avoid InCallMMI dispatching to IMS @{}/// @}}/// M: CC: FTA requires call should be dialed out even out of service @{if (SystemProperties.getInt("gsm.gcf.testmode", 0) != 2) {if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE&& mSST.mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE&& !isEmergency) {throw new CallStateException("cannot dial in current state");}}/// @}if (DBG) logd("Trying (non-IMS) CS call");if (isPhoneTypeGsm()) {/// M: CC: For 3G VT only @{//return dialInternal(dialString, null, VideoProfile.STATE_AUDIO_ONLY, intentExtras);return dialInternal(dialString, null, videoState, intentExtras);/// @}} else {return dialInternal(dialString, null, videoState, intentExtras);}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127

dialInternal

这里主要是判断是否是MMI code如果是的话就只执行MMIcode的指令,否则继续往下下发拨号动作。

    @Overrideprotected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,Bundle intentExtras)throws CallStateException {// Need to make sure dialString gets parsed properly/// M: Ignore stripping for VoLTE SIP uri. @{// String newDialString = PhoneNumberUtils.stripSeparators(dialString);String newDialString = dialString;if (!PhoneNumberUtils.isUriNumber(dialString)) {// Need to make sure dialString gets parsed properlynewDialString = PhoneNumberUtils.stripSeparators(dialString);}/// @}if (isPhoneTypeGsm()) {// handle in-call MMI first if applicableif (handleInCallMmiCommands(newDialString)) {return null;}// Only look at the Network portion for mmiString networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);GsmMmiCode mmi =GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get());if (DBG) logd("dialing w/ mmi '" + mmi + "'...");if (mmi == null) {/// M: CC: For 3G VT only @{//return mCT.dial(newDialString, uusInfo, intentExtras);if (videoState == VideoProfile.STATE_AUDIO_ONLY) {return mCT.dial(newDialString, uusInfo, intentExtras);} else {if (!is3GVTEnabled()) {throw new CallStateException("cannot vtDial for non-3GVT-capable device");}return mCT.vtDial(newDialString, uusInfo, intentExtras);}/// @}} else if (mmi.isTemporaryModeCLIR()) {/// M: CC: For 3G VT only @{//return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras);if (videoState == VideoProfile.STATE_AUDIO_ONLY) {return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras);} else {if (!is3GVTEnabled()) {throw new CallStateException("cannot vtDial for non-3GVT-capable device");}return mCT.vtDial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras);}/// @}} else {mPendingMMIs.add(mmi);/// M: @{Rlog.d(LOG_TAG, "dialInternal: " + dialString + ", mmi=" + mmi);dumpPendingMmi();/// @}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);}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

GsmCdmaCallTracker

dial

  • 清楚所有已断开的链接,并通知call的状态改变
  • 如果当前有一个call处于前台,我们需要将它hold住,并通过一个500毫秒的延时来执行hold这个操作,直到我们收到EVENT_SWITCH_RESULT执行结束的标记,如果不延时在多方会议通话的时候可能出现问题
  • 设置为mute
    public synchronized Connection dial(String dialString, int clirMode, UUSInfo uusInfo,Bundle intentExtras)throws CallStateException {// note that this triggers call state changed notifclearDisconnected();if (!canDial()) {throw new CallStateException("cannot dial in current state");}String origNumber = dialString;dialString = convertNumberIfNecessary(mPhone, dialString);// The new call must be assigned to the foreground call.// That call must be idle, so place anything that's// there on holdif (mForegroundCall.getState() == GsmCdmaCall.State.ACTIVE) {// this will probably be done by the radio anyway// but the dial might fail before this happens// and we need to make sure the foreground call is clear// for the newly dialed connection/// M: CC: Proprietary CRSS handling @{mWaitingForHoldRequest.set();/// @}switchWaitingOrHoldingAndActive();// This is a hack to delay DIAL so that it is sent out to RIL only after// EVENT_SWITCH_RESULT is received. We've seen failures when adding a new call to// multi-way conference calls due to DIAL being sent out before SWITCH is processedtry {Thread.sleep(500);} catch (InterruptedException e) {// do nothing}// Fake local state so that// a) foregroundCall is empty for the newly dialed connection// b) hasNonHangupStateChanged remains false in the// next poll, so that we don't clear a failed dialing callfakeHoldForegroundBeforeDial();}if (mForegroundCall.getState() != GsmCdmaCall.State.IDLE) {//we should have failed in !canDial() above before we get herethrow new CallStateException("cannot dial in current state");}mPendingMO = new GsmCdmaConnection(mPhone, checkForTestEmergencyNumber(dialString),this, mForegroundCall);mHangupPendingMO = false;if ( mPendingMO.getAddress() == null || mPendingMO.getAddress().length() == 0|| mPendingMO.getAddress().indexOf(PhoneNumberUtils.WILD) >= 0) {// Phone number is invalidmPendingMO.mCause = DisconnectCause.INVALID_NUMBER;/// M: CC: Proprietary CRSS handling @{mWaitingForHoldRequest.reset();/// @}// handlePollCalls() will notice this call not present// and will mark it as dropped.pollCallsWhenSafe();} else {// Always unmute when initiating a new callsetMute(false);/// M: CC: Proprietary CRSS handling @{//mCi.dial(mPendingMO.getAddress(), clirMode, uusInfo, obtainCompleteMessage());if (!mWaitingForHoldRequest.isWaiting()) {/// M: CC: Proprietary ECC handling@{/// M: CC: ECC Retry @{if (PhoneNumberUtils.isEmergencyNumber(mPhone.getSubId(), dialString)/// @}&& !PhoneNumberUtils.isSpecialEmergencyNumber(dialString)) {int serviceCategory = PhoneNumberUtils.getServiceCategoryFromEcc(dialString);mCi.setEccServiceCategory(serviceCategory);mCi.emergencyDial(mPendingMO.getAddress(), clirMode, uusInfo,obtainCompleteMessage(EVENT_DIAL_CALL_RESULT));/// @}} else {mCi.dial(mPendingMO.getAddress(), clirMode, uusInfo,obtainCompleteMessage(EVENT_DIAL_CALL_RESULT));}} else {mWaitingForHoldRequest.set(mPendingMO.getAddress(), clirMode, uusInfo);}/// @}}if (mNumberConverted) {mPendingMO.setConverted(origNumber);mNumberConverted = false;}updatePhoneState();mPhone.notifyPreciseCallStateChanged();return mPendingMO;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101

Log信息

    Line 10357: 12-19 09:17:32.193 I/Telecom (  988): CallIntentProcessor: onReceive - isUnknownCall: false: PCR.oR@AOY Line 10473: 12-19 09:17:32.288 V/Telecom (  988): CallsManager: startOutgoingCall found accounts = [PhoneAccountHandle{TelephonyConnectionService, 89860115881029413909, UserHandle{0}}]: PCR.oR@AOY Line 10553: 12-19 09:17:32.351 V/Telecom (  988): NewOutgoingCallIntentBroadcaster: Processing call intent in OutgoingCallIntentBroadcaster.: PCR.oR@AOY Line 10872: 12-19 09:17:32.406 V/Telecom (  988): NewOutgoingCallIntentBroadcaster: isPotentialEmergencyNumber = false: PCR.oR@AOY Line 10877: 12-19 09:17:32.407 I/Telecom (  988): NewOutgoingCallIntentBroadcaster: Sending NewOutgoingCallBroadcast for [TC@2, CONNECTING, null, tel:10010, A, childs(0), has_parent(false), [Capabilities:], [Properties:]] to UserHandle{0}: PCR.oR@AOY Line 10878: 12-19 09:17:32.408 V/Telecom (  988): NewOutgoingCallIntentBroadcaster: Broadcasting intent: Intent { act=android.intent.action.NEW_OUTGOING_CALL flg=0x10000000 (has extras) }.: PCR.oR@AOY Line 11902: 12-19 09:17:33.374 V/Telecom (  988): NewOutgoingCallBroadcastIntentReceiver: onReceive: Intent { act=android.intent.action.NEW_OUTGOING_CALL flg=0x10000010 (has extras) }: NOCBIR.oR@AOw Line 11903: 12-19 09:17:33.374 I/Telecom (  988): NewOutgoingCallBroadcastIntentReceiver: Received new-outgoing-call-broadcast for [TC@2, CONNECTING, null, tel:10010, A, childs(0), has_parent(false), [Capabilities:], [Properties:]] with data 10010: NOCBIR.oR@AOw Line 11950: 12-19 09:17:33.426 V/Telecom (  988): NewOutgoingCallBroadcastIntentReceiver: Call number unmodified after new outgoing call intent broadcast.: NOCBIR.oR@AOw Line 11951: 12-19 09:17:33.426 D/Telecom (  988): CallsManager: broadcastCallPlacedIntent Entry: NOCBIR.oR@AOw Line 11954: 12-19 09:17:33.427 D/Telecom (  988): CallsManager: Creating a new outgoing call with handle: tel:10010: NOCBIR.oR@AOw Line 12034: 12-19 09:17:33.495 D/Telecom (  988): CallsManager: [TC@2, CONNECTING, null, tel:10010, A, childs(0), has_parent(false), [Capabilities:], [Properties:]] Starting with speakerphone because car is docked.: NOCBIR.oR@AOw Line 12038: 12-19 09:17:33.498 V/Telecom (  988): CreateConnectionProcessor: process: NOCBIR.oR@AOw Line 12044: 12-19 09:17:33.513 I/Telecom (  988): PhoneAccountRegistrar: SimCallManager queried, returning: null: NOCBIR.oR@AOwLine 12045: 12-19 09:17:33.513 V/Telecom (  988): CreateConnectionProcessor: setConnectionManager, not changing: NOCBIR.oR@AOwLine 12046: 12-19 09:17:33.514 V/Telecom (  988): CreateConnectionProcessor: attemptNextPhoneAccount: NOCBIR.oR@AOw Line 12047: 12-19 09:17:33.515 I/Telecom (  988): CreateConnectionProcessor: Trying attempt CallAttemptRecord(PhoneAccountHandle{TelephonyConnectionService, 89860115881029413909, UserHandle{0}},PhoneAccountHandle{TelephonyConnectionService, 89860115881029413909, UserHandle{0}}): NOCBIR.oR@AOw Line 12050: 12-19 09:17:33.517 D/Telecom (  988): ConnectionServiceWrapper: createConnection([TC@2, CONNECTING, com.android.phone/com.android.services.telephony.TelephonyConnectionService, tel:10010, A, childs(0), has_parent(false), [Capabilities:], [Properties:]]) via ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}.: NOCBIR.oR@AOw Line 12051: 12-19 09:17:33.517 D/Telecom (  988): ConnectionServiceWrapper: bind(): NOCBIR.oR@AOw Line 12073: 12-19 09:17:33.553 D/Telecom (  988): ConnectionServiceWrapper: Telecom -> ConnectionService: addConnectionServiceAdapter com.android.server.telecom.ConnectionServiceWrapper$Adapter@edb67c1: SBC.oSC@AO0 Line 12077: 12-19 09:17:33.558 D/TelecomFramework( 1489): : Enqueueing pre-init request TC@2 Line 12090: 12-19 09:17:33.585 D/TelecomFramework( 1489): TelephonyConnectionService: createConnection, callManagerAccount: PhoneAccountHandle{TelephonyConnectionService, 89860115881029413909, UserHandle{0}}, callId: TC@2, request: ConnectionRequest tel:10010 Bundle[mParcelledData.dataSize=392], isIncoming: false, isUnknown: false Line 12092: 12-19 09:17:33.587 I/Telephony( 1489): TelephonyConnectionService: onCreateOutgoingConnection, request: ConnectionRequest tel:10010 Bundle[mParcelledData.dataSize=392] Line 12093: 12-19 09:17:33.589 D/Telephony( 1489): TelephonyConnectionService: onCreateOutgoingConnection, ConnectionRequest.PhoneAccountHandle{TelephonyConnectionService, 89860115881029413909, UserHandle{0}} 12-19 09:17:33.645 D/Telephony( 1489): TelephonyConnectionService: Service state:0, isAirplaneModeOn:falseLine 12196: 12-19 09:17:33.764 D/GsmCdmaPhone( 1489): [GsmCdmaPhone] imsUseEnabled=false, useImsForEmergency=false, useImsForUt=false, isUt=false, imsPhone=Handler (com.android.internal.telephony.imsphone.ImsPhone) {cea3f01}, imsPhone.isVolteEnabled()=false, imsPhone.isVowifiEnabled()=false, imsPhone.isVideoEnabled()=false, imsPhone.getServiceState().getState()=1 Line 12200: 12-19 09:17:33.765 W/GsmCdmaPhone( 1489): IMS: imsphone = Handler (com.android.internal.telephony.imsphone.ImsPhone) {cea3f01}isEmergencyNumber = false Line 12201: 12-19 09:17:33.765 W/GsmCdmaPhone( 1489): service state = 1 Line 12202: 12-19 09:17:33.765 D/GsmCdmaPhone( 1489): [GsmCdmaPhone] Trying (non-IMS) CS call Line 12240: 12-19 09:17:33.796 D/GsmCdmaPhone( 1489): [GsmCdmaPhone] dialing w/ mmi 'null'... Line 12258: 12-19 09:17:33.808 D/RILJ    ( 1489): [3939]> SET_MUTE false [SUB0] Line 12270: 12-19 09:17:33.815 I/AT      ( 1015): AT> AT+CMUT=0 (RIL_CMD_READER_2, tid:515433460816)  Line 12273: 12-19 09:17:33.817 D/RILJ    ( 1489): [3940]> DIAL [SUB0] Line 12426: 12-19 09:17:33.874 D/TelecomFramework( 1489): TelephonyConnectionService: createConnection, connection: [TelephonyConnection objId:156910251 telecomCallID:TC@2 type:gsm state:DIALING capabilities:[Capabilities: CAPABILITY_SUPPORT_HOLD CAPABILITY_MUTE CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO CAPABILITY_SEPARATE_FROM_CONFERENCE CAPABILITY_DISCONNECT_FROM_CONFERENCE] properties:[Properties:] address:tel:10010 originalConnection: callId: TC@2 incoming: false state: DIALING post dial state: NOT_STARTED partOfConf:N] Line 12440: 12-19 09:17:33.881 V/TelecomFramework( 1489): TelephonyConnectionService: createConnection, number: 10010, state: DIALING, capabilities: [Capabilities: CAPABILITY_SUPPORT_HOLD CAPABILITY_MUTE CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO CAPABILITY_SEPARATE_FROM_CONFERENCE CAPABILITY_DISCONNECT_FROM_CONFERENCE], properties: [Properties:]12-19 09:17:33.881 D/TelecomFramework( 1489): TelephonyConnectionService: createConnection, calling handleCreateConnectionSuccessful TC@2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

总结

通过上面流程的分析,和部分逻辑代码的跟踪,我们可以大致了解整个拨号流程所涉及到的目录和类,大致明白了整个过程中的一些状态判断和逻辑处理,后续还会对incallUI界面的构成和流程中某些细分领域的详细研究。

android N 拨打电话流程(MO)相关推荐

  1. Android 10 拨打电话流程

    接续上一章节,理解Android 10 拨打电话流程 packages/apps/Dialer/java/com/android/dialer/dialpadview/DialpadFragment. ...

  2. Android5.1 Telephony流程分析——拨打电话流程(MO CALL)

    本文代码以MTK平台Android 5.1为分析对象,与Google原生AOSP有些许差异,请读者知悉. 此图主要是根据Android源代码拨打电话流程来绘制,记录了电话拨打的主要过程: 参考博客:h ...

  3. Java模拟拨打电话程序_java_编写android拨打电话apk应用实例代码,android 实现拨打电话的app,代 - phpStudy...

    编写android拨打电话apk应用实例代码 android 实现拨打电话的app,代码非常简单,功能也很实用,分享给大家. MainActivity.java package com.bblei.c ...

  4. Android Tel 拨打电话及来电流程分析

    打电话流程 接下来分析一下打电话的流程.输入电话号码的流程这里忽略.输入电话号码之后会点击拨打图标.之后就会走拨打电话的流程了.这部分是在packages/apps/Dialer/src/com/an ...

  5. 脚本控制向Android模拟拨打电话,发送短信,定位设置功能

    做行为触发的时候要向模拟器实现拨打电话,发送短信,定位设置的的功能,可以很方便通过telnet localhost  5554实现. 写个脚本很快的搞定了.网上资料很多,脚本的很少,也所积点德啦. 写 ...

  6. android调用拨号界面拨打电话功能,Android实现拨打电话功能

    添加权限: 实现: package com.example.call_person; import android.annotation.SuppressLint; import android.co ...

  7. Android实现拨打电话

    一.添加拨打电话的权限 <uses-permission android:name="android.permission.CALL_PHONE"/> 二.两种方法 1 ...

  8. android如何拨打电话

    方法一:直接拨打电话,需要添加权限 <uses-permission android:name="android.permission.CALL_PHONE" /> / ...

  9. Android手机拨打电话、手动发送短信与自动拨打电话、自动发送短信(代码很简单哦)

    Android实现手动拨打电话,即点击后跳转到手机默认电话号码输入页面,可以将相应号码传送过去: <span style="font-size:18px;"> Inte ...

最新文章

  1. SQL基础【十三、通配符】
  2. 开源项目SlidingMenu的使用(Android)
  3. X-Mas Musings –在Grails集成测试中不要使用随机服务器端口
  4. 图像变换dpi(tif->jpg),直方图均衡化,腐蚀膨胀,分水岭,模板匹配,直线检测
  5. windows server 2003 AD之FSMO角色
  6. 【推荐】不到100行实现的全面NLP教程(pytorch+tensorflow)
  7. 锐起无盘服务器优化,(锐起无盘系统制作系统优化教程.doc
  8. LaTeX数学公式 合集
  9. Mybatis关联关系
  10. linux怎么做冗余备份,linux下使用raid实现冗余备份
  11. 汽车电线束双绞线技术参数设定
  12. ip 华三secondary_H3C交换机配置端口IP sub实例
  13. 数字IC后端工程师应该如何快速入门提高工作技能?
  14. 换博客拉 http://vergilwang.iteye.com/
  15. JAVA简单计算器(简单实现两数加减乘除)
  16. Win10删除文件夹
  17. HyperLynx(三十二)高速串行总线仿真(四)
  18. E销宝:dsp广告应该怎么投放?
  19. 物联网充电桩(电动自行车)管理方案
  20. 加速度 陀逻计的设备方向的使用

热门文章

  1. 毕业设计 超声波红外自动调速风扇系统
  2. 静不下心学习,怎么办?
  3. 最优化学习 算法收敛性
  4. java中构造函数的作用
  5. 香港十大现货白银交易软件排名(最新版)
  6. 服务器系统盘 回写盘价格,服务器内存当回写盘
  7. vue + blockly 示例
  8. HBASE中column family的设计,rowkey的设计,以及row key的设计原则问题
  9. excel怎么把竖排变成横排_Python 合并 Excel 表格
  10. speedoffice如何将表格竖向变成横向