下列情况都会触发更新运营商名称。
1 卡loaded
2 IMS_CAPABILITY_CHANGED
3 LOCALE_CHANGED
4 SubscriptionsChanged
5 ServiceStateChanged
更新运营商名称的入口为ServiceStateTracker.updateSpnDisplay()。
这里面会根据多种条件来判断显示SPN还是PLMN,或者是两者都显示,
PLMN是查询状态时通过RIL.getOperator()去获取的,保存在ServiceState的mVoiceOperatorAlphaLong/mVoiceOperatorAlphaShort中。
SPN可以保存在EF_SPN (0x6F46)、EF_SPN_CPHS(0x6F14)或者EF_SPN_SHORT_CPHS(0x6F18)中,
卡READY后在fetchSimRecords()中读取,之后保存在IccRecords.mSpn中
最后发送广播SPN_STRINGS_UPDATED_ACTION进行通知。
如果WFC打开了,会先读取WFC运营商的显示格式
运营商的显示可以为PLMN和(或)SPN,SPN从SIM卡中读取,PLMN为当前注册的网络。
GSM基本规则如下:
1 当设置了OperatorBrandOverride时,只显示PLMN
2 没有SPN或SPN未加载时,显示PLMN,
3 当注册到HPLMN或EF_SPDI列表中的PLMN时,则
a.显示SPN
b.若EF_SPN的第一字节的bit0为1,则显示PLMN,否则不显示PLMN
4 其它情况
a.显示PLMN
b.若EF_SPN的第一字节的bit1为0,则显示SPN,否则不显示SPN
相应代码为:
// See TS 22.101 Annex A and TS 51.011 10.3.11 for details.
SIMRecords.getDisplayRule()
有了显示规则,接下来就是获取需要显示的SPN/PLMN了。
1 PLMN
STATE_EMERGENCY_ONLY:R.string.emergency_calls_only
STATE_OUT_OF_SERVICE:R.string.lockscreen_carrier_default
STATE_IN_SERVICE:mSS.getOperatorAlpha()
其它状态:R.string.lockscreen_carrier_default
2 SPN
如果注上了WFC,则需要将SPN转换为WFC的格式
接下来再看PLMN及SPN的获取。
PLMN是查询状态时通过RIL.getOperator()去获取的,
public void pollState(boolean modemTriggered) {
......
switch (mCi.getRadioState()) {
case RADIO_UNAVAILABLE:
......
case RADIO_OFF:
......
default:
// Issue all poll-related commands at once then count down the responses, which
// are allowed to arrive out-of-order
mPollingContext[0]++;
mCi.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR, mPollingContext));
......
}
请求返回后,保存到ServiceState的mVoiceOperatorAlphaLong/mVoiceOperatorAlphaShort中,
如果有OperatorBrandOverride的话,则会使用brandOverride的值。
void handlePollStateResultMessage(int what, AsyncResult ar) {
int ints[];
switch (what) {
......
case EVENT_POLL_STATE_OPERATOR: {
if (mPhone.isPhoneTypeGsm()) {
String opNames[] = (String[]) ar.result;
if (opNames != null && opNames.length >= 3) {
// FIXME: Giving brandOverride higher precedence, is this desired?
String brandOverride = mUiccController.getUiccCard(getPhoneId()) != null ?
mUiccController.getUiccCard(getPhoneId()).getOperatorBrandOverride() : null;
if (brandOverride != null) {
log("EVENT_POLL_STATE_OPERATOR: use brandOverride=" + brandOverride);
mNewSS.setOperatorName(brandOverride, brandOverride, opNames[2]);
} else {
mNewSS.setOperatorName(opNames[0], opNames[1], opNames[2]);
}
}
} else {
......
}
break;
}
SPN可以保存在EF_SPN(0x6F46)、EF_SPN_CPHS(0x6F14)或者EF_SPN_SHORT_CPHS(0x6F18)中,
卡READY后在fetchSimRecords()中读取,之后保存在IccRecords.mSpn中
protected void fetchSimRecords() {
......
getSpnFsm(true, null);
......
}
我们会最先从EF_SPN(0x6F46)中读取,如果没有,则会再从EF_SPN_CPHS(0x6F14)中读取,若还是没有,最后会从EF_SPN_SHORT_CPHS(0x6F18)中读取。
private void getSpnFsm(boolean start, AsyncResult ar) {
......
switch(mSpnState){
case INIT:
setServiceProviderName(null);
mFh.loadEFTransparent(EF_SPN,
obtainMessage(EVENT_GET_SPN_DONE));
mRecordsToLoad++;
mSpnState = GetSpnFsmState.READ_SPN_3GPP;
break;
case READ_SPN_3GPP:
if (ar != null && ar.exception == null) {
data = (byte[]) ar.result;
mSpnDisplayCondition = 0xff & data[0];
setServiceProviderName(IccUtils.adnStringFieldToString(
data, 1, data.length - 1));
// for card double-check and brand override
// we have to do this:
final String spn = getServiceProviderName();
if (spn == null || spn.length() == 0) {
mSpnState = GetSpnFsmState.READ_SPN_CPHS;
} else {
if (DBG) log("Load EF_SPN: " + spn
+ " spnDisplayCondition: " + mSpnDisplayCondition);
mTelephonyManager.setSimOperatorNameForPhone(
mParentApp.getPhoneId(), spn);
mSpnState = GetSpnFsmState.IDLE;
}
} else {
mSpnState = GetSpnFsmState.READ_SPN_CPHS;
}
if (mSpnState == GetSpnFsmState.READ_SPN_CPHS) {
mFh.loadEFTransparent( EF_SPN_CPHS,
obtainMessage(EVENT_GET_SPN_DONE));
mRecordsToLoad++;
// See TS 51.011 10.3.11. Basically, default to
// show PLMN always, and SPN also if roaming.
mSpnDisplayCondition = -1;
}
break;
case READ_SPN_CPHS:
if (ar != null && ar.exception == null) {
data = (byte[]) ar.result;
setServiceProviderName(IccUtils.adnStringFieldToString(
data, 0, data.length));
// for card double-check and brand override
// we have to do this:
final String spn = getServiceProviderName();
if (spn == null || spn.length() == 0) {
mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS;
} else {
// Display CPHS Operator Name only when not roaming
mSpnDisplayCondition = 2;
if (DBG) log("Load EF_SPN_CPHS: " + spn);
mTelephonyManager.setSimOperatorNameForPhone(
mParentApp.getPhoneId(), spn);
mSpnState = GetSpnFsmState.IDLE;
}
} else {
mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS;
}
if (mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS) {
mFh.loadEFTransparent(
EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE));
mRecordsToLoad++;
}
break;
case READ_SPN_SHORT_CPHS:
if (ar != null && ar.exception == null) {
data = (byte[]) ar.result;
setServiceProviderName(IccUtils.adnStringFieldToString(
data, 0, data.length));
// for card double-check and brand override
// we have to do this:
final String spn = getServiceProviderName();
if (spn == null || spn.length() == 0) {
if (DBG) log("No SPN loaded in either CHPS or 3GPP");
} else {
// Display CPHS Operator Name only when not roaming
mSpnDisplayCondition = 2;
if (DBG) log("Load EF_SPN_SHORT_CPHS: " + spn);
mTelephonyManager.setSimOperatorNameForPhone(
mParentApp.getPhoneId(), spn);
}
} else {
setServiceProviderName(null);
if (DBG) log("No SPN loaded in either CHPS or 3GPP");
}
mSpnState = GetSpnFsmState.IDLE;
break;
default:
mSpnState = GetSpnFsmState.IDLE;
}
}