開關按鈕位置:
設置--> 更多--> 移動網絡--> 增強型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;