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