SystemUI如何获得SIM卡相关的mcc/mnc值

SystemUI获得SIM卡相关的mcc/mnc值,分两种情况讨论

1. 存储在SIM卡中的mcc/mnc

这个值是存储在SIM卡IMSI(国际移动用户识别码 International Mobile Subscriber Identification Number)中的固定值,不会被更改。有以下两种途径可以取得。

1.1 通过TelephonyManager获得

在TelephonyManager中有如下方法:

//TelephonyManager.java

    /**
     * Returns the MCC+MNC (mobile country code + mobile network code) of the
     * provider of the SIM for a particular subscription. 5 or 6 decimal digits.
     * 

* Availability: SIM state must be {@link #SIM_STATE_READY} * * @see #getSimState * * @param subId for which SimOperator is returned * @hide */ public String getSimOperatorNumeric(int subId) { int phoneId = SubscriptionManager.getPhoneId(subId); return getSimOperatorNumericForPhone(phoneId); } /** * Returns the MCC+MNC (mobile country code + mobile network code) of the * provider of the SIM for a particular subscription. 5 or 6 decimal digits. *

* * @param phoneId for which SimOperator is returned * @hide */ public String getSimOperatorNumericForPhone(int phoneId) { return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, ""); }

↓↓↓

  • 由于subId并不固定,是根据放进sim卡槽时候的计数来统计的,但是如果相关类中有SubscriptionInfo对象的话,是可以直接取到的:
     int subId = mSubscriptionInfo.getSubscriptionId();
    
  • 另一种phoneId则比较简单了,它与sim卡数量有关,单卡时为0,双卡时根据sim slot位置分别取0和1。

1.2 通过SubscriptionInfo获得

在有些特殊情况下,比如SIM卡处于PIN码LOCK状态时,1.1所提到的方法是取不到的,这个时候只能通过SubscriptionInfo来取。

// SubscriptionInfo.java

    /**
     * @return the MCC.
     */
    public int getMcc() {
        return this.mMcc;
    }

    /**
     * @return the MNC.
     */
    public int getMnc() {
        return this.mMnc;
    }

注意,由于这个方法取到的mcc/mnc均为int值,比如中国联通的“46001”,则有mcc为“460”,mnc为“1”,与固定String字符串进行匹配比对的话,需要先将String拆分为两部分后分别强转成int型后才可进行比对。

2. SIM卡注册网络的mcc/mnc

非漫游情况下,注册网络的mcc/mnc就是SIM卡中存储的。但是如果你的SIM卡在其他国家并没有该运营商的基站,只能通过漫游到其他运营商的网络上维持服务时,注册网络的mcc/mnc对应的就是该运营商的值,与SIM卡无关了。

2.1 通过ServiceState获得

熟悉Android Telephony流程的朋友应该都知道,CS、PS域的注册状态,漫游状态,运营商名字的显示,网络模式等都是用模板类ServiceState.java来保存的。
SystemUI中有不少类都注册了PhoneStateListener这个callback,用来时刻关注设备的一些telephony相关状态,当网络服务状态有变化时,会回调其onServiceStateChanged(ServiceState serviceState)方法,这样我们就可以直接从ServiceState里面取了。

// ServiceState.java

    /**
     * Get current registered operator numeric id.
     *
     * In GSM/UMTS, numeric format is 3 digit country code plus 2 or 3 digit
     * network code.
     *
     * @return numeric format of operator, null if unregistered or unknown
     */
    /*
     * The country code can be decoded using
     * {@link com.android.internal.telephony.MccTable#countryCodeForMcc(int)}.
     */
    public String getOperatorNumeric() {
        return mVoiceOperatorNumeric;
    }

    /**
     * Get current registered voice network operator numeric id.
     * @return numeric format of operator, null if unregistered or unknown
     * @hide
     */
    public String getVoiceOperatorNumeric() {
        return mVoiceOperatorNumeric;
    }

    /**
     * Get current registered data network operator numeric id.
     * @return numeric format of operator, null if unregistered or unknown
     * @hide
     */
    public String getDataOperatorNumeric() {
        return mDataOperatorNumeric;
    }

一般来说,voice语音业务和data数据业务对应的OperatorNumeric是一样的,所以getOperatorNumeric()默认取了voice的。

2.2 通过监听Telephony广播获得

由于该Intent action为MTK新增的,故以下方法介绍均以MTK源码为基础。

上面的方法必须在voice与data均注册成功的前提下才能获得,但是在一些很特殊的环境下,比如SIM卡虽然漫游上了某个其他运营商的网络,但由于两家运营商之间并没有协议,导致无法注册上服务,此时voice和data取得的OperatorNumeric均为空的。

在MTK源码中,MtkServiceStateTracker在处理PLMN String即mcc/mnc时,会通过action为“TelephonyIntents.ACTION_LOCATED_PLMN_CHANGED”的广播,把它作为extra参数传递出去。

// MtkServiceStateTracker.java

    private void updateLocatedPlmn(String plmn) {

        if (((mLocatedPlmn == null) && (plmn != null)) ||
            ((mLocatedPlmn != null) && (plmn == null)) ||
            ((mLocatedPlmn != null) && (plmn != null) && !(mLocatedPlmn.equals(plmn)))) {
            log("updateLocatedPlmn(),previous plmn= " + mLocatedPlmn + " ,update to: " + plmn);
            Intent intent = new Intent(TelephonyIntents.ACTION_LOCATED_PLMN_CHANGED);
            if (TelephonyManager.getDefault().getPhoneCount() == 1) {
                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
            }
            intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn);

            ...
            mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
        }

        mLocatedPlmn = plmn;
    }

由此可知,只要在需要取的类中,注册一个监听“ACTION_LOCATED_PLMN_CHANGED”的BroadcastReceiver就行了,在设备开机之后便可以第一时间拿到漫游网络的mcc/mnc值,具体如下:

    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (action.equals(TelephonyIntents.ACTION_LOCATED_PLMN_CHANGED)) {
                mLocatedPlmn = intent.getStringExtra(TelephonyIntents.EXTRA_PLMN);
                // mLocatedPlmn即为漫游网络的mcc/mnc值,接下来用它操作即可
                ...
            }
        }
    };

你可能感兴趣的:(SystemUI如何获得SIM卡相关的mcc/mnc值)