美文网首页
SystemUI如何获得SIM卡相关的mcc/mnc值

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

作者: Soetsu | 来源:发表于2019-08-03 15:57 被阅读0次

    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.
         * <p>
         * 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.
         * <p>
         *
         * @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值

          本文链接:https://www.haomeiwen.com/subject/dqsjdctx.html