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