use of com.android.internal.telephony.gsm.SimTlv in project XobotOS by xamarin.
the class IsimUiccRecords method isimTlvToString.
/**
* ISIM records for IMS are stored inside a Tag-Length-Value record as a UTF-8 string
* with tag value 0x80.
* @param record the byte array containing the IMS data string
* @return the decoded String value, or null if the record can't be decoded
*/
private static String isimTlvToString(byte[] record) {
SimTlv tlv = new SimTlv(record, 0, record.length);
do {
if (tlv.getTag() == TAG_ISIM_VALUE) {
return new String(tlv.getData(), Charset.forName("UTF-8"));
}
} while (tlv.nextObject());
Log.e(LOG_TAG, "[ISIM] can't find TLV tag in ISIM record, returning null");
return null;
}
use of com.android.internal.telephony.gsm.SimTlv in project android_frameworks_opt_telephony by LineageOS.
the class SIMRecords method handleMessage.
// ***** Overridden from Handler
@Override
public void handleMessage(Message msg) {
AsyncResult ar;
AdnRecord adn;
byte[] data;
boolean isRecordLoadResponse = false;
if (mDestroyed.get()) {
loge("Received message " + msg + "[" + msg.what + "] " + " while being destroyed. Ignoring.");
return;
}
try {
switch(msg.what) {
/* IO events */
case EVENT_GET_IMSI_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
loge("Exception querying IMSI, Exception:" + ar.exception);
break;
}
setImsi((String) ar.result);
break;
case EVENT_GET_MBI_DONE:
boolean isValidMbdn;
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
isValidMbdn = false;
if (ar.exception == null) {
// Refer TS 51.011 Section 10.3.44 for content details
log("EF_MBI: " + IccUtils.bytesToHexString(data));
// Voice mail record number stored first
mMailboxIndex = data[0] & 0xff;
// check if dailing numbe id valid
if (mMailboxIndex != 0 && mMailboxIndex != 0xff) {
log("Got valid mailbox number for MBDN");
isValidMbdn = true;
}
}
// one more record to load
mRecordsToLoad += 1;
if (isValidMbdn) {
// Note: MBDN was not included in NUM_OF_SIM_RECORDS_LOADED
new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6, mMailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
} else {
// If this EF not present, try mailbox as in CPHS standard
// CPHS (CPHS4_2.WW6) is a european standard.
new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1, 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
}
break;
case EVENT_GET_CPHS_MAILBOX_DONE:
case EVENT_GET_MBDN_DONE:
// Resetting the voice mail number and voice mail tag to null
// as these should be updated from the data read from EF_MBDN.
// If they are not reset, incase of invalid data/exception these
// variables are retaining their previous values and are
// causing invalid voice mailbox info display to user.
mVoiceMailNum = null;
mVoiceMailTag = null;
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
log("Invalid or missing EF" + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? "[MAILBOX]" : "[MBDN]"));
if (msg.what == EVENT_GET_MBDN_DONE) {
// load CPHS on fail...
// FIXME right now, only load line1's CPHS voice mail entry
mRecordsToLoad += 1;
new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1, 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
}
break;
}
adn = (AdnRecord) ar.result;
log("VM: " + adn + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? " EF[MAILBOX]" : " EF[MBDN]"));
if (adn.isEmpty() && msg.what == EVENT_GET_MBDN_DONE) {
// Bug #645770 fall back to CPHS
// FIXME should use SST to decide
// FIXME right now, only load line1's CPHS voice mail entry
mRecordsToLoad += 1;
new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1, 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
break;
}
mVoiceMailNum = adn.getNumber();
mVoiceMailTag = adn.getAlphaTag();
break;
case EVENT_GET_MSISDN_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
log("Invalid or missing EF[MSISDN]");
break;
}
adn = (AdnRecord) ar.result;
mMsisdn = adn.getNumber();
mMsisdnTag = adn.getAlphaTag();
log("MSISDN: " + /*mMsisdn*/
Rlog.pii(LOG_TAG, mMsisdn));
break;
case EVENT_SET_MSISDN_DONE:
isRecordLoadResponse = false;
ar = (AsyncResult) msg.obj;
if (ar.exception == null) {
mMsisdn = mNewMsisdn;
mMsisdnTag = mNewMsisdnTag;
log("Success to update EF[MSISDN]");
}
if (ar.userObj != null) {
AsyncResult.forMessage(((Message) ar.userObj)).exception = ar.exception;
((Message) ar.userObj).sendToTarget();
}
break;
case EVENT_GET_MWIS_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (DBG)
log("EF_MWIS : " + IccUtils.bytesToHexString(data));
if (ar.exception != null) {
if (DBG)
log("EVENT_GET_MWIS_DONE exception = " + ar.exception);
break;
}
if ((data[0] & 0xff) == 0xff) {
if (DBG)
log("SIMRecords: Uninitialized record MWIS");
break;
}
mEfMWIS = data;
break;
case EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (DBG)
log("EF_CPHS_MWI: " + IccUtils.bytesToHexString(data));
if (ar.exception != null) {
if (DBG) {
log("EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE exception = " + ar.exception);
}
break;
}
mEfCPHS_MWI = data;
break;
case EVENT_GET_ICCID_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
break;
}
mIccId = IccUtils.bcdToString(data, 0, data.length);
mFullIccId = IccUtils.bchToString(data, 0, data.length);
log("iccid: " + SubscriptionInfo.givePrintableIccid(mFullIccId));
break;
case EVENT_GET_AD_DONE:
isRecordLoadResponse = true;
mMncLength = UNKNOWN;
try {
if (!mCarrierTestOverride.isInTestMode()) {
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
break;
}
log("EF_AD: " + IccUtils.bytesToHexString(data));
if (data.length < 3) {
log("Corrupt AD data on SIM");
break;
}
if (data.length == 3) {
log("MNC length not present in EF_AD");
break;
}
int len = data[3] & 0xf;
if (len == 2 || len == 3) {
mMncLength = len;
} else {
log("Received invalid or unset MNC Length=" + len);
}
}
} finally {
updateOperatorPlmn();
}
break;
case EVENT_GET_SPN_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
getSpnFsm(false, ar);
break;
case EVENT_GET_CFF_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
mEfCff = null;
} else {
log("EF_CFF_CPHS: " + IccUtils.bytesToHexString(data));
mEfCff = data;
}
break;
case EVENT_GET_SPDI_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
break;
}
parseEfSpdi(data);
break;
case EVENT_UPDATE_DONE:
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
logw("update failed. ", ar.exception);
}
break;
case EVENT_GET_PNN_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
break;
}
SimTlv tlv = new SimTlv(data, 0, data.length);
for (; tlv.isValidObject(); tlv.nextObject()) {
if (tlv.getTag() == TAG_FULL_NETWORK_NAME) {
mPnnHomeName = IccUtils.networkNameToString(tlv.getData(), 0, tlv.getData().length);
log("PNN: " + mPnnHomeName);
break;
}
}
break;
case EVENT_GET_ALL_SMS_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
break;
}
handleSmses((ArrayList<byte[]>) ar.result);
break;
case EVENT_MARK_SMS_READ_DONE:
log("marked read: sms " + msg.arg1);
break;
case EVENT_SMS_ON_SIM:
isRecordLoadResponse = false;
ar = (AsyncResult) msg.obj;
Integer index = (Integer) ar.result;
if (ar.exception != null || index == null) {
loge("Error on SMS_ON_SIM with exp " + ar.exception + " index " + index);
} else {
log("READ EF_SMS RECORD index=" + index);
mFh.loadEFLinearFixed(EF_SMS, index, obtainMessage(EVENT_GET_SMS_DONE));
}
break;
case EVENT_GET_SMS_DONE:
isRecordLoadResponse = false;
ar = (AsyncResult) msg.obj;
if (ar.exception == null) {
handleSms((byte[]) ar.result);
} else {
loge("Error on GET_SMS with exp " + ar.exception);
}
break;
case EVENT_GET_SST_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
break;
}
mUsimServiceTable = new UsimServiceTable(data);
if (DBG)
log("SST: " + mUsimServiceTable);
break;
case EVENT_GET_INFO_CPHS_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
break;
}
mCphsInfo = (byte[]) ar.result;
if (DBG)
log("iCPHS: " + IccUtils.bytesToHexString(mCphsInfo));
break;
case EVENT_SET_MBDN_DONE:
isRecordLoadResponse = false;
ar = (AsyncResult) msg.obj;
if (DBG)
log("EVENT_SET_MBDN_DONE ex:" + ar.exception);
if (ar.exception == null) {
mVoiceMailNum = mNewVoiceMailNum;
mVoiceMailTag = mNewVoiceMailTag;
}
if (isCphsMailboxEnabled()) {
adn = new AdnRecord(mVoiceMailTag, mVoiceMailNum);
Message onCphsCompleted = (Message) ar.userObj;
/* write to cphs mailbox whenever it is available but
* we only need notify caller once if both updating are
* successful.
*
* so if set_mbdn successful, notify caller here and set
* onCphsCompleted to null
*/
if (ar.exception == null && ar.userObj != null) {
AsyncResult.forMessage(((Message) ar.userObj)).exception = null;
((Message) ar.userObj).sendToTarget();
if (DBG)
log("Callback with MBDN successful.");
onCphsCompleted = null;
}
new AdnRecordLoader(mFh).updateEF(adn, EF_MAILBOX_CPHS, EF_EXT1, 1, null, obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE, onCphsCompleted));
} else {
if (ar.userObj != null) {
CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
if (ar.exception != null && configManager != null) {
PersistableBundle b = configManager.getConfigForSubId(SubscriptionController.getInstance().getSubIdUsingPhoneId(mParentApp.getPhoneId()));
if (b != null && b.getBoolean(CarrierConfigManager.KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL)) {
// GsmCdmaPhone will store vm number on device
// when IccVmNotSupportedException occurred
AsyncResult.forMessage(((Message) ar.userObj)).exception = new IccVmNotSupportedException("Update SIM voice mailbox error");
} else {
AsyncResult.forMessage(((Message) ar.userObj)).exception = ar.exception;
}
} else {
AsyncResult.forMessage(((Message) ar.userObj)).exception = ar.exception;
}
((Message) ar.userObj).sendToTarget();
}
}
break;
case EVENT_SET_CPHS_MAILBOX_DONE:
isRecordLoadResponse = false;
ar = (AsyncResult) msg.obj;
if (ar.exception == null) {
mVoiceMailNum = mNewVoiceMailNum;
mVoiceMailTag = mNewVoiceMailTag;
} else {
if (DBG)
log("Set CPHS MailBox with exception: " + ar.exception);
}
if (ar.userObj != null) {
if (DBG)
log("Callback with CPHS MB successful.");
AsyncResult.forMessage(((Message) ar.userObj)).exception = ar.exception;
((Message) ar.userObj).sendToTarget();
}
break;
case EVENT_GET_CFIS_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
mEfCfis = null;
} else {
log("EF_CFIS: " + IccUtils.bytesToHexString(data));
mEfCfis = data;
}
break;
case EVENT_GET_CSP_CPHS_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
loge("Exception in fetching EF_CSP data " + ar.exception);
break;
}
data = (byte[]) ar.result;
log("EF_CSP: " + IccUtils.bytesToHexString(data));
handleEfCspData(data);
break;
case EVENT_GET_GID1_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
loge("Exception in get GID1 " + ar.exception);
mGid1 = null;
break;
}
mGid1 = IccUtils.bytesToHexString(data);
log("GID1: " + mGid1);
break;
case EVENT_GET_GID2_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
loge("Exception in get GID2 " + ar.exception);
mGid2 = null;
break;
}
mGid2 = IccUtils.bytesToHexString(data);
log("GID2: " + mGid2);
break;
case EVENT_GET_PLMN_W_ACT_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null || data == null) {
loge("Failed getting User PLMN with Access Tech Records: " + ar.exception);
break;
} else {
log("Received a PlmnActRecord, raw=" + IccUtils.bytesToHexString(data));
mPlmnActRecords = PlmnActRecord.getRecords(data);
if (VDBG)
log("PlmnActRecords=" + Arrays.toString(mPlmnActRecords));
}
break;
case EVENT_GET_OPLMN_W_ACT_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null || data == null) {
loge("Failed getting Operator PLMN with Access Tech Records: " + ar.exception);
break;
} else {
log("Received a PlmnActRecord, raw=" + IccUtils.bytesToHexString(data));
mOplmnActRecords = PlmnActRecord.getRecords(data);
if (VDBG)
log("OplmnActRecord[]=" + Arrays.toString(mOplmnActRecords));
}
break;
case EVENT_GET_HPLMN_W_ACT_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null || data == null) {
loge("Failed getting Home PLMN with Access Tech Records: " + ar.exception);
break;
} else {
log("Received a PlmnActRecord, raw=" + IccUtils.bytesToHexString(data));
mHplmnActRecords = PlmnActRecord.getRecords(data);
log("HplmnActRecord[]=" + Arrays.toString(mHplmnActRecords));
}
break;
case EVENT_GET_EHPLMN_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null || data == null) {
loge("Failed getting Equivalent Home PLMNs: " + ar.exception);
break;
} else {
mEhplmns = parseBcdPlmnList(data, "Equivalent Home");
}
break;
case EVENT_GET_FPLMN_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null || data == null) {
loge("Failed getting Forbidden PLMNs: " + ar.exception);
} else {
mFplmns = parseBcdPlmnList(data, "Forbidden");
}
if (msg.arg1 == HANDLER_ACTION_SEND_RESPONSE) {
if (VDBG)
logv("getForbiddenPlmns(): send async response");
isRecordLoadResponse = false;
int key = msg.arg2;
Message response = retrievePendingTransaction(key).first;
if (response != null) {
if (ar.exception == null && data != null && mFplmns != null) {
AsyncResult.forMessage(response, Arrays.copyOf(mFplmns, mFplmns.length), null);
} else {
AsyncResult.forMessage(response, null, ar.exception);
}
response.sendToTarget();
} else {
loge("Failed to retrieve a response message for FPLMN");
break;
}
}
break;
case EVENT_GET_FPLMN_SIZE_DONE:
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
Message response = (Message) ar.userObj;
AsyncResult.forMessage(response).exception = ar.exception;
response.sendToTarget();
break;
}
int key = msg.arg2;
Pair<Message, Object> transaction = retrievePendingTransaction(key);
Message response = transaction.first;
List<String> fplmns = (List<String>) transaction.second;
int dataLength = (int) ar.result;
if (dataLength < 0 || dataLength % FPLMN_BYTE_SIZE != 0) {
loge("Failed to retrieve a correct fplmn size: " + dataLength);
AsyncResult.forMessage(response, -1, null);
response.sendToTarget();
break;
}
int maxWritebaleFplmns = dataLength / FPLMN_BYTE_SIZE;
List<String> fplmnsToWrite;
if (fplmns.size() <= maxWritebaleFplmns) {
fplmnsToWrite = fplmns;
} else {
fplmnsToWrite = fplmns.subList(0, maxWritebaleFplmns);
}
key = storePendingTransaction(response, fplmnsToWrite);
byte[] encodededFplmns = IccUtils.encodeFplmns(fplmns, dataLength);
mFh.updateEFTransparent(EF_FPLMN, encodededFplmns, obtainMessage(EVENT_SET_FPLMN_DONE, msg.arg1, key));
break;
case EVENT_SET_FPLMN_DONE:
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
loge("Failed setting Forbidden PLMNs: " + ar.exception);
} else {
transaction = retrievePendingTransaction(msg.arg2);
response = transaction.first;
mFplmns = ((List<String>) transaction.second).toArray(new String[0]);
if (msg.arg1 == HANDLER_ACTION_SEND_RESPONSE) {
AsyncResult.forMessage(response, mFplmns.length, null);
response.sendToTarget();
}
log("Successfully setted fplmns " + ar.result);
}
break;
default:
// IccRecords handles generic record load responses
super.handleMessage(msg);
}
} catch (RuntimeException exc) {
// I don't want these exceptions to be fatal
logw("Exception parsing SIM record", exc);
} finally {
// Count up record load responses even if they are fails
if (isRecordLoadResponse) {
onRecordLoaded();
}
}
}
use of com.android.internal.telephony.gsm.SimTlv in project android_frameworks_opt_telephony by LineageOS.
the class SIMRecords method parseEfSpdi.
/**
* Parse TS 51.011 EF[SPDI] record
* This record contains the list of numeric network IDs that
* are treated specially when determining SPN display
*/
private void parseEfSpdi(byte[] data) {
SimTlv tlv = new SimTlv(data, 0, data.length);
byte[] plmnEntries = null;
for (; tlv.isValidObject(); tlv.nextObject()) {
// Skip SPDI tag, if existant
if (tlv.getTag() == TAG_SPDI) {
tlv = new SimTlv(tlv.getData(), 0, tlv.getData().length);
}
// There should only be one TAG_SPDI_PLMN_LIST
if (tlv.getTag() == TAG_SPDI_PLMN_LIST) {
plmnEntries = tlv.getData();
break;
}
}
if (plmnEntries == null) {
return;
}
List<String> tmpSpdi = new ArrayList<>(plmnEntries.length / 3);
for (int i = 0; i + 2 < plmnEntries.length; i += 3) {
String plmnCode = IccUtils.bcdPlmnToString(plmnEntries, i);
if (!TextUtils.isEmpty(plmnCode)) {
log("EF_SPDI PLMN: " + plmnCode);
tmpSpdi.add(plmnCode);
}
}
mSpdi = tmpSpdi.toArray(new String[tmpSpdi.size()]);
}
Aggregations