UiccControllerpublic class UiccController extends android.os.Handler This class is responsible for keeping all knowledge about
Universal Integrated Circuit Card (UICC), also know as SIM's,
in the system. It is also used as API to get appropriate
applications to pass them to phone and service trackers.
UiccController is created with the call to make() function.
UiccController is a singleton and make() must only be called once
and throws an exception if called multiple times.
Once created UiccController registers with RIL for "on" and "unsol_sim_status_changed"
notifications. When such notification arrives UiccController will call
getIccCardStatus (GET_SIM_STATUS). Based on the response of GET_SIM_STATUS
request appropriate tree of uicc objects will be created.
Following is class diagram for uicc classes:
UiccController
#
|
UiccCard
# #
| ------------------
UiccCardApplication CatService
# #
| |
IccRecords IccFileHandler
^ ^ ^ ^ ^ ^ ^ ^
SIMRecords---- | | | | | | ---SIMFileHandler
RuimRecords----- | | | | ----RuimFileHandler
IsimUiccRecords--- | | -----UsimFileHandler
| ------CsimFileHandler
----IsimFileHandler
Legend: # stands for Composition
^ stands for Generalization
See also {@link com.android.internal.telephony.IccCard}
and {@link com.android.internal.telephony.uicc.IccCardProxy} |
Fields Summary |
---|
private static final boolean | DBG | private static final String | LOG_TAG | public static final int | APP_FAM_3GPP | public static final int | APP_FAM_3GPP2 | public static final int | APP_FAM_IMS | private static final int | EVENT_ICC_STATUS_CHANGED | private static final int | EVENT_GET_ICC_STATUS_DONE | private static final int | EVENT_RADIO_UNAVAILABLE | private static final int | EVENT_SIM_REFRESH | private static final String | DECRYPT_STATE | private com.android.internal.telephony.CommandsInterface[] | mCis | private UiccCard[] | mUiccCards | private static final Object | mLock | private static UiccController | mInstance | private android.content.Context | mContext | protected android.os.RegistrantList | mIccChangedRegistrants |
Constructors Summary |
---|
private UiccController(android.content.Context c, com.android.internal.telephony.CommandsInterface[] ci)
if (DBG) log("Creating UiccController");
mContext = c;
mCis = ci;
for (int i = 0; i < mCis.length; i++) {
Integer index = new Integer(i);
mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, index);
// TODO remove this once modem correctly notifies the unsols
if (DECRYPT_STATE.equals(SystemProperties.get("vold.decrypt"))) {
mCis[i].registerForAvailable(this, EVENT_ICC_STATUS_CHANGED, index);
} else {
mCis[i].registerForOn(this, EVENT_ICC_STATUS_CHANGED, index);
}
mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, index);
mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, index);
}
|
Methods Summary |
---|
public void | dump(java.io.FileDescriptor fd, java.io.PrintWriter pw, java.lang.String[] args)
pw.println("UiccController: " + this);
pw.println(" mContext=" + mContext);
pw.println(" mInstance=" + mInstance);
pw.println(" mIccChangedRegistrants: size=" + mIccChangedRegistrants.size());
for (int i = 0; i < mIccChangedRegistrants.size(); i++) {
pw.println(" mIccChangedRegistrants[" + i + "]="
+ ((Registrant)mIccChangedRegistrants.get(i)).getHandler());
}
pw.println();
pw.flush();
pw.println(" mUiccCards: size=" + mUiccCards.length);
for (int i = 0; i < mUiccCards.length; i++) {
if (mUiccCards[i] == null) {
pw.println(" mUiccCards[" + i + "]=null");
} else {
pw.println(" mUiccCards[" + i + "]=" + mUiccCards[i]);
mUiccCards[i].dump(fd, pw, args);
}
}
| private java.lang.Integer | getCiIndex(android.os.Message msg)
AsyncResult ar;
Integer index = new Integer(PhoneConstants.DEFAULT_CARD_INDEX);
/*
* The events can be come in two ways. By explicitly sending it using
* sendMessage, in this case the user object passed is msg.obj and from
* the CommandsInterface, in this case the user object is msg.obj.userObj
*/
if (msg != null) {
if (msg.obj != null && msg.obj instanceof Integer) {
index = (Integer)msg.obj;
} else if(msg.obj != null && msg.obj instanceof AsyncResult) {
ar = (AsyncResult)msg.obj;
if (ar.userObj != null && ar.userObj instanceof Integer) {
index = (Integer)ar.userObj;
}
}
}
return index;
| public IccFileHandler | getIccFileHandler(int phoneId, int family)
synchronized (mLock) {
UiccCardApplication app = getUiccCardApplication(phoneId, family);
if (app != null) {
return app.getIccFileHandler();
}
return null;
}
| public IccRecords | getIccRecords(int phoneId, int family)
synchronized (mLock) {
UiccCardApplication app = getUiccCardApplication(phoneId, family);
if (app != null) {
return app.getIccRecords();
}
return null;
}
| public static com.android.internal.telephony.uicc.UiccController | getInstance()
synchronized (mLock) {
if (mInstance == null) {
throw new RuntimeException(
"UiccController.getInstance can't be called before make()");
}
return mInstance;
}
| public UiccCard | getUiccCard(int phoneId)
synchronized (mLock) {
if (isValidCardIndex(phoneId)) {
return mUiccCards[phoneId];
}
return null;
}
| public UiccCardApplication | getUiccCardApplication(int phoneId, int family)
synchronized (mLock) {
if (isValidCardIndex(phoneId)) {
UiccCard c = mUiccCards[phoneId];
if (c != null) {
return mUiccCards[phoneId].getApplication(family);
}
}
return null;
}
| public UiccCard[] | getUiccCards()
// Return cloned array since we don't want to give out reference
// to internal data structure.
synchronized (mLock) {
return mUiccCards.clone();
}
| public void | handleMessage(android.os.Message msg)
synchronized (mLock) {
Integer index = getCiIndex(msg);
if (index < 0 || index >= mCis.length) {
Rlog.e(LOG_TAG, "Invalid index : " + index + " received with event " + msg.what);
return;
}
AsyncResult ar = (AsyncResult)msg.obj;
switch (msg.what) {
case EVENT_ICC_STATUS_CHANGED:
if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index));
break;
case EVENT_GET_ICC_STATUS_DONE:
if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
onGetIccCardStatusDone(ar, index);
break;
case EVENT_RADIO_UNAVAILABLE:
if (DBG) log("EVENT_RADIO_UNAVAILABLE, dispose card");
if (mUiccCards[index] != null) {
mUiccCards[index].dispose();
}
mUiccCards[index] = null;
mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
break;
case EVENT_SIM_REFRESH:
if (DBG) log("Received EVENT_SIM_REFRESH");
onSimRefresh(ar, index);
break;
default:
Rlog.e(LOG_TAG, " Unknown Event " + msg.what);
}
}
| private boolean | isValidCardIndex(int index)
return (index >= 0 && index < mUiccCards.length);
| private void | log(java.lang.String string)
Rlog.d(LOG_TAG, string);
| public static com.android.internal.telephony.uicc.UiccController | make(android.content.Context c, com.android.internal.telephony.CommandsInterface[] ci)
synchronized (mLock) {
if (mInstance != null) {
throw new RuntimeException("MSimUiccController.make() should only be called once");
}
mInstance = new UiccController(c, ci);
return (UiccController)mInstance;
}
| private synchronized void | onGetIccCardStatusDone(android.os.AsyncResult ar, java.lang.Integer index)
if (ar.exception != null) {
Rlog.e(LOG_TAG,"Error getting ICC status. "
+ "RIL_REQUEST_GET_ICC_STATUS should "
+ "never return an error", ar.exception);
return;
}
if (!isValidCardIndex(index)) {
Rlog.e(LOG_TAG,"onGetIccCardStatusDone: invalid index : " + index);
return;
}
IccCardStatus status = (IccCardStatus)ar.result;
if (mUiccCards[index] == null) {
//Create new card
mUiccCards[index] = new UiccCard(mContext, mCis[index], status, index);
} else {
//Update already existing card
mUiccCards[index].update(mContext, mCis[index] , status);
}
if (DBG) log("Notifying IccChangedRegistrants");
mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
| private void | onSimRefresh(android.os.AsyncResult ar, java.lang.Integer index)
if (ar.exception != null) {
Rlog.e(LOG_TAG, "Sim REFRESH with exception: " + ar.exception);
return;
}
if (!isValidCardIndex(index)) {
Rlog.e(LOG_TAG,"onSimRefresh: invalid index : " + index);
return;
}
IccRefreshResponse resp = (IccRefreshResponse) ar.result;
Rlog.d(LOG_TAG, "onSimRefresh: " + resp);
if (mUiccCards[index] == null) {
Rlog.e(LOG_TAG,"onSimRefresh: refresh on null card : " + index);
return;
}
if (resp.refreshResult != IccRefreshResponse.REFRESH_RESULT_RESET ||
resp.aid == null) {
Rlog.d(LOG_TAG, "Ignoring reset: " + resp);
return;
}
boolean changed = mUiccCards[index].resetAppWithAid(resp.aid);
if (changed) {
boolean requirePowerOffOnSimRefreshReset = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_requireRadioPowerOffOnSimRefreshReset);
if (requirePowerOffOnSimRefreshReset) {
mCis[index].setRadioPower(false, null);
} else {
mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
}
mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
}
// TODO: For a card level notification, we should delete the CarrierPrivilegeRules and the
// CAT service.
| public void | registerForIccChanged(android.os.Handler h, int what, java.lang.Object obj)
synchronized (mLock) {
Registrant r = new Registrant (h, what, obj);
mIccChangedRegistrants.add(r);
//Notify registrant right after registering, so that it will get the latest ICC status,
//otherwise which may not happen until there is an actual change in ICC status.
r.notifyRegistrant();
}
| public void | unregisterForIccChanged(android.os.Handler h)
synchronized (mLock) {
mIccChangedRegistrants.remove(h);
}
|
|