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 toString()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 { getEfName()199 String getEfName(); onRecordLoaded(AsyncResult ar)200 void onRecordLoaded(AsyncResult ar); 201 } 202 203 // ***** Constructor IccRecords(UiccCardApplication app, Context c, CommandsInterface ci)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 setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1, String gid2, String pnn, String spn)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 */ dispose()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 onReady()249 public abstract void onReady(); 250 251 //***** Public Methods getAdnCache()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 */ storePendingResponseMessage(Message msg)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 */ retrievePendingResponseMessage(Integer key)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 */ getIccId()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 */ getFullIccId()296 public String getFullIccId() { 297 return mFullIccId; 298 } 299 registerForRecordsLoaded(Handler h, int what, Object obj)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 unregisterForRecordsLoaded(Handler h)313 public void unregisterForRecordsLoaded(Handler h) { 314 mRecordsLoadedRegistrants.remove(h); 315 } 316 unregisterForRecordsOverride(Handler h)317 public void unregisterForRecordsOverride(Handler h) { 318 mRecordsOverrideRegistrants.remove(h); 319 } 320 registerForRecordsOverride(Handler h, int what, Object obj)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 */ registerForLockedRecordsLoaded(Handler h, int what, Object obj)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 */ unregisterForLockedRecordsLoaded(Handler h)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 */ registerForNetworkLockedRecordsLoaded(Handler h, int what, Object obj)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 */ unregisterForNetworkLockedRecordsLoaded(Handler h)376 public void unregisterForNetworkLockedRecordsLoaded(Handler h) { 377 mNetworkLockedRecordsLoadedRegistrants.remove(h); 378 } 379 registerForImsiReady(Handler h, int what, Object obj)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 } unregisterForImsiReady(Handler h)392 public void unregisterForImsiReady(Handler h) { 393 mImsiReadyRegistrants.remove(h); 394 } 395 registerForSpnUpdate(Handler h, int what, Object obj)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 } unregisterForSpnUpdate(Handler h)408 public void unregisterForSpnUpdate(Handler h) { 409 mSpnUpdatedRegistrants.remove(h); 410 } 411 registerForRecordsEvents(Handler h, int what, Object obj)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 } unregisterForRecordsEvents(Handler h)421 public void unregisterForRecordsEvents(Handler h) { 422 mRecordsEventsRegistrants.remove(h); 423 } 424 registerForNewSms(Handler h, int what, Object obj)425 public void registerForNewSms(Handler h, int what, Object obj) { 426 Registrant r = new Registrant (h, what, obj); 427 mNewSmsRegistrants.add(r); 428 } unregisterForNewSms(Handler h)429 public void unregisterForNewSms(Handler h) { 430 mNewSmsRegistrants.remove(h); 431 } 432 registerForNetworkSelectionModeAutomatic( Handler h, int what, Object obj)433 public void registerForNetworkSelectionModeAutomatic( 434 Handler h, int what, Object obj) { 435 Registrant r = new Registrant (h, what, obj); 436 mNetworkSelectionModeAutomaticRegistrants.add(r); 437 } unregisterForNetworkSelectionModeAutomatic(Handler h)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 */ getIMSI()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 */ setImsi(String imsi)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 */ getNAI()472 public String getNAI() { 473 return null; 474 } 475 getMsisdnNumber()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 */ getGid1()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 */ getGid2()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 */ getPnnHomeName()508 public String getPnnHomeName() { 509 if (mCarrierTestOverride.isInTestMode() 510 && mCarrierTestOverride.getFakePnnHomeName() != null) { 511 return mCarrierTestOverride.getFakePnnHomeName(); 512 } else { 513 return mPnnHomeName; 514 } 515 } 516 setMsisdnNumber(String alphaTag, String number, Message onComplete)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 getMsisdnAlphaTag()526 public String getMsisdnAlphaTag() { 527 return mMsisdnTag; 528 } 529 getVoiceMailNumber()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 */ getServiceProviderName()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 setServiceProviderName(String spn)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 */ setVoiceMailNumber(String alphaTag, String voiceNumber, Message onComplete)598 public abstract void setVoiceMailNumber(String alphaTag, String voiceNumber, 599 Message onComplete); 600 getVoiceMailAlphaTag()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 */ setVoiceMessageWaiting(int line, int countWaiting)612 public abstract void setVoiceMessageWaiting(int line, int countWaiting); 613 614 /** 615 * Called by GsmCdmaPhone to update VoiceMail count 616 */ getVoiceMessageCount()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 */ onRefresh(boolean fileChanged, int[] fileList)624 public abstract void onRefresh(boolean fileChanged, int[] fileList); 625 getRecordsLoaded()626 public boolean getRecordsLoaded() { 627 return mRecordsToLoad == 0 && mRecordsRequested; 628 } 629 getLockedRecordsLoaded()630 protected boolean getLockedRecordsLoaded() { 631 return mRecordsToLoad == 0 632 && mLockedRecordsReqReason == LOCKED_RECORDS_REQ_REASON_LOCKED; 633 } 634 getNetworkLockedRecordsLoaded()635 protected boolean getNetworkLockedRecordsLoaded() { 636 return mRecordsToLoad == 0 637 && mLockedRecordsReqReason == LOCKED_RECORDS_REQ_REASON_NETWORK_LOCKED; 638 } 639 640 //***** Overridden from Handler 641 @Override handleMessage(Message msg)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 */ getSimLanguage()704 public String getSimLanguage() { 705 return mPrefLang; 706 } 707 setSimLanguage(byte[] efLi, byte[] efPl)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 findBestLanguage(byte[] languages, String[] locales)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 handleFileUpdate(int efid)744 protected abstract void handleFileUpdate(int efid); 745 handleRefresh(IccRefreshResponse refreshResponse)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 onRecordLoaded()770 protected abstract void onRecordLoaded(); 771 onAllRecordsLoaded()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 */ getDisplayRule(ServiceState serviceState)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 */ isCspPlmnEnabled()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 */ getOperatorNumeric()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 */ getVoiceCallForwardingFlag()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 */ setVoiceCallForwardingFlag(int line, boolean enable, String number)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 */ isLoaded()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 */ isProvisioned()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 */ log(String s)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 */ loge(String s)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 */ getIsimRecords()865 public IsimRecords getIsimRecords() { 866 return null; 867 } 868 getUsimServiceTable()869 public UsimServiceTable getUsimServiceTable() { 870 return null; 871 } 872 setSystemProperty(String key, String val)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 */ getIccSimChallengeResponse(int authContext, String data)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 dump(FileDescriptor fd, PrintWriter pw, String[] args)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