開關VoLTE流程分析(一)

開關按鈕位置:
  設置--> 更多--> 移動網絡--> 增強型4G LTE模式

控件初始化addEnhanced4GLteSwitchPreference,該設置開關使用了SwitchPreference控件,addEnhanced4GLteSwitchPreference()添加控件(packages/services/telephony/src/com/android/phone/MobileNetworkSettings.java)

複製代碼
    private void addEnhanced4GLteSwitchPreference(PreferenceScreen preferenceScreen) {
        log("[addEnhanced4GLteSwitchPreference] ImsEnabled :"
                + ImsManager.isVolteEnabledByPlatform(this));
        if (mButton4glte != null) { //去掉Google原生開關按鈕
            log("[addEnhanced4GLteSwitchPreference] Remove mButton4glte!");
            preferenceScreen.removePreference(mButton4glte);
        }
        if (ImsManager.isVolteEnabledByPlatform(this)) { //判斷是否支持VoLTE
            int order = mButtonEnabledNetworks.getOrder() + 1;
                     //VoLTE開關初始化
            mEnhancedButton4glte = new Enhanced4GLteSwitchPreference(this, mPhone.getSubId()); 
            /// Still use Google's key, title, and summary.
            mEnhancedButton4glte.setKey(BUTTON_4G_LTE_KEY); //Key用於SharePreference存儲信息
            if (ImsManager.isWfcEnabledByPlatform(this)) { //判斷是否支持WIFI Call
                mEnhancedButton4glte.setTitle(R.string.wfc_volte_switch_title);
            } else {
                mEnhancedButton4glte.setTitle(R.string.enhanced_4g_lte_mode_title);
            }
            mEnhancedButton4glte.setSummary(R.string.enhanced_4g_lte_mode_summary);
            mEnhancedButton4glte.setOnPreferenceChangeListener(this); //設置監聽接口,狀態發生變化onPreferenceChange()方法將被調用
            mEnhancedButton4glte.setOrder(order);
            //preferenceScreen.addPreference(mEnhancedButton4glte);
        }
複製代碼

 

監聽方法onPreferenceChangeMTK,該接聽方法onPreferenceChangeMTK(),重新原生onPreferenceChange();

複製代碼
    private boolean onPreferenceChangeMTK(Preference preference, Object objValue) {
        log("[onPreferenceChangeMTK] preference = " + preference.getTitle());
        if (mEnhancedButton4glte == preference) { 
            log("[onPreferenceChangeMTK] IsChecked = " + mEnhancedButton4glte.isChecked());
            Enhanced4GLteSwitchPreference ltePref = (Enhanced4GLteSwitchPreference) preference;
            ltePref.setChecked(!ltePref.isChecked()); //設置控件狀態,默認關閉是false,打開即是true
            ImsManager.setEnhanced4gLteModeSetting(this, ltePref.isChecked()); //設置VoLTE參數
            return true;
        }
        return false;
    }
複製代碼

有如下打印信息:

 

設置VoLTE狀態setEnhanced4gLteModeSetting,frameworks/opt/net/ims/src/java/com/android/ims/ImsManager.java

複製代碼
    public static void setEnhanced4gLteModeSetting(Context context, boolean enabled) {
        int value = enabled ? 1 : 0;
          //設置Settings.Global.ENHANCED_4G_MODE_ENABLED變量
        android.provider.Settings.Global.putInt(
                context.getContentResolver(),
                android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, value);

        if (isNonTtyOrTtyOnVolteEnabled(context)) { //不支持TTY或者VoLTE支持TTY
            ImsManager imsManager = ImsManager.getInstance(context,
                    SubscriptionManager.getDefaultVoicePhoneId()); //獲取ImsManager對象
            if (imsManager != null) {
                try {
                    imsManager.setAdvanced4GMode(enabled); //設置VoLTE
                } catch (ImsException ie) {
                    // do nothing
                }
            }
        }
    }
複製代碼

設置VoLTE

複製代碼
    private void setAdvanced4GMode(boolean turnOn) throws ImsException {
        checkAndThrowExceptionIfServiceUnavailable();

        try {
            ImsConfig config = getConfigInterface(); //IMS 配置參數
            if (config != null) {
                             //設置FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE網絡參數
                config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
                        TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null);
            }
        } catch (ImsException e) {
            log("setAdvanced4GMode() : " + e);
        }

        log("setAdvanced4GMode():" + turnOn);
        if (turnOn) {
            turnOnIms(); //打開IMS 服務
        } else if (isImsTurnOffAllowed()) {
            log("setAdvanced4GMode() : imsServiceAllowTurnOff -> turnOffIms");
            turnOffIms(); //關閉IMS 服務
        }
複製代碼

有如下打印信息:

 

打開IMS 服務

複製代碼
    private void turnOnIms() throws ImsException {
        checkAndThrowExceptionIfServiceUnavailable();

        try {
            mImsService.turnOnIms(mPhoneId);
        } catch (RemoteException e) {
            throw new ImsException("turnOnIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
        }
    }
複製代碼

mImsService 是IImsService 的實例對象,該對象在createImsService()中創建:

複製代碼
       //綁定IMS Service
    private void createImsService(boolean checkService) {
        if (checkService) { //判斷IMS Service 服務是否已經存在
            IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId));

            if (binder == null) {
                /// M: add for debug @{
                if (DBG) log("ImsManager: createImsService binder is null");
                /// @}
                return;
            }
        }
        //獲取指向Service的IBinder對象
        IBinder b = ServiceManager.getService(getImsServiceName(mPhoneId));

        if (b != null) {
            try {
                b.linkToDeath(mDeathRecipient, 0);
            } catch (RemoteException e) {
            }
        }

        mImsService = IImsService.Stub.asInterface(b);
        /// M: add for debug @{
        if (DBG) log("ImsManager: mImsService = " + mImsService);
        /// @}
        }
複製代碼

getImsServiceName()獲取IMS Service 名:

    private static String getImsServiceName(int phoneId) {
        // TODO: MSIM implementation needs to decide on service name as a function of phoneId
        return IMS_SERVICE;  //服務名即"ims"
    }

而getImsServiceName()方法在ImsManager類的構造方法中即被調用,所以mImsService對象開機即獲取到。

 

方法turnOnIms,調用mImsService的turnOnIms()方法在IImsService.Stub繼承類中實現:

vendor/mediatek/proprietary/packages/services/ims/src/com/mediatek/ims/ImsService.java

複製代碼
    /**
     * Used for turning on IMS when its in OFF state.
     */
    @Override
    public void turnOnIms(int phoneId) {
        Rlog.d(LOG_TAG, "turnOnIms, mActivePhoneId = " + mActivePhoneId +
            " phoneId = " + phoneId);
        phoneId = getMainCapabilityPhoneId();
        Rlog.d(LOG_TAG, "turnOnIms, MainCapabilityPhoneId = " + phoneId);

        if (mActivePhoneId != phoneId) {
            mActivePhoneId = phoneId;
        }
    }
複製代碼
複製代碼
   /**
    * to get main capability phone id.
    *
    * @return The phone id with highest capability.
    */
   private int getMainCapabilityPhoneId() { //此接口可能獲取主卡phoneID
             //獲取服務"phoneEx"
       ITelephonyEx telephony = ITelephonyEx.Stub.asInterface(
               ServiceManager.getService(mContext.TELEPHONY_SERVICE_EX));

       if (telephony != null) {
           try {
               int mainPhoneId = telephony.getMainCapabilityPhoneId(); //調用getMainCapabilityPhoneId()方法
               Rlog.d(LOG_TAG, "getMainCapabilityPhoneId: mainPhoneId = " + mainPhoneId);
               return mainPhoneId;
           }
           ..........
       } 
   }
複製代碼

有如下打印信息:

 

獲取主PhoneID

PhoneInterfaceManagerEx extends ITelephonyEx.Stub;
packages/services/telephony/src/com/mediatek/phone/PhoneInterfaceManagerEx.java

複製代碼
    /**
     * Get main capability phone id.
     * @return The phone id with highest capability.
     */
    public int getMainCapabilityPhoneId() {
        return RadioCapabilitySwitchUtil.getMainCapabilityPhoneId();
    }
複製代碼

 

創建ImsConfig,在setAdvanced4GMode()接口中,獲取ImsConfig對象:

            ImsConfig config = getConfigInterface();
            if (config != null) {
                config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
                        TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null);
            }

getConfigInterface()的實現:

複製代碼
    public ImsConfig getConfigInterface() throws ImsException {
        checkAndThrowExceptionIfServiceUnavailable();
        // M: Remove cache of ImsConfig in AOSP, always get ImsConfig with mainCapability Id 
        mConfig = getConfigInterface(mPhoneId, mImsService, mContext);
        return mConfig;
    }

    public static ImsConfig getConfigInterface(int phoneId, IImsService service, Context context) throws ImsException {
        ImsConfig config = null;

        try {
            if (service == null) { //獲取IMS服務
                IBinder b = ServiceManager.getService(getImsServiceName(phoneId));
                service = IImsService.Stub.asInterface(b); 
            }

            IImsConfig binder = service.getConfigInterface(phoneId); //調用ImsService的getConfigInterface()接口
            if (binder == null) {
                throw new ImsException("getConfigInterface()",
                            ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
            }

            config = new ImsConfig(binder, context); //初始化ImsConfig對象
        } catch (RemoteException e) {
            throw new ImsException("getConfigInterface()", e,
                ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
        }
        if (DBG) log("getConfigInterface(), config= " + config);
        return config;
複製代碼

 

根據PhoneID創建IImsConfig

根據Log打印信息,獲取Main Phone ID創建ImsConfig配置文件:

 

該接口ImsService.java中定義:
vendor/mediatek/proprietary/packages/services/ims/src/com/mediatek/ims/ImsService.java

複製代碼
  //Config interface to get/set IMS service/capability parameters.
    public IImsConfig getConfigInterface(int phoneId) {
        // Always get main capability phone Id for ImsConfig
        phoneId = getMainCapabilityPhoneId();
        Rlog.w(LOG_TAG, "Get config interface on main capability phone " + phoneId);

        IImsConfig instance = null;
        Rlog.w(LOG_TAG, "getConfigInterface phone " + phoneId);
        synchronized (mImsConfigInstanceMap) {
            if (mImsConfigInstanceMap.containsKey(phoneId)) {
                instance = mImsConfigInstanceMap.get(phoneId);
            } else {
                instance = new ImsConfigImpl(mContext, mImsRILAdapter, phoneId);
                mImsConfigInstanceMap.put(phoneId, instance);
            }
        }
        return instance;
複製代碼

IImsConfig是一個接口類,定義:
frameworks/base/telephony/java/com/android/ims/internal/IImsConfig.aidl
該類由ImsConfigImpl類繼承,實現其接口函數;

 

初始化ImsConfig對象,ImsConfigImpl對象的初始化後,傳給ImsConfig類的構造函數,創建ImsConfig:

frameworks/opt/net/ims/src/java/com/android/ims/ImsConfig.java

    public ImsConfig(IImsConfig iconfig, Context context) {
        if (DBG) Rlog.d(TAG, "ImsConfig creates");
        miConfig = iconfig; //IImsConfig對象由ImsConfigImpl初始化完成
        mContext = context;
    }

 

設置FeatureValue,在setAdvanced4GMode()接口中,設置FeatureValue,調用ImsConfig接口:

複製代碼
            if (config != null) {
                config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE,
                        TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null);
            }

    /**
     * Sets the value for IMS feature item for specified network type.
     *
     * @param feature, as defined in FeatureConstants.
     * @param network, as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
     * @param value, as defined in FeatureValueConstants.
     * @param listener, provided if caller needs to be notified for set result.
     * @return void
     *
     * @throws ImsException if calling the IMS service results in an error.
     */
    public void setFeatureValue(int feature, int network, int value,
            ImsConfigListener listener) throws ImsException {
        if (DBG) {
            Rlog.d(TAG, "setFeatureValue: feature = " + feature + ", network =" + network +
                    ", value =" + value + ", listener =" + listener);
        }
        try {
            miConfig.setFeatureValue(feature, network, value, listener);
        } catch (RemoteException e) {
            throw new ImsException("setFeatureValue()", e,
                    ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
        }
    }
複製代碼

miConfig是IImsConfig接口類對象,其setFeatureValue()方法在ImsConfigImpl類中實現;

ImsConfigImpl類setFeatureValue()方法的實現:

複製代碼
    public void setFeatureValue(int feature, int network, int value, ImsConfigListener listener) {
        try {
            try {
                if (DEBUG) Log.d(TAG, "setFeatureValue(" +
                      feature + ", " + network + ", " + value + ") on phone " + mPhoneId +
                      " from pid " + Binder.getCallingPid() + ", uid " + Binder.getCallingUid() +
                      ", listener " + listener);
                mStorage.setFeatureValue(feature, network, value); //ImsConfigStorage存儲變量信息

                    case ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE:
                        int oldVoLTEValue = SystemProperties.getInt(PROPERTY_VOLTE_ENALBE, 0);                        
                        int wfcEnable = SystemProperties.getInt(PROPERTY_WFC_ENALBE, 0);
                        if (value != oldVoLTEValue) {
                            if (value == ImsConfig.FeatureValueConstants.ON) {
                                SystemProperties.set(PROPERTY_VOLTE_ENALBE,"1");//根據參數設置變量                                 
                                //mRilAdapter.turnOnVolte(null);
                                if (wfcEnable == 0){
                                    //mRilAdapter.turnOnImsVoice(null);
                                }
                            } else {
                                SystemProperties.set(PROPERTY_VOLTE_ENALBE,"0");
                                //mRilAdapter.turnOffVolte(null);
                                if (wfcEnable == 0){
                                    //mRilAdapter.turnOffImsVoice(null);
                                }
                            }
                        }
                        break;
複製代碼

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章