1 /* 2 * Copyright (C) 2006 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; 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 26 import com.android.internal.telephony.gsm.UsimServiceTable; 27 import com.android.internal.telephony.ims.IsimRecords; 28 29 import java.util.concurrent.atomic.AtomicBoolean; 30 31 /** 32 * {@hide} 33 */ 34 public abstract class IccRecords extends Handler implements IccConstants { 35 36 protected static final boolean DBG = true; 37 // ***** Instance Variables 38 protected AtomicBoolean mDestroyed = new AtomicBoolean(false); 39 protected Context mContext; 40 protected CommandsInterface mCi; 41 protected IccFileHandler mFh; 42 protected UiccCardApplication mParentApp; 43 44 protected RegistrantList recordsLoadedRegistrants = new RegistrantList(); 45 protected RegistrantList mImsiReadyRegistrants = new RegistrantList(); 46 protected RegistrantList mRecordsEventsRegistrants = new RegistrantList(); 47 protected RegistrantList mNewSmsRegistrants = new RegistrantList(); 48 protected RegistrantList mNetworkSelectionModeAutomaticRegistrants = new RegistrantList(); 49 50 protected int recordsToLoad; // number of pending load requests 51 52 protected AdnRecordCache adnCache; 53 54 // ***** Cached SIM State; cleared on channel close 55 56 protected boolean recordsRequested = false; // true if we've made requests for the sim records 57 58 public String iccid; 59 protected String msisdn = null; // My mobile number 60 protected String msisdnTag = null; 61 protected String voiceMailNum = null; 62 protected String voiceMailTag = null; 63 protected String newVoiceMailNum = null; 64 protected String newVoiceMailTag = null; 65 protected boolean isVoiceMailFixed = false; 66 protected int countVoiceMessages = 0; 67 protected String mImsi; 68 69 protected int mncLength = UNINITIALIZED; 70 protected int mailboxIndex = 0; // 0 is no mailbox dailing number associated 71 72 protected String spn; 73 74 // ***** Constants 75 76 // Markers for mncLength 77 protected static final int UNINITIALIZED = -1; 78 protected static final int UNKNOWN = 0; 79 80 // Bitmasks for SPN display rules. 81 protected static final int SPN_RULE_SHOW_SPN = 0x01; 82 protected static final int SPN_RULE_SHOW_PLMN = 0x02; 83 84 // ***** Event Constants 85 protected static final int EVENT_SET_MSISDN_DONE = 30; 86 public static final int EVENT_MWI = 0; // Message Waiting indication 87 public static final int EVENT_CFI = 1; // Call Forwarding indication 88 public static final int EVENT_SPN = 2; // Service Provider Name 89 90 public static final int EVENT_GET_ICC_RECORD_DONE = 100; 91 92 /** 93 * Generic ICC record loaded callback. Subclasses can call EF load methods on 94 * {@link IccFileHandler} passing a Message for onLoaded with the what field set to 95 * {@link #EVENT_GET_ICC_RECORD_DONE} and the obj field set to an instance 96 * of this interface. The {@link #handleMessage} method in this class will print a 97 * log message using {@link #getEfName()} and decrement {@link #recordsToLoad}. 98 * 99 * If the record load was successful, {@link #onRecordLoaded} will be called with the result. 100 * Otherwise, an error log message will be output by {@link #handleMessage} and 101 * {@link #onRecordLoaded} will not be called. 102 */ 103 public interface IccRecordLoaded { 104 String getEfName(); 105 void onRecordLoaded(AsyncResult ar); 106 } 107 108 // ***** Constructor 109 public IccRecords(UiccCardApplication app, Context c, CommandsInterface ci) { 110 mContext = c; 111 mCi = ci; 112 mFh = app.getIccFileHandler(); 113 mParentApp = app; 114 } 115 116 /** 117 * Call when the IccRecords object is no longer going to be used. 118 */ 119 public void dispose() { 120 mDestroyed.set(true); 121 mParentApp = null; 122 mFh = null; 123 mCi = null; 124 mContext = null; 125 } 126 127 public abstract void onReady(); 128 129 //***** Public Methods 130 public AdnRecordCache getAdnCache() { 131 return adnCache; 132 } 133 134 public void registerForRecordsLoaded(Handler h, int what, Object obj) { 135 if (mDestroyed.get()) { 136 return; 137 } 138 139 Registrant r = new Registrant(h, what, obj); 140 recordsLoadedRegistrants.add(r); 141 142 if (recordsToLoad == 0 && recordsRequested == true) { 143 r.notifyRegistrant(new AsyncResult(null, null, null)); 144 } 145 } 146 public void unregisterForRecordsLoaded(Handler h) { 147 recordsLoadedRegistrants.remove(h); 148 } 149 150 public void registerForImsiReady(Handler h, int what, Object obj) { 151 if (mDestroyed.get()) { 152 return; 153 } 154 155 Registrant r = new Registrant(h, what, obj); 156 mImsiReadyRegistrants.add(r); 157 158 if (mImsi != null) { 159 r.notifyRegistrant(new AsyncResult(null, null, null)); 160 } 161 } 162 public void unregisterForImsiReady(Handler h) { 163 mImsiReadyRegistrants.remove(h); 164 } 165 166 public void registerForRecordsEvents(Handler h, int what, Object obj) { 167 Registrant r = new Registrant (h, what, obj); 168 mRecordsEventsRegistrants.add(r); 169 } 170 public void unregisterForRecordsEvents(Handler h) { 171 mRecordsEventsRegistrants.remove(h); 172 } 173 174 public void registerForNewSms(Handler h, int what, Object obj) { 175 Registrant r = new Registrant (h, what, obj); 176 mNewSmsRegistrants.add(r); 177 } 178 public void unregisterForNewSms(Handler h) { 179 mNewSmsRegistrants.remove(h); 180 } 181 182 public void registerForNetworkSelectionModeAutomatic( 183 Handler h, int what, Object obj) { 184 Registrant r = new Registrant (h, what, obj); 185 mNetworkSelectionModeAutomaticRegistrants.add(r); 186 } 187 public void unregisterForNetworkSelectionModeAutomatic(Handler h) { 188 mNetworkSelectionModeAutomaticRegistrants.remove(h); 189 } 190 191 /** 192 * Get the International Mobile Subscriber ID (IMSI) on a SIM 193 * for GSM, UMTS and like networks. Default is null if IMSI is 194 * not supported or unavailable. 195 * 196 * @return null if SIM is not yet ready or unavailable 197 */ 198 public String getIMSI() { 199 return null; 200 } 201 202 /** 203 * Imsi could be set by ServiceStateTrackers in case of cdma 204 * @param imsi 205 */ 206 public void setImsi(String imsi) { 207 this.mImsi = imsi; 208 mImsiReadyRegistrants.notifyRegistrants(); 209 } 210 211 public String getMsisdnNumber() { 212 return msisdn; 213 } 214 215 /** 216 * Set subscriber number to SIM record 217 * 218 * The subscriber number is stored in EF_MSISDN (TS 51.011) 219 * 220 * When the operation is complete, onComplete will be sent to its handler 221 * 222 * @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters) 223 * @param number dailing nubmer (up to 20 digits) 224 * if the number starts with '+', then set to international TOA 225 * @param onComplete 226 * onComplete.obj will be an AsyncResult 227 * ((AsyncResult)onComplete.obj).exception == null on success 228 * ((AsyncResult)onComplete.obj).exception != null on fail 229 */ 230 public void setMsisdnNumber(String alphaTag, String number, 231 Message onComplete) { 232 233 msisdn = number; 234 msisdnTag = alphaTag; 235 236 if(DBG) log("Set MSISDN: " + msisdnTag +" " + msisdn); 237 238 239 AdnRecord adn = new AdnRecord(msisdnTag, msisdn); 240 241 new AdnRecordLoader(mFh).updateEF(adn, EF_MSISDN, EF_EXT1, 1, null, 242 obtainMessage(EVENT_SET_MSISDN_DONE, onComplete)); 243 } 244 245 public String getMsisdnAlphaTag() { 246 return msisdnTag; 247 } 248 249 public String getVoiceMailNumber() { 250 return voiceMailNum; 251 } 252 253 /** 254 * Return Service Provider Name stored in SIM (EF_SPN=0x6F46) or in RUIM (EF_RUIM_SPN=0x6F41) 255 * @return null if SIM is not yet ready or no RUIM entry 256 */ 257 public String getServiceProviderName() { 258 return spn; 259 } 260 261 /** 262 * Set voice mail number to SIM record 263 * 264 * The voice mail number can be stored either in EF_MBDN (TS 51.011) or 265 * EF_MAILBOX_CPHS (CPHS 4.2) 266 * 267 * If EF_MBDN is available, store the voice mail number to EF_MBDN 268 * 269 * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS 270 * 271 * So the voice mail number will be stored in both EFs if both are available 272 * 273 * Return error only if both EF_MBDN and EF_MAILBOX_CPHS fail. 274 * 275 * When the operation is complete, onComplete will be sent to its handler 276 * 277 * @param alphaTag alpha-tagging of the dailing nubmer (upto 10 characters) 278 * @param voiceNumber dailing nubmer (upto 20 digits) 279 * if the number is start with '+', then set to international TOA 280 * @param onComplete 281 * onComplete.obj will be an AsyncResult 282 * ((AsyncResult)onComplete.obj).exception == null on success 283 * ((AsyncResult)onComplete.obj).exception != null on fail 284 */ 285 public abstract void setVoiceMailNumber(String alphaTag, String voiceNumber, 286 Message onComplete); 287 288 public String getVoiceMailAlphaTag() { 289 return voiceMailTag; 290 } 291 292 /** 293 * Sets the SIM voice message waiting indicator records 294 * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported 295 * @param countWaiting The number of messages waiting, if known. Use 296 * -1 to indicate that an unknown number of 297 * messages are waiting 298 */ 299 public abstract void setVoiceMessageWaiting(int line, int countWaiting); 300 301 /** @return true if there are messages waiting, false otherwise. */ 302 public boolean getVoiceMessageWaiting() { 303 return countVoiceMessages != 0; 304 } 305 306 /** 307 * Returns number of voice messages waiting, if available 308 * If not available (eg, on an older CPHS SIM) -1 is returned if 309 * getVoiceMessageWaiting() is true 310 */ 311 public int getVoiceMessageCount() { 312 return countVoiceMessages; 313 } 314 315 /** 316 * Called by STK Service when REFRESH is received. 317 * @param fileChanged indicates whether any files changed 318 * @param fileList if non-null, a list of EF files that changed 319 */ 320 public abstract void onRefresh(boolean fileChanged, int[] fileList); 321 322 323 public boolean getRecordsLoaded() { 324 if (recordsToLoad == 0 && recordsRequested == true) { 325 return true; 326 } else { 327 return false; 328 } 329 } 330 331 //***** Overridden from Handler 332 @Override 333 public void handleMessage(Message msg) { 334 switch (msg.what) { 335 case EVENT_GET_ICC_RECORD_DONE: 336 try { 337 AsyncResult ar = (AsyncResult) msg.obj; 338 IccRecordLoaded recordLoaded = (IccRecordLoaded) ar.userObj; 339 if (DBG) log(recordLoaded.getEfName() + " LOADED"); 340 341 if (ar.exception != null) { 342 loge("Record Load Exception: " + ar.exception); 343 } else { 344 recordLoaded.onRecordLoaded(ar); 345 } 346 }catch (RuntimeException exc) { 347 // I don't want these exceptions to be fatal 348 loge("Exception parsing SIM record: " + exc); 349 } finally { 350 // Count up record load responses even if they are fails 351 onRecordLoaded(); 352 } 353 break; 354 355 default: 356 super.handleMessage(msg); 357 } 358 } 359 360 protected abstract void onRecordLoaded(); 361 362 protected abstract void onAllRecordsLoaded(); 363 364 /** 365 * Returns the SpnDisplayRule based on settings on the SIM and the 366 * specified plmn (currently-registered PLMN). See TS 22.101 Annex A 367 * and TS 51.011 10.3.11 for details. 368 * 369 * If the SPN is not found on the SIM, the rule is always PLMN_ONLY. 370 * Generally used for GSM/UMTS and the like SIMs. 371 */ 372 public abstract int getDisplayRule(String plmn); 373 374 /** 375 * Return true if "Restriction of menu options for manual PLMN selection" 376 * bit is set or EF_CSP data is unavailable, return false otherwise. 377 * Generally used for GSM/UMTS and the like SIMs. 378 */ 379 public boolean isCspPlmnEnabled() { 380 return false; 381 } 382 383 /** 384 * Returns the 5 or 6 digit MCC/MNC of the operator that 385 * provided the SIM card. Returns null of SIM is not yet ready 386 * or is not valid for the type of IccCard. Generally used for 387 * GSM/UMTS and the like SIMS 388 */ 389 public String getOperatorNumeric() { 390 return null; 391 } 392 393 /** 394 * Get the current Voice call forwarding flag for GSM/UMTS and the like SIMs 395 * 396 * @return true if enabled 397 */ 398 public boolean getVoiceCallForwardingFlag() { 399 return false; 400 } 401 402 /** 403 * Set the voice call forwarding flag for GSM/UMTS and the like SIMs 404 * 405 * @param line to enable/disable 406 * @param enable 407 */ 408 public void setVoiceCallForwardingFlag(int line, boolean enable) { 409 } 410 411 /** 412 * Indicates wether SIM is in provisioned state or not. 413 * Overridden only if SIM can be dynamically provisioned via OTA. 414 * 415 * @return true if provisioned 416 */ 417 public boolean isProvisioned () { 418 return true; 419 } 420 421 /** 422 * Write string to log file 423 * 424 * @param s is the string to write 425 */ 426 protected abstract void log(String s); 427 428 /** 429 * Write error string to log file. 430 * 431 * @param s is the string to write 432 */ 433 protected abstract void loge(String s); 434 435 /** 436 * Return an interface to retrieve the ISIM records for IMS, if available. 437 * @return the interface to retrieve the ISIM records, or null if not supported 438 */ 439 public IsimRecords getIsimRecords() { 440 return null; 441 } 442 443 public UsimServiceTable getUsimServiceTable() { 444 return null; 445 } 446 } 447