最近做一个高通项目的移植,发现网络设置中的cdma和gsm设置项目是同时出现的,之前mtk的项目也是遇到过同样的问题。修改起来很简单,不过要探究根源还是小费力气的。packages/services/Telephony/src/com/android/phone/MobileNetworkSettings.java
private void updateBody() {
...
PersistableBundle carrierConfig =
PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
...
} else if (carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL) == true) {
prefSet.removePreference(mButtonEnabledNetworks);
// set the listener for the mButtonPreferredNetworkMode list preference so we can issue
// change Preferred Network Mode.
mButtonPreferredNetworkMode.setOnPreferenceChangeListener(this);
mCdmaOptions = new CdmaOptions(this, prefSet, mPhone);
mGsmUmtsOptions = new GsmUmtsOptions(this, prefSet, phoneSubId);
...
发现走到了CarrierConfigManager.KEY_WORLD_PHONE_BOOL的分支,所以两个设置项全部会显示。
packages/services/Telephony/src/com/android/phone/PhoneGlobals.java
public PersistableBundle getCarrierConfigForSubId(int subId) {
return configLoader.getConfigForSubId(subId);
}
PhoneGlobals只是简单跳转,真正工作在packages/services/Telephony/src/com/android/phone/CarrierConfigLoader.java
@Override public
@NonNull
PersistableBundle getConfigForSubId(int subId) {
try {
mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, null);
// SKIP checking run-time READ_PHONE_STATE since using PRIVILEGED
} catch (SecurityException e) {
mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, null);
}
int phoneId = SubscriptionManager.getPhoneId(subId);
PersistableBundle retConfig = CarrierConfigManager.getDefaultConfig(); //获取初始设置
if (SubscriptionManager.isValidPhoneId(phoneId)) {
PersistableBundle config = mConfigFromDefaultApp[phoneId]; //从默认app获取设置
if (config != null)
retConfig.putAll(config);
config = mConfigFromCarrierApp[phoneId]; //从其它app获取设置
if (config != null)
retConfig.putAll(config);
}
return retConfig;
}
可见设置值的来源有三处
1.初始设置
frameworks/base/telephony/java/android/telephony/CarrierConfigManager.java
public static PersistableBundle getDefaultConfig() {
return new PersistableBundle(sDefaults);
}
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
static {
sDefaults = new PersistableBundle();
sDefaults.putBoolean(KEY_ADDITIONAL_CALL_SETTING_BOOL, true);
sDefaults.putBoolean(KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL, false);
sDefaults.putBoolean(KEY_ALLOW_LOCAL_DTMF_TONES_BOOL, true);
...
}
是在代码中静态初始化的
2.默认app
packages/apps/CarrierConfig
首先看AndroidManifest.xml
<service android:name=".DefaultCarrierConfigService"
android:permission="android.permission.BIND_CARRIER_SERVICES">
<intent-filter>
<action android:name="android.service.carrier.CarrierService" />
</intent-filter>
</service>
这个apk的核心就是一个服务,action是android.service.carrier.CarrierService,实现该action的apk都可以作为设置来源。该apk也只有一个java文件
packages/apps/CarrierConfig/src/com/android/carrierconfig/DefaultCarrierConfigService.java
读取配置的核心代码如下
public PersistableBundle onLoadConfig(CarrierIdentifier id) {
...
PersistableBundle config = null;
try {
synchronized (this) {
if (mFactory == null) {
mFactory = XmlPullParserFactory.newInstance();
}
}
XmlPullParser parser = mFactory.newPullParser();
String fileName = "carrier_config_" + id.getMcc() + id.getMnc() + ".xml"; //从asets中读取配置
parser.setInput(getApplicationContext().getAssets().open(fileName), "utf-8");
config = readConfigFromXml(parser, id);
}
catch (IOException | XmlPullParserException e) {
Log.d(TAG, e.toString());
// We can return an empty config for unknown networks.
config = new PersistableBundle();
}
// Treat vendor.xml as if it were appended to the carrier config file we read.
XmlPullParser vendorInput = getApplicationContext().getResources().getXml(R.xml.vendor); //从vendor.xml读取配置
try {
PersistableBundle vendorConfig = readConfigFromXml(vendorInput, id);
config.putAll(vendorConfig);
}
catch (IOException | XmlPullParserException e) {
Log.e(TAG, e.toString());
}
return config;
}
分为两步,一是从assets目录依据mcc和mnc读取xml配置,例如中国移动的
packages/apps/CarrierConfig/assets/carrier_config_46000.xml
<carrier_config_list>
<carrier_config>
<boolean name="carrier_volte_available_bool" value="true" />
<boolean name="hide_network_settings_bool" value="true" />
</carrier_config>
</carrier_config_list>
其中之配置了两个项目。
二是从res中的vendor.xml读取,这个xml默认代码是空的。
3.其它app
private String getCarrierPackageForPhoneId(int phoneId) {
List<String> carrierPackageNames = TelephonyManager.from(mContext)
.getCarrierPackageNamesForIntentAndPhone(
new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), phoneId);
if (carrierPackageNames != null && carrierPackageNames.size() > 0) {
loge("carrierPackageNames = " + carrierPackageNames.get(0));
return carrierPackageNames.get(0);
} else {
return null;
}
}
public static final String CARRIER_SERVICE_INTERFACE = "android.service.carrier.CarrierService";
其中可以看出匹配action为android.service.carrier.CarrierService的apk就可以作为配置来源,这个就要厂商自己实现了,默认代码是没有的。
其中CarrierConfigManager.KEY_WORLD_PHONE_BOOL在初始配置中就是为true的,app没有配置。
————————————————
版权声明:本文为优快云博主「李光宇」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/firedancer0089/article/details/76687482