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.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 import android.telephony.ServiceState; 27 import android.telephony.SubscriptionInfo; 28 import android.telephony.TelephonyManager; 29 import android.text.TextUtils; 30 31 import com.android.internal.telephony.CommandsInterface; 32 33 import java.io.FileDescriptor; 34 import java.io.PrintWriter; 35 import java.io.UnsupportedEncodingException; 36 import java.util.Arrays; 37 import java.util.HashMap; 38 import java.util.concurrent.atomic.AtomicBoolean; 39 import java.util.concurrent.atomic.AtomicInteger; 40 41 /** 42 * {@hide} 43 */ 44 public abstract class IccRecords extends Handler implements IccConstants { 45 protected static final boolean DBG = true; 46 protected static final boolean VDBG = false; // STOPSHIP if true 47 48 // ***** Instance Variables 49 protected AtomicBoolean mDestroyed = new AtomicBoolean(false); 50 protected AtomicBoolean mLoaded = new AtomicBoolean(false); 51 protected Context mContext; 52 protected CommandsInterface mCi; 53 protected IccFileHandler mFh; 54 protected UiccCardApplication mParentApp; 55 protected TelephonyManager mTelephonyManager; 56 57 protected RegistrantList mRecordsLoadedRegistrants = new RegistrantList(); 58 protected RegistrantList mLockedRecordsLoadedRegistrants = new RegistrantList(); 59 protected RegistrantList mNetworkLockedRecordsLoadedRegistrants = new RegistrantList(); 60 protected RegistrantList mImsiReadyRegistrants = new RegistrantList(); 61 protected RegistrantList mRecordsEventsRegistrants = new RegistrantList(); 62 protected RegistrantList mNewSmsRegistrants = new RegistrantList(); 63 protected RegistrantList mNetworkSelectionModeAutomaticRegistrants = new RegistrantList(); 64 protected RegistrantList mSpnUpdatedRegistrants = new RegistrantList(); 65 protected RegistrantList mRecordsOverrideRegistrants = new RegistrantList(); 66 67 protected int mRecordsToLoad; // number of pending load requests 68 69 protected AdnRecordCache mAdnCache; 70 71 // ***** Cached SIM State; cleared on channel close 72 73 // SIM is not locked 74 protected static final int LOCKED_RECORDS_REQ_REASON_NONE = 0; 75 // Records requested for PIN or PUK locked SIM 76 protected static final int LOCKED_RECORDS_REQ_REASON_LOCKED = 1; 77 // Records requested for network locked SIM 78 protected static final int LOCKED_RECORDS_REQ_REASON_NETWORK_LOCKED = 2; 79 80 protected boolean mRecordsRequested = false; // true if we've made requests for the sim records 81 protected int mLockedRecordsReqReason = LOCKED_RECORDS_REQ_REASON_NONE; 82 83 protected String mIccId; // Includes only decimals (no hex) 84 85 protected String mFullIccId; // Includes hex characters in ICCID 86 protected String mMsisdn = null; // My mobile number 87 protected String mMsisdnTag = null; 88 protected String mNewMsisdn = null; 89 protected String mNewMsisdnTag = null; 90 protected String mVoiceMailNum = null; 91 protected String mVoiceMailTag = null; 92 protected String mNewVoiceMailNum = null; 93 protected String mNewVoiceMailTag = null; 94 protected boolean mIsVoiceMailFixed = false; 95 protected String mImsi; 96 private IccIoResult auth_rsp; 97 98 protected int mMncLength = UNINITIALIZED; 99 protected int mMailboxIndex = 0; // 0 is no mailbox dailing number associated 100 101 private String mSpn; 102 103 protected String mGid1; 104 protected String mGid2; 105 106 protected String mPnnHomeName; 107 108 protected String mPrefLang; 109 110 protected PlmnActRecord[] mHplmnActRecords; 111 protected PlmnActRecord[] mOplmnActRecords; 112 protected PlmnActRecord[] mPlmnActRecords; 113 114 protected String[] mEhplmns; 115 protected String[] mFplmns; 116 117 private final Object mLock = new Object(); 118 119 CarrierTestOverride mCarrierTestOverride; 120 121 //Arbitrary offset for the Handler 122 protected static final int HANDLER_ACTION_BASE = 0x12E500; 123 protected static final int HANDLER_ACTION_NONE = HANDLER_ACTION_BASE + 0; 124 protected static final int HANDLER_ACTION_SEND_RESPONSE = HANDLER_ACTION_BASE + 1; 125 protected static AtomicInteger sNextRequestId = new AtomicInteger(1); 126 protected final HashMap<Integer, Message> mPendingResponses = new HashMap<>(); 127 128 // ***** Constants 129 130 // Markers for mncLength 131 protected static final int UNINITIALIZED = -1; 132 protected static final int UNKNOWN = 0; 133 134 // Bitmasks for SPN display rules. 135 public static final int SPN_RULE_SHOW_SPN = 0x01; 136 public static final int SPN_RULE_SHOW_PLMN = 0x02; 137 138 // ***** Event Constants 139 public static final int EVENT_MWI = 0; // Message Waiting indication 140 public static final int EVENT_CFI = 1; // Call Forwarding indication 141 public static final int EVENT_SPN = 2; // Service Provider Name 142 143 public static final int EVENT_GET_ICC_RECORD_DONE = 100; 144 public static final int EVENT_REFRESH = 31; // ICC refresh occurred 145 protected static final int EVENT_APP_READY = 1; 146 private static final int EVENT_AKA_AUTHENTICATE_DONE = 90; 147 148 public static final int CALL_FORWARDING_STATUS_DISABLED = 0; 149 public static final int CALL_FORWARDING_STATUS_ENABLED = 1; 150 public static final int CALL_FORWARDING_STATUS_UNKNOWN = -1; 151 152 public static final int DEFAULT_VOICE_MESSAGE_COUNT = -2; 153 public static final int UNKNOWN_VOICE_MESSAGE_COUNT = -1; 154 155 @Override 156 public String toString() { 157 String iccIdToPrint = SubscriptionInfo.givePrintableIccid(mFullIccId); 158 return "mDestroyed=" + mDestroyed 159 + " mContext=" + mContext 160 + " mCi=" + mCi 161 + " mFh=" + mFh 162 + " mParentApp=" + mParentApp 163 + " recordsToLoad=" + mRecordsToLoad 164 + " adnCache=" + mAdnCache 165 + " recordsRequested=" + mRecordsRequested 166 + " lockedRecordsReqReason=" + mLockedRecordsReqReason 167 + " iccid=" + iccIdToPrint 168 + (mCarrierTestOverride.isInTestMode() ? "mFakeIccid=" 169 + mCarrierTestOverride.getFakeIccid() : "") 170 + " msisdnTag=" + mMsisdnTag 171 + " voiceMailNum=" + Rlog.pii(VDBG, mVoiceMailNum) 172 + " voiceMailTag=" + mVoiceMailTag 173 + " voiceMailNum=" + Rlog.pii(VDBG, mNewVoiceMailNum) 174 + " newVoiceMailTag=" + mNewVoiceMailTag 175 + " isVoiceMailFixed=" + mIsVoiceMailFixed 176 + " mImsi=" + ((mImsi != null) ? 177 mImsi.substring(0, 6) + Rlog.pii(VDBG, mImsi.substring(6)) : "null") 178 + (mCarrierTestOverride.isInTestMode() ? " mFakeImsi=" 179 + mCarrierTestOverride.getFakeIMSI() : "") 180 + " mncLength=" + mMncLength 181 + " mailboxIndex=" + mMailboxIndex 182 + " spn=" + mSpn 183 + (mCarrierTestOverride.isInTestMode() ? " mFakeSpn=" 184 + mCarrierTestOverride.getFakeSpn() : ""); 185 } 186 187 /** 188 * Generic ICC record loaded callback. Subclasses can call EF load methods on 189 * {@link IccFileHandler} passing a Message for onLoaded with the what field set to 190 * {@link #EVENT_GET_ICC_RECORD_DONE} and the obj field set to an instance 191 * of this interface. The {@link #handleMessage} method in this class will print a 192 * log message using {@link #getEfName()} and decrement {@link #mRecordsToLoad}. 193 * 194 * If the record load was successful, {@link #onRecordLoaded} will be called with the result. 195 * Otherwise, an error log message will be output by {@link #handleMessage} and 196 * {@link #onRecordLoaded} will not be called. 197 */ 198 public interface IccRecordLoaded { 199 String getEfName(); 200 void onRecordLoaded(AsyncResult ar); 201 } 202 203 // ***** Constructor 204 public IccRecords(UiccCardApplication app, Context c, CommandsInterface ci) { 205 mContext = c; 206 mCi = ci; 207 mFh = app.getIccFileHandler(); 208 mParentApp = app; 209 mTelephonyManager = (TelephonyManager) mContext.getSystemService( 210 Context.TELEPHONY_SERVICE); 211 212 mCarrierTestOverride = new CarrierTestOverride(); 213 mCi.registerForIccRefresh(this, EVENT_REFRESH, null); 214 } 215 216 // Override IccRecords for testing 217 public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1, 218 String gid2, String pnn, String spn) { 219 mCarrierTestOverride.override(mccmnc, imsi, iccid, gid1, gid2, pnn, spn); 220 mTelephonyManager.setSimOperatorNameForPhone(mParentApp.getPhoneId(), spn); 221 mTelephonyManager.setSimOperatorNumericForPhone(mParentApp.getPhoneId(), mccmnc); 222 mRecordsOverrideRegistrants.notifyRegistrants(); 223 } 224 225 /** 226 * Call when the IccRecords object is no longer going to be used. 227 */ 228 public void dispose() { 229 mDestroyed.set(true); 230 231 // It is possible that there is another thread waiting for the response 232 // to requestIccSimAuthentication() in getIccSimChallengeResponse(). 233 auth_rsp = null; 234 synchronized (mLock) { 235 mLock.notifyAll(); 236 } 237 238 mCi.unregisterForIccRefresh(this); 239 mParentApp = null; 240 mFh = null; 241 mCi = null; 242 mContext = null; 243 if (mAdnCache != null) { 244 mAdnCache.reset(); 245 } 246 mLoaded.set(false); 247 } 248 249 public abstract void onReady(); 250 251 //***** Public Methods 252 public AdnRecordCache getAdnCache() { 253 return mAdnCache; 254 } 255 256 /** 257 * Adds a message to the pending requests list by generating a unique 258 * (integer) hash key and returning it. The message should never be null. 259 */ 260 public int storePendingResponseMessage(Message msg) { 261 int key = sNextRequestId.getAndIncrement(); 262 synchronized (mPendingResponses) { 263 mPendingResponses.put(key, msg); 264 } 265 return key; 266 } 267 268 /** 269 * Returns the pending request, if any or null 270 */ 271 public Message retrievePendingResponseMessage(Integer key) { 272 Message m; 273 synchronized (mPendingResponses) { 274 return mPendingResponses.remove(key); 275 } 276 } 277 278 /** 279 * Returns the ICC ID stripped at the first hex character. Some SIMs have ICC IDs 280 * containing hex digits; {@link #getFullIccId()} should be used to get the full ID including 281 * hex digits. 282 * @return ICC ID without hex digits 283 */ 284 public String getIccId() { 285 if (mCarrierTestOverride.isInTestMode() && mCarrierTestOverride.getFakeIccid() != null) { 286 return mCarrierTestOverride.getFakeIccid(); 287 } else { 288 return mIccId; 289 } 290 } 291 292 /** 293 * Returns the full ICC ID including hex digits. 294 * @return full ICC ID including hex digits 295 */ 296 public String getFullIccId() { 297 return mFullIccId; 298 } 299 300 public void registerForRecordsLoaded(Handler h, int what, Object obj) { 301 if (mDestroyed.get()) { 302 return; 303 } 304 305 Registrant r = new Registrant(h, what, obj); 306 mRecordsLoadedRegistrants.add(r); 307 308 if (getRecordsLoaded()) { 309 r.notifyRegistrant(new AsyncResult(null, null, null)); 310 } 311 } 312 313 public void unregisterForRecordsLoaded(Handler h) { 314 mRecordsLoadedRegistrants.remove(h); 315 } 316 317 public void unregisterForRecordsOverride(Handler h) { 318 mRecordsOverrideRegistrants.remove(h); 319 } 320 321 public void registerForRecordsOverride(Handler h, int what, Object obj) { 322 if (mDestroyed.get()) { 323 return; 324 } 325 326 Registrant r = new Registrant(h, what, obj); 327 mRecordsOverrideRegistrants.add(r); 328 329 if (getRecordsLoaded()) { 330 r.notifyRegistrant(new AsyncResult(null, null, null)); 331 } 332 } 333 334 /** 335 * Register to be notified when records are loaded for a PIN or PUK locked SIM 336 */ 337 public void registerForLockedRecordsLoaded(Handler h, int what, Object obj) { 338 if (mDestroyed.get()) { 339 return; 340 } 341 342 Registrant r = new Registrant(h, what, obj); 343 mLockedRecordsLoadedRegistrants.add(r); 344 345 if (getLockedRecordsLoaded()) { 346 r.notifyRegistrant(new AsyncResult(null, null, null)); 347 } 348 } 349 350 /** 351 * Unregister corresponding to registerForLockedRecordsLoaded() 352 */ 353 public void unregisterForLockedRecordsLoaded(Handler h) { 354 mLockedRecordsLoadedRegistrants.remove(h); 355 } 356 357 /** 358 * Register to be notified when records are loaded for a network locked SIM 359 */ 360 public void registerForNetworkLockedRecordsLoaded(Handler h, int what, Object obj) { 361 if (mDestroyed.get()) { 362 return; 363 } 364 365 Registrant r = new Registrant(h, what, obj); 366 mNetworkLockedRecordsLoadedRegistrants.add(r); 367 368 if (getNetworkLockedRecordsLoaded()) { 369 r.notifyRegistrant(new AsyncResult(null, null, null)); 370 } 371 } 372 373 /** 374 * Unregister corresponding to registerForLockedRecordsLoaded() 375 */ 376 public void unregisterForNetworkLockedRecordsLoaded(Handler h) { 377 mNetworkLockedRecordsLoadedRegistrants.remove(h); 378 } 379 380 public void registerForImsiReady(Handler h, int what, Object obj) { 381 if (mDestroyed.get()) { 382 return; 383 } 384 385 Registrant r = new Registrant(h, what, obj); 386 mImsiReadyRegistrants.add(r); 387 388 if (getIMSI() != null) { 389 r.notifyRegistrant(new AsyncResult(null, null, null)); 390 } 391 } 392 public void unregisterForImsiReady(Handler h) { 393 mImsiReadyRegistrants.remove(h); 394 } 395 396 public void registerForSpnUpdate(Handler h, int what, Object obj) { 397 if (mDestroyed.get()) { 398 return; 399 } 400 401 Registrant r = new Registrant(h, what, obj); 402 mSpnUpdatedRegistrants.add(r); 403 404 if (!TextUtils.isEmpty(mSpn)) { 405 r.notifyRegistrant(new AsyncResult(null, null, null)); 406 } 407 } 408 public void unregisterForSpnUpdate(Handler h) { 409 mSpnUpdatedRegistrants.remove(h); 410 } 411 412 public void registerForRecordsEvents(Handler h, int what, Object obj) { 413 Registrant r = new Registrant (h, what, obj); 414 mRecordsEventsRegistrants.add(r); 415 416 /* Notify registrant of all the possible events. This is to make sure registrant is 417 notified even if event occurred in the past. */ 418 r.notifyResult(EVENT_MWI); 419 r.notifyResult(EVENT_CFI); 420 } 421 public void unregisterForRecordsEvents(Handler h) { 422 mRecordsEventsRegistrants.remove(h); 423 } 424 425 public void registerForNewSms(Handler h, int what, Object obj) { 426 Registrant r = new Registrant (h, what, obj); 427 mNewSmsRegistrants.add(r); 428 } 429 public void unregisterForNewSms(Handler h) { 430 mNewSmsRegistrants.remove(h); 431 } 432 433 public void registerForNetworkSelectionModeAutomatic( 434 Handler h, int what, Object obj) { 435 Registrant r = new Registrant (h, what, obj); 436 mNetworkSelectionModeAutomaticRegistrants.add(r); 437 } 438 public void unregisterForNetworkSelectionModeAutomatic(Handler h) { 439 mNetworkSelectionModeAutomaticRegistrants.remove(h); 440 } 441 442 /** 443 * Get the International Mobile Subscriber ID (IMSI) on a SIM 444 * for GSM, UMTS and like networks. Default is null if IMSI is 445 * not supported or unavailable. 446 * 447 * @return null if SIM is not yet ready or unavailable 448 */ 449 public String getIMSI() { 450 if (mCarrierTestOverride.isInTestMode() && mCarrierTestOverride.getFakeIMSI() != null) { 451 return mCarrierTestOverride.getFakeIMSI(); 452 } else { 453 return mImsi; 454 } 455 } 456 457 /** 458 * Imsi could be set by ServiceStateTrackers in case of cdma 459 * @param imsi 460 */ 461 public void setImsi(String imsi) { 462 mImsi = imsi; 463 mImsiReadyRegistrants.notifyRegistrants(); 464 } 465 466 /** 467 * Get the Network Access ID (NAI) on a CSIM for CDMA like networks. Default is null if IMSI is 468 * not supported or unavailable. 469 * 470 * @return null if NAI is not yet ready or unavailable 471 */ 472 public String getNAI() { 473 return null; 474 } 475 476 public String getMsisdnNumber() { 477 return mMsisdn; 478 } 479 480 /** 481 * Get the Group Identifier Level 1 (GID1) on a SIM for GSM. 482 * @return null if SIM is not yet ready 483 */ 484 public String getGid1() { 485 if (mCarrierTestOverride.isInTestMode() && mCarrierTestOverride.getFakeGid1() != null) { 486 return mCarrierTestOverride.getFakeGid1(); 487 } else { 488 return mGid1; 489 } 490 } 491 492 /** 493 * Get the Group Identifier Level 2 (GID2) on a SIM. 494 * @return null if SIM is not yet ready 495 */ 496 public String getGid2() { 497 if (mCarrierTestOverride.isInTestMode() && mCarrierTestOverride.getFakeGid2() != null) { 498 return mCarrierTestOverride.getFakeGid2(); 499 } else { 500 return mGid2; 501 } 502 } 503 504 /** 505 * Get the PLMN network name on a SIM. 506 * @return null if SIM is not yet ready 507 */ 508 public String getPnnHomeName() { 509 if (mCarrierTestOverride.isInTestMode() 510 && mCarrierTestOverride.getFakePnnHomeName() != null) { 511 return mCarrierTestOverride.getFakePnnHomeName(); 512 } else { 513 return mPnnHomeName; 514 } 515 } 516 517 public void setMsisdnNumber(String alphaTag, String number, 518 Message onComplete) { 519 loge("setMsisdn() should not be invoked on base IccRecords"); 520 // synthesize a "File Not Found" exception and return it 521 AsyncResult.forMessage(onComplete).exception = 522 (new IccIoResult(0x6A, 0x82, (byte[]) null)).getException(); 523 onComplete.sendToTarget(); 524 } 525 526 public String getMsisdnAlphaTag() { 527 return mMsisdnTag; 528 } 529 530 public String getVoiceMailNumber() { 531 return mVoiceMailNum; 532 } 533 534 /** 535 * Return Service Provider Name stored in SIM (EF_SPN=0x6F46) or in RUIM (EF_RUIM_SPN=0x6F41). 536 * 537 * @return null if SIM is not yet ready or no RUIM entry 538 */ 539 public String getServiceProviderName() { 540 if (mCarrierTestOverride.isInTestMode() && mCarrierTestOverride.getFakeSpn() != null) { 541 return mCarrierTestOverride.getFakeSpn(); 542 } 543 String providerName = mSpn; 544 545 // Check for null pointers, mParentApp can be null after dispose, 546 // which did occur after removing a SIM. 547 UiccCardApplication parentApp = mParentApp; 548 if (parentApp != null) { 549 UiccProfile profile = parentApp.getUiccProfile(); 550 if (profile != null) { 551 String brandOverride = profile.getOperatorBrandOverride(); 552 if (brandOverride != null) { 553 log("getServiceProviderName: override, providerName=" + providerName); 554 providerName = brandOverride; 555 } else { 556 log("getServiceProviderName: no brandOverride, providerName=" + providerName); 557 } 558 } else { 559 log("getServiceProviderName: card is null, providerName=" + providerName); 560 } 561 } else { 562 log("getServiceProviderName: mParentApp is null, providerName=" + providerName); 563 } 564 return providerName; 565 } 566 567 protected void setServiceProviderName(String spn) { 568 if (!TextUtils.equals(mSpn, spn)) { 569 mSpnUpdatedRegistrants.notifyRegistrants(); 570 mSpn = spn; 571 } 572 } 573 574 /** 575 * Set voice mail number to SIM record 576 * 577 * The voice mail number can be stored either in EF_MBDN (TS 51.011) or 578 * EF_MAILBOX_CPHS (CPHS 4.2) 579 * 580 * If EF_MBDN is available, store the voice mail number to EF_MBDN 581 * 582 * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS 583 * 584 * So the voice mail number will be stored in both EFs if both are available 585 * 586 * Return error only if both EF_MBDN and EF_MAILBOX_CPHS fail. 587 * 588 * When the operation is complete, onComplete will be sent to its handler 589 * 590 * @param alphaTag alpha-tagging of the dailing nubmer (upto 10 characters) 591 * @param voiceNumber dailing nubmer (upto 20 digits) 592 * if the number is start with '+', then set to international TOA 593 * @param onComplete 594 * onComplete.obj will be an AsyncResult 595 * ((AsyncResult)onComplete.obj).exception == null on success 596 * ((AsyncResult)onComplete.obj).exception != null on fail 597 */ 598 public abstract void setVoiceMailNumber(String alphaTag, String voiceNumber, 599 Message onComplete); 600 601 public String getVoiceMailAlphaTag() { 602 return mVoiceMailTag; 603 } 604 605 /** 606 * Sets the SIM voice message waiting indicator records 607 * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported 608 * @param countWaiting The number of messages waiting, if known. Use 609 * -1 to indicate that an unknown number of 610 * messages are waiting 611 */ 612 public abstract void setVoiceMessageWaiting(int line, int countWaiting); 613 614 /** 615 * Called by GsmCdmaPhone to update VoiceMail count 616 */ 617 public abstract int getVoiceMessageCount(); 618 619 /** 620 * Called by STK Service when REFRESH is received. 621 * @param fileChanged indicates whether any files changed 622 * @param fileList if non-null, a list of EF files that changed 623 */ 624 public abstract void onRefresh(boolean fileChanged, int[] fileList); 625 626 public boolean getRecordsLoaded() { 627 return mRecordsToLoad == 0 && mRecordsRequested; 628 } 629 630 protected boolean getLockedRecordsLoaded() { 631 return mRecordsToLoad == 0 632 && mLockedRecordsReqReason == LOCKED_RECORDS_REQ_REASON_LOCKED; 633 } 634 635 protected boolean getNetworkLockedRecordsLoaded() { 636 return mRecordsToLoad == 0 637 && mLockedRecordsReqReason == LOCKED_RECORDS_REQ_REASON_NETWORK_LOCKED; 638 } 639 640 //***** Overridden from Handler 641 @Override 642 public void handleMessage(Message msg) { 643 AsyncResult ar; 644 645 switch (msg.what) { 646 case EVENT_GET_ICC_RECORD_DONE: 647 try { 648 ar = (AsyncResult) msg.obj; 649 IccRecordLoaded recordLoaded = (IccRecordLoaded) ar.userObj; 650 if (DBG) log(recordLoaded.getEfName() + " LOADED"); 651 652 if (ar.exception != null) { 653 loge("Record Load Exception: " + ar.exception); 654 } else { 655 recordLoaded.onRecordLoaded(ar); 656 } 657 }catch (RuntimeException exc) { 658 // I don't want these exceptions to be fatal 659 loge("Exception parsing SIM record: " + exc); 660 } finally { 661 // Count up record load responses even if they are fails 662 onRecordLoaded(); 663 } 664 break; 665 666 case EVENT_REFRESH: 667 ar = (AsyncResult)msg.obj; 668 if (DBG) log("Card REFRESH occurred: "); 669 if (ar.exception == null) { 670 handleRefresh((IccRefreshResponse)ar.result); 671 } else { 672 loge("Icc refresh Exception: " + ar.exception); 673 } 674 break; 675 676 case EVENT_AKA_AUTHENTICATE_DONE: 677 ar = (AsyncResult)msg.obj; 678 auth_rsp = null; 679 if (DBG) log("EVENT_AKA_AUTHENTICATE_DONE"); 680 if (ar.exception != null) { 681 loge("Exception ICC SIM AKA: " + ar.exception); 682 } else { 683 try { 684 auth_rsp = (IccIoResult)ar.result; 685 if (DBG) log("ICC SIM AKA: auth_rsp = " + auth_rsp); 686 } catch (Exception e) { 687 loge("Failed to parse ICC SIM AKA contents: " + e); 688 } 689 } 690 synchronized (mLock) { 691 mLock.notifyAll(); 692 } 693 694 break; 695 696 default: 697 super.handleMessage(msg); 698 } 699 } 700 701 /** 702 * Returns the SIM language derived from the EF-LI and EF-PL sim records. 703 */ 704 public String getSimLanguage() { 705 return mPrefLang; 706 } 707 708 protected void setSimLanguage(byte[] efLi, byte[] efPl) { 709 String[] locales = mContext.getAssets().getLocales(); 710 try { 711 mPrefLang = findBestLanguage(efLi, locales); 712 } catch (UnsupportedEncodingException uee) { 713 log("Unable to parse EF-LI: " + Arrays.toString(efLi)); 714 } 715 716 if (mPrefLang == null) { 717 try { 718 mPrefLang = findBestLanguage(efPl, locales); 719 } catch (UnsupportedEncodingException uee) { 720 log("Unable to parse EF-PL: " + Arrays.toString(efLi)); 721 } 722 } 723 } 724 725 protected static String findBestLanguage(byte[] languages, String[] locales) 726 throws UnsupportedEncodingException { 727 if ((languages == null) || (locales == null)) return null; 728 729 // Each 2-bytes consists of one language 730 for (int i = 0; (i + 1) < languages.length; i += 2) { 731 String lang = new String(languages, i, 2, "ISO-8859-1"); 732 for (int j = 0; j < locales.length; j++) { 733 if (locales[j] != null && locales[j].length() >= 2 && 734 locales[j].substring(0, 2).equalsIgnoreCase(lang)) { 735 return lang; 736 } 737 } 738 } 739 740 // no match found. return null 741 return null; 742 } 743 744 protected abstract void handleFileUpdate(int efid); 745 746 protected void handleRefresh(IccRefreshResponse refreshResponse){ 747 if (refreshResponse == null) { 748 if (DBG) log("handleRefresh received without input"); 749 return; 750 } 751 752 if (!TextUtils.isEmpty(refreshResponse.aid) && 753 !refreshResponse.aid.equals(mParentApp.getAid())) { 754 // This is for different app. Ignore. 755 return; 756 } 757 758 switch (refreshResponse.refreshResult) { 759 case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE: 760 if (DBG) log("handleRefresh with SIM_FILE_UPDATED"); 761 handleFileUpdate(refreshResponse.efId); 762 break; 763 default: 764 // unknown refresh operation 765 if (DBG) log("handleRefresh with unknown operation"); 766 break; 767 } 768 } 769 770 protected abstract void onRecordLoaded(); 771 772 protected abstract void onAllRecordsLoaded(); 773 774 /** 775 * Returns the SpnDisplayRule based on settings on the SIM and the 776 * current service state. See TS 22.101 Annex A and TS 51.011 10.3.11 777 * for details. 778 * 779 * If the SPN is not found on the SIM, the rule is always PLMN_ONLY. 780 * Generally used for GSM/UMTS and the like SIMs. 781 * 782 * @param serviceState Service state 783 * @return the display rule 784 * 785 * @see #SPN_RULE_SHOW_SPN 786 * @see #SPN_RULE_SHOW_PLMN 787 */ 788 public abstract int getDisplayRule(ServiceState serviceState); 789 790 /** 791 * Return true if "Restriction of menu options for manual PLMN selection" 792 * bit is set or EF_CSP data is unavailable, return false otherwise. 793 * Generally used for GSM/UMTS and the like SIMs. 794 */ 795 public boolean isCspPlmnEnabled() { 796 return false; 797 } 798 799 /** 800 * Returns the 5 or 6 digit MCC/MNC of the operator that 801 * provided the SIM card. Returns null of SIM is not yet ready 802 * or is not valid for the type of IccCard. Generally used for 803 * GSM/UMTS and the like SIMS 804 */ 805 public String getOperatorNumeric() { 806 return null; 807 } 808 809 /** 810 * Get the current Voice call forwarding flag for GSM/UMTS and the like SIMs 811 * 812 * @return CALL_FORWARDING_STATUS_XXX (DISABLED/ENABLED/UNKNOWN) 813 */ 814 public int getVoiceCallForwardingFlag() { 815 return CALL_FORWARDING_STATUS_UNKNOWN; 816 } 817 818 /** 819 * Set the voice call forwarding flag for GSM/UMTS and the like SIMs 820 * 821 * @param line to enable/disable 822 * @param enable 823 * @param number to which CFU is enabled 824 */ 825 public void setVoiceCallForwardingFlag(int line, boolean enable, String number) { 826 } 827 828 /** 829 * Indicates wether the ICC records have been loaded or not 830 * 831 * @return true if the records have been loaded, false otherwise. 832 */ 833 public boolean isLoaded() { 834 return mLoaded.get(); 835 } 836 837 /** 838 * Indicates wether SIM is in provisioned state or not. 839 * Overridden only if SIM can be dynamically provisioned via OTA. 840 * 841 * @return true if provisioned 842 */ 843 public boolean isProvisioned () { 844 return true; 845 } 846 847 /** 848 * Write string to log file 849 * 850 * @param s is the string to write 851 */ 852 protected abstract void log(String s); 853 854 /** 855 * Write error string to log file. 856 * 857 * @param s is the string to write 858 */ 859 protected abstract void loge(String s); 860 861 /** 862 * Return an interface to retrieve the ISIM records for IMS, if available. 863 * @return the interface to retrieve the ISIM records, or null if not supported 864 */ 865 public IsimRecords getIsimRecords() { 866 return null; 867 } 868 869 public UsimServiceTable getUsimServiceTable() { 870 return null; 871 } 872 873 protected void setSystemProperty(String key, String val) { 874 TelephonyManager.getDefault().setTelephonyProperty(mParentApp.getPhoneId(), key, val); 875 876 log("[key, value]=" + key + ", " + val); 877 } 878 879 /** 880 * Returns the response of the SIM application on the UICC to authentication 881 * challenge/response algorithm. The data string and challenge response are 882 * Base64 encoded Strings. 883 * Can support EAP-SIM, EAP-AKA with results encoded per 3GPP TS 31.102. 884 * 885 * @param authContext parameter P2 that specifies the authentication context per 3GPP TS 31.102 (Section 7.1.2) 886 * @param data authentication challenge data 887 * @return challenge response 888 */ 889 public String getIccSimChallengeResponse(int authContext, String data) { 890 if (DBG) log("getIccSimChallengeResponse:"); 891 892 try { 893 synchronized(mLock) { 894 CommandsInterface ci = mCi; 895 UiccCardApplication parentApp = mParentApp; 896 if (ci != null && parentApp != null) { 897 ci.requestIccSimAuthentication(authContext, data, 898 parentApp.getAid(), 899 obtainMessage(EVENT_AKA_AUTHENTICATE_DONE)); 900 try { 901 mLock.wait(); 902 } catch (InterruptedException e) { 903 loge("getIccSimChallengeResponse: Fail, interrupted" 904 + " while trying to request Icc Sim Auth"); 905 return null; 906 } 907 } else { 908 loge( "getIccSimChallengeResponse: " 909 + "Fail, ci or parentApp is null"); 910 return null; 911 } 912 } 913 } catch(Exception e) { 914 loge( "getIccSimChallengeResponse: " 915 + "Fail while trying to request Icc Sim Auth"); 916 return null; 917 } 918 919 if (auth_rsp == null) { 920 loge("getIccSimChallengeResponse: No authentication response"); 921 return null; 922 } 923 924 if (DBG) log("getIccSimChallengeResponse: return auth_rsp"); 925 926 return android.util.Base64.encodeToString(auth_rsp.payload, android.util.Base64.NO_WRAP); 927 } 928 929 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 930 pw.println("IccRecords: " + this); 931 pw.println(" mDestroyed=" + mDestroyed); 932 pw.println(" mCi=" + mCi); 933 pw.println(" mFh=" + mFh); 934 pw.println(" mParentApp=" + mParentApp); 935 pw.println(" recordsLoadedRegistrants: size=" + mRecordsLoadedRegistrants.size()); 936 for (int i = 0; i < mRecordsLoadedRegistrants.size(); i++) { 937 pw.println(" recordsLoadedRegistrants[" + i + "]=" 938 + ((Registrant)mRecordsLoadedRegistrants.get(i)).getHandler()); 939 } 940 pw.println(" mLockedRecordsLoadedRegistrants: size=" 941 + mLockedRecordsLoadedRegistrants.size()); 942 for (int i = 0; i < mLockedRecordsLoadedRegistrants.size(); i++) { 943 pw.println(" mLockedRecordsLoadedRegistrants[" + i + "]=" 944 + ((Registrant) mLockedRecordsLoadedRegistrants.get(i)).getHandler()); 945 } 946 pw.println(" mNetworkLockedRecordsLoadedRegistrants: size=" 947 + mNetworkLockedRecordsLoadedRegistrants.size()); 948 for (int i = 0; i < mNetworkLockedRecordsLoadedRegistrants.size(); i++) { 949 pw.println(" mLockedRecordsLoadedRegistrants[" + i + "]=" 950 + ((Registrant) mNetworkLockedRecordsLoadedRegistrants.get(i)).getHandler()); 951 } 952 pw.println(" mImsiReadyRegistrants: size=" + mImsiReadyRegistrants.size()); 953 for (int i = 0; i < mImsiReadyRegistrants.size(); i++) { 954 pw.println(" mImsiReadyRegistrants[" + i + "]=" 955 + ((Registrant)mImsiReadyRegistrants.get(i)).getHandler()); 956 } 957 pw.println(" mRecordsEventsRegistrants: size=" + mRecordsEventsRegistrants.size()); 958 for (int i = 0; i < mRecordsEventsRegistrants.size(); i++) { 959 pw.println(" mRecordsEventsRegistrants[" + i + "]=" 960 + ((Registrant)mRecordsEventsRegistrants.get(i)).getHandler()); 961 } 962 pw.println(" mNewSmsRegistrants: size=" + mNewSmsRegistrants.size()); 963 for (int i = 0; i < mNewSmsRegistrants.size(); i++) { 964 pw.println(" mNewSmsRegistrants[" + i + "]=" 965 + ((Registrant)mNewSmsRegistrants.get(i)).getHandler()); 966 } 967 pw.println(" mNetworkSelectionModeAutomaticRegistrants: size=" 968 + mNetworkSelectionModeAutomaticRegistrants.size()); 969 for (int i = 0; i < mNetworkSelectionModeAutomaticRegistrants.size(); i++) { 970 pw.println(" mNetworkSelectionModeAutomaticRegistrants[" + i + "]=" 971 + ((Registrant)mNetworkSelectionModeAutomaticRegistrants.get(i)).getHandler()); 972 } 973 pw.println(" mRecordsRequested=" + mRecordsRequested); 974 pw.println(" mLockedRecordsReqReason=" + mLockedRecordsReqReason); 975 pw.println(" mRecordsToLoad=" + mRecordsToLoad); 976 pw.println(" mRdnCache=" + mAdnCache); 977 978 String iccIdToPrint = SubscriptionInfo.givePrintableIccid(mFullIccId); 979 pw.println(" iccid=" + iccIdToPrint); 980 pw.println(" mMsisdn=" + Rlog.pii(VDBG, mMsisdn)); 981 pw.println(" mMsisdnTag=" + mMsisdnTag); 982 pw.println(" mVoiceMailNum=" + Rlog.pii(VDBG, mVoiceMailNum)); 983 pw.println(" mVoiceMailTag=" + mVoiceMailTag); 984 pw.println(" mNewVoiceMailNum=" + Rlog.pii(VDBG, mNewVoiceMailNum)); 985 pw.println(" mNewVoiceMailTag=" + mNewVoiceMailTag); 986 pw.println(" mIsVoiceMailFixed=" + mIsVoiceMailFixed); 987 pw.println(" mImsi=" + ((mImsi != null) ? 988 mImsi.substring(0, 6) + Rlog.pii(VDBG, mImsi.substring(6)) : "null")); 989 if (mCarrierTestOverride.isInTestMode()) { 990 pw.println(" mFakeImsi=" + mCarrierTestOverride.getFakeIMSI()); 991 } 992 pw.println(" mMncLength=" + mMncLength); 993 pw.println(" mMailboxIndex=" + mMailboxIndex); 994 pw.println(" mSpn=" + mSpn); 995 if (mCarrierTestOverride.isInTestMode()) { 996 pw.println(" mFakeSpn=" + mCarrierTestOverride.getFakeSpn()); 997 } 998 pw.flush(); 999 } 1000 } 1001