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.telephony.Rlog;
     26 
     27 import com.android.internal.telephony.CommandsInterface;
     28 
     29 import java.io.FileDescriptor;
     30 import java.io.PrintWriter;
     31 
     32 /**
     33  * This class is responsible for keeping all knowledge about
     34  * Universal Integrated Circuit Card (UICC), also know as SIM's,
     35  * in the system. It is also used as API to get appropriate
     36  * applications to pass them to phone and service trackers.
     37  *
     38  * UiccController is created with the call to make() function.
     39  * UiccController is a singleton and make() must only be called once
     40  * and throws an exception if called multiple times.
     41  *
     42  * Once created UiccController registers with RIL for "on" and "unsol_sim_status_changed"
     43  * notifications. When such notification arrives UiccController will call
     44  * getIccCardStatus (GET_SIM_STATUS). Based on the response of GET_SIM_STATUS
     45  * request appropriate tree of uicc objects will be created.
     46  *
     47  * Following is class diagram for uicc classes:
     48  *
     49  *                       UiccController
     50  *                            #
     51  *                            |
     52  *                        UiccCard
     53  *                          #   #
     54  *                          |   ------------------
     55  *                    UiccCardApplication    CatService
     56  *                      #            #
     57  *                      |            |
     58  *                 IccRecords    IccFileHandler
     59  *                 ^ ^ ^           ^ ^ ^ ^ ^
     60  *    SIMRecords---- | |           | | | | ---SIMFileHandler
     61  *    RuimRecords----- |           | | | ----RuimFileHandler
     62  *    IsimUiccRecords---           | | -----UsimFileHandler
     63  *                                 | ------CsimFileHandler
     64  *                                 ----IsimFileHandler
     65  *
     66  * Legend: # stands for Composition
     67  *         ^ stands for Generalization
     68  *
     69  * See also {@link com.android.internal.telephony.IccCard}
     70  * and {@link com.android.internal.telephony.uicc.IccCardProxy}
     71  */
     72 public class UiccController extends Handler {
     73     private static final boolean DBG = true;
     74     private static final String LOG_TAG = "UiccController";
     75 
     76     public static final int APP_FAM_3GPP =  1;
     77     public static final int APP_FAM_3GPP2 = 2;
     78     public static final int APP_FAM_IMS   = 3;
     79 
     80     private static final int EVENT_ICC_STATUS_CHANGED = 1;
     81     private static final int EVENT_GET_ICC_STATUS_DONE = 2;
     82 
     83     private static final Object mLock = new Object();
     84     private static UiccController mInstance;
     85 
     86     private Context mContext;
     87     private CommandsInterface mCi;
     88     private UiccCard mUiccCard;
     89 
     90     private RegistrantList mIccChangedRegistrants = new RegistrantList();
     91 
     92     public static UiccController make(Context c, CommandsInterface ci) {
     93         synchronized (mLock) {
     94             if (mInstance != null) {
     95                 throw new RuntimeException("UiccController.make() should only be called once");
     96             }
     97             mInstance = new UiccController(c, ci);
     98             return mInstance;
     99         }
    100     }
    101 
    102     public static UiccController getInstance() {
    103         synchronized (mLock) {
    104             if (mInstance == null) {
    105                 throw new RuntimeException(
    106                         "UiccController.getInstance can't be called before make()");
    107             }
    108             return mInstance;
    109         }
    110     }
    111 
    112     public UiccCard getUiccCard() {
    113         synchronized (mLock) {
    114             return mUiccCard;
    115         }
    116     }
    117 
    118     // Easy to use API
    119     public UiccCardApplication getUiccCardApplication(int family) {
    120         synchronized (mLock) {
    121             if (mUiccCard != null) {
    122                 return mUiccCard.getApplication(family);
    123             }
    124             return null;
    125         }
    126     }
    127 
    128     // Easy to use API
    129     public IccRecords getIccRecords(int family) {
    130         synchronized (mLock) {
    131             if (mUiccCard != null) {
    132                 UiccCardApplication app = mUiccCard.getApplication(family);
    133                 if (app != null) {
    134                     return app.getIccRecords();
    135                 }
    136             }
    137             return null;
    138         }
    139     }
    140 
    141     // Easy to use API
    142     public IccFileHandler getIccFileHandler(int family) {
    143         synchronized (mLock) {
    144             if (mUiccCard != null) {
    145                 UiccCardApplication app = mUiccCard.getApplication(family);
    146                 if (app != null) {
    147                     return app.getIccFileHandler();
    148                 }
    149             }
    150             return null;
    151         }
    152     }
    153 
    154     //Notifies when card status changes
    155     public void registerForIccChanged(Handler h, int what, Object obj) {
    156         synchronized (mLock) {
    157             Registrant r = new Registrant (h, what, obj);
    158             mIccChangedRegistrants.add(r);
    159             //Notify registrant right after registering, so that it will get the latest ICC status,
    160             //otherwise which may not happen until there is an actual change in ICC status.
    161             r.notifyRegistrant();
    162         }
    163     }
    164 
    165     public void unregisterForIccChanged(Handler h) {
    166         synchronized (mLock) {
    167             mIccChangedRegistrants.remove(h);
    168         }
    169     }
    170 
    171     @Override
    172     public void handleMessage (Message msg) {
    173         synchronized (mLock) {
    174             switch (msg.what) {
    175                 case EVENT_ICC_STATUS_CHANGED:
    176                     if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
    177                     mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
    178                     break;
    179                 case EVENT_GET_ICC_STATUS_DONE:
    180                     if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
    181                     AsyncResult ar = (AsyncResult)msg.obj;
    182                     onGetIccCardStatusDone(ar);
    183                     break;
    184                 default:
    185                     Rlog.e(LOG_TAG, " Unknown Event " + msg.what);
    186             }
    187         }
    188     }
    189 
    190     private UiccController(Context c, CommandsInterface ci) {
    191         if (DBG) log("Creating UiccController");
    192         mContext = c;
    193         mCi = ci;
    194         mCi.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null);
    195         // TODO remove this once modem correctly notifies the unsols
    196         mCi.registerForOn(this, EVENT_ICC_STATUS_CHANGED, null);
    197     }
    198 
    199     private synchronized void onGetIccCardStatusDone(AsyncResult ar) {
    200         if (ar.exception != null) {
    201             Rlog.e(LOG_TAG,"Error getting ICC status. "
    202                     + "RIL_REQUEST_GET_ICC_STATUS should "
    203                     + "never return an error", ar.exception);
    204             return;
    205         }
    206 
    207         IccCardStatus status = (IccCardStatus)ar.result;
    208 
    209         if (mUiccCard == null) {
    210             //Create new card
    211             mUiccCard = new UiccCard(mContext, mCi, status);
    212         } else {
    213             //Update already existing card
    214             mUiccCard.update(mContext, mCi , status);
    215         }
    216 
    217         if (DBG) log("Notifying IccChangedRegistrants");
    218         mIccChangedRegistrants.notifyRegistrants();
    219     }
    220 
    221     private void log(String string) {
    222         Rlog.d(LOG_TAG, string);
    223     }
    224 
    225     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    226         pw.println("UiccController: " + this);
    227         pw.println(" mContext=" + mContext);
    228         pw.println(" mInstance=" + mInstance);
    229         pw.println(" mCi=" + mCi);
    230         pw.println(" mUiccCard=" + mUiccCard);
    231         pw.println(" mIccChangedRegistrants: size=" + mIccChangedRegistrants.size());
    232         for (int i = 0; i < mIccChangedRegistrants.size(); i++) {
    233             pw.println("  mIccChangedRegistrants[" + i + "]="
    234                     + ((Registrant)mIccChangedRegistrants.get(i)).getHandler());
    235         }
    236         pw.println();
    237         pw.flush();
    238         if (mUiccCard != null) {
    239             mUiccCard.dump(fd, pw, args);
    240         }
    241     }
    242 }
    243