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值,接下来用它操作即可
...
}
}
};