1. 應(yīng)用進(jìn)程
從點(diǎn)擊撥號(hào)按鈕流程說起
packages/apps/Dialer/src/com/android/dialer/dialpad/DialpadFragment.java
@Override
public void onClick(View view) {
int resId = view.getId();
if (resId == R.id.dialpad_floating_action_button) {
view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
// 執(zhí)行該方法
handleDialButtonPressed();
} else if (resId == R.id.deleteButton) {
keyPressed(KeyEvent.KEYCODE_DEL);
} ...
}
handleDialButtonPressed又會(huì)調(diào)用handleDialButtonPressed(Constants.DIAL_NUMBER_INTENT_NORMAL);
packages/apps/Dialer/src/com/android/dialer/dialpad/DialpadFragment.java
private void handleDialButtonPressed(int type) {
if (isDigitsEmpty()) { // No number entered.
handleDialButtonClickWithEmptyDigits();
} else {
final String number = mDigits.getText().toString();
// 1. 通過mProhibitedPhoneNumberRegexp正則表達(dá)式判斷號(hào)碼是否被禁止
if (number != null
&& !TextUtils.isEmpty(mProhibitedPhoneNumberRegexp)
&& number.matches(mProhibitedPhoneNumberRegexp)) {
Log.i(TAG, "The phone number is prohibited explicitly by a rule.");
...
} else {
final Intent intent;
/** M: [IP Dial] check the type of call @{ */
if (type != Constants.DIAL_NUMBER_INTENT_NORMAL) {
intent = IntentUtil.getCallIntent(IntentUtil.getCallUri(number),
LogState.INITIATION_DIALPAD, type);
} else {
// 2. 封裝撥號(hào)Intent
intent = new CallIntentBuilder(number).
setCallInitiationType(LogState.INITIATION_DIALPAD)
.build();
}
/** @} */
// 3. 啟動(dòng)對(duì)應(yīng)Intent
DialerUtils.startActivityWithErrorToast(getActivity(), intent);
hideAndClearDialpad(false);
}
}
}
跟蹤步驟2流程可知該Intent由以下幾個(gè)部分組成
- Action為:Intent.ACTION_CALL(android.intent.action.CALL)
- Flag為:FLAG_ACTIVITY_NEW_TASK
- 號(hào)碼uri為 tel:10010
步驟3中startActivityWithErrorToast方法會(huì)調(diào)用到如下方法
packages/apps/Dialer/src/com/android/dialer/util/DialerUtils.java
public static void startActivityWithErrorToast(Context context, Intent intent, int msgId) {
try {
if ((IntentUtil.CALL_ACTION.equals(intent.getAction())
&& context instanceof Activity)) {
...
// 1. 調(diào)用TelecomUtil的placeCall繼續(xù)處理
final boolean hasCallPermission = TelecomUtil.placeCall((Activity) context, intent);
if (!hasCallPermission) {
Toast.makeText(context, "Cannot place call without Phone permission",
Toast.LENGTH_SHORT);
}
}
...
} catch (ActivityNotFoundException e) {
Toast.makeText(context, msgId, Toast.LENGTH_SHORT).show();
}
}
packages/apps/Dialer/src/com/android/dialer/util/TelecomUtil.java
public static boolean placeCall(Activity activity, Intent intent) {
// 1.
if (hasCallPhonePermission(activity)) {
// 2.
TelecomManagerCompat.placeCall(activity, getTelecomManager(activity), intent);
return true;
}
return false;
}
hasCallPhonePermission方法返回true的條件
- 當(dāng)前Dialer為系統(tǒng)默認(rèn)Dialer
- 檢查
Manifest.permission.CALL_PHONE
權(quán)限是否已經(jīng)授權(quán)
packages/apps/ContactsCommon/src/com/android/contacts/common/compat/telecom/TelecomManagerCompat.java
public static void placeCall(@Nullable Activity activity,
@Nullable TelecomManager telecomManager, @Nullable Intent intent) {
if (activity == null || telecomManager == null || intent == null) {
return;
}
// 當(dāng)前平臺(tái)N > M,返回true
if (CompatUtils.isMarshmallowCompatible()) {
telecomManager.placeCall(intent.getData(), intent.getExtras());
return;
}
activity.startActivityForResult(intent, 0);
}
frameworks/base/telecomm/java/android/telecom/TelecomManager.java
public void placeCall(Uri address, Bundle extras) {
// 1. 通過AIDL得到TelecomService的服務(wù)端的代理
ITelecomService service = getTelecomService();
if (service != null) {
if (address == null) {
Log.w(TAG, "Cannot place call to empty address.");
}
try {
// 2. TelecomService進(jìn)一步處理call
service.placeCall(address, extras == null ? new Bundle() : extras,
mContext.getOpPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#placeCall", e);
}
}
}
- 首先通過getTelecomService方法內(nèi)部為
ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE))
得到TelecomService的服務(wù)端代理浮庐。通過AIDL使用規(guī)則搜索new ITelecomService.Stub()
碴开,即可看到服務(wù)端在TelecomServiceImpl中實(shí)現(xiàn)。 - 調(diào)用placeCall進(jìn)一步處理院仿,此處address就是
tel:10010
2. Telecom進(jìn)程處理
packages/services/Telecomm/src/com/android/server/telecom/TelecomServiceImpl.java
private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub() {
/**
* @see android.telecom.TelecomManager#placeCall
*/
@Override
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);
}
// 1. create得到的是UserCallIntentProcessor對(duì)象谬以,然后進(jìn)一步處理?yè)艽螂娫挼腎ntent
mUserCallIntentProcessorFactory.create(mContext, userHandle)
.processIntent(
intent, callingPackage, hasCallAppOp && hasCallPermission);
}
...
}
通過UserCallIntentProcessor的processIntent方法進(jìn)一步處理?yè)艽螂娫挼腎ntent
packages/services/Telecomm/src/com/android/server/telecom/components/UserCallIntentProcessor.java
/**
* Processes intents sent to the activity.
*
* @param intent The intent.
*/
public void processIntent(Intent intent, String callingPackageName,
boolean canCallNonEmergency) {
// 1. 判斷是否支持語(yǔ)音通話声登,通過讀取config_voice_capable值
if (!isVoiceCapable()) {
return;
}
String action = intent.getAction();
// 2. 判斷ACTION是否為打電話
if (Intent.ACTION_CALL.equals(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) {
...
// 3. 將是否為默認(rèn)Dialer或是系統(tǒng)的Dialer的boolean值放入Intent的Extra中
intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER,
isDefaultOrSystemDialer(callingPackageName));
intent.putExtra(CallIntentProcessor.KEY_INITIATING_USER, mUserHandle);
sendBroadcastToReceiver(intent);
}
private boolean sendBroadcastToReceiver(Intent intent) {
// 4. 進(jìn)一步完善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");
// 5. 發(fā)送廣播,只有系統(tǒng)用戶可以接收
mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
return true;
}
- 判斷config_voice_capable判斷語(yǔ)音通話是否支持哈街,該值在
frameworks/base/core/res/res/values/strings.xml
中配置 - 判斷Action是否為
ACTION_CALL
,Intent.ACTION_CALL_PRIVILEGED
,Intent.ACTION_CALL_EMERGENCY
之一,是才繼續(xù)處理 - MO 的Intent添加是否為默認(rèn)Dialer或者系統(tǒng)Dialer的信息
- 默認(rèn)Dialer通過獲取數(shù)據(jù)庫(kù)判斷
Settings.Secure.getStringForUser(context.getContentResolver(), Settings.Secure.DIALER_DEFAULT_APPLICATION, user);
- 系統(tǒng)Dialer通過
packages/services/Telecomm/res/values/config.xml
中如下屬性獲取
<string name="ui_default_package" translatable="false">com.android.dialer</string>
- MO 的Intent添加如下信息
- 是否來電 由于是去電留瞳,故為false
- 指定接收廣播的類為PrimaryCallReceiver
- 發(fā)送廣播,指定只有System用戶可以接收該廣播
packages/services/Telecomm/src/com/android/server/telecom/components/PrimaryCallReceiver.java
@Override
public void onReceive(Context context, Intent intent) {
Log.startSession("PCR.oR");
synchronized (getTelecomSystem().getLock()) {
if (!ExtensionManager.getCallMgrExt()
.shouldPreventVideoCallIfLowBattery(context, intent)) {
getTelecomSystem().getCallIntentProcessor().processIntent(intent);
}
}
Log.endSession();
}
getTelecomSystem().getCallIntentProcessor()返回的類型為CallIntentProcessor,通過processIntent方法將接收到的Intent進(jìn)一步處理
packages/services/Telecomm/src/com/android/server/telecom/CallIntentProcessor.java
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();
}
前面并沒有設(shè)置KEY_IS_UNKNOWN_CALL屬性,故為false骚秦,走processOutgoingCallIntent
packages/services/Telecomm/src/com/android/server/telecom/CallIntentProcessor.java
/**
* 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) {
...
// 1. 創(chuàng)建Call對(duì)象
Call call = callsManager
.startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser);
if (call != null) {
NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
context, callsManager, call, intent, new PhoneNumberUtilsAdapterImpl(),
isPrivilegedDialer);
// 2.
final int result = broadcaster.processIntent();
final boolean success = result == DisconnectCause.NOT_DISCONNECTED;
if (!success && call != null) {
disconnectCallAndShowErrorDialog(context, call, result);
}
}
}
- 先看下call對(duì)象是如何創(chuàng)建并拉起IncallUI界面
packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java
Call startOutgoingCall(Uri handle, PhoneAccountHandle phoneAccountHandle, Bundle extras,
UserHandle initiatingUser) {
boolean isReusedCall = true;
Call call = reuseOutgoingCall(handle);
// 1. 創(chuàng)建Call對(duì)象
if (call == null) {
call = new Call(getNextCallId(), mContext,
this,
mLock,
mConnectionServiceRepository,
mContactsAsyncHelper,
mCallerInfoAsyncQueryFactory,
handle,
null /* gatewayInfo */,
null /* connectionManagerPhoneAccount */,
null /* phoneAccountHandle */,
Call.CALL_DIRECTION_OUTGOING /* callDirection */,
false /* forceAttachToExistingConnection */,
false /* isConference */
);
call.setInitiatingUser(initiatingUser);
call.initAnalytics();
isReusedCall = false;
}
...
// 獲取當(dāng)前激活的卡列表
List<PhoneAccountHandle> accounts = constructPossiblePhoneAccounts(handle, initiatingUser);
Log.v(this, "startOutgoingCall found accounts = " + accounts);
if (phoneAccountHandle == null && accounts.size() > 0 && !call.isEmergencyCall()) {
if(accounts.size() > 1) {
// 雙激活卡下取通話主卡賬戶,沒有通話主卡則為空
PhoneAccountHandle defaultPhoneAccountHandle =
mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme(handle.getScheme(),
initiatingUser);
if (defaultPhoneAccountHandle != null &&
accounts.contains(defaultPhoneAccountHandle)) {
phoneAccountHandle = defaultPhoneAccountHandle;
}
} else {
// 單激活卡直接取該卡賬戶
phoneAccountHandle = accounts.get(0);
}
}
...
call.setTargetPhoneAccount(phoneAccountHandle);
boolean isPotentialInCallMMICode = isPotentialInCallMMICode(handle);
if (!isReusedCall && !makeRoomForOutgoingCall(call, call.isEmergencyCall())) {
// just cancel at this point.
Log.d(this, "No remaining room for outgoing call: %s", call);
showToastInfomation(mContext.getResources()
.getString(R.string.outgoing_call_failed));
if (mCalls.contains(call)) {
// This call can already exist if it is a reused call,
// See {@link #reuseOutgoingCall}.
call.disconnect();
}
return null;
}
boolean needsAccountSelection = phoneAccountHandle == null && accounts.size() > 1 &&
!call.isEmergencyCall();
Log.i(this, "MO - dump: needSelect = %s; phoneAccountHandle = %s; accounts.size() = %s.",
needsAccountSelection, phoneAccountHandle, accounts.size());
// 是否需要彈出雙卡選擇框(雙卡下沒有指定賬戶呼出非緊急號(hào)碼且當(dāng)前無通話主卡)
if (needsAccountSelection) {
// 設(shè)置當(dāng)前call為等待用戶選擇SIM卡狀態(tài)CallState.SELECT_PHONE_ACCOUNT
call.setState(CallState.SELECT_PHONE_ACCOUNT, "needs account selection");
extras = new Bundle(extras);
extras.putParcelableList(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS, accounts);
} else {
// 設(shè)置當(dāng)前call為連接狀態(tài)CallState.CONNECTING
call.setState(
CallState.CONNECTING,
phoneAccountHandle == null ? "no-handle" : phoneAccountHandle.toString());
}
setIntentExtrasAndStartTime(call, extras);
// 如果是MMI Code 不添加call到mCalls列表中
if ((isPotentialMMICode(handle) || isPotentialInCallMMICode)
&& TelecomUtils.isSupportMMICode(call.getTargetPhoneAccount())
&& !needsAccountSelection) {
call.addListener(this);
} else if (!mCalls.contains(call)) {
// We check if mCalls already contains the call because we could potentially be reusing
// a call which was previously added (See {@link #reuseOutgoingCall}).
// 添加當(dāng)前call到mCalls列表中
addCall(call);
}
return call;
}
看下addCall方法
private void addCall(Call call) {
...
call.addListener(this);
// 1. 將call添加到mCall列表中
mCalls.add(call);
...
// 2. 遍歷所有mListeners調(diào)用onCallAdded方法
for (CallsManagerListener listener : mListeners) {
listener.onCallAdded(call);
}
Trace.endSection();
}
mListeners主要來源于CallManager的構(gòu)造方法中添加的Listener
mListeners.add(mInCallWakeLockController);
mListeners.add(statusBarNotifier);
mListeners.add(mCallLogManager);
mListeners.add(mPhoneStateBroadcaster);
mListeners.add(mInCallController);
mListeners.add(mCallAudioManager);
mListeners.add(missedCallNotifier);
mListeners.add(mHeadsetMediaButton);
mListeners.add(mProximitySensorManager);
///M: add listener for phone recording
mListeners.add(PhoneRecorderHandler.getInstance());
這里說下mInCallController,其實(shí)InCallController對(duì)象她倘,內(nèi)部封裝了與incallui服務(wù)的相關(guān)操作,實(shí)際上就是一個(gè)遠(yuǎn)程服務(wù)代理類作箍,當(dāng)callsmanager添加一路call時(shí)硬梁, 回調(diào)InCallController的onCallAdded方法
@Override
public void onCallAdded(Call call) {
if (!isBoundToServices()) {
bindToServices(call);
} else {
adjustServiceBindingsForEmergency();
addCall(call);
for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
ComponentName componentName = entry.getKey();
IInCallService inCallService = entry.getValue();
ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(call,
true /* includeVideoProvider */, mCallsManager.getPhoneAccountRegistrar());
try {
// 1.
inCallService.addCall(parcelableCall);
} catch (RemoteException ignored) {
}
}
}
}
調(diào)用inCallService的addCall方法告訴incallui當(dāng)前添加了一路通話,incallui收到后會(huì)拉起界面胞得,具體過程在此就不詳述了荧止。
- 接著剛才得到call對(duì)象后的下一步分析,通過NewOutgoingCallIntentBroadcaster對(duì)象的的processIntent()進(jìn)一步做處理
packages/services/Telecomm/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
public int processIntent() {
Intent intent = mIntent;
...
boolean isVoicemailNumber = PhoneAccount.SCHEME_VOICEMAIL.equals(handle.getScheme());
// 1. 如果語(yǔ)音信箱的號(hào)碼調(diào)用CallsManager的placeOutgoingCall方法直接撥號(hào)
if (isVoicemailNumber) {
if (Intent.ACTION_CALL.equals(action)
|| Intent.ACTION_CALL_PRIVILEGED.equals(action)) {
// 標(biāo)識(shí)call已準(zhǔn)備就緒
mCall.setNewOutgoingCallIntentBroadcastIsDone();
...
mCallsManager.placeOutgoingCall(mCall, handle, null, speakerphoneOn,
VideoProfile.STATE_AUDIO_ONLY);
return DisconnectCause.NOT_DISCONNECTED;
} else {
Log.d(this, "Unhandled intent %s. Ignoring and not placing call.", intent);
return DisconnectCause.OUTGOING_CANCELED;
}
}
...
// 判斷是否為潛在的緊急撥號(hào)
final boolean isPotentialEmergencyNumber = isPotentialEmergencyNumber(number);
Log.v(this, "isPotentialEmergencyNumber = %s", isPotentialEmergencyNumber);
// 2. 根據(jù)是否是緊急撥號(hào)重新修正Action
rewriteCallIntentAction(intent, isPotentialEmergencyNumber);
action = intent.getAction();
boolean callImmediately = false;
if (Intent.ACTION_CALL.equals(action)) {
if (isPotentialEmergencyNumber) {
// 如果是系統(tǒng)Dialer或者默認(rèn)dialer撥緊急號(hào)碼則callImmediately會(huì)置為true,否則會(huì)啟動(dòng)系統(tǒng)dialer由用戶進(jìn)一步?jīng)Q定如何操作
if (!mIsDefaultOrSystemPhoneApp) {
launchSystemDialer(intent.getData());
return DisconnectCause.OUTGOING_CANCELED;
} else {
callImmediately = true;
}
}
} else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) {
if (!isPotentialEmergencyNumber) {
return DisconnectCause.OUTGOING_CANCELED;
}
callImmediately = true;
} else {
return DisconnectCause.INVALID_NUMBER;
}
// 3. 如果是緊急撥號(hào)跃巡,callImmediately會(huì)賦值為true危号,直接調(diào)用 mCallsManager.placeOutgoingCall進(jìn)行撥號(hào)
if (callImmediately) {
...
mCallsManager.placeOutgoingCall(mCall, Uri.fromParts(scheme, number, null), null,
speakerphoneOn, videoState);
}
UserHandle targetUser = mCall.getInitiatingUser();
// 4. 調(diào)用該方法發(fā)送廣播
broadcastIntent(intent, number, !callImmediately, targetUser);
return DisconnectCause.NOT_DISCONNECTED;
}
- VoiceMail直接調(diào)用mCallsManager.placeOutgoingCall,并return
- rewriteCallIntentAction內(nèi)部會(huì)判斷如果Action是
Intent.ACTION_CALL_PRIVILEGED
素邪,然后還是緊急撥號(hào)外莲,則轉(zhuǎn)化Action為Intent.ACTION_CALL_EMERGENCY
,不是緊急撥號(hào)則使用Intent.ACTION_CALL
- 緊急撥號(hào),callImmediately置為true兔朦,直接調(diào)用 mCallsManager.placeOutgoingCall方法撥打電話
packages/services/Telecomm/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
private void broadcastIntent(
Intent originalCallIntent,
String number,
boolean receiverRequired,
UserHandle targetUser) {
Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
if (number != null) {
broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
}
broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
checkAndCopyProviderExtras(originalCallIntent, broadcastIntent);
mContext.sendOrderedBroadcastAsUser(
broadcastIntent,
targetUser,
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
}
發(fā)送了一個(gè)Action為Intent.ACTION_NEW_OUTGOING_CALL
的有序廣播偷线,如果是非緊急撥號(hào),則指定最終廣播接收者(也就是最后一個(gè)接收該廣播)為NewOutgoingCallBroadcastIntentReceiver沽甥,緊急撥號(hào)則為空声邦。
NewOutgoingCallIntentBroadcaster$NewOutgoingCallBroadcastIntentReceiver.java
**
* Processes the result of the outgoing call broadcast intent, and performs callbacks to
* the OutgoingCallIntentBroadcasterListener as necessary.
*/
public class NewOutgoingCallBroadcastIntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
try {
// 1. 得到最終撥號(hào)的號(hào)碼
String resultNumber = getResultData();
...
Uri resultHandleUri = Uri.fromParts(
mPhoneNumberUtilsAdapter.isUriNumber(resultNumber) ?
PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL,
resultNumber, null);
Uri originalUri = mIntent.getData();
// 2. 打印號(hào)碼是否被被其它廣播接收者更改過的log
if (originalUri.getSchemeSpecificPart().equals(resultNumber)) {
} else {
}
GatewayInfo gatewayInfo = getGateWayInfoFromIntent(intent, resultHandleUri);
// 標(biāo)識(shí)call準(zhǔn)備就緒
mCall.setNewOutgoingCallIntentBroadcastIsDone();
// 3. 調(diào)用該方法
mCallsManager.placeOutgoingCall(mCall, resultHandleUri, gatewayInfo,
mIntent.getBooleanExtra(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE,
false),
mIntent.getIntExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
VideoProfile.STATE_AUDIO_ONLY));
...
}
- 得到最終的號(hào)碼
- 判斷號(hào)碼是否被中間的廣播接收者更改過
- 調(diào)用最重要的mCallsManager.placeOutgoingCall方法進(jìn)行撥號(hào),無論voicemail摆舟,emergencyNumber,正常撥號(hào)都會(huì)調(diào)用該方法進(jìn)行最終的撥號(hào)亥曹。
packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java
public void placeOutgoingCall(Call call, Uri handle, GatewayInfo gatewayInfo,
boolean speakerphoneOn, int videoState) {
...
// 1. 指定了激活的SIM卡或者是緊急撥號(hào),就調(diào)用call.startCreateConnection方法
if (call.getTargetPhoneAccount() != null || call.isEmergencyCall()) {
call.startCreateConnection(mPhoneAccountRegistrar);
}
...
}
packages/services/Telecomm/src/com/android/server/telecom/Call.java
void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {
mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,
phoneAccountRegistrar, mContext);
mCreateConnectionProcessor.process();
}
創(chuàng)建CreateConnectionProcessor盏檐,并調(diào)用process方法
packages/services/Telecomm/src/com/android/server/telecom/CreateConnectionProcessor.java
public void process() {
clearTimeout();
mAttemptRecords = new ArrayList<>();
if (mCall.getTargetPhoneAccount() != null) {
mAttemptRecords.add(new CallAttemptRecord(
mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
}
adjustAttemptsForConnectionManager();
adjustAttemptsForEmergency();
mAttemptRecordIterator = mAttemptRecords.iterator();
// 執(zhí)行該方法
attemptNextPhoneAccount();
}
private void attemptNextPhoneAccount() {
...
PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;
// 1. 得到ConnectionServiceWrapper對(duì)象
mService = mRepository.getService(phoneAccount.getComponentName(),
phoneAccount.getUserHandle());
mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);
mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
mCall.setConnectionService(mService);
setTimeoutIfNeeded(mService, attempt);
// 2. 建立連接
mService.createConnection(mCall, this);
...
}
packages/services/Telecomm/src/com/android/server/telecom/ConnectionServiceWrapper.java
public void createConnection(final Call call, final CreateConnectionResponse response) {
BindCallback callback = new BindCallback() {
@Override
public void onSuccess() {
...
// 2.
mServiceInterface.createConnection(
call.getConnectionManagerPhoneAccount(),
callId,
new ConnectionRequest(
call.getTargetPhoneAccount(),
call.getHandle(),
extras,
call.getVideoState(),
callId),
call.shouldAttachToExistingConnection(),
call.isUnknown());
...
}
...
};
// 1. 內(nèi)部會(huì)跨進(jìn)程綁定遠(yuǎn)程Service ConnectionService
mBinder.bind(callback, call);
}
- 綁定遠(yuǎn)程Service ConnectionService,當(dāng)綁定成功后歇式,會(huì)調(diào)用onServiceConnected方法,該方法中會(huì)回調(diào)callback的onSuccess方法并將返回的binder對(duì)象通過
IConnectionService.Stub.asInterface(binder);
得到遠(yuǎn)程Service的代理胡野,賦值給mServiceInterface - IPC調(diào)用遠(yuǎn)程Service ConnectionService的createConnection方法,對(duì)應(yīng)類為TelephonyConnectionService材失。
3. Telephony進(jìn)程
TelephonyConnectionService的createConnection方法在父類中實(shí)現(xiàn)
frameworks/base/telecomm/java/android/telecom/ConnectionService.java
@Override
public void createConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
String id,
ConnectionRequest request,
boolean isIncoming,
boolean isUnknown) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = connectionManagerPhoneAccount;
args.arg2 = id;
args.arg3 = request;
args.argi1 = isIncoming ? 1 : 0;
args.argi2 = isUnknown ? 1 : 0;
// 解析參數(shù),并發(fā)送MSG_CREATE_CONNECTION消息交由Handler處理
mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
}
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
...
case MSG_CREATE_CONNECTION: {
SomeArgs args = (SomeArgs) msg.obj;
try {
final PhoneAccountHandle connectionManagerPhoneAccount =
(PhoneAccountHandle) args.arg1;
final String id = (String) args.arg2;
final ConnectionRequest request = (ConnectionRequest) args.arg3;
final boolean isIncoming = args.argi1 == 1;
final boolean isUnknown = args.argi2 == 1;
...
// 走該方法
createConnection(
connectionManagerPhoneAccount,
id,
request,
isIncoming,
isUnknown);
...
}
private void createConnection(
final PhoneAccountHandle callManagerAccount,
final String callId,
final ConnectionRequest request,
boolean isIncoming,
boolean isUnknown) {
...
// 1. 來電走onCreateIncomingConnection,去電走onCreateOutgoingConnection
Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
: isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
: onCreateOutgoingConnection(callManagerAccount, request);
...
connection.setTelecomCallId(callId);
if (connection.getState() != Connection.STATE_DISCONNECTED) {
addConnection(callId, connection);
}
...
去電通過onCreateOutgoingConnection創(chuàng)建通話連接,實(shí)現(xiàn)在實(shí)體類TelephonyConnectionService實(shí)現(xiàn)硫豆。
packages/services/Telephony/src/com/android/services/telephony/TelephonyConnectionService.java
@Override
public Connection onCreateOutgoingConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
final ConnectionRequest request) {
if (PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
...
number = phone.getVoiceMailNumber();
// 1. Voicemail撥號(hào)龙巨,但Voicemail號(hào)碼為空錯(cuò)誤
if (TextUtils.isEmpty(number)) {
return Connection.createFailedConnection(
DisconnectCauseUtil.toTelecomDisconnectCause(
android.telephony.DisconnectCause.VOICEMAIL_NUMBER_MISSING,
"Voicemail scheme provided but no voicemail number set."));
}
// Convert voicemail: to tel:
}
// 飛行模式撥號(hào)錯(cuò)誤
// 還有其他一些出錯(cuò)情況的判斷,出錯(cuò)就會(huì)界面給出對(duì)應(yīng)提示
...
// 3. 繼續(xù)撥號(hào)這段邏輯
placeOutgoingConnection(connection, phone, request);
packages/services/Telephony/src/com/android/services/telephony/TelephonyConnectionService.java
private void placeOutgoingConnection(
TelephonyConnection connection, Phone phone, ConnectionRequest request) {
String number = connection.getAddress().getSchemeSpecificPart();
...
com.android.internal.telephony.Connection originalConnection;
try {
originalConnection =
phone.dial(number, null, request.getVideoState(), request.getExtras());
}
...
}
調(diào)用phone對(duì)象的dial()方法實(shí)現(xiàn)真正撥號(hào).在Android N上熊响,cdma和gsm都由GsmCdmaPhone對(duì)象統(tǒng)一處理旨别。
frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@Override
public Connection dial(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)
throws CallStateException {
...
// VOLTE開啟或者VOWIFI開啟都會(huì)為true
boolean imsUseEnabled = isImsUseEnabled()
&& imsPhone != null
&& (imsPhone.isVolteEnabled() || imsPhone.isWifiCallingEnabled() ||
(imsPhone.isVideoEnabled() && VideoProfile.isVideo(videoState)))
&& (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE);
...
if ((imsUseEnabled && (!isUt || useImsForUt)) || useImsForEmergency) {
try {
if (videoState == VideoProfile.STATE_AUDIO_ONLY) {
// 調(diào)用imsPhone撥打電話
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);
}...
}
} ...
}
...
// 正常撥號(hào)走此處
return dialInternal(dialString, null, videoState, intentExtras);
}
frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@Override
protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
Bundle intentExtras)
throws CallStateException {
if (isPhoneTypeGsm()) {
if (handleInCallMmiCommands(newDialString)) {
return null;
}
String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
GsmMmiCode mmi =
GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get());
if (mmi == null) {
// 1. Gsm撥號(hào)
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
}
return null;
}
} else {
// 2. 非Gsm撥號(hào)
return mCT.dial(newDialString);
}
}
實(shí)際都是通過mCT的dial進(jìn)行呼出,mCT實(shí)際為GsmCdmaCallTracker對(duì)象,這里以CDMA進(jìn)行分析汗茄,也就是走注釋2處秸弛。
frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
private Connection dial(String dialString, int clirMode) throws CallStateException {
// 1. 將Call設(shè)置為IDLE狀態(tài),并通知狀態(tài)發(fā)生改變
clearDisconnected();
...
mPendingMO = new GsmCdmaConnection(mPhone, checkForTestEmergencyNumber(dialString),
this, mForegroundCall);
if(!isPhoneInEcmMode || (isPhoneInEcmMode && isEmergencyCall)) {
/// M: Proprietary ECC handling @{
//mCi.dial(mPendingMO.getAddress(), clirMode, obtainCompleteMessage());
if (isEmergencyCall) {
mCi.emergencyDial(mPendingMO.getAddress(), clirMode, null,
obtainCompleteMessage());
} else {
// 2. 通過RILJ撥打電話
mCi.dial(mPendingMO.getAddress(), clirMode, obtainCompleteMessage());
}
/// @}
}
...
// 3. 在此更新Phone狀態(tài)集精確的Call狀態(tài)
updatePhoneState();
mPhone.notifyPreciseCallStateChanged();
return mPendingMO;
}
- 設(shè)置IDLE方法如下
public GsmCdmaCall mRingingCall = new GsmCdmaCall(this);
public GsmCdmaCall mForegroundCall = new GsmCdmaCall(this);
public GsmCdmaCall mBackgroundCall = new GsmCdmaCall(this);
public void clearDisconnected() {
// 1. clearDisconnected內(nèi)部會(huì)將Call狀態(tài)設(shè)置為IDLE
mRingingCall.clearDisconnected();
mForegroundCall.clearDisconnected();
mBackgroundCall.clearDisconnected();
// 2. 內(nèi)部會(huì)調(diào)用mPhone的notifyPhoneStateChanged更新Phone的狀態(tài)
updatePhoneState();
// 3. 更新精確Phone狀態(tài)
mPhone.notifyPreciseCallStateChanged();
}
Call的所有狀態(tài)為枚舉類型
public enum State {
IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED, DISCONNECTING;
}
- mCi是CommandsInterface類型,跟蹤賦值可以看到其實(shí)通過Phone對(duì)象獲取的洪碳,而Phone對(duì)象是由PhoneFactory創(chuàng)建的递览,代碼如下
frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneFactory.java
public static void makeDefaultPhone(Context context) {
...
int numPhones = TelephonyManager.getDefault().getPhoneCount();
int[] networkModes = new int[numPhones];
sPhones = new Phone[numPhones];
sCommandsInterfaces = new RIL[numPhones];
sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones];
for (int i = 0; i < numPhones; i++) {
networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE;
// 1. 創(chuàng)建RIL
sCommandsInterfaces[i] = new RIL(context, networkModes[i],
cdmaSubscription, i);
}
SubscriptionController.init(context, sCommandsInterfaces);
RadioManager.init(context, numPhones, sCommandsInterfaces);
sUiccController = UiccController.make(context, sCommandsInterfaces);
for (int i = 0; i < numPhones; i++) {
Phone phone = null;
// 2. 創(chuàng)建Phone對(duì)象,實(shí)際對(duì)應(yīng)GsmCdmaPhone,并傳入對(duì)應(yīng)的RIL對(duì)象,sCommandsInterfaces[i]就對(duì)應(yīng)Phone中的mCi變量
int phoneType = TelephonyManager.getPhoneType(networkModes[i]);
if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
phone = new GsmCdmaPhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i,
PhoneConstants.PHONE_TYPE_GSM,
TelephonyComponentFactory.getInstance());
} else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
phone = new GsmCdmaPhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i,
PhoneConstants.PHONE_TYPE_CDMA_LTE,
TelephonyComponentFactory.getInstance());
}
sPhones[i] = phone;
}
sPhone = sPhones[0];
sCommandsInterface = sCommandsInterfaces[0];
}
知道了mCi是RIL瞳腌,由于是java文件也稱作RILJ绞铃。我們繼續(xù)分析mCi.dial撥打電話的方法。
4. RILJ與RILC的交互
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
@Override
public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
if (!PhoneNumberUtils.isUriNumber(address)) {
// 1. 封裝為RILRequest
RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);
rr.mParcel.writeString(address);
rr.mParcel.writeInt(clirMode);
...
// 2. 調(diào)用send
send(rr);
} else {
RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL_WITH_SIP_URI, result);
rr.mParcel.writeString(address);
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
mEventLog.writeRilDial(rr.mSerial, clirMode, uusInfo);
send(rr);
}
}
private void send(RILRequest rr) {
Message msg;
if (mSocket == null) {
rr.onError(RADIO_NOT_AVAILABLE, null);
rr.release();
return;
}
msg = mSender.obtainMessage(EVENT_SEND, rr);
acquireWakeLock(rr, FOR_WAKELOCK);
// 3. 交由mSender子線程的Handler處理
msg.sendToTarget();
}
將撥號(hào)信息及撥號(hào)請(qǐng)求RIL_REQUEST_DIAL封裝在RILRequest中嫂侍,在注釋3處交由與RILC的服務(wù)端進(jìn)行通信的子線程mSender中
class RILSender extends Handler implements Runnable {
public RILSender(Looper looper) {
super(looper);
}
byte[] dataLength = new byte[4];
@Override public void
handleMessage(Message msg) {
RILRequest rr = (RILRequest)(msg.obj);
RILRequest req = null;
switch (msg.what) {
case EVENT_SEND:
case EVENT_SEND_ACK:
try {
LocalSocket s;
// 1. 得到客戶端LocalSocket對(duì)象
s = mSocket;
...
byte[] data;
data = rr.mParcel.marshall();
...
// parcel length in big endian
dataLength[0] = dataLength[1] = 0;
dataLength[2] = (byte)((data.length >> 8) & 0xff);
dataLength[3] = (byte)((data.length) & 0xff);
// 2. 向服務(wù)端發(fā)送數(shù)據(jù)長(zhǎng)度
s.getOutputStream().write(dataLength);
// 3. 向服務(wù)端發(fā)送數(shù)據(jù)
s.getOutputStream().write(data);
if (msg.what == EVENT_SEND_ACK) {
rr.release();
return;
}
} catch (IOException ex) {
...
當(dāng)服務(wù)端給出回應(yīng)后后會(huì)在RILReceiver中接收到,代碼如下
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
class RILReceiver implements Runnable {
byte[] buffer;
RILReceiver() {
buffer = new byte[RIL_MAX_COMMAND_BYTES];
}
@Override
public void
run() {
int retryCount = 0;
String rilSocket = "rild";
try {for (;;) {
LocalSocket s = null;
LocalSocketAddress l;
...
try {
s = new LocalSocket();
l = new LocalSocketAddress(rilSocket,
LocalSocketAddress.Namespace.RESERVED);
// 1. 連接name為rild的服務(wù)端Socket,也就是RILC部分
s.connect(l);
} catch (IOException ex){
...
}
mSocket = s;
int length = 0;
try {
InputStream is = mSocket.getInputStream();
for (;;) {
Parcel p;
// 2. 阻塞讀取服務(wù)端發(fā)來的消息儿捧,一有消息就會(huì)繼續(xù)執(zhí)行接下來的代碼荚坞,如果length為-1,就會(huì)推出循環(huán)
length = readRilMessage(is, buffer);
if (length < 0) {
break;
}
p = Parcel.obtain();
p.unmarshall(buffer, 0, length);
p.setDataPosition(0);
// 3. 接收到上報(bào)的消息后就會(huì)通過該方法處理
processResponse(p);
p.recycle();
}
} catch (java.io.IOException ex) {
...
}
//4. 退出循環(huán)菲盾,也就切斷了和Modem的聯(lián)系颓影,需要設(shè)置Radio狀態(tài)為RADIO_UNAVAILABLE
setRadioState (RadioState.RADIO_UNAVAILABLE);
try {
mSocket.close();
} catch (IOException ex) {
}
mSocket = null;
...
}
}
主要看下上報(bào)消息的處理
private void processResponse (Parcel p) {
int type;
type = p.readInt();
if (type == RESPONSE_UNSOLICITED || type == RESPONSE_UNSOLICITED_ACK_EXP) {
// 處理URC消息,也就是modem主動(dòng)上報(bào)消息的處理
processUnsolicited (p, type);
} else if (type == RESPONSE_SOLICITED || type == RESPONSE_SOLICITED_ACK_EXP) {
// 處理非URC消息,modem回復(fù)上層下發(fā)的請(qǐng)求亿汞,例如撥號(hào)
RILRequest rr = processSolicited (p, type);
if (rr != null) {
if (type == RESPONSE_SOLICITED) {
decrementWakeLock(rr);
}
rr.release();
return;
}
} else if (type == RESPONSE_SOLICITED_ACK) {
...
}
}
發(fā)起撥號(hào)請(qǐng)求瞭空,modem回應(yīng)的消息應(yīng)在processSolicited中處理,繼續(xù)看該方法疗我。
private RILRequest processSolicited (Parcel p, int type) {
int serial, error;
boolean found = false;
serial = p.readInt();
error = p.readInt();
RILRequest rr;
// 1. 根據(jù)serial找到對(duì)應(yīng)的RILRequest
rr = findAndRemoveRequestFromList(serial);
...
try {switch (rr.mRequest) {
case RIL_REQUEST_GET_SIM_STATUS: ret = responseIccCardStatus(p); break;
case RIL_REQUEST_ENTER_SIM_PIN: ret = responseInts(p); break;
case RIL_REQUEST_ENTER_SIM_PUK: ret = responseInts(p); break;
case RIL_REQUEST_ENTER_SIM_PIN2: ret = responseInts(p); break;
case RIL_REQUEST_ENTER_SIM_PUK2: ret = responseInts(p); break;
case RIL_REQUEST_CHANGE_SIM_PIN: ret = responseInts(p); break;
case RIL_REQUEST_CHANGE_SIM_PIN2: ret = responseInts(p); break;
case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: ret = responseInts(p); break;
case RIL_REQUEST_GET_CURRENT_CALLS: ret = responseCallList(p); break;
// 2. 撥號(hào)時(shí)建立的RILRequest的mRequest為RIL_REQUEST_DIAL,responseVoid返回的null,表示只關(guān)心Modem是否回應(yīng),無需其他內(nèi)容
case RIL_REQUEST_DIAL: ret = responseVoid(p); break;
...
}
...
if (error == 0) {
if (rr.mResult != null) {
AsyncResult.forMessage(rr.mResult, ret, null);
// 3. 發(fā)送到對(duì)應(yīng)的Handler處理
rr.mResult.sendToTarget();
}
}
return rr;
}
注釋3處南捂,撥號(hào)后接收到Modem的回應(yīng)吴裤,封裝消息后又交由對(duì)應(yīng)Handler處理。mResults是什么溺健?mResult是調(diào)用RIL的dial方法傳入的Message類型的result麦牺,該方法調(diào)用是在
GsmCdmaCallTracker中,具體如下
frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
public class GsmCdmaCallTracker extends CallTracker {
private Connection dial(String dialString, int clirMode) throws CallStateException {
...
// 1. 調(diào)用obtainCompleteMessage返回一個(gè)Message
mCi.dial(mPendingMO.getAddress(), clirMode, obtainCompleteMessage());
...
}
public Message obtainCompleteMessage() {
return obtainCompleteMessage(EVENT_OPERATION_COMPLETE);
}
public Message obtainCompleteMessage(int what) {
mPendingOperations++;
mLastRelevantPoll = null;
mNeedsPoll = true;
// 2. 返回一個(gè)what為EVENT_OPERATION_COMPLETE的Message
return obtainMessage(what);
}
@Override
public void handleMessage(Message msg) {
AsyncResult ar;
switch (msg.what) {
// 3. 處理what為EVENT_OPERATION_COMPLETE消息
case EVENT_OPERATION_COMPLETE:
operationComplete();
break;
...
}
GsmCdmaCallTracker間接繼承Handler鞭缭,注釋1處調(diào)用RIL的dial時(shí)傳入了一個(gè)what為EVENT_OPERATION_COMPLETE的Message剖膳。當(dāng)在RIL中調(diào)用rr.mResult.sendToTarget()時(shí),就會(huì)在注釋3處接收到岭辣,然后調(diào)用operationComplete()方法
private void operationComplete() {
mPendingOperations--;
if (mPendingOperations == 0 && mNeedsPoll) {
// 封裝了EVENT_POLL_CALLS_RESULT消息吱晒,調(diào)用RIL的getCurrentCalls獲取Call狀態(tài)
mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
mCi.getCurrentCalls(mLastRelevantPoll);
} else if (mPendingOperations < 0) {
// this should never happen
Rlog.e(LOG_TAG,"GsmCdmaCallTracker.pendingOperations < 0");
mPendingOperations = 0;
}
}
接下來的流程又進(jìn)入與RIL層的socket通信,過程與前面一樣沦童,最后GsmCdmaCallTracker收到EVENT_POLL_CALLS_RESULT消息進(jìn)行處理仑濒,調(diào)用了handlePollCalls((AsyncResult)msg.obj)
方法
@Override
protected synchronized void handlePollCalls(AsyncResult ar) {
...
// 1. 更新Phone狀態(tài)
updatePhoneState();
if (unknownConnectionAppeared) {
if (isPhoneTypeGsm()) {
for (Connection c : newUnknownConnectionsGsm) {
mPhone.notifyUnknownConnection(c);
}
} else {
mPhone.notifyUnknownConnection(newUnknownConnectionCdma);
}
}
if (hasNonHangupStateChanged || newRinging != null || hasAnyCallDisconnected) {
// 2. 更新Call精確的狀態(tài)
mPhone.notifyPreciseCallStateChanged();
}
}
注冊(cè)了該phone電話狀態(tài)監(jiān)聽的對(duì)象將會(huì)收到通知
Call的所有狀態(tài)定義在Call中
public enum State {
IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED, DISCONNECTING;
public boolean isAlive() {
return !(this == IDLE || this == DISCONNECTED || this == DISCONNECTING);
}
public boolean isRinging() {
return this == INCOMING || this == WAITING;
}
public boolean isDialing() {
return this == DIALING || this == ALERTING;
}
}
Call狀態(tài)與PreciseCallState封裝的精確Call狀態(tài)對(duì)應(yīng)關(guān)系如下
public static int convertPreciseCallState(Call.State state) {
switch (state) {
case ACTIVE:
return PreciseCallState.PRECISE_CALL_STATE_ACTIVE;
case HOLDING:
return PreciseCallState.PRECISE_CALL_STATE_HOLDING;
case DIALING:
return PreciseCallState.PRECISE_CALL_STATE_DIALING;
case ALERTING:
return PreciseCallState.PRECISE_CALL_STATE_ALERTING;
case INCOMING:
return PreciseCallState.PRECISE_CALL_STATE_INCOMING;
case WAITING:
return PreciseCallState.PRECISE_CALL_STATE_WAITING;
case DISCONNECTED:
return PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED;
case DISCONNECTING:
return PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING;
default:
return PreciseCallState.PRECISE_CALL_STATE_IDLE;
}
}
具體notifyPreciseCallStateChanged發(fā)送過程自行閱讀源碼。
后續(xù)modem會(huì)主動(dòng)上報(bào)一些電話狀態(tài)的變化:RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED偷遗,對(duì)于URC消息在processUnsolicited 中處理
private void processUnsolicited (Parcel p, int type) {
int response;
Object ret;
response = p.readInt();
...
switch(response) {
...
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
// 1. 利用Resistrant機(jī)制通知對(duì)應(yīng)的所有注冊(cè)者
mCallStateRegistrants
.notifyRegistrants(new AsyncResult(null, null, null));
break;
...
}
先說下RegistrantList機(jī)制墩瞳,如果需要接收Modem上報(bào)的消息,就需要注冊(cè)到對(duì)應(yīng)的RegistrantList中氏豌,待Modem有對(duì)應(yīng)消息時(shí)喉酌,就會(huì)通知對(duì)應(yīng)的RegistrantList列表”么看下RIL中的不同類型的RegistrantList列表
// Radio狀態(tài)列表
protected RegistrantList mRadioStateChangedRegistrants = new RegistrantList();
protected RegistrantList mOnRegistrants = new RegistrantList();
protected RegistrantList mAvailRegistrants = new RegistrantList();
protected RegistrantList mOffOrNotAvailRegistrants = new RegistrantList();
protected RegistrantList mNotAvailRegistrants = new RegistrantList();
// Call狀態(tài)注冊(cè)著列表
protected RegistrantList mCallStateRegistrants = new RegistrantList();
// Network狀態(tài)注冊(cè)者列表
protected RegistrantList mNetworkStateRegistrants = new RegistrantList();
// 注冊(cè)接口方法
@Override
public void registerForCallStateChanged(Handler h, int what, Object obj) {
Registrant r = new Registrant (h, what, obj);
mCallStateRegistrants.add(r);
}
...
而監(jiān)聽Modem上傳Call狀態(tài)的是在GsmCdmaCallTracker構(gòu)造方法中注冊(cè)的
mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
當(dāng)Modem上報(bào)Call狀態(tài)時(shí)通過mCallStateRegistrants .notifyRegistrants(new AsyncResult(null, null, null))
方法泪电,內(nèi)部會(huì)調(diào)用注冊(cè)傳入的Handler(也就是GsmCdmaCallTracker)的sendMessage發(fā)送消息,消息類型是EVENT_CALL_STATE_CHANGE就調(diào)用pollCallsWhenSafe()方法涣旨。
protected void pollCallsWhenSafe() {
mNeedsPoll = true;
if (checkNoOperationsPending()) {
mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
mCi.getCurrentCalls(mLastRelevantPoll);
}
}
與RIL Socket通信得到Call狀態(tài)歪架,和前面獲取Call狀態(tài)過程相同。
至此霹陡,撥號(hào)流程就完了和蚪,通過實(shí)際問題打印log會(huì)有更深刻的認(rèn)識(shí)止状。下面對(duì)總結(jié)下大體流程。