android6.0 Phone源碼分析之Phone适配過程
分析過Phone源碼的人知道,在Phone去電過程中會調用到phone.dial()方法,而此處的Phone可以為GSMPhone或者CDMALTEPhone。對于Phone的适配,android采用了工廠模式。本文主要分析Phone的适配過程,重要的類主要有PhoneApp, PhoneFactory,PhoneGlobals等。
1.Phone程序的初始化
在android系統中,有許多永久存在的應用,它們對應的設定是androidmanifest.xml檔案的persistent屬性,若屬性值為true,則此應用為永久性應用,系統開機啟動時會自動加載。此外,若應用因某種原因退出,系統會再次自動啟動此應用。而在Phone應用中的PhoneApp類在androidmanifest.xml中的persistent屬性為true。
<application android:name="PhoneApp"
android:persistent="true"
android:label="@string/phoneAppLabel"
android:icon="@mipmap/ic_launcher_phone"
android:allowBackup="false"
android:supportsRtl="true"
android:usesCleartextTraffic="true">
<provider android:name="IccProvider"
分析PhoneApp類:
@Override
public void onCreate() {
if (UserHandle.myUserId() == ) {
// We are running as the primary user, so should bring up
// the global phone state.
mPhoneGlobals = new PhoneGlobals(this);
mPhoneGlobals.onCreate();
mTelephonyGlobals = new TelephonyGlobals(this);
mTelephonyGlobals.onCreate();
}
在PhoneApp類啟動後,會在onCreate()中初始化PhoneGlobals和TelephonyGlobals兩個類。PhoneGlobals類用來初始化phone,以及擷取phone,而TelephonyGlobals類主要用來處理PSTN呼叫,它是5.0新添加的類,先分析PhoneGlobals。
2.PhoneGlobals類分析
public void onCreate() {
...
if (mCM == null) {
// Initialize the telephony framework
PhoneFactory.makeDefaultPhones(this);
// Start TelephonyDebugService After the default
// phone is created.
Intent intent = new Intent(this,
TelephonyDebugService.class);
startService(intent);
//擷取CallManager執行個體
mCM = CallManager.getInstance();
for (Phone phone : PhoneFactory.getPhones()) {
//将phone注冊到CallManager中
mCM.registerPhone(phone);
}
...
// Create the CallController singleton, which is the
//interface to the telephony layer for user-initiated
//telephony functionality(like making outgoing calls)
//初始化callController
callController = CallController.init(this,
callLogger, callGatewayManager);
...
}
由以上代碼可知,PhoneGlobals類先通過PhoneFactory初始化Phone,然後将所有的Phone注冊到CallManager,此時就可以通過PhoneFactory的getPhone(int phoneId)方法,通過phoneId來擷取相應的Phone.接着先分析makeDefaultPhones()方法。
public static void makeDefaultPhone(Context context) {
...
//擷取Phone的sim數量
int numPhones =
TelephonyManager.getDefault().getPhoneCount();
...
//循環對所有的Sim卡進行Phone類型的初始化
for (int i = ; i < numPhones; i++) {
PhoneBase phone = null;
//擷取Phone的類型
int phoneType =TelephonyManager
.getPhoneType(networkModes[i]);
if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
//初始化為GSM模式
phone = new GSMPhone(context,
sCommandsInterfaces[i],sPhoneNotifier, i);
phone.startMonitoringImsService();
} else if (phoneType ==
PhoneConstants.PHONE_TYPE_CDMA) {
//初始化為CMDALTE模式
phone = new CDMALTEPhone(context,
sCommandsInterfaces[i], sPhoneNotifier, i);
phone.startMonitoringImsService();
}
//生成Phone代理,并放入PhoneFactory的工廠
sProxyPhones[i] = new PhoneProxy(phone);
}
//将PhoneFactory的所有Phone代碼交給ProxyController管理
mProxyController = ProxyController.getInstance(context,
sProxyPhones,mUiccController, sCommandsInterfaces);
...
}
首先擷取Phone中sim卡的數量,然後分别對對應的Sim卡進行Phone的初始化,可以初始化為GSMPhone和CDMALTEPhone兩種。接着将其加入到PhoneFactory的ProxyPhones數組中進行,最後再将其交給ProxyController進行控制管理,至此,Phone的準備工作已經結束。
3.Phone适配
在去電過程(MO)中,會調用onCreateOutgoingConnection()建立去電Connection
@Override
public Connection onCreateOutgoingConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
final ConnectionRequest request) {
//根據請求擷取tel
Uri handle = request.getAddress();
...
//擷取PhoneAccount的類型
String scheme = handle.getScheme();
...
//擷取Phone
final Phone phone = getPhoneForAccount(
request.getAccountHandle(), false);
...
//建立連接配接
final TelephonyConnection connection =
createConnectionFor(phone, null, true /* isOutgoing */, request.getAccountHandle());
...
//設定tel
connection.setAddress(handle,
PhoneConstants.PRESENTATION_ALLOWED);
//初始化
connection.setInitializing();
connection.setVideoState(request.getVideoState());
if (useEmergencyCallHelper) {//緊急号碼
...
}else{//非緊急号碼,根據初始化好的connection建立連接配接
placeOutgoingConnection(connection, phone, request);
}
return connection;
}
由以上代碼可知,根據請求通過getPhoneForAccount()方法來擷取Phone.
private Phone getPhoneForAccount(PhoneAccountHandle
accountHandle, boolean isEmergency) {
if (isEmergency) {//緊急号碼
return PhoneFactory.getDefaultPhone();
}
//擷取subId
int subId = PhoneUtils.
getSubIdForPhoneAccountHandle(accountHandle);
if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {//有效ID
//擷取phoneId
int phoneId = SubscriptionController.
getInstance().getPhoneId(subId);
//根據phoneId從PhoneFactory擷取Phone
return PhoneFactory.getPhone(phoneId);
}
return null;
}
首先通過PhoneUtils擷取subId,然後再從SubscriptionController中擷取相應的phoneId,最後再根據phoneId從PhoneFactory中擷取phone.
public static int getSubIdForPhoneAccountHandle(
PhoneAccountHandle handle) {
if (handle != null && handle.getComponentName().
equals(getPstnConnectionServiceName())) {
Phone phone = getPhoneFromIccId(handle.getId());
if (phone != null) {
return phone.getSubId();
}
}
return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
}
接着分析getPhoneFromIccId()方法.
private static Phone getPhoneFromIccId(String iccId) {
if (!TextUtils.isEmpty(iccId)) {
for (Phone phone : PhoneFactory.getPhones()) {
String phoneIccId = phone.getIccSerialNumber();
if (iccId.equals(phoneIccId)) {
return phone;
}
}
}
return null;
}
由代碼可知,通過比較所有Phone與此Account的iccId來擷取相應的phone.最後會通過得到的phone來建立相應的Connection,最後實作去電。