天天看點

android6.0 Phone源碼分析之Phone适配過程android6.0 Phone源碼分析之Phone适配過程

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,最後實作去電。