Part1
高通平台双卡网络模式通常是卡槽1支持4、3、2G网络,卡槽2一般会默认写为固定,在之前的android L及L以下,msm8909、msm8916平台上基本设置为GSM only,因为需求是在msm8996的android M的,所以指定平台分析下大概走一下设置流程。
从网络设置app(NetworkSetting)界面来开始定位,package/service/Telephony下的MobileNetworkSettings.java
设置网络模式的菜单是ListPreference
private ListPreference mButtonPreferredNetworkMode;
点击该Preference对应的是网络模式对应的array数组,安卓原生会把所有的网络模式都显示出来,适合调试阶段找问题,但是这样不符合市场上机型的好的界面交互.
给用户呈现的应该是上文提到的4/3/2G的网络模式菜单选择
setScreenState() 方法下通过运营商获取mccmnc来分别定制相应的网络模式菜单
先判断一下sim卡的状态
int simState = TelephonyManager.getDefault().getSimState(mPhone.getPhoneId());
getPreferenceScreen().setEnabled(simState != TelephonyManager.SIM_STATE_ABSENT);
以下以国内电信网络模式为例,
setEntries()设置网络模式字符串,setEntryValues设置网络模式对应的数值
if((mccmnc.equals("46003")||mccmnc.equals("46005")||mccmnc.equals("46011"))) {
mButtonPreferredNetworkMode.setEntries(
R.array.preferred_network_mode_choices_FQ1_CT);
mButtonPreferredNetworkMode.setEntryValues(
R.array.preferred_network_mode_values_FQ1_CT);
if(subController.getDefaultDataSubId()==subId) {
//判断当前的subId是否为走数据的Sub,通常情况下,只让终端用户手动选择数据卡的网络模式
if ((getPreferredNetworkModeForSubId()!= 22)) {
if (getPreferredNetworkModeForSubId()== 4) {
setPreferredNetworkMode(4);
}else
setPreferredNetworkMode(22);
}
} else if(subController.getDefaultDataSubId()!=subId){
if((prefSet != null)) {
//非数据卡,直接移除网络模式设置preference
prefSet.removePreference(mButtonPreferredNetworkMode);
}
}
另外,高通andriod M上在PhoneFeature app上直接固定了卡槽二的网络模式,更准确的说是在M之前,一直都是在以下位置把卡槽2默认设置为GSM
vendor\qcom\proprietary\qrdplus\Extension\apps\PhoneFeatures\src\com\qualcomm\qti\phonefeature\PrefNetworkRequest.java
public PrefNetworkRequest(Context context, int slot, int networkMode, Message callback) {
super(sSyncQueue);
mContext = context;
mCallback = callback;
commands = new ArrayList<PrefNetworkSetCommand>();
//屏蔽下面的代码,移除固定卡槽2的网络模式设置
/*if (networkMode != Phone.NT_MODE_GSM_ONLY) {
for (int index = 0; index < Constants.PHONE_COUNT; index++) {
if (index != slot)
commands.add(new PrefNetworkSetCommand(index, Phone.NT_MODE_GSM_ONLY));
}
}*/
if (slot >= 0 && slot < Constants.PHONE_COUNT) {
commands.add(new PrefNetworkSetCommand(slot, networkMode));
}
}
而android N之后,默认网络模式有小小的改动
frameworks\base\packages\SettingsProvider\src\com\android\providers\settings\DatabaseHelper.java
for (int phoneId = 0; phoneId < phoneCount; phoneId++) {
mode = TelephonyManager.getTelephonyProperty(phoneId,
"ro.telephony.default_network",
Integer.toString(RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA)
if (phoneId == 0) {
val = mode;
} else {
val = val + "," + mode;
}
}
Part2
Part1描述的内容总结起来主要是干了两件事
1.针对不同的运营商,化繁为简,优化网络模式菜单
2.解除了卡槽2不能设置任意网络模式的限制
我们最终的目标肯定是直接就能设置好网络模式,并且作为支持热插拔的手机设备,更是要找到检测到sim的状态后,就需要设置好相应的网络模式,保证不同sim卡能准确匹配网络.
然后小提一下Modem端的NV10,这是个网络模式的NV,通过QXDM读取该NV,可以获取当前所有subId的网络模式,上层设置网络模式,实际就是对NV10做修改,另外在之前VoLte的普及度没那么高的前提下,由于CDMA在硬件上只支持单通道,所以对于电信卡的卡槽,就得及时匹配网络,否则就会出现下面的状态:
1.电信卡未注册上4G网络,那么界面显示空信号格,因为没有CDMA的网络模式被分配到电信卡的卡槽
2.电信卡注册上4G网络,一旦打电话,电信的通话需要回落到CDMA,而没有匹配的网络模式,直接导致无法呼出或被呼入
通过每次插拔卡的radio log定位到sim卡检测相关的class
frameworks\opt\telephony\src\java\com\android\internal\telephony\SubscriptionInfoUpdater.java
此处不要以mccmnc去做不同运营商来区分,最好iccid去做判断
handle处理sim卡加载后的,两个卡槽的网络模式分配,重点关注方法
private void handleSimLoaded(int slotId) {
此处就是把2个卡槽做固定判断处理,以slotId为变量参数,
尤其是电信卡
int SubId = sirInfo.getSubscriptionId();
int SlotId = mSubscriptionManager.getSlotId(SubId);
int nwmode = RILConstants.PREFERRED_NETWORK_MODE;
try {
nwmode = android.provider.Settings.Global.getInt(
mPhone[SlotId].getContext().getContentResolver(),
Settings.Global.PREFERRED_NETWORK_MODE + SubId);
} catch (SettingNotFoundException snfe) {
}
try {
nwmode = TelephonyManager.getIntAtIndex(
mContext.getContentResolver(),
Settings.Global.PREFERRED_NETWORK_MODE, slotId);
} catch (SettingNotFoundException retrySnfe) {
Rlog.e(LOG_TAG, "Settings Exception Reading Value At Index for"+
" Settings.Global.PREFERRED_NETWORK_MODE");
}
}
}
以上读取默认的网络模式,下面以电信卡在卡槽1和移动卡在卡槽2卡作为例子,设置slotId的网络模式
isCTCard就是去判断下当前的iccid是不是电信卡的iccid
if(isCTCard(0)&&(!isCTCard(1))) {
logd("nw ******sim1 is CT card******");
if (slotId == 1) {
if (nwmode == 16) {
mPhone[1].setPreferredNetworkType(16, null);
Settings.Global.putInt(mPhone[1].getContext().getContentResolver(),
Settings.Global.PREFERRED_NETWORK_MODE + SubId,
16);
logd(" nw "+" 111 CMCC card 3G mode, only sim1 is CT card 3G mode nwmode = "+ nwmode);
} if (nwmode == 3) {
mPhone[1].setPreferredNetworkType(3, null);
Settings.Global.putInt(mPhone[1].getContext().getContentResolver(),
Settings.Global.PREFERRED_NETWORK_MODE + SubId,
3);
logd(" nw "+" 111 CU card 3G mode, only sim1 is CT card 3G mode nwmode = "+ nwmode);
} if (nwmode == 20) {
mPhone[1].setPreferredNetworkType(20, null);
Settings.Global.putInt(mPhone[1].getContext().getContentResolver(),
Settings.Global.PREFERRED_NETWORK_MODE + SubId,
20);
logd(" nw "+" 111 if equals 20 set 20");
} if (nwmode == 1) {
mPhone[1].setPreferredNetworkType(1, null);
Settings.Global.putInt(mPhone[1].getContext().getContentResolver(),
Settings.Global.PREFERRED_NETWORK_MODE + SubId,
1);
logd(" nw "+" 111 if equals 1 set 1");
}
else if ((nwmode != 20)&&(nwmode != 16)&&(nwmode != 3)&&(nwmode != 1)) {
mPhone[1].setPreferredNetworkType(20, null);
Settings.Global.putInt(mPhone[1].getContext().getContentResolver(),
Settings.Global.PREFERRED_NETWORK_MODE + SubId,
20);
logd(" dhflogsw "+" 111 normal mode only sim1 is CT card nwmode = "+ nwmode);
}
}
if (slotId == 0) {
if (nwmode == 4) {
mPhone[0].setPreferredNetworkType(4, null);
Settings.Global.putInt(mPhone[0].getContext().getContentResolver(),
Settings.Global.PREFERRED_NETWORK_MODE + SubId,
4);
logd(" nw "+" 111 only sim1 is CT card 3G mode ");
} else {
mPhone[0].setPreferredNetworkType(22, null);
Settings.Global.putInt(mPhone[0].getContext().getContentResolver(),
Settings.Global.PREFERRED_NETWORK_MODE + SubId,
22);
logd(" nw "+" 111 only sim1 is CT card LTE mode ");
}
}
关于sim卡的检测
当手机重启或者检测到sim卡状态改变时,RIL会发起sim卡信息的查询,将读到的信息写入数据库,保存至subscriptionManager
这部分引用FamilyYuan的blog,链接https://blog.csdn.net/myfriend0/article/details/79364548,感谢.
另外,这部分内容是两三年前改过的东西,最近觉得有必要写出来梳理一下,如有不正确的地方,请指正.