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