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 的具体读取会在后面的文档中写出。



0 0
原创粉丝点击