/* * Copyright (C) 2011-2012 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.uicc; import android.content.Context; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; import android.util.Log; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IccCardStatus; import com.android.internal.telephony.IccFileHandler; import com.android.internal.telephony.IccRecords; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.UiccCard; import com.android.internal.telephony.UiccCardApplication; /** * 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.IccCardProxy} */ public class UiccController extends Handler { private static final boolean DBG = true; private static final String LOG_TAG = "RIL_UiccController"; public static final int APP_FAM_3GPP = 1; public static final int APP_FAM_3GPP2 = 2; public static final int APP_FAM_IMS = 3; private static final int EVENT_ICC_STATUS_CHANGED = 1; private static final int EVENT_GET_ICC_STATUS_DONE = 2; private static final Object mLock = new Object(); private static UiccController mInstance; private Context mContext; private CommandsInterface mCi; private UiccCard mUiccCard; private RegistrantList mIccChangedRegistrants = new RegistrantList(); public static UiccController make(Context c, CommandsInterface ci) { synchronized (mLock) { if (mInstance != null) { throw new RuntimeException("UiccController.make() should only be called once"); } mInstance = new UiccController(c, ci); return mInstance; } } public static UiccController getInstance() { synchronized (mLock) { if (mInstance == null) { throw new RuntimeException( "UiccController.getInstance can't be called before make()"); } return mInstance; } } public UiccCard getUiccCard() { synchronized (mLock) { return mUiccCard; } } // Easy to use API public UiccCardApplication getUiccCardApplication(int family) { synchronized (mLock) { if (mUiccCard != null) { return mUiccCard.getApplication(family); } return null; } } // Easy to use API public IccRecords getIccRecords(int family) { synchronized (mLock) { if (mUiccCard != null) { UiccCardApplication app = mUiccCard.getApplication(family); if (app != null) { return app.getIccRecords(); } } return null; } } // Easy to use API public IccFileHandler getIccFileHandler(int family) { synchronized (mLock) { if (mUiccCard != null) { UiccCardApplication app = mUiccCard.getApplication(family); if (app != null) { return app.getIccFileHandler(); } } return null; } } //Notifies when card status changes public void registerForIccChanged(Handler h, int what, 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(Handler h) { synchronized (mLock) { mIccChangedRegistrants.remove(h); } } @Override public void handleMessage (Message msg) { synchronized (mLock) { switch (msg.what) { case EVENT_ICC_STATUS_CHANGED: if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus"); mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE)); break; case EVENT_GET_ICC_STATUS_DONE: if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE"); AsyncResult ar = (AsyncResult)msg.obj; onGetIccCardStatusDone(ar); break; default: Log.e(LOG_TAG, " Unknown Event " + msg.what); } } } private UiccController(Context c, CommandsInterface ci) { if (DBG) log("Creating UiccController"); mContext = c; mCi = ci; mCi.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null); // TODO remove this once modem correctly notifies the unsols mCi.registerForOn(this, EVENT_ICC_STATUS_CHANGED, null); } private synchronized void onGetIccCardStatusDone(AsyncResult ar) { if (ar.exception != null) { Log.e(LOG_TAG,"Error getting ICC status. " + "RIL_REQUEST_GET_ICC_STATUS should " + "never return an error", ar.exception); return; } IccCardStatus status = (IccCardStatus)ar.result; if (mUiccCard == null) { //Create new card mUiccCard = new UiccCard(mContext, mCi, status); } else { //Update already existing card mUiccCard.update(mContext, mCi , status); } if (DBG) log("Notifying IccChangedRegistrants"); mIccChangedRegistrants.notifyRegistrants(); } private void log(String string) { Log.d(LOG_TAG, string); } }