Home | History | Annotate | Download | only in uicc
      1 /*
      2  * Copyright (C) 2011-2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.telephony.uicc;
     18 
     19 import android.content.Context;
     20 import android.os.AsyncResult;
     21 import android.os.Handler;
     22 import android.os.Message;
     23 import android.os.Registrant;
     24 import android.os.RegistrantList;
     25 import android.util.Log;
     26 
     27 import com.android.internal.telephony.CommandsInterface;
     28 import com.android.internal.telephony.IccCardStatus;
     29 import com.android.internal.telephony.IccFileHandler;
     30 import com.android.internal.telephony.IccRecords;
     31 import com.android.internal.telephony.PhoneConstants;
     32 import com.android.internal.telephony.UiccCard;
     33 import com.android.internal.telephony.UiccCardApplication;
     34 
     35 /**
     36  * This class is responsible for keeping all knowledge about
     37  * Universal Integrated Circuit Card (UICC), also know as SIM's,
     38  * in the system. It is also used as API to get appropriate
     39  * applications to pass them to phone and service trackers.
     40  *
     41  * UiccController is created with the call to make() function.
     42  * UiccController is a singleton and make() must only be called once
     43  * and throws an exception if called multiple times.
     44  *
     45  * Once created UiccController registers with RIL for "on" and "unsol_sim_status_changed"
     46  * notifications. When such notification arrives UiccController will call
     47  * getIccCardStatus (GET_SIM_STATUS). Based on the response of GET_SIM_STATUS
     48  * request appropriate tree of uicc objects will be created.
     49  *
     50  * Following is class diagram for uicc classes:
     51  *
     52  *                       UiccController
     53  *                            #
     54  *                            |
     55  *                        UiccCard
     56  *                          #   #
     57  *                          |   ------------------
     58  *                    UiccCardApplication    CatService
     59  *                      #            #
     60  *                      |            |
     61  *                 IccRecords    IccFileHandler
     62  *                 ^ ^ ^           ^ ^ ^ ^ ^
     63  *    SIMRecords---- | |           | | | | ---SIMFileHandler
     64  *    RuimRecords----- |           | | | ----RuimFileHandler
     65  *    IsimUiccRecords---           | | -----UsimFileHandler
     66  *                                 | ------CsimFileHandler
     67  *                                 ----IsimFileHandler
     68  *
     69  * Legend: # stands for Composition
     70  *         ^ stands for Generalization
     71  *
     72  * See also {@link com.android.internal.telephony.IccCard}
     73  * and {@link com.android.internal.telephony.IccCardProxy}
     74  */
     75 public class UiccController extends Handler {
     76     private static final boolean DBG = true;
     77     private static final String LOG_TAG = "RIL_UiccController";
     78 
     79     public static final int APP_FAM_3GPP =  1;
     80     public static final int APP_FAM_3GPP2 = 2;
     81     public static final int APP_FAM_IMS   = 3;
     82 
     83     private static final int EVENT_ICC_STATUS_CHANGED = 1;
     84     private static final int EVENT_GET_ICC_STATUS_DONE = 2;
     85 
     86     private static final Object mLock = new Object();
     87     private static UiccController mInstance;
     88 
     89     private Context mContext;
     90     private CommandsInterface mCi;
     91     private UiccCard mUiccCard;
     92 
     93     private RegistrantList mIccChangedRegistrants = new RegistrantList();
     94 
     95     public static UiccController make(Context c, CommandsInterface ci) {
     96         synchronized (mLock) {
     97             if (mInstance != null) {
     98                 throw new RuntimeException("UiccController.make() should only be called once");
     99             }
    100             mInstance = new UiccController(c, ci);
    101             return mInstance;
    102         }
    103     }
    104 
    105     public static UiccController getInstance() {
    106         synchronized (mLock) {
    107             if (mInstance == null) {
    108                 throw new RuntimeException(
    109                         "UiccController.getInstance can't be called before make()");
    110             }
    111             return mInstance;
    112         }
    113     }
    114 
    115     public UiccCard getUiccCard() {
    116         synchronized (mLock) {
    117             return mUiccCard;
    118         }
    119     }
    120 
    121     // Easy to use API
    122     public UiccCardApplication getUiccCardApplication(int family) {
    123         synchronized (mLock) {
    124             if (mUiccCard != null) {
    125                 return mUiccCard.getApplication(family);
    126             }
    127             return null;
    128         }
    129     }
    130 
    131     // Easy to use API
    132     public IccRecords getIccRecords(int family) {
    133         synchronized (mLock) {
    134             if (mUiccCard != null) {
    135                 UiccCardApplication app = mUiccCard.getApplication(family);
    136                 if (app != null) {
    137                     return app.getIccRecords();
    138                 }
    139             }
    140             return null;
    141         }
    142     }
    143 
    144     // Easy to use API
    145     public IccFileHandler getIccFileHandler(int family) {
    146         synchronized (mLock) {
    147             if (mUiccCard != null) {
    148                 UiccCardApplication app = mUiccCard.getApplication(family);
    149                 if (app != null) {
    150                     return app.getIccFileHandler();
    151                 }
    152             }
    153             return null;
    154         }
    155     }
    156 
    157     //Notifies when card status changes
    158     public void registerForIccChanged(Handler h, int what, Object obj) {
    159         synchronized (mLock) {
    160             Registrant r = new Registrant (h, what, obj);
    161             mIccChangedRegistrants.add(r);
    162             //Notify registrant right after registering, so that it will get the latest ICC status,
    163             //otherwise which may not happen until there is an actual change in ICC status.
    164             r.notifyRegistrant();
    165         }
    166     }
    167 
    168     public void unregisterForIccChanged(Handler h) {
    169         synchronized (mLock) {
    170             mIccChangedRegistrants.remove(h);
    171         }
    172     }
    173 
    174     @Override
    175     public void handleMessage (Message msg) {
    176         synchronized (mLock) {
    177             switch (msg.what) {
    178                 case EVENT_ICC_STATUS_CHANGED:
    179                     if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
    180                     mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
    181                     break;
    182                 case EVENT_GET_ICC_STATUS_DONE:
    183                     if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
    184                     AsyncResult ar = (AsyncResult)msg.obj;
    185                     onGetIccCardStatusDone(ar);
    186                     break;
    187                 default:
    188                     Log.e(LOG_TAG, " Unknown Event " + msg.what);
    189             }
    190         }
    191     }
    192 
    193     private UiccController(Context c, CommandsInterface ci) {
    194         if (DBG) log("Creating UiccController");
    195         mContext = c;
    196         mCi = ci;
    197         mCi.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null);
    198         // TODO remove this once modem correctly notifies the unsols
    199         mCi.registerForOn(this, EVENT_ICC_STATUS_CHANGED, null);
    200     }
    201 
    202     private synchronized void onGetIccCardStatusDone(AsyncResult ar) {
    203         if (ar.exception != null) {
    204             Log.e(LOG_TAG,"Error getting ICC status. "
    205                     + "RIL_REQUEST_GET_ICC_STATUS should "
    206                     + "never return an error", ar.exception);
    207             return;
    208         }
    209 
    210         IccCardStatus status = (IccCardStatus)ar.result;
    211 
    212         if (mUiccCard == null) {
    213             //Create new card
    214             mUiccCard = new UiccCard(mContext, mCi, status);
    215         } else {
    216             //Update already existing card
    217             mUiccCard.update(mContext, mCi , status);
    218         }
    219 
    220         if (DBG) log("Notifying IccChangedRegistrants");
    221         mIccChangedRegistrants.notifyRegistrants();
    222     }
    223 
    224     private void log(String string) {
    225         Log.d(LOG_TAG, string);
    226     }
    227 }
    228