您的位置:首页 > 移动开发 > Android开发

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

2016-02-17 20:06 621 查看
        前面的两节分别介绍了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():
@GsmServiceStateTracker.java
protected void updateSpnDisplay() {
IccRecords iccRecords = mIccRecords;
String plmn = null;
boolean showPlmn = false;
int rule = (iccRecords != null) ? iccRecords.getDisplayRule(mSS.getOperatorNumeric()) : 0;
if (mSS.getVoiceRegState() == ServiceState.STATE_OUT_OF_SERVICE || mSS.getVoiceRegState() == ServiceState.STATE_EMERGENCY_ONLY) {
//当前无网络
showPlmn = true;
if (mEmergencyOnly) {
// No service but emergency call allowed
plmn = Resources.getSystem().  getText(com.android.internal.R.string.emergency_calls_only).toString();
} else {
// No service at all
plmn = Resources.getSystem().  getText(com.android.internal.R.string.lockscreen_carrier_default).toString();
}
} else if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
//当前注册网络OK
plmn = mSS.getOperatorAlphaLong();
showPlmn = !TextUtils.isEmpty(plmn) && ((rule & SIMRecords.SPN_RULE_SHOW_PLMN) == SIMRecords.SPN_RULE_SHOW_PLMN);
} else {
if (DBG) log("updateSpnDisplay: radio is off w/ showPlmn=" + showPlmn + " plmn=" + plmn);
}

String spn = (iccRecords != null) ? iccRecords.getServiceProviderName() : "";
boolean showSpn = !TextUtils.isEmpty(spn)
&& ((rule & SIMRecords.SPN_RULE_SHOW_SPN)
== SIMRecords.SPN_RULE_SHOW_SPN);

//发送Intent通知
if (showPlmn != mCurShowPlmn
|| showSpn != mCurShowSpn
|| !TextUtils.equals(spn, mCurSpn)
|| !TextUtils.equals(plmn, mCurPlmn)) {
Intent intent = new Intent(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra(TelephonyIntents.EXTRA_SHOW_SPN, showSpn);
intent.putExtra(TelephonyIntents.EXTRA_SPN, spn);
intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn);
intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn);
mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}

mCurShowSpn = showSpn;
mCurShowPlmn = showPlmn;
mCurSpn = spn;
mCurPlmn = plmn;
}
        上面的更新过程分为两步,分别完成SPN的读取和广播的发送,我们主要来看读取SPN的过程。

        在读取过程中,先对当前的网络状态进行分类:
        1、如果当前网络处于STATE_OUT_OF_SERVICE或者STATE_EMERGENCY_ONLY状态,则分别显示“No service”和“Emergency calls only”字串。

        2、对于当前网络注册成功的情况(STATE_IN_SERVICE),则根据3GPP协议来确定当前显示的PLMN显示规则。


        我们主要关注第二种情况下显示规则的确认。

        我们先来看一下显示的rule,他是通过以下调用来定义的:
int rule = (iccRecords != null) ? iccRecords.getDisplayRule(mSS.getOperatorNumeric()) : 0;
        也就时说,这里的rule是通过SIMRecords的getDisplayRule()方法得到的:
@SIMRecords.java
public int getDisplayRule(String plmn) {
int rule;
if (TextUtils.isEmpty(mSpn) || mSpnDisplayCondition == -1) {
//如果SPN为空,则显示PLMN(Rule 2)
rule = SPN_RULE_SHOW_PLMN;
} else if (isOnMatchingPlmn(plmn)) {
//如果当前注册的PLMN为HPLMN或者注册的PLMN存在于SIM中的EF_SPDI字段内,则显示SPN(Rule 3.1)
rule = SPN_RULE_SHOW_SPN;
if ((mSpnDisplayCondition & 0x01) == 0x01) {
//如果SPN的bit1=1,则需要同时显示SPN和PLMN(Rule 3.2)
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) {
//如果注册的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的变化。

        这就是SPN的显示机制,以下是该机制的逻辑图:
        
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息