Android运营商名称的显示规则
来源:互联网 发布:上海汇纳网络信息科技 编辑:程序博客网 时间:2024/05/21 11:15
在安卓的开发中经常会遇到与运营商相关Issue,运营商的名称会在多个地方显示,比如:锁屏界面、通知栏、快捷栏、状态栏、SIM卡管理、短信等地方显示。但这些名称又不尽数相同,读取的地方也不同。为了更好解决相关的Issue,我们需要知道这些名字来自哪里,又什么样的显示规则?!
一、在MTK的Android 方案中,3GPP TS 51.011 规定的显示规则如下:
1、运营商名字分为 SPN 和 Registered plmn(包括EONS, CPHS (即ONS), S-CPHS, NITZ, PLMN;优先级依次降低)
2、如果没有SPN文件,那么就显示Registered plmn
3. 若有SPN,注册的plmn是HPLMN或者注册的plmn在SIM卡文件EF_SPDI中,那么:
(1) 如果有SPN就要显示SPN
(2) 如果SPN的bit1 = 1, 则需要同时显示Registered plmn,如果SPN的bit1=0,则不需要同时显示Registered plmn
4. 若有SPN,注册的plmn是Roaming plmn且注册的plmn也不在SIM卡文件EF_SPDI中,那么:
(1) 显示Registered plmn
(2) 如果SPN的bit2=0,则需要同时显示SPN,如果SPN的bit2=1,则不需要同时显示SPN
流程图标如下:
上图中的PLMN的取值如下:
其中客户可以客制化的部分是Spn-conf.xml/Virtual-spn-conf-by-***.xml;换句话说,如果你修改了相关xml
没有生效,应该是按照spec显示了更高优先级的名字(EONS, CPHS, NITZ…)
因此,我们修改运营商名字多数是修改下面的文件:
A、vendor/mediatek/proprietary/frameworks/base/telephony/etc/virtual-spn-conf-by-efpnn.xml
B、vendor/mediatek/proprietary/frameworks/base/telephony/etc/virtual-spn-conf-by-imsi.xml
C、vendor/mediatek/proprietary/frameworks/base/telephony/etc/virtual-spn-conf-by-efgid1.xml
D、vendor/mediatek/proprietary/frameworks/base/telephony/etc/virtual-spn-conf-by-efspn.xml
E、device/mediatek/common/spn-conf.xml
二、具体的代码流程
既然知道了规则以及流程,那么下面通过代码来看具体的内容:
1、在GsmServiceStateTracker.java中,接收到EVENT_SIM_RECORDS_LOADED消息或者ACTION_LOCALE_CHANGED广播后,就会触发SPN的更新显示机制。其入口为updateSpnDisplay():
接收ACTION_LOCALE_CHANGED 广播:
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { ...... if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) { updateSpnDisplay(); } ......}
接收EVENT_SIM_RECORDS_LOADED 消息:
public void handleMessage (Message msg) {....... switch (msg.what) { case EVENT_SIM_RECORDS_LOADED: // Gsm doesn't support OTASP so its not needed mPhone.notifyOtaspChanged(OTASP_NOT_NEEDED); updatePhoneObject(); ////updateSpnDisplay(); // pollState() result may be faster than load EF complete, so // update ss.alphaLongShortName refreshSpnDisplay();//刷新SPN 列表,这里会跳转到updateSpnDisplay(); ///M: SVLTE signal strength support.@{ notifyServiceStateChanged(); ///M: SVLTE signal strength support.@} break; }}更新SPN的入口函数updateSpnDisplay():
protected void updateSpnDisplay() { updateSpnDisplay(false); }
protected void updateSpnDisplay(boolean forceUpdate) { SIMRecords simRecords = null; IccRecords r = mPhone.mIccRecords.get(); if (r != null) { simRecords = (SIMRecords) r; } int rule = (simRecords != null) ? simRecords.getDisplayRule( mSS.getOperatorNumeric()) : SIMRecords.SPN_RULE_SHOW_PLMN; String strNumPlmn = mSS.getOperatorNumeric(); String spn = (simRecords != null) ? simRecords.getServiceProviderName() : ""; String sEons = null; boolean showPlmn = false; String plmn = null; String realPlmn = null; String mSimOperatorNumeric = (simRecords != null) ? simRecords.getOperatorNumeric() : ""; sEons = (simRecords != null) ? simRecords.getEonsIfExist(mSS.getOperatorNumeric(), mCellLoc.getLac(), true) : null; if (sEons != null) { plmn = sEons; } else if (strNumPlmn != null && strNumPlmn.equals(mSimOperatorNumeric)) { plmn = (simRecords != null) ? simRecords.getSIMCPHSOns() : ""; } if (plmn == null || plmn.equals("")) { plmn = mSS.getOperatorAlphaLong(); if (plmn == null || plmn.equals(mSS.getOperatorNumeric())) { plmn = mSS.getOperatorAlphaShort(); } } realPlmn = plmn; if ((mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE) && (mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE)) {//当前无网络 showPlmn = true; plmn = Resources.getSystem(). getText(com.android.internal.R.string.lockscreen_carrier_default).toString(); } if (mVoiceCapable && mEmergencyOnly && mCi.getRadioState().isOn() && (mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE)) { //当前无网络,显示紧急号码 showPlmn = true; plmn = Resources.getSystem().getText( com.android.internal.R.string.emergency_calls_only).toString(); } ...... //这其中有Imei 号异常的判断,数据服务的判断...... if ((mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) || (mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE)) {//当前注册网络OK showPlmn = !TextUtils.isEmpty(plmn) && ((rule & SIMRecords.SPN_RULE_SHOW_PLMN) == SIMRecords.SPN_RULE_SHOW_PLMN); } // Update SPN_STRINGS_UPDATED_ACTION IFF any value changes if (mSubId != subId || showPlmn != mCurShowPlmn || showSpn != mCurShowSpn || !TextUtils.equals(spn, mCurSpn) || !TextUtils.equals(dataSpn, mCurDataSpn) || !TextUtils.equals(plmn, mCurPlmn) || forceUpdate) { //发送Intent通知 Intent intent = new Intent(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION); // For multiple SIM support, share the same intent, do not replace the other one if (TelephonyManager.getDefault().getPhoneCount() == 1) { intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); } intent.putExtra(TelephonyIntents.EXTRA_SHOW_SPN, showSpn); intent.putExtra(TelephonyIntents.EXTRA_SPN, spn); intent.putExtra(TelephonyIntents.EXTRA_DATA_SPN, dataSpn); intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn); intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn); //M: Femtocell (CSG) info intent.putExtra(TelephonyIntents.EXTRA_HNB_NAME, mHhbName); intent.putExtra(TelephonyIntents.EXTRA_CSG_ID, mCsgId); intent.putExtra(TelephonyIntents.EXTRA_DOMAIN, mFemtocellDomain); if (isInSvlteMode()) { //use cdma phone id to send intent log("use SvlteSST phone id:" + mSvlteSST.getPhoneId()); SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mSvlteSST.getPhoneId()); } else { SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); } mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL); int phoneId = mPhone.getPhoneId(); int slotId = SvlteUtils.getSlotId(phoneId); boolean setResult = mSubscriptionController.setPlmnSpn(slotId, showPlmn, plmn, showSpn, spn); if (isInSvlteMode() && mSvlteSST != null) { mSvlteSST.setUpdateSvlteSpnSstType(SST_TYPE); } if (!setResult) { mSpnUpdatePending = true; } } if ((showSpn == true) && (showPlmn == false) && (spn != null)) { mSS.setOperatorAlphaLong(spn); updateOperatorAlpha(spn); } else { mSS.setOperatorAlphaLong(realPlmn); updateOperatorAlpha(realPlmn); } mSubId = subId; mCurShowSpn = showSpn; mCurShowPlmn = showPlmn; mCurSpn = spn; mCurDataSpn = dataSpn; mCurPlmn = plmn; }
String spn = (simRecords != null) ? simRecords.getServiceProviderName() : "";上面的更新过程分为两步,分别完成SPN的读取和广播的发送,我们主要来看读取SPN的过程。
在读取过程中,先对当前的网络状态进行分类:
1、如果当前网络处于无服务状态或者mEmergencyOnly状态,则分别显示“No service”和“Emergency calls only”字串。
2、对于当前网络注册成功的情况(STATE_IN_SERVICE),则根据3GPP协议来确定当前显示的PLMN显示规则。
我们主要关注第二种情况下显示规则的确认。
我们先来看一下显示的rule,他是通过以下调用来定义的:
int rule = (simRecords != null) ? simRecords.getDisplayRule( mSS.getOperatorNumeric()) : SIMRecords.SPN_RULE_SHOW_PLMN;也就时说,这里的rule是通过SIMRecords的getDisplayRule()方法得到的:
@SIMRecords.java public int getDisplayRule(String plmn) { int rule; boolean bSpnActive = false; String spn = getServiceProviderName(); if (mEfSST != null && mParentApp != null) { if (mParentApp.getType() == AppType.APPTYPE_USIM) { if (mEfSST.length >= 3 && (mEfSST[2] & 0x04) == 4) { bSpnActive = true; } } else if ((mEfSST.length >= 5) && (mEfSST[4] & 0x02) == 2) { bSpnActive = true; } } if (mParentApp != null && mParentApp.getUiccCard() != null && mParentApp.getUiccCard().getOperatorBrandOverride() != null) { // If the operator has been overridden, treat it as the SPN file on the SIM did not exist. rule = SPN_RULE_SHOW_PLMN; } else if (!bSpnActive || TextUtils.isEmpty(spn) || spn.equals("") || mSpnDisplayCondition == -1) { // No EF_SPN content was found on the SIM, or not yet loaded. Just show ONS. 如果SPN为空,则显示PLMN(Rule 2) rule = SPN_RULE_SHOW_PLMN; } else if (isOnMatchingPlmn(plmn)) { rule = SPN_RULE_SHOW_SPN; if ((mSpnDisplayCondition & 0x01) == 0x01) { // ONS required when registered to HPLMN or PLMN in EF_SPDI//如果当前注册的PLMN为HPLMN或者注册的PLMN存在于SIM中的EF_SPDI字段内,则显示SPN(Rule 3.1) rule |= SPN_RULE_SHOW_PLMN; } } else {//如果注册的PLMN为Roaming PLMN,并且注册的PLMN不在EF_SPDI中,则显示PLMN(Rule 4.1) rule = SPN_RULE_SHOW_PLMN; if ((mSpnDisplayCondition & 0x02) == 0x00) { // SPN required if not registered to HPLMN or PLMN in EF_SPDI//如果注册的PLMN为Roaming PLMN,并且注册的PLMN不在EF_SPDI中,并且SPN的bit2=0,则要同时显示PLMN和SPN(Rule 4.2) rule |= SPN_RULE_SHOW_SPN; } } return rule; }
上面的过程刚好匹配3GPP对PLMN的显示规则,其中的mSpnDisplayCondition就是在SIMRecords获取到SPN时解析出来的data的bit1数据。当该方法结束时,返回出来了int类型的rule变量,该变量只有前两位bit有效,其中bit1=1代表显示SPN,bit2=1代表显示PLMN。
然后回到updateSpnDisplay()方法中,此时将会通过mSS.getOperatorAlphaLong()得到当前的PLMN值,以及通过rule得到当前是否需要显示PLMN(showPlmn),然后通过iccRecords.getServiceProviderName()得到当前的SPN以及通过rule得到当前是否需要显示SPN。
拿到上面的数据之后,就通过广播(SPN_STRINGS_UPDATED_ACTION)的形式通知其他模块SPN的变化。
关于PLMN 和SPN 的具体读取会在后面的文档中写出。
- Android运营商名称的显示规则
- 运营商名称显示规则
- Android运营商名称显示之PLMN与SPN显示规则
- Android运营商名称显示之PLMN与SPN显示规则
- Android运营商名字显示规则
- Android运营商名称显示之PLMN与SPN显示规则(原)
- Android运营商名称显示之PLMN的读取(原)
- Android运营商名称显示之SPN的读取(原)
- Android运营商名称显示之SPN的读取
- Android运营商名称显示之PLMN的读取
- Android运营商名称显示之PLMN的读取
- Android运营商名称显示之SPN的读取
- android 网络运营商名称显示规则(锁屏界面,下拉列表)
- Android运营商名称显示(原)
- 改运营商显示名称的详细教程
- 网络运营商名称显示&SIM名称显示
- 让你的iPhone运营商名称显示任意中文!
- 插入某电信卡运营商名称不显示的问题
- JavaBean、EJB、EntityBean的区别
- LabVIEW使用UDP组播发送数据
- bash执行多条命令
- Java并发编程规则:同步容器与并发容器
- 得到上一个页面地址
- Android运营商名称的显示规则
- 计算机
- 引用CSS文件到html网页里方法
- 树形结构 数据库表设计
- Linux git版本管理的使用/git教程
- linux 离线源制作(基本适用所有离线包安装)
- ModBus/TCP协议分析
- 用原生javascript封装ajax技术
- 浅析JavaScript数组逆序