Merge change 21774 into eclair
* changes: Implement USIM and add support for importing emails from USIM.
This commit is contained in:
@@ -23,6 +23,8 @@ import android.util.Log;
|
|||||||
|
|
||||||
import com.android.internal.telephony.GsmAlphabet;
|
import com.android.internal.telephony.GsmAlphabet;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -38,6 +40,7 @@ public class AdnRecord implements Parcelable {
|
|||||||
|
|
||||||
String alphaTag = "";
|
String alphaTag = "";
|
||||||
String number = "";
|
String number = "";
|
||||||
|
String[] emails;
|
||||||
int extRecord = 0xff;
|
int extRecord = 0xff;
|
||||||
int efid; // or 0 if none
|
int efid; // or 0 if none
|
||||||
int recordNumber; // or 0 if none
|
int recordNumber; // or 0 if none
|
||||||
@@ -74,13 +77,15 @@ public class AdnRecord implements Parcelable {
|
|||||||
int recordNumber;
|
int recordNumber;
|
||||||
String alphaTag;
|
String alphaTag;
|
||||||
String number;
|
String number;
|
||||||
|
String[] emails;
|
||||||
|
|
||||||
efid = source.readInt();
|
efid = source.readInt();
|
||||||
recordNumber = source.readInt();
|
recordNumber = source.readInt();
|
||||||
alphaTag = source.readString();
|
alphaTag = source.readString();
|
||||||
number = source.readString();
|
number = source.readString();
|
||||||
|
emails = source.readStringArray();
|
||||||
|
|
||||||
return new AdnRecord(efid, recordNumber, alphaTag, number);
|
return new AdnRecord(efid, recordNumber, alphaTag, number, emails);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AdnRecord[] newArray(int size) {
|
public AdnRecord[] newArray(int size) {
|
||||||
@@ -90,29 +95,38 @@ public class AdnRecord implements Parcelable {
|
|||||||
|
|
||||||
|
|
||||||
//***** Constructor
|
//***** Constructor
|
||||||
public
|
public AdnRecord (byte[] record) {
|
||||||
AdnRecord (byte[] record) {
|
|
||||||
this(0, 0, record);
|
this(0, 0, record);
|
||||||
}
|
}
|
||||||
|
|
||||||
public
|
public AdnRecord (int efid, int recordNumber, byte[] record) {
|
||||||
AdnRecord (int efid, int recordNumber, byte[] record) {
|
|
||||||
this.efid = efid;
|
this.efid = efid;
|
||||||
this.recordNumber = recordNumber;
|
this.recordNumber = recordNumber;
|
||||||
parseRecord(record);
|
parseRecord(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
public
|
public AdnRecord (String alphaTag, String number) {
|
||||||
AdnRecord (String alphaTag, String number) {
|
|
||||||
this(0, 0, alphaTag, number);
|
this(0, 0, alphaTag, number);
|
||||||
}
|
}
|
||||||
|
|
||||||
public
|
public AdnRecord (String alphaTag, String number, String[] emails) {
|
||||||
AdnRecord (int efid, int recordNumber, String alphaTag, String number) {
|
this(0, 0, alphaTag, number, emails);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdnRecord (int efid, int recordNumber, String alphaTag, String number, String[] emails) {
|
||||||
this.efid = efid;
|
this.efid = efid;
|
||||||
this.recordNumber = recordNumber;
|
this.recordNumber = recordNumber;
|
||||||
this.alphaTag = alphaTag;
|
this.alphaTag = alphaTag;
|
||||||
this.number = number;
|
this.number = number;
|
||||||
|
this.emails = emails;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdnRecord(int efid, int recordNumber, String alphaTag, String number) {
|
||||||
|
this.efid = efid;
|
||||||
|
this.recordNumber = recordNumber;
|
||||||
|
this.alphaTag = alphaTag;
|
||||||
|
this.number = number;
|
||||||
|
this.emails = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//***** Instance Methods
|
//***** Instance Methods
|
||||||
@@ -125,12 +139,20 @@ public class AdnRecord implements Parcelable {
|
|||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String[] getEmails() {
|
||||||
|
return emails;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmails(String[] emails) {
|
||||||
|
this.emails = emails;
|
||||||
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ADN Record '" + alphaTag + "' '" + number + "'";
|
return "ADN Record '" + alphaTag + "' '" + number + " " + emails + "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return alphaTag.equals("") && number.equals("");
|
return alphaTag.equals("") && number.equals("") && emails == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasExtendedRecord() {
|
public boolean hasExtendedRecord() {
|
||||||
@@ -139,7 +161,8 @@ public class AdnRecord implements Parcelable {
|
|||||||
|
|
||||||
public boolean isEqual(AdnRecord adn) {
|
public boolean isEqual(AdnRecord adn) {
|
||||||
return ( alphaTag.equals(adn.getAlphaTag()) &&
|
return ( alphaTag.equals(adn.getAlphaTag()) &&
|
||||||
number.equals(adn.getNumber()) );
|
number.equals(adn.getNumber()) &&
|
||||||
|
Arrays.equals(emails, adn.getEmails()));
|
||||||
}
|
}
|
||||||
//***** Parcelable Implementation
|
//***** Parcelable Implementation
|
||||||
|
|
||||||
@@ -152,6 +175,7 @@ public class AdnRecord implements Parcelable {
|
|||||||
dest.writeInt(recordNumber);
|
dest.writeInt(recordNumber);
|
||||||
dest.writeString(alphaTag);
|
dest.writeString(alphaTag);
|
||||||
dest.writeString(number);
|
dest.writeString(number);
|
||||||
|
dest.writeStringArray(emails);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -274,10 +298,13 @@ public class AdnRecord implements Parcelable {
|
|||||||
|
|
||||||
extRecord = 0xff & record[record.length - 1];
|
extRecord = 0xff & record[record.length - 1];
|
||||||
|
|
||||||
|
emails = null;
|
||||||
|
|
||||||
} catch (RuntimeException ex) {
|
} catch (RuntimeException ex) {
|
||||||
Log.w(LOG_TAG, "Error parsing AdnRecord", ex);
|
Log.w(LOG_TAG, "Error parsing AdnRecord", ex);
|
||||||
number = "";
|
number = "";
|
||||||
alphaTag = "";
|
alphaTag = "";
|
||||||
|
emails = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,14 +16,16 @@
|
|||||||
|
|
||||||
package com.android.internal.telephony;
|
package com.android.internal.telephony;
|
||||||
|
|
||||||
import android.util.SparseArray;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.AsyncResult;
|
import android.os.AsyncResult;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
import com.android.internal.telephony.gsm.UsimPhoneBookManager;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import com.android.internal.telephony.IccConstants;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@hide}
|
* {@hide}
|
||||||
@@ -32,6 +34,7 @@ public final class AdnRecordCache extends Handler implements IccConstants {
|
|||||||
//***** Instance Variables
|
//***** Instance Variables
|
||||||
|
|
||||||
PhoneBase phone;
|
PhoneBase phone;
|
||||||
|
private UsimPhoneBookManager mUsimPhoneBookManager;
|
||||||
|
|
||||||
// Indexed by EF ID
|
// Indexed by EF ID
|
||||||
SparseArray<ArrayList<AdnRecord>> adnLikeFiles
|
SparseArray<ArrayList<AdnRecord>> adnLikeFiles
|
||||||
@@ -55,6 +58,7 @@ public final class AdnRecordCache extends Handler implements IccConstants {
|
|||||||
|
|
||||||
public AdnRecordCache(PhoneBase phone) {
|
public AdnRecordCache(PhoneBase phone) {
|
||||||
this.phone = phone;
|
this.phone = phone;
|
||||||
|
mUsimPhoneBookManager = new UsimPhoneBookManager(phone, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//***** Called from SIMRecords
|
//***** Called from SIMRecords
|
||||||
@@ -64,6 +68,7 @@ public final class AdnRecordCache extends Handler implements IccConstants {
|
|||||||
*/
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
adnLikeFiles.clear();
|
adnLikeFiles.clear();
|
||||||
|
mUsimPhoneBookManager.reset();
|
||||||
|
|
||||||
clearWaiters();
|
clearWaiters();
|
||||||
clearUserWriters();
|
clearUserWriters();
|
||||||
@@ -103,14 +108,14 @@ public final class AdnRecordCache extends Handler implements IccConstants {
|
|||||||
*
|
*
|
||||||
* See 3GPP TS 51.011 for this mapping
|
* See 3GPP TS 51.011 for this mapping
|
||||||
*/
|
*/
|
||||||
private int
|
int extensionEfForEf(int efid) {
|
||||||
extensionEfForEf(int efid) {
|
|
||||||
switch (efid) {
|
switch (efid) {
|
||||||
case EF_MBDN: return EF_EXT6;
|
case EF_MBDN: return EF_EXT6;
|
||||||
case EF_ADN: return EF_EXT1;
|
case EF_ADN: return EF_EXT1;
|
||||||
case EF_SDN: return EF_EXT3;
|
case EF_SDN: return EF_EXT3;
|
||||||
case EF_FDN: return EF_EXT2;
|
case EF_FDN: return EF_EXT2;
|
||||||
case EF_MSISDN: return EF_EXT1;
|
case EF_MSISDN: return EF_EXT1;
|
||||||
|
case EF_PBR: return 0; // The EF PBR doesn't have an extension record
|
||||||
default: return -1;
|
default: return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,11 +228,15 @@ public final class AdnRecordCache extends Handler implements IccConstants {
|
|||||||
* record
|
* record
|
||||||
*/
|
*/
|
||||||
public void
|
public void
|
||||||
requestLoadAllAdnLike (int efid, Message response) {
|
requestLoadAllAdnLike (int efid, int extensionEf, Message response) {
|
||||||
ArrayList<Message> waiters;
|
ArrayList<Message> waiters;
|
||||||
ArrayList<AdnRecord> result;
|
ArrayList<AdnRecord> result;
|
||||||
|
|
||||||
result = getRecordsIfLoaded(efid);
|
if (efid == EF_PBR) {
|
||||||
|
result = mUsimPhoneBookManager.loadEfFilesFromUsim();
|
||||||
|
} else {
|
||||||
|
result = getRecordsIfLoaded(efid);
|
||||||
|
}
|
||||||
|
|
||||||
// Have we already loaded this efid?
|
// Have we already loaded this efid?
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@@ -258,9 +267,8 @@ public final class AdnRecordCache extends Handler implements IccConstants {
|
|||||||
|
|
||||||
adnLikeWaiters.put(efid, waiters);
|
adnLikeWaiters.put(efid, waiters);
|
||||||
|
|
||||||
int extensionEF = extensionEfForEf(efid);
|
|
||||||
|
|
||||||
if (extensionEF < 0) {
|
if (extensionEf < 0) {
|
||||||
// respond with error if not known ADN-like record
|
// respond with error if not known ADN-like record
|
||||||
|
|
||||||
if (response != null) {
|
if (response != null) {
|
||||||
@@ -272,7 +280,7 @@ public final class AdnRecordCache extends Handler implements IccConstants {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
new AdnRecordLoader(phone).loadAllFromEF(efid, extensionEF,
|
new AdnRecordLoader(phone).loadAllFromEF(efid, extensionEf,
|
||||||
obtainMessage(EVENT_LOAD_ALL_ADN_LIKE_DONE, efid, 0));
|
obtainMessage(EVENT_LOAD_ALL_ADN_LIKE_DONE, efid, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,7 +319,7 @@ public final class AdnRecordCache extends Handler implements IccConstants {
|
|||||||
adnLikeWaiters.delete(efid);
|
adnLikeWaiters.delete(efid);
|
||||||
|
|
||||||
if (ar.exception == null) {
|
if (ar.exception == null) {
|
||||||
adnLikeFiles.put(efid, (ArrayList<AdnRecord>) (ar.result));
|
adnLikeFiles.put(efid, (ArrayList<AdnRecord>) ar.result);
|
||||||
}
|
}
|
||||||
notifyWaiters(waiters, ar);
|
notifyWaiters(waiters, ar);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -655,7 +655,7 @@ public abstract class IccCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean hasApplicationType(IccCardApplication.AppType type) {
|
public boolean isApplicationOnIcc(IccCardApplication.AppType type) {
|
||||||
if (mIccCardStatus == null) return false;
|
if (mIccCardStatus == null) return false;
|
||||||
|
|
||||||
for (int i = 0 ; i < mIccCardStatus.getNumApplications(); i++) {
|
for (int i = 0 ; i < mIccCardStatus.getNumApplications(); i++) {
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ public interface IccConstants {
|
|||||||
static final int EF_CFIS = 0x6FCB;
|
static final int EF_CFIS = 0x6FCB;
|
||||||
static final int EF_IMG = 0x4f20;
|
static final int EF_IMG = 0x4f20;
|
||||||
|
|
||||||
|
// USIM SIM file ids from TS 31.102
|
||||||
|
public static final int EF_PBR = 0x4F30;
|
||||||
|
|
||||||
// GSM SIM file ids from CPHS (phase 2, version 4.2) CPHS4_2.WW6
|
// GSM SIM file ids from CPHS (phase 2, version 4.2) CPHS4_2.WW6
|
||||||
static final int EF_MAILBOX_CPHS = 0x6F17;
|
static final int EF_MAILBOX_CPHS = 0x6F17;
|
||||||
static final int EF_VOICE_MAIL_INDICATOR_CPHS = 0x6F11;
|
static final int EF_VOICE_MAIL_INDICATOR_CPHS = 0x6F11;
|
||||||
@@ -59,6 +62,7 @@ public interface IccConstants {
|
|||||||
|
|
||||||
static final String MF_SIM = "3F00";
|
static final String MF_SIM = "3F00";
|
||||||
static final String DF_TELECOM = "7F10";
|
static final String DF_TELECOM = "7F10";
|
||||||
|
static final String DF_PHONEBOOK = "5F3A";
|
||||||
static final String DF_GRAPHICS = "5F50";
|
static final String DF_GRAPHICS = "5F50";
|
||||||
static final String DF_GSM = "7F20";
|
static final String DF_GSM = "7F20";
|
||||||
static final String DF_CDMA = "7F25";
|
static final String DF_CDMA = "7F25";
|
||||||
|
|||||||
@@ -115,7 +115,8 @@ public abstract class IccPhoneBookInterfaceManager extends IIccPhoneBook.Stub {
|
|||||||
* Replace oldAdn with newAdn in ADN-like record in EF
|
* Replace oldAdn with newAdn in ADN-like record in EF
|
||||||
*
|
*
|
||||||
* getAdnRecordsInEf must be called at least once before this function,
|
* getAdnRecordsInEf must be called at least once before this function,
|
||||||
* otherwise an error will be returned
|
* otherwise an error will be returned. Currently the email field
|
||||||
|
* if set in the ADN record is ignored.
|
||||||
* throws SecurityException if no WRITE_CONTACTS permission
|
* throws SecurityException if no WRITE_CONTACTS permission
|
||||||
*
|
*
|
||||||
* @param efid must be one among EF_ADN, EF_FDN, and EF_SDN
|
* @param efid must be one among EF_ADN, EF_FDN, and EF_SDN
|
||||||
@@ -167,7 +168,8 @@ public abstract class IccPhoneBookInterfaceManager extends IIccPhoneBook.Stub {
|
|||||||
* Update an ADN-like EF record by record index
|
* Update an ADN-like EF record by record index
|
||||||
*
|
*
|
||||||
* This is useful for iteration the whole ADN file, such as write the whole
|
* This is useful for iteration the whole ADN file, such as write the whole
|
||||||
* phone book or erase/format the whole phonebook
|
* phone book or erase/format the whole phonebook. Currently the email field
|
||||||
|
* if set in the ADN record is ignored.
|
||||||
* throws SecurityException if no WRITE_CONTACTS permission
|
* throws SecurityException if no WRITE_CONTACTS permission
|
||||||
*
|
*
|
||||||
* @param efid must be one among EF_ADN, EF_FDN, and EF_SDN
|
* @param efid must be one among EF_ADN, EF_FDN, and EF_SDN
|
||||||
@@ -237,12 +239,13 @@ public abstract class IccPhoneBookInterfaceManager extends IIccPhoneBook.Stub {
|
|||||||
"Requires android.permission.READ_CONTACTS permission");
|
"Requires android.permission.READ_CONTACTS permission");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
efid = updateEfForIccType(efid);
|
||||||
if (DBG) logd("getAdnRecordsInEF: efid=" + efid);
|
if (DBG) logd("getAdnRecordsInEF: efid=" + efid);
|
||||||
|
|
||||||
synchronized(mLock) {
|
synchronized(mLock) {
|
||||||
checkThread();
|
checkThread();
|
||||||
Message response = mBaseHandler.obtainMessage(EVENT_LOAD_DONE);
|
Message response = mBaseHandler.obtainMessage(EVENT_LOAD_DONE);
|
||||||
adnCache.requestLoadAllAdnLike(efid, response);
|
adnCache.requestLoadAllAdnLike(efid, adnCache.extensionEfForEf(efid), response);
|
||||||
try {
|
try {
|
||||||
mLock.wait();
|
mLock.wait();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@@ -262,5 +265,15 @@ public abstract class IccPhoneBookInterfaceManager extends IIccPhoneBook.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int updateEfForIccType(int efid) {
|
||||||
|
// Check if we are trying to read ADN records
|
||||||
|
if (efid == IccConstants.EF_ADN) {
|
||||||
|
if (phone.getIccCard().isApplicationOnIcc(IccCardApplication.AppType.APPTYPE_USIM)) {
|
||||||
|
return IccConstants.EF_PBR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return efid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ public class IccProvider extends ContentProvider {
|
|||||||
|
|
||||||
private static final String[] ADDRESS_BOOK_COLUMN_NAMES = new String[] {
|
private static final String[] ADDRESS_BOOK_COLUMN_NAMES = new String[] {
|
||||||
"name",
|
"name",
|
||||||
"number"
|
"number",
|
||||||
|
"emails"
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final int ADN = 1;
|
private static final int ADN = 1;
|
||||||
@@ -55,6 +56,7 @@ public class IccProvider extends ContentProvider {
|
|||||||
|
|
||||||
private static final String STR_TAG = "tag";
|
private static final String STR_TAG = "tag";
|
||||||
private static final String STR_NUMBER = "number";
|
private static final String STR_NUMBER = "number";
|
||||||
|
private static final String STR_EMAILS = "emails";
|
||||||
private static final String STR_PIN2 = "pin2";
|
private static final String STR_PIN2 = "pin2";
|
||||||
|
|
||||||
private static final UriMatcher URL_MATCHER =
|
private static final UriMatcher URL_MATCHER =
|
||||||
@@ -172,7 +174,8 @@ public class IccProvider extends ContentProvider {
|
|||||||
|
|
||||||
String tag = initialValues.getAsString("tag");
|
String tag = initialValues.getAsString("tag");
|
||||||
String number = initialValues.getAsString("number");
|
String number = initialValues.getAsString("number");
|
||||||
boolean success = addIccRecordToEf(efType, tag, number, pin2);
|
// TODO(): Read email instead of sending null.
|
||||||
|
boolean success = addIccRecordToEf(efType, tag, number, null, pin2);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return null;
|
return null;
|
||||||
@@ -238,6 +241,7 @@ public class IccProvider extends ContentProvider {
|
|||||||
// parse where clause
|
// parse where clause
|
||||||
String tag = null;
|
String tag = null;
|
||||||
String number = null;
|
String number = null;
|
||||||
|
String[] emails = null;
|
||||||
String pin2 = null;
|
String pin2 = null;
|
||||||
|
|
||||||
String[] tokens = where.split("AND");
|
String[] tokens = where.split("AND");
|
||||||
@@ -261,6 +265,9 @@ public class IccProvider extends ContentProvider {
|
|||||||
tag = normalizeValue(val);
|
tag = normalizeValue(val);
|
||||||
} else if (STR_NUMBER.equals(key)) {
|
} else if (STR_NUMBER.equals(key)) {
|
||||||
number = normalizeValue(val);
|
number = normalizeValue(val);
|
||||||
|
} else if (STR_EMAILS.equals(key)) {
|
||||||
|
//TODO(): Email is null.
|
||||||
|
emails = null;
|
||||||
} else if (STR_PIN2.equals(key)) {
|
} else if (STR_PIN2.equals(key)) {
|
||||||
pin2 = normalizeValue(val);
|
pin2 = normalizeValue(val);
|
||||||
}
|
}
|
||||||
@@ -274,7 +281,7 @@ public class IccProvider extends ContentProvider {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean success = deleteIccRecordFromEf(efType, tag, number, pin2);
|
boolean success = deleteIccRecordFromEf(efType, tag, number, emails, pin2);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -307,9 +314,11 @@ public class IccProvider extends ContentProvider {
|
|||||||
|
|
||||||
String tag = values.getAsString("tag");
|
String tag = values.getAsString("tag");
|
||||||
String number = values.getAsString("number");
|
String number = values.getAsString("number");
|
||||||
|
String[] emails = null;
|
||||||
String newTag = values.getAsString("newTag");
|
String newTag = values.getAsString("newTag");
|
||||||
String newNumber = values.getAsString("newNumber");
|
String newNumber = values.getAsString("newNumber");
|
||||||
|
String[] newEmails = null;
|
||||||
|
// TODO(): Update for email.
|
||||||
boolean success = updateIccRecordInEf(efType, tag, number,
|
boolean success = updateIccRecordInEf(efType, tag, number,
|
||||||
newTag, newNumber, pin2);
|
newTag, newNumber, pin2);
|
||||||
|
|
||||||
@@ -355,9 +364,9 @@ public class IccProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean
|
private boolean
|
||||||
addIccRecordToEf(int efType, String name, String number, String pin2) {
|
addIccRecordToEf(int efType, String name, String number, String[] emails, String pin2) {
|
||||||
if (DBG) log("addIccRecordToEf: efType=" + efType + ", name=" + name +
|
if (DBG) log("addIccRecordToEf: efType=" + efType + ", name=" + name +
|
||||||
", number=" + number);
|
", number=" + number + ", emails=" + emails);
|
||||||
|
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
|
|
||||||
@@ -384,7 +393,7 @@ public class IccProvider extends ContentProvider {
|
|||||||
|
|
||||||
private boolean
|
private boolean
|
||||||
updateIccRecordInEf(int efType, String oldName, String oldNumber,
|
updateIccRecordInEf(int efType, String oldName, String oldNumber,
|
||||||
String newName, String newNumber,String pin2) {
|
String newName, String newNumber, String pin2) {
|
||||||
if (DBG) log("updateIccRecordInEf: efType=" + efType +
|
if (DBG) log("updateIccRecordInEf: efType=" + efType +
|
||||||
", oldname=" + oldName + ", oldnumber=" + oldNumber +
|
", oldname=" + oldName + ", oldnumber=" + oldNumber +
|
||||||
", newname=" + newName + ", newnumber=" + newNumber);
|
", newname=" + newName + ", newnumber=" + newNumber);
|
||||||
@@ -407,9 +416,10 @@ public class IccProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean deleteIccRecordFromEf(int efType, String name, String number, String pin2) {
|
private boolean deleteIccRecordFromEf(int efType, String name, String number, String[] emails,
|
||||||
|
String pin2) {
|
||||||
if (DBG) log("deleteIccRecordFromEf: efType=" + efType +
|
if (DBG) log("deleteIccRecordFromEf: efType=" + efType +
|
||||||
", name=" + name + ", number=" + number + ", pin2=" + pin2);
|
", name=" + name + ", number=" + number + ", emails=" + emails + ", pin2=" + pin2);
|
||||||
|
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
|
|
||||||
@@ -438,13 +448,26 @@ public class IccProvider extends ContentProvider {
|
|||||||
private void loadRecord(AdnRecord record,
|
private void loadRecord(AdnRecord record,
|
||||||
ArrayList<ArrayList> results) {
|
ArrayList<ArrayList> results) {
|
||||||
if (!record.isEmpty()) {
|
if (!record.isEmpty()) {
|
||||||
ArrayList<String> contact = new ArrayList<String>(2);
|
ArrayList<String> contact = new ArrayList<String>();
|
||||||
String alphaTag = record.getAlphaTag();
|
String alphaTag = record.getAlphaTag();
|
||||||
String number = record.getNumber();
|
String number = record.getNumber();
|
||||||
|
String[] emails = record.getEmails();
|
||||||
|
|
||||||
if (DBG) log("loadRecord: " + alphaTag + ", " + number);
|
if (DBG) log("loadRecord: " + alphaTag + ", " + number + ",");
|
||||||
contact.add(alphaTag);
|
contact.add(alphaTag);
|
||||||
contact.add(number);
|
contact.add(number);
|
||||||
|
StringBuilder emailString = new StringBuilder();
|
||||||
|
|
||||||
|
if (emails != null) {
|
||||||
|
for (String email: emails) {
|
||||||
|
if (DBG) log("Adding email:" + email);
|
||||||
|
emailString.append(email);
|
||||||
|
emailString.append(",");
|
||||||
|
}
|
||||||
|
contact.add(emailString.toString());
|
||||||
|
} else {
|
||||||
|
contact.add(null);
|
||||||
|
}
|
||||||
results.add(contact);
|
results.add(contact);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,15 +19,18 @@ package com.android.internal.telephony.gsm;
|
|||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.internal.telephony.IccCard;
|
||||||
|
import com.android.internal.telephony.IccCardApplication;
|
||||||
import com.android.internal.telephony.IccConstants;
|
import com.android.internal.telephony.IccConstants;
|
||||||
import com.android.internal.telephony.IccFileHandler;
|
import com.android.internal.telephony.IccFileHandler;
|
||||||
|
import com.android.internal.telephony.Phone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@hide}
|
* {@hide}
|
||||||
*/
|
*/
|
||||||
public final class SIMFileHandler extends IccFileHandler implements IccConstants {
|
public final class SIMFileHandler extends IccFileHandler implements IccConstants {
|
||||||
static final String LOG_TAG = "GSM";
|
static final String LOG_TAG = "GSM";
|
||||||
|
private Phone mPhone;
|
||||||
|
|
||||||
//***** Instance Variables
|
//***** Instance Variables
|
||||||
|
|
||||||
@@ -35,6 +38,7 @@ public final class SIMFileHandler extends IccFileHandler implements IccConstants
|
|||||||
|
|
||||||
SIMFileHandler(GSMPhone phone) {
|
SIMFileHandler(GSMPhone phone) {
|
||||||
super(phone);
|
super(phone);
|
||||||
|
mPhone = phone;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
@@ -53,7 +57,6 @@ public final class SIMFileHandler extends IccFileHandler implements IccConstants
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected String getEFPath(int efid) {
|
protected String getEFPath(int efid) {
|
||||||
// TODO(): Make changes when USIM is supported
|
|
||||||
// TODO(): DF_GSM can be 7F20 or 7F21 to handle backward compatibility.
|
// TODO(): DF_GSM can be 7F20 or 7F21 to handle backward compatibility.
|
||||||
// Implement this after discussion with OEMs.
|
// Implement this after discussion with OEMs.
|
||||||
switch(efid) {
|
switch(efid) {
|
||||||
@@ -79,8 +82,23 @@ public final class SIMFileHandler extends IccFileHandler implements IccConstants
|
|||||||
case EF_SPN_SHORT_CPHS:
|
case EF_SPN_SHORT_CPHS:
|
||||||
case EF_INFO_CPHS:
|
case EF_INFO_CPHS:
|
||||||
return MF_SIM + DF_GSM;
|
return MF_SIM + DF_GSM;
|
||||||
|
|
||||||
|
case EF_PBR:
|
||||||
|
// we only support global phonebook.
|
||||||
|
return MF_SIM + DF_TELECOM + DF_PHONEBOOK;
|
||||||
}
|
}
|
||||||
return getCommonIccEFPath(efid);
|
String path = getCommonIccEFPath(efid);
|
||||||
|
if (path == null) {
|
||||||
|
// The EFids in USIM phone book entries are decided by the card manufacturer.
|
||||||
|
// So if we don't match any of the cases above and if its a USIM return
|
||||||
|
// the phone book path.
|
||||||
|
IccCard card = phone.getIccCard();
|
||||||
|
if (card != null && card.isApplicationOnIcc(IccCardApplication.AppType.APPTYPE_USIM)) {
|
||||||
|
return MF_SIM + DF_TELECOM + DF_PHONEBOOK;
|
||||||
|
}
|
||||||
|
Log.e(LOG_TAG, "Error: EF Path being returned in null");
|
||||||
|
}
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void logd(String msg) {
|
protected void logd(String msg) {
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ public class SimTlv
|
|||||||
|
|
||||||
public boolean nextObject() {
|
public boolean nextObject() {
|
||||||
if (!hasValidTlvObject) return false;
|
if (!hasValidTlvObject) return false;
|
||||||
|
|
||||||
curOffset = curDataOffset + curDataLength;
|
curOffset = curDataOffset + curDataLength;
|
||||||
hasValidTlvObject = parseCurrentTlvObject();
|
hasValidTlvObject = parseCurrentTlvObject();
|
||||||
return hasValidTlvObject;
|
return hasValidTlvObject;
|
||||||
@@ -88,11 +87,12 @@ public class SimTlv
|
|||||||
|
|
||||||
private boolean parseCurrentTlvObject() {
|
private boolean parseCurrentTlvObject() {
|
||||||
// 0x00 and 0xff are invalid tag values
|
// 0x00 and 0xff are invalid tag values
|
||||||
if (record[curOffset] == 0 || (record[curOffset] & 0xff) == 0xff) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (record[curOffset] == 0 || (record[curOffset] & 0xff) == 0xff) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if ((record[curOffset + 1] & 0xff) < 0x80) {
|
if ((record[curOffset + 1] & 0xff) < 0x80) {
|
||||||
// one byte length 0 - 0x7f
|
// one byte length 0 - 0x7f
|
||||||
curDataLength = record[curOffset + 1] & 0xff;
|
curDataLength = record[curOffset + 1] & 0xff;
|
||||||
|
|||||||
@@ -0,0 +1,424 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.internal.telephony.gsm;
|
||||||
|
|
||||||
|
import android.os.AsyncResult;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.internal.telephony.AdnRecord;
|
||||||
|
import com.android.internal.telephony.AdnRecordCache;
|
||||||
|
import com.android.internal.telephony.IccConstants;
|
||||||
|
import com.android.internal.telephony.IccUtils;
|
||||||
|
import com.android.internal.telephony.PhoneBase;
|
||||||
|
|
||||||
|
import org.apache.harmony.luni.lang.reflect.ListOfTypes;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class implements reading and parsing USIM records.
|
||||||
|
* Refer to Spec 3GPP TS 31.102 for more details.
|
||||||
|
*
|
||||||
|
* {@hide}
|
||||||
|
*/
|
||||||
|
public class UsimPhoneBookManager extends Handler implements IccConstants {
|
||||||
|
private static final String LOG_TAG = "GSM";
|
||||||
|
private static final boolean DBG = true;
|
||||||
|
private PbrFile mPbrFile;
|
||||||
|
private Boolean mIsPbrPresent;
|
||||||
|
private PhoneBase mPhone;
|
||||||
|
private AdnRecordCache mAdnCache;
|
||||||
|
private Object mLock = new Object();
|
||||||
|
private ArrayList<AdnRecord> mPhoneBookRecords;
|
||||||
|
private boolean mEmailPresentInIap = false;
|
||||||
|
private int mEmailTagNumberInIap = 0;
|
||||||
|
private ArrayList<byte[]> mIapFileRecord;
|
||||||
|
private ArrayList<byte[]> mEmailFileRecord;
|
||||||
|
private Map<Integer, ArrayList<String>> mEmailsForAdnRec;
|
||||||
|
|
||||||
|
private static final int EVENT_PBR_LOAD_DONE = 1;
|
||||||
|
private static final int EVENT_USIM_ADN_LOAD_DONE = 2;
|
||||||
|
private static final int EVENT_IAP_LOAD_DONE = 3;
|
||||||
|
private static final int EVENT_EMAIL_LOAD_DONE = 4;
|
||||||
|
|
||||||
|
private static final int USIM_TYPE1_TAG = 0xA8;
|
||||||
|
private static final int USIM_TYPE2_TAG = 0xA9;
|
||||||
|
private static final int USIM_TYPE3_TAG = 0xAA;
|
||||||
|
private static final int USIM_EFADN_TAG = 0xC0;
|
||||||
|
private static final int USIM_EFIAP_TAG = 0xC1;
|
||||||
|
private static final int USIM_EFEXT1_TAG = 0xC2;
|
||||||
|
private static final int USIM_EFSNE_TAG = 0xC3;
|
||||||
|
private static final int USIM_EFANR_TAG = 0xC4;
|
||||||
|
private static final int USIM_EFPBC_TAG = 0xC5;
|
||||||
|
private static final int USIM_EFGRP_TAG = 0xC6;
|
||||||
|
private static final int USIM_EFAAS_TAG = 0xC7;
|
||||||
|
private static final int USIM_EFGSD_TAG = 0xC8;
|
||||||
|
private static final int USIM_EFUID_TAG = 0xC9;
|
||||||
|
private static final int USIM_EFEMAIL_TAG = 0xCA;
|
||||||
|
private static final int USIM_EFCCP1_TAG = 0xCB;
|
||||||
|
|
||||||
|
public UsimPhoneBookManager(PhoneBase phone, AdnRecordCache cache) {
|
||||||
|
mPhone = phone;
|
||||||
|
mPhoneBookRecords = new ArrayList<AdnRecord>();
|
||||||
|
mPbrFile = null;
|
||||||
|
// We assume its present, after the first read this is updated.
|
||||||
|
// So we don't have to read from UICC if its not present on subsequent reads.
|
||||||
|
mIsPbrPresent = true;
|
||||||
|
mAdnCache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
mPhoneBookRecords.clear();
|
||||||
|
mIapFileRecord = null;
|
||||||
|
mEmailFileRecord = null;
|
||||||
|
mPbrFile = null;
|
||||||
|
mIsPbrPresent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<AdnRecord> loadEfFilesFromUsim() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
if (!mPhoneBookRecords.isEmpty()) return mPhoneBookRecords;
|
||||||
|
if (!mIsPbrPresent) return null;
|
||||||
|
|
||||||
|
// Check if the PBR file is present in the cache, if not read it
|
||||||
|
// from the USIM.
|
||||||
|
if (mPbrFile == null) {
|
||||||
|
readPbrFileAndWait();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mPbrFile == null) return null;
|
||||||
|
|
||||||
|
int numRecs = mPbrFile.mFileIds.size();
|
||||||
|
for (int i = 0; i < numRecs; i++) {
|
||||||
|
readAdnFileAndWait(i);
|
||||||
|
readEmailFileAndWait(i);
|
||||||
|
}
|
||||||
|
// All EF files are loaded, post the response.
|
||||||
|
}
|
||||||
|
return mPhoneBookRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readPbrFileAndWait() {
|
||||||
|
mPhone.getIccFileHandler().loadEFLinearFixedAll(EF_PBR, obtainMessage(EVENT_PBR_LOAD_DONE));
|
||||||
|
try {
|
||||||
|
mLock.wait();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Log.e(LOG_TAG, "Interrupted Exception in readAdnFileAndWait");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readEmailFileAndWait(int recNum) {
|
||||||
|
Map <Integer,Integer> fileIds;
|
||||||
|
fileIds = mPbrFile.mFileIds.get(recNum);
|
||||||
|
if (fileIds == null) return;
|
||||||
|
|
||||||
|
if (fileIds.containsKey(USIM_EFEMAIL_TAG)) {
|
||||||
|
int efid = fileIds.get(USIM_EFEMAIL_TAG);
|
||||||
|
// Check if the EFEmail is a Type 1 file or a type 2 file.
|
||||||
|
// If mEmailPresentInIap is true, its a type 2 file.
|
||||||
|
// So we read the IAP file and then read the email records.
|
||||||
|
// instead of reading directly.
|
||||||
|
if (mEmailPresentInIap) {
|
||||||
|
readIapFileAndWait(fileIds.get(USIM_EFIAP_TAG));
|
||||||
|
if (mIapFileRecord == null) {
|
||||||
|
Log.e(LOG_TAG, "Error: IAP file is empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Read the EFEmail file.
|
||||||
|
mPhone.getIccFileHandler().loadEFLinearFixedAll(fileIds.get(USIM_EFEMAIL_TAG),
|
||||||
|
obtainMessage(EVENT_EMAIL_LOAD_DONE));
|
||||||
|
try {
|
||||||
|
mLock.wait();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Log.e(LOG_TAG, "Interrupted Exception in readEmailFileAndWait");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mEmailFileRecord == null) {
|
||||||
|
Log.e(LOG_TAG, "Error: Email file is empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updatePhoneAdnRecord();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readIapFileAndWait(int efid) {
|
||||||
|
mPhone.getIccFileHandler().loadEFLinearFixedAll(efid, obtainMessage(EVENT_IAP_LOAD_DONE));
|
||||||
|
try {
|
||||||
|
mLock.wait();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Log.e(LOG_TAG, "Interrupted Exception in readIapFileAndWait");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePhoneAdnRecord() {
|
||||||
|
if (mEmailFileRecord == null) return;
|
||||||
|
int numAdnRecs = mPhoneBookRecords.size();
|
||||||
|
if (mIapFileRecord != null) {
|
||||||
|
// The number of records in the IAP file is same as the number of records in ADN file.
|
||||||
|
// The order of the pointers in an EFIAP shall be the same as the order of file IDs
|
||||||
|
// that appear in the TLV object indicated by Tag 'A9' in the reference file record.
|
||||||
|
// i.e value of mEmailTagNumberInIap
|
||||||
|
|
||||||
|
for (int i = 0; i < numAdnRecs; i++) {
|
||||||
|
byte[] record = null;
|
||||||
|
try {
|
||||||
|
record = mIapFileRecord.get(i);
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
Log.e(LOG_TAG, "Error: Improper ICC card: No IAP record for ADN, continuing");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int recNum = record[mEmailTagNumberInIap];
|
||||||
|
|
||||||
|
if (recNum != -1) {
|
||||||
|
String[] emails = new String[1];
|
||||||
|
// SIM record numbers are 1 based
|
||||||
|
emails[0] = readEmailRecord(recNum - 1);
|
||||||
|
AdnRecord rec = mPhoneBookRecords.get(i);
|
||||||
|
if (rec != null) {
|
||||||
|
rec.setEmails(emails);
|
||||||
|
} else {
|
||||||
|
// might be a record with only email
|
||||||
|
rec = new AdnRecord("", "", emails);
|
||||||
|
}
|
||||||
|
mPhoneBookRecords.set(i, rec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICC cards can be made such that they have an IAP file but all
|
||||||
|
// records are empty. So we read both type 1 and type 2 file
|
||||||
|
// email records, just to be sure.
|
||||||
|
|
||||||
|
int len = mPhoneBookRecords.size();
|
||||||
|
// Type 1 file, the number of records is the same as the number of
|
||||||
|
// records in the ADN file.
|
||||||
|
if (mEmailsForAdnRec == null) {
|
||||||
|
parseType1EmailFile(len);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < numAdnRecs; i++) {
|
||||||
|
ArrayList<String> emailList = null;
|
||||||
|
try {
|
||||||
|
emailList = mEmailsForAdnRec.get(i);
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (emailList == null) continue;
|
||||||
|
|
||||||
|
AdnRecord rec = mPhoneBookRecords.get(i);
|
||||||
|
|
||||||
|
String[] emails = new String[emailList.size()];
|
||||||
|
System.arraycopy(emailList.toArray(), 0, emails, 0, emailList.size());
|
||||||
|
rec.setEmails(emails);
|
||||||
|
mPhoneBookRecords.set(i, rec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseType1EmailFile(int numRecs) {
|
||||||
|
mEmailsForAdnRec = new HashMap<Integer, ArrayList<String>>();
|
||||||
|
byte[] emailRec = null;
|
||||||
|
for (int i = 0; i < numRecs; i++) {
|
||||||
|
try {
|
||||||
|
emailRec = mEmailFileRecord.get(i);
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
Log.e(LOG_TAG, "Error: Improper ICC card: No email record for ADN, continuing");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int adnRecNum = emailRec[emailRec.length - 1];
|
||||||
|
|
||||||
|
if (adnRecNum == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String email = readEmailRecord(i);
|
||||||
|
|
||||||
|
if (email == null || email.equals("")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SIM record numbers are 1 based.
|
||||||
|
ArrayList<String> val = mEmailsForAdnRec.get(adnRecNum - 1);
|
||||||
|
if (val == null) {
|
||||||
|
val = new ArrayList<String>();
|
||||||
|
}
|
||||||
|
val.add(email);
|
||||||
|
// SIM record numbers are 1 based.
|
||||||
|
mEmailsForAdnRec.put(adnRecNum - 1, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readEmailRecord(int recNum) {
|
||||||
|
byte[] emailRec = null;
|
||||||
|
try {
|
||||||
|
emailRec = mEmailFileRecord.get(recNum);
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The length of the record is X+2 byte, where X bytes is the email address
|
||||||
|
String email = IccUtils.adnStringFieldToString(emailRec, 0, emailRec.length - 2);
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readAdnFileAndWait(int recNum) {
|
||||||
|
Map <Integer,Integer> fileIds;
|
||||||
|
fileIds = mPbrFile.mFileIds.get(recNum);
|
||||||
|
if (fileIds == null) return;
|
||||||
|
|
||||||
|
mAdnCache.requestLoadAllAdnLike(fileIds.get(USIM_EFADN_TAG),
|
||||||
|
fileIds.get(USIM_EFEXT1_TAG), obtainMessage(EVENT_USIM_ADN_LOAD_DONE));
|
||||||
|
try {
|
||||||
|
mLock.wait();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Log.e(LOG_TAG, "Interrupted Exception in readAdnFileAndWait");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createPbrFile(ArrayList<byte[]> records) {
|
||||||
|
if (records == null) {
|
||||||
|
mPbrFile = null;
|
||||||
|
mIsPbrPresent = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mPbrFile = new PbrFile(records);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
AsyncResult ar;
|
||||||
|
|
||||||
|
switch(msg.what) {
|
||||||
|
case EVENT_PBR_LOAD_DONE:
|
||||||
|
ar = (AsyncResult) msg.obj;
|
||||||
|
if (ar.exception == null) {
|
||||||
|
createPbrFile((ArrayList<byte[]>)ar.result);
|
||||||
|
}
|
||||||
|
synchronized (mLock) {
|
||||||
|
mLock.notify();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EVENT_USIM_ADN_LOAD_DONE:
|
||||||
|
log("Loading USIM ADN records done");
|
||||||
|
ar = (AsyncResult) msg.obj;
|
||||||
|
if (ar.exception == null) {
|
||||||
|
mPhoneBookRecords.addAll((ArrayList<AdnRecord>)ar.result);
|
||||||
|
}
|
||||||
|
synchronized (mLock) {
|
||||||
|
mLock.notify();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EVENT_IAP_LOAD_DONE:
|
||||||
|
log("Loading USIM IAP records done");
|
||||||
|
ar = (AsyncResult) msg.obj;
|
||||||
|
if (ar.exception == null) {
|
||||||
|
mIapFileRecord = ((ArrayList<byte[]>)ar.result);
|
||||||
|
}
|
||||||
|
synchronized (mLock) {
|
||||||
|
mLock.notify();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EVENT_EMAIL_LOAD_DONE:
|
||||||
|
log("Loading USIM Email records done");
|
||||||
|
ar = (AsyncResult) msg.obj;
|
||||||
|
if (ar.exception == null) {
|
||||||
|
mEmailFileRecord = ((ArrayList<byte[]>)ar.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (mLock) {
|
||||||
|
mLock.notify();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PbrFile {
|
||||||
|
// RecNum <EF Tag, efid>
|
||||||
|
HashMap<Integer,Map<Integer,Integer>> mFileIds;
|
||||||
|
|
||||||
|
PbrFile(ArrayList<byte[]> records) {
|
||||||
|
mFileIds = new HashMap<Integer, Map<Integer, Integer>>();
|
||||||
|
SimTlv recTlv;
|
||||||
|
int recNum = 0;
|
||||||
|
for (byte[] record: records) {
|
||||||
|
recTlv = new SimTlv(record, 0, record.length);
|
||||||
|
parseTag(recTlv, recNum);
|
||||||
|
recNum ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseTag(SimTlv tlv, int recNum) {
|
||||||
|
SimTlv tlvEf;
|
||||||
|
int tag;
|
||||||
|
byte[] data;
|
||||||
|
Map<Integer, Integer> val = new HashMap<Integer, Integer>();
|
||||||
|
do {
|
||||||
|
tag = tlv.getTag();
|
||||||
|
switch(tag) {
|
||||||
|
case USIM_TYPE1_TAG: // A8
|
||||||
|
case USIM_TYPE3_TAG: // AA
|
||||||
|
case USIM_TYPE2_TAG: // A9
|
||||||
|
data = tlv.getData();
|
||||||
|
tlvEf = new SimTlv(data, 0, data.length);
|
||||||
|
parseEf(tlvEf, val, tag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (tlv.nextObject());
|
||||||
|
mFileIds.put(recNum, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseEf(SimTlv tlv, Map<Integer, Integer> val, int parentTag) {
|
||||||
|
int tag;
|
||||||
|
byte[] data;
|
||||||
|
int tagNumberWithinParentTag = 0;
|
||||||
|
do {
|
||||||
|
tag = tlv.getTag();
|
||||||
|
if (parentTag == USIM_TYPE2_TAG && tag == USIM_EFEMAIL_TAG) {
|
||||||
|
mEmailPresentInIap = true;
|
||||||
|
mEmailTagNumberInIap = tagNumberWithinParentTag;
|
||||||
|
}
|
||||||
|
switch(tag) {
|
||||||
|
case USIM_EFEMAIL_TAG:
|
||||||
|
case USIM_EFADN_TAG:
|
||||||
|
case USIM_EFEXT1_TAG:
|
||||||
|
case USIM_EFANR_TAG:
|
||||||
|
case USIM_EFPBC_TAG:
|
||||||
|
case USIM_EFGRP_TAG:
|
||||||
|
case USIM_EFAAS_TAG:
|
||||||
|
case USIM_EFGSD_TAG:
|
||||||
|
case USIM_EFUID_TAG:
|
||||||
|
case USIM_EFCCP1_TAG:
|
||||||
|
case USIM_EFIAP_TAG:
|
||||||
|
case USIM_EFSNE_TAG:
|
||||||
|
data = tlv.getData();
|
||||||
|
int efid = data[0] << 8 | data[1];
|
||||||
|
val.put(tag, efid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tagNumberWithinParentTag ++;
|
||||||
|
} while(tlv.nextObject());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void log(String msg) {
|
||||||
|
if(DBG) Log.d(LOG_TAG, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user