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