FileDocCategorySizeDatePackage
UiccController.javaAPI DocAndroid 5.1 API13734Thu Mar 12 22:22:54 GMT 2015com.android.internal.telephony.uicc

UiccController

public 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 voiddump(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.IntegergetCiIndex(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 IccFileHandlergetIccFileHandler(int phoneId, int family)

        synchronized (mLock) {
            UiccCardApplication app = getUiccCardApplication(phoneId, family);
            if (app != null) {
                return app.getIccFileHandler();
            }
            return null;
        }
    
public IccRecordsgetIccRecords(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.UiccControllergetInstance()

        synchronized (mLock) {
            if (mInstance == null) {
                throw new RuntimeException(
                        "UiccController.getInstance can't be called before make()");
            }
            return mInstance;
        }
    
public UiccCardgetUiccCard(int phoneId)

        synchronized (mLock) {
            if (isValidCardIndex(phoneId)) {
                return mUiccCards[phoneId];
            }
            return null;
        }
    
public UiccCardApplicationgetUiccCardApplication(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 voidhandleMessage(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 booleanisValidCardIndex(int index)

        return (index >= 0 && index < mUiccCards.length);
    
private voidlog(java.lang.String string)

        Rlog.d(LOG_TAG, string);
    
public static com.android.internal.telephony.uicc.UiccControllermake(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 voidonGetIccCardStatusDone(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 voidonSimRefresh(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 voidregisterForIccChanged(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 voidunregisterForIccChanged(android.os.Handler h)

        synchronized (mLock) {
            mIccChangedRegistrants.remove(h);
        }