Android运营商名称显示之PLMN与SPN显示规则

  前面的两节分别介绍了 PLMNSPN的读取方法,那么在锁屏、状态栏、通知栏这些地方的运营商名称究竟是来自于PLMN呢?还是来自于SPN呢?
        在3GPP中规定的运营商名称显示规则如下:
        1、名称可以为SPN或PLMN
        2、如果没有SPN文件,那么就显示PLMN
        3、若有SPN,并且注册的PLMN是HPLMN或者注册的PLMN在SIM卡文件EF_SPDI中,那么:
            (1)如果有SPN就要显示SPN
            (2)如果SPN的bit1 = 1, 则需要同时显示PLMN,如果SPN的bit1=0,则不需要同时显示PLMN
        4、若有SPN,注册的PLMN是Roaming PLMN且注册的PLMN也不在SIM卡文件EF_SPDI中,那么
            (1)显示PLMN
            (2)如果SPN的bit2=0,则需要同时显示SPN,如果SPN的bit2=1,则不需要同时显示SPN

        下面我们用代码来梳理上面的规则。
        在GsmServiceStateTracker中,接收到EVENT_SIM_RECORDS_LOADED消息或者ACTION_LOCALE_CHANGED广播后,就会触发SPN的更新显示机制。其入口为updateSpnDisplay():
  1. @GsmServiceStateTracker.java  
  2. protected void updateSpnDisplay() {  
  3.     IccRecords iccRecords = mIccRecords;  
  4.     String plmn = null;  
  5.     boolean showPlmn = false;  
  6.     int rule = (iccRecords != null) ? iccRecords.getDisplayRule(mSS.getOperatorNumeric()) : 0;  
  7.     if (mSS.getVoiceRegState() == ServiceState.STATE_OUT_OF_SERVICE || mSS.getVoiceRegState() == ServiceState.STATE_EMERGENCY_ONLY) {  
  8.         //当前无网络  
  9.         showPlmn = true;  
  10.         if (mEmergencyOnly) {  
  11.             // No service but emergency call allowed  
  12.             plmn = Resources.getSystem().  getText(com.android.internal.R.string.emergency_calls_only).toString();  
  13.         } else {  
  14.             // No service at all  
  15.             plmn = Resources.getSystem().  getText(com.android.internal.R.string.lockscreen_carrier_default).toString();  
  16.         }  
  17.     } else if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {  
  18.         //当前注册网络OK  
  19.         plmn = mSS.getOperatorAlphaLong();  
  20.         showPlmn = !TextUtils.isEmpty(plmn) && ((rule & SIMRecords.SPN_RULE_SHOW_PLMN) == SIMRecords.SPN_RULE_SHOW_PLMN);  
  21.     } else {  
  22.         if (DBG) log("updateSpnDisplay: radio is off w/ showPlmn=" + showPlmn + " plmn=" + plmn);  
  23.     }  
  24.   
  25.   
  26.     String spn = (iccRecords != null) ? iccRecords.getServiceProviderName() : "";  
  27.     boolean showSpn = !TextUtils.isEmpty(spn)  
  28.         && ((rule & SIMRecords.SPN_RULE_SHOW_SPN)  
  29.                 == SIMRecords.SPN_RULE_SHOW_SPN);  
  30.   
  31.   
  32.     //发送Intent通知  
  33.     if (showPlmn != mCurShowPlmn  
  34.             || showSpn != mCurShowSpn  
  35.             || !TextUtils.equals(spn, mCurSpn)  
  36.             || !TextUtils.equals(plmn, mCurPlmn)) {  
  37.         Intent intent = new Intent(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);  
  38.         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);  
  39.         intent.putExtra(TelephonyIntents.EXTRA_SHOW_SPN, showSpn);  
  40.         intent.putExtra(TelephonyIntents.EXTRA_SPN, spn);  
  41.         intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn);  
  42.         intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn);  
  43.         mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);  
  44.     }  
  45.   
  46.   
  47.     mCurShowSpn = showSpn;  
  48.     mCurShowPlmn = showPlmn;  
  49.     mCurSpn = spn;  
  50.     mCurPlmn = plmn;  
  51. }  
        上面的更新过程分为两步,分别完成SPN的读取和广播的发送,我们主要来看读取SPN的过程。
        在读取过程中,先对当前的网络状态进行分类:
        1、如果当前网络处于STATE_OUT_OF_SERVICE或者STATE_EMERGENCY_ONLY状态,则分别显示“No service”和“Emergency calls only”字串。
        2、对于当前网络注册成功的情况(STATE_IN_SERVICE),则根据3GPP协议来确定当前显示的PLMN显示规则。

        我们主要关注第二种情况下显示规则的确认。
        我们先来看一下显示的rule,他是通过以下调用来定义的:
  1. int rule = (iccRecords != null) ? iccRecords.getDisplayRule(mSS.getOperatorNumeric()) : 0;  
        也就时说,这里的rule是通过SIMRecords的getDisplayRule()方法得到的:
  1. @SIMRecords.java  
  2. public int getDisplayRule(String plmn) {  
  3.     int rule;  
  4.     if (TextUtils.isEmpty(mSpn) || mSpnDisplayCondition == -1) {  
  5.         //如果SPN为空,则显示PLMN(Rule 2)  
  6.         rule = SPN_RULE_SHOW_PLMN;  
  7.     } else if (isOnMatchingPlmn(plmn)) {  
  8.         //如果当前注册的PLMN为HPLMN或者注册的PLMN存在于SIM中的EF_SPDI字段内,则显示SPN(Rule 3.1)  
  9.         rule = SPN_RULE_SHOW_SPN;  
  10.         if ((mSpnDisplayCondition & 0x01) == 0x01) {  
  11.             //如果SPN的bit1=1,则需要同时显示SPN和PLMN(Rule 3.2)  
  12.             rule |= SPN_RULE_SHOW_PLMN;  
  13.         }  
  14.     } else {  
  15.         //如果注册的PLMN为Roaming PLMN,并且注册的PLMN不在EF_SPDI中,则显示PLMN(Rule 4.1)  
  16.         rule = SPN_RULE_SHOW_PLMN;  
  17.         if ((mSpnDisplayCondition & 0x02) == 0x00) {  
  18.             //如果注册的PLMN为Roaming PLMN,并且注册的PLMN不在EF_SPDI中,并且SPN的bit2=0,则要同时显示PLMN和SPN(Rule 4.2)  
  19.             rule |= SPN_RULE_SHOW_SPN;  
  20.         }  
  21.     }  
  22.     return rule;  
  23. }  
        上面的过程刚好匹配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的变化。
        这就是SPN的显示机制,以下是该机制的逻辑图:
        




  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值