CarrierConfigManager解析

最近做一个高通项目的移植,发现网络设置中的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

在Android系统中,根据SIM卡的移动国家代码(MCC)和移动网络代码(MNC)定制短信和通话设置是运营商配置(CarrierConfig)的一部分。通过使用CarrierConfigManager,开发者可以获取和管理这些特定的参数。例如,要设置短信文本长度超过特定阈值自动转为彩信的功能,可以按照以下步骤操作: 参考资源链接:[Android运营商配置详解:CarrierConfigManager与定制参数](https://wenku.youkuaiyun.com/doc/64545716fcc5391368099d29?spm=1055.2569.3001.10343) 首先,需要确认你的应用具有访问运营商配置的权限。然后,可以使用CarrierConfigManager获取特定的配置值。下面是一个简单的代码示例,展示如何实现这一功能: ```java // 获取CarrierConfigManager实例 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE); if (configManager != null) { // 使用SIM卡的MCC/MNC查询特定的配置 Bundle carrierConfig = configManager.getConfigForSubId(subscriptionId); if (carrierConfig != null) { // 获取短信转彩信的文本长度阈值 int smsToMmsLengthThreshold = carrierConfig.getInt(KEY_MMS_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD_INT, defaultValue); // 根据短信长度阈值进行判断和处理 if (smsText.length() >= smsToMmsLengthThreshold) { // 短信文本长度超过了阈值,执行彩信相关操作 convertSmsToMms(smsText); } else { // 短信文本长度在阈值之内,正常发送短信 sendSms(smsText); } } } ``` 在上述代码中,`KEY_MMS_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD_INT`是你需要根据实际配置项来替换的键值,`defaultValue`是当配置项不存在时使用的默认值,`convertSmsToMms`和`sendSms`是假设的函数,用于将短信转换为彩信或发送短信,具体实现依赖于你的应用逻辑。 通过这种方式,开发者可以根据不同的运营商配置进行程序的逻辑处理,从而提供更加个性化和优化的用户体验。更多关于Android运营商配置的详细信息和高级定制技巧,可以参考《Android运营商配置详解:CarrierConfigManager与定制参数》这一资源,它将为你提供全面的指南和深度的技术解析。 参考资源链接:[Android运营商配置详解:CarrierConfigManager与定制参数](https://wenku.youkuaiyun.com/doc/64545716fcc5391368099d29?spm=1055.2569.3001.10343)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值