SIMRecords.java revision 2fe945394877c98706b4d56bcdc3dcde1eaccce8
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 static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA; 20import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY; 21import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC; 22import android.content.Context; 23import android.os.AsyncResult; 24import android.os.Message; 25import android.os.SystemProperties; 26import android.telephony.PhoneNumberUtils; 27import android.telephony.SmsMessage; 28import android.text.TextUtils; 29import android.telephony.Rlog; 30 31import com.android.internal.telephony.CommandsInterface; 32import com.android.internal.telephony.MccTable; 33import com.android.internal.telephony.SmsConstants; 34import com.android.internal.telephony.gsm.SimTlv; 35 36import java.io.FileDescriptor; 37import java.io.PrintWriter; 38import java.util.ArrayList; 39import java.util.Arrays; 40 41/** 42 * {@hide} 43 */ 44public class SIMRecords extends IccRecords { 45 protected static final String LOG_TAG = "SIMRecords"; 46 47 private static final boolean CRASH_RIL = false; 48 49 // ***** Instance Variables 50 51 VoiceMailConstants mVmConfig; 52 53 54 SpnOverride mSpnOverride; 55 56 // ***** Cached SIM State; cleared on channel close 57 58 private boolean mCallForwardingEnabled; 59 60 61 /** 62 * States only used by getSpnFsm FSM 63 */ 64 private GetSpnFsmState mSpnState; 65 66 /** CPHS service information (See CPHS 4.2 B.3.1.1) 67 * It will be set in onSimReady if reading GET_CPHS_INFO successfully 68 * mCphsInfo[0] is CPHS Phase 69 * mCphsInfo[1] and mCphsInfo[2] is CPHS Service Table 70 */ 71 private byte[] mCphsInfo = null; 72 boolean mCspPlmnEnabled = true; 73 74 byte[] mEfMWIS = null; 75 byte[] mEfCPHS_MWI =null; 76 byte[] mEfCff = null; 77 byte[] mEfCfis = null; 78 79 80 int mSpnDisplayCondition; 81 // Numeric network codes listed in TS 51.011 EF[SPDI] 82 ArrayList<String> mSpdiNetworks = null; 83 84 String mPnnHomeName = null; 85 86 UsimServiceTable mUsimServiceTable; 87 88 @Override 89 public String toString() { 90 return "SimRecords: " + super.toString() 91 + " mVmConfig" + mVmConfig 92 + " mSpnOverride=" + "mSpnOverride" 93 + " callForwardingEnabled=" + mCallForwardingEnabled 94 + " spnState=" + mSpnState 95 + " mCphsInfo=" + mCphsInfo 96 + " mCspPlmnEnabled=" + mCspPlmnEnabled 97 + " efMWIS=" + mEfMWIS 98 + " efCPHS_MWI=" + mEfCPHS_MWI 99 + " mEfCff=" + mEfCff 100 + " mEfCfis=" + mEfCfis 101 + " getOperatorNumeric=" + getOperatorNumeric(); 102 } 103 104 // ***** Constants 105 106 // From TS 51.011 EF[SPDI] section 107 static final int TAG_SPDI = 0xA3; 108 static final int TAG_SPDI_PLMN_LIST = 0x80; 109 110 // Full Name IEI from TS 24.008 111 static final int TAG_FULL_NETWORK_NAME = 0x43; 112 113 // Short Name IEI from TS 24.008 114 static final int TAG_SHORT_NETWORK_NAME = 0x45; 115 116 // active CFF from CPHS 4.2 B.4.5 117 static final int CFF_UNCONDITIONAL_ACTIVE = 0x0a; 118 static final int CFF_UNCONDITIONAL_DEACTIVE = 0x05; 119 static final int CFF_LINE1_MASK = 0x0f; 120 static final int CFF_LINE1_RESET = 0xf0; 121 122 // CPHS Service Table (See CPHS 4.2 B.3.1) 123 private static final int CPHS_SST_MBN_MASK = 0x30; 124 private static final int CPHS_SST_MBN_ENABLED = 0x30; 125 126 // EF_CFIS related constants 127 // Spec reference TS 51.011 section 10.3.46. 128 private static final int CFIS_BCD_NUMBER_LENGTH_OFFSET = 2; 129 private static final int CFIS_TON_NPI_OFFSET = 3; 130 private static final int CFIS_ADN_CAPABILITY_ID_OFFSET = 14; 131 private static final int CFIS_ADN_EXTENSION_ID_OFFSET = 15; 132 133 // ***** Event Constants 134 private static final int EVENT_GET_IMSI_DONE = 3; 135 private static final int EVENT_GET_ICCID_DONE = 4; 136 private static final int EVENT_GET_MBI_DONE = 5; 137 private static final int EVENT_GET_MBDN_DONE = 6; 138 private static final int EVENT_GET_MWIS_DONE = 7; 139 private static final int EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE = 8; 140 protected static final int EVENT_GET_AD_DONE = 9; // Admin data on SIM 141 protected static final int EVENT_GET_MSISDN_DONE = 10; 142 private static final int EVENT_GET_CPHS_MAILBOX_DONE = 11; 143 private static final int EVENT_GET_SPN_DONE = 12; 144 private static final int EVENT_GET_SPDI_DONE = 13; 145 private static final int EVENT_UPDATE_DONE = 14; 146 private static final int EVENT_GET_PNN_DONE = 15; 147 protected static final int EVENT_GET_SST_DONE = 17; 148 private static final int EVENT_GET_ALL_SMS_DONE = 18; 149 private static final int EVENT_MARK_SMS_READ_DONE = 19; 150 private static final int EVENT_SET_MBDN_DONE = 20; 151 private static final int EVENT_SMS_ON_SIM = 21; 152 private static final int EVENT_GET_SMS_DONE = 22; 153 private static final int EVENT_GET_CFF_DONE = 24; 154 private static final int EVENT_SET_CPHS_MAILBOX_DONE = 25; 155 private static final int EVENT_GET_INFO_CPHS_DONE = 26; 156 // private static final int EVENT_SET_MSISDN_DONE = 30; Defined in IccRecords as 30 157 private static final int EVENT_SIM_REFRESH = 31; 158 private static final int EVENT_GET_CFIS_DONE = 32; 159 private static final int EVENT_GET_CSP_CPHS_DONE = 33; 160 private static final int EVENT_GET_GID1_DONE = 34; 161 162 // Lookup table for carriers known to produce SIMs which incorrectly indicate MNC length. 163 164 private static final String[] MCCMNC_CODES_HAVING_3DIGITS_MNC = { 165 "302370", "302720", "310260", 166 "405025", "405026", "405027", "405028", "405029", "405030", "405031", "405032", 167 "405033", "405034", "405035", "405036", "405037", "405038", "405039", "405040", 168 "405041", "405042", "405043", "405044", "405045", "405046", "405047", "405750", 169 "405751", "405752", "405753", "405754", "405755", "405756", "405799", "405800", 170 "405801", "405802", "405803", "405804", "405805", "405806", "405807", "405808", 171 "405809", "405810", "405811", "405812", "405813", "405814", "405815", "405816", 172 "405817", "405818", "405819", "405820", "405821", "405822", "405823", "405824", 173 "405825", "405826", "405827", "405828", "405829", "405830", "405831", "405832", 174 "405833", "405834", "405835", "405836", "405837", "405838", "405839", "405840", 175 "405841", "405842", "405843", "405844", "405845", "405846", "405847", "405848", 176 "405849", "405850", "405851", "405852", "405853", "405875", "405876", "405877", 177 "405878", "405879", "405880", "405881", "405882", "405883", "405884", "405885", 178 "405886", "405908", "405909", "405910", "405911", "405912", "405913", "405914", 179 "405915", "405916", "405917", "405918", "405919", "405920", "405921", "405922", 180 "405923", "405924", "405925", "405926", "405927", "405928", "405929", "405930", 181 "405931", "405932", "502142", "502143", "502145", "502146", "502147", "502148" 182 }; 183 184 // ***** Constructor 185 186 public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) { 187 super(app, c, ci); 188 189 mAdnCache = new AdnRecordCache(mFh); 190 191 mVmConfig = new VoiceMailConstants(); 192 mSpnOverride = new SpnOverride(); 193 194 mRecordsRequested = false; // No load request is made till SIM ready 195 196 // recordsToLoad is set to 0 because no requests are made yet 197 mRecordsToLoad = 0; 198 199 mCi.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null); 200 mCi.registerForIccRefresh(this, EVENT_SIM_REFRESH, null); 201 202 // Start off by setting empty state 203 resetRecords(); 204 mParentApp.registerForReady(this, EVENT_APP_READY, null); 205 if (DBG) log("SIMRecords X ctor this=" + this); 206 } 207 208 @Override 209 public void dispose() { 210 if (DBG) log("Disposing SIMRecords this=" + this); 211 //Unregister for all events 212 mCi.unregisterForIccRefresh(this); 213 mCi.unSetOnSmsOnSim(this); 214 mParentApp.unregisterForReady(this); 215 resetRecords(); 216 super.dispose(); 217 } 218 219 @Override 220 protected void finalize() { 221 if(DBG) log("finalized"); 222 } 223 224 protected void resetRecords() { 225 mImsi = null; 226 mMsisdn = null; 227 mVoiceMailNum = null; 228 mCountVoiceMessages = 0; 229 mMncLength = UNINITIALIZED; 230 mIccId = null; 231 // -1 means no EF_SPN found; treat accordingly. 232 mSpnDisplayCondition = -1; 233 mEfMWIS = null; 234 mEfCPHS_MWI = null; 235 mSpdiNetworks = null; 236 mPnnHomeName = null; 237 mGid1 = null; 238 239 mAdnCache.reset(); 240 241 log("SIMRecords: onRadioOffOrNotAvailable set 'gsm.sim.operator.numeric' to operator=null"); 242 SystemProperties.set(PROPERTY_ICC_OPERATOR_NUMERIC, null); 243 SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, null); 244 SystemProperties.set(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, null); 245 246 // recordsRequested is set to false indicating that the SIM 247 // read requests made so far are not valid. This is set to 248 // true only when fresh set of read requests are made. 249 mRecordsRequested = false; 250 } 251 252 253 //***** Public Methods 254 255 /** 256 * {@inheritDoc} 257 */ 258 @Override 259 public String getIMSI() { 260 return mImsi; 261 } 262 263 @Override 264 public String getMsisdnNumber() { 265 return mMsisdn; 266 } 267 268 @Override 269 public String getGid1() { 270 return mGid1; 271 } 272 273 @Override 274 public UsimServiceTable getUsimServiceTable() { 275 return mUsimServiceTable; 276 } 277 278 /** 279 * Set subscriber number to SIM record 280 * 281 * The subscriber number is stored in EF_MSISDN (TS 51.011) 282 * 283 * When the operation is complete, onComplete will be sent to its handler 284 * 285 * @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters) 286 * @param number dailing nubmer (up to 20 digits) 287 * if the number starts with '+', then set to international TOA 288 * @param onComplete 289 * onComplete.obj will be an AsyncResult 290 * ((AsyncResult)onComplete.obj).exception == null on success 291 * ((AsyncResult)onComplete.obj).exception != null on fail 292 */ 293 @Override 294 public void setMsisdnNumber(String alphaTag, String number, 295 Message onComplete) { 296 297 mMsisdn = number; 298 mMsisdnTag = alphaTag; 299 300 if(DBG) log("Set MSISDN: " + mMsisdnTag + " " + /*mMsisdn*/ "xxxxxxx"); 301 302 303 AdnRecord adn = new AdnRecord(mMsisdnTag, mMsisdn); 304 305 new AdnRecordLoader(mFh).updateEF(adn, EF_MSISDN, EF_EXT1, 1, null, 306 obtainMessage(EVENT_SET_MSISDN_DONE, onComplete)); 307 } 308 309 @Override 310 public String getMsisdnAlphaTag() { 311 return mMsisdnTag; 312 } 313 314 @Override 315 public String getVoiceMailNumber() { 316 return mVoiceMailNum; 317 } 318 319 /** 320 * Set voice mail number to SIM record 321 * 322 * The voice mail number can be stored either in EF_MBDN (TS 51.011) or 323 * EF_MAILBOX_CPHS (CPHS 4.2) 324 * 325 * If EF_MBDN is available, store the voice mail number to EF_MBDN 326 * 327 * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS 328 * 329 * So the voice mail number will be stored in both EFs if both are available 330 * 331 * Return error only if both EF_MBDN and EF_MAILBOX_CPHS fail. 332 * 333 * When the operation is complete, onComplete will be sent to its handler 334 * 335 * @param alphaTag alpha-tagging of the dailing nubmer (upto 10 characters) 336 * @param voiceNumber dailing nubmer (upto 20 digits) 337 * if the number is start with '+', then set to international TOA 338 * @param onComplete 339 * onComplete.obj will be an AsyncResult 340 * ((AsyncResult)onComplete.obj).exception == null on success 341 * ((AsyncResult)onComplete.obj).exception != null on fail 342 */ 343 @Override 344 public void setVoiceMailNumber(String alphaTag, String voiceNumber, 345 Message onComplete) { 346 if (mIsVoiceMailFixed) { 347 AsyncResult.forMessage((onComplete)).exception = 348 new IccVmFixedException("Voicemail number is fixed by operator"); 349 onComplete.sendToTarget(); 350 return; 351 } 352 353 mNewVoiceMailNum = voiceNumber; 354 mNewVoiceMailTag = alphaTag; 355 356 AdnRecord adn = new AdnRecord(mNewVoiceMailTag, mNewVoiceMailNum); 357 358 if (mMailboxIndex != 0 && mMailboxIndex != 0xff) { 359 360 new AdnRecordLoader(mFh).updateEF(adn, EF_MBDN, EF_EXT6, 361 mMailboxIndex, null, 362 obtainMessage(EVENT_SET_MBDN_DONE, onComplete)); 363 364 } else if (isCphsMailboxEnabled()) { 365 366 new AdnRecordLoader(mFh).updateEF(adn, EF_MAILBOX_CPHS, 367 EF_EXT1, 1, null, 368 obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE, onComplete)); 369 370 } else { 371 AsyncResult.forMessage((onComplete)).exception = 372 new IccVmNotSupportedException("Update SIM voice mailbox error"); 373 onComplete.sendToTarget(); 374 } 375 } 376 377 @Override 378 public String getVoiceMailAlphaTag() 379 { 380 return mVoiceMailTag; 381 } 382 383 /** 384 * Sets the SIM voice message waiting indicator records 385 * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported 386 * @param countWaiting The number of messages waiting, if known. Use 387 * -1 to indicate that an unknown number of 388 * messages are waiting 389 */ 390 @Override 391 public void 392 setVoiceMessageWaiting(int line, int countWaiting) { 393 if (line != 1) { 394 // only profile 1 is supported 395 return; 396 } 397 398 // range check 399 if (countWaiting < 0) { 400 countWaiting = -1; 401 } else if (countWaiting > 0xff) { 402 // TS 23.040 9.2.3.24.2 403 // "The value 255 shall be taken to mean 255 or greater" 404 countWaiting = 0xff; 405 } 406 407 mCountVoiceMessages = countWaiting; 408 409 mRecordsEventsRegistrants.notifyResult(EVENT_MWI); 410 411 try { 412 if (mEfMWIS != null) { 413 // TS 51.011 10.3.45 414 415 // lsb of byte 0 is 'voicemail' status 416 mEfMWIS[0] = (byte)((mEfMWIS[0] & 0xfe) 417 | (mCountVoiceMessages == 0 ? 0 : 1)); 418 419 // byte 1 is the number of voice messages waiting 420 if (countWaiting < 0) { 421 // The spec does not define what this should be 422 // if we don't know the count 423 mEfMWIS[1] = 0; 424 } else { 425 mEfMWIS[1] = (byte) countWaiting; 426 } 427 428 mFh.updateEFLinearFixed( 429 EF_MWIS, 1, mEfMWIS, null, 430 obtainMessage (EVENT_UPDATE_DONE, EF_MWIS)); 431 } 432 433 if (mEfCPHS_MWI != null) { 434 // Refer CPHS4_2.WW6 B4.2.3 435 mEfCPHS_MWI[0] = (byte)((mEfCPHS_MWI[0] & 0xf0) 436 | (mCountVoiceMessages == 0 ? 0x5 : 0xa)); 437 438 mFh.updateEFTransparent( 439 EF_VOICE_MAIL_INDICATOR_CPHS, mEfCPHS_MWI, 440 obtainMessage (EVENT_UPDATE_DONE, EF_VOICE_MAIL_INDICATOR_CPHS)); 441 } 442 } catch (ArrayIndexOutOfBoundsException ex) { 443 logw("Error saving voice mail state to SIM. Probably malformed SIM record", ex); 444 } 445 } 446 447 // Validate data is !null and the MSP (Multiple Subscriber Profile) 448 // byte is between 1 and 4. See ETSI TS 131 102 v11.3.0 section 4.2.64. 449 private boolean validEfCfis(byte[] data) { 450 return ((data != null) && (data[0] >= 1) && (data[0] <= 4)); 451 } 452 453 /** 454 * {@inheritDoc} 455 */ 456 @Override 457 public boolean getVoiceCallForwardingFlag() { 458 return mCallForwardingEnabled; 459 } 460 461 /** 462 * {@inheritDoc} 463 */ 464 @Override 465 public void setVoiceCallForwardingFlag(int line, boolean enable, String dialNumber) { 466 467 if (line != 1) return; // only line 1 is supported 468 469 mCallForwardingEnabled = enable; 470 471 mRecordsEventsRegistrants.notifyResult(EVENT_CFI); 472 473 try { 474 if (validEfCfis(mEfCfis)) { 475 // lsb is of byte 1 is voice status 476 if (enable) { 477 mEfCfis[1] |= 1; 478 } else { 479 mEfCfis[1] &= 0xfe; 480 } 481 482 log("setVoiceCallForwardingFlag: enable=" + enable 483 + " mEfCfis=" + IccUtils.bytesToHexString(mEfCfis)); 484 485 // Update dialNumber if not empty and CFU is enabled. 486 // Spec reference for EF_CFIS contents, TS 51.011 section 10.3.46. 487 if (enable && !TextUtils.isEmpty(dialNumber)) { 488 log("EF_CFIS: updating cf number, " + dialNumber); 489 byte[] bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(dialNumber); 490 491 System.arraycopy(bcdNumber, 0, mEfCfis, CFIS_TON_NPI_OFFSET, bcdNumber.length); 492 493 mEfCfis[CFIS_BCD_NUMBER_LENGTH_OFFSET] = (byte) (bcdNumber.length); 494 mEfCfis[CFIS_ADN_CAPABILITY_ID_OFFSET] = (byte) 0xFF; 495 mEfCfis[CFIS_ADN_EXTENSION_ID_OFFSET] = (byte) 0xFF; 496 } 497 498 mFh.updateEFLinearFixed( 499 EF_CFIS, 1, mEfCfis, null, 500 obtainMessage (EVENT_UPDATE_DONE, EF_CFIS)); 501 } else { 502 log("setVoiceCallForwardingFlag: ignoring enable=" + enable 503 + " invalid mEfCfis=" + IccUtils.bytesToHexString(mEfCfis)); 504 } 505 506 if (mEfCff != null) { 507 if (enable) { 508 mEfCff[0] = (byte) ((mEfCff[0] & CFF_LINE1_RESET) 509 | CFF_UNCONDITIONAL_ACTIVE); 510 } else { 511 mEfCff[0] = (byte) ((mEfCff[0] & CFF_LINE1_RESET) 512 | CFF_UNCONDITIONAL_DEACTIVE); 513 } 514 515 mFh.updateEFTransparent( 516 EF_CFF_CPHS, mEfCff, 517 obtainMessage (EVENT_UPDATE_DONE, EF_CFF_CPHS)); 518 } 519 } catch (ArrayIndexOutOfBoundsException ex) { 520 logw("Error saving call forwarding flag to SIM. " 521 + "Probably malformed SIM record", ex); 522 523 } 524 } 525 526 /** 527 * Called by STK Service when REFRESH is received. 528 * @param fileChanged indicates whether any files changed 529 * @param fileList if non-null, a list of EF files that changed 530 */ 531 @Override 532 public void onRefresh(boolean fileChanged, int[] fileList) { 533 if (fileChanged) { 534 // A future optimization would be to inspect fileList and 535 // only reload those files that we care about. For now, 536 // just re-fetch all SIM records that we cache. 537 fetchSimRecords(); 538 } 539 } 540 541 /** 542 * {@inheritDoc} 543 */ 544 @Override 545 public String getOperatorNumeric() { 546 if (mImsi == null) { 547 log("getOperatorNumeric: IMSI == null"); 548 return null; 549 } 550 if (mMncLength == UNINITIALIZED || mMncLength == UNKNOWN) { 551 log("getSIMOperatorNumeric: bad mncLength"); 552 return null; 553 } 554 555 // Length = length of MCC + length of MNC 556 // length of mcc = 3 (TS 23.003 Section 2.2) 557 return mImsi.substring(0, 3 + mMncLength); 558 } 559 560 // ***** Overridden from Handler 561 @Override 562 public void handleMessage(Message msg) { 563 AsyncResult ar; 564 AdnRecord adn; 565 566 byte data[]; 567 568 boolean isRecordLoadResponse = false; 569 570 if (mDestroyed.get()) { 571 loge("Received message " + msg + "[" + msg.what + "] " + 572 " while being destroyed. Ignoring."); 573 return; 574 } 575 576 try { switch (msg.what) { 577 case EVENT_APP_READY: 578 onReady(); 579 break; 580 581 /* IO events */ 582 case EVENT_GET_IMSI_DONE: 583 isRecordLoadResponse = true; 584 585 ar = (AsyncResult)msg.obj; 586 587 if (ar.exception != null) { 588 loge("Exception querying IMSI, Exception:" + ar.exception); 589 break; 590 } 591 592 mImsi = (String) ar.result; 593 594 // IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more 595 // than 15 (and usually 15). 596 if (mImsi != null && (mImsi.length() < 6 || mImsi.length() > 15)) { 597 loge("invalid IMSI " + mImsi); 598 mImsi = null; 599 } 600 601 log("IMSI: " + /* imsi.substring(0, 6) +*/ "xxxxxxx"); 602 603 if (((mMncLength == UNKNOWN) || (mMncLength == 2)) && 604 ((mImsi != null) && (mImsi.length() >= 6))) { 605 String mccmncCode = mImsi.substring(0, 6); 606 for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) { 607 if (mccmnc.equals(mccmncCode)) { 608 mMncLength = 3; 609 break; 610 } 611 } 612 } 613 614 if (mMncLength == UNKNOWN) { 615 // the SIM has told us all it knows, but it didn't know the mnc length. 616 // guess using the mcc 617 try { 618 int mcc = Integer.parseInt(mImsi.substring(0,3)); 619 mMncLength = MccTable.smallestDigitsMccForMnc(mcc); 620 } catch (NumberFormatException e) { 621 mMncLength = UNKNOWN; 622 loge("Corrupt IMSI!"); 623 } 624 } 625 626 if (mMncLength != UNKNOWN && mMncLength != UNINITIALIZED) { 627 // finally have both the imsi and the mncLength and can parse the imsi properly 628 MccTable.updateMccMncConfiguration(mContext, 629 mImsi.substring(0, 3 + mMncLength), false); 630 } 631 mImsiReadyRegistrants.notifyRegistrants(); 632 break; 633 634 case EVENT_GET_MBI_DONE: 635 boolean isValidMbdn; 636 isRecordLoadResponse = true; 637 638 ar = (AsyncResult)msg.obj; 639 data = (byte[]) ar.result; 640 641 isValidMbdn = false; 642 if (ar.exception == null) { 643 // Refer TS 51.011 Section 10.3.44 for content details 644 log("EF_MBI: " + IccUtils.bytesToHexString(data)); 645 646 // Voice mail record number stored first 647 mMailboxIndex = data[0] & 0xff; 648 649 // check if dailing numbe id valid 650 if (mMailboxIndex != 0 && mMailboxIndex != 0xff) { 651 log("Got valid mailbox number for MBDN"); 652 isValidMbdn = true; 653 } 654 } 655 656 // one more record to load 657 mRecordsToLoad += 1; 658 659 if (isValidMbdn) { 660 // Note: MBDN was not included in NUM_OF_SIM_RECORDS_LOADED 661 new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6, 662 mMailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE)); 663 } else { 664 // If this EF not present, try mailbox as in CPHS standard 665 // CPHS (CPHS4_2.WW6) is a european standard. 666 new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS, 667 EF_EXT1, 1, 668 obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); 669 } 670 671 break; 672 case EVENT_GET_CPHS_MAILBOX_DONE: 673 case EVENT_GET_MBDN_DONE: 674 //Resetting the voice mail number and voice mail tag to null 675 //as these should be updated from the data read from EF_MBDN. 676 //If they are not reset, incase of invalid data/exception these 677 //variables are retaining their previous values and are 678 //causing invalid voice mailbox info display to user. 679 mVoiceMailNum = null; 680 mVoiceMailTag = null; 681 isRecordLoadResponse = true; 682 683 ar = (AsyncResult)msg.obj; 684 685 if (ar.exception != null) { 686 687 log("Invalid or missing EF" 688 + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? "[MAILBOX]" : "[MBDN]")); 689 690 // Bug #645770 fall back to CPHS 691 // FIXME should use SST to decide 692 693 if (msg.what == EVENT_GET_MBDN_DONE) { 694 //load CPHS on fail... 695 // FIXME right now, only load line1's CPHS voice mail entry 696 697 mRecordsToLoad += 1; 698 new AdnRecordLoader(mFh).loadFromEF( 699 EF_MAILBOX_CPHS, EF_EXT1, 1, 700 obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); 701 } 702 break; 703 } 704 705 adn = (AdnRecord)ar.result; 706 707 log("VM: " + adn + 708 ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? " EF[MAILBOX]" : " EF[MBDN]")); 709 710 if (adn.isEmpty() && msg.what == EVENT_GET_MBDN_DONE) { 711 // Bug #645770 fall back to CPHS 712 // FIXME should use SST to decide 713 // FIXME right now, only load line1's CPHS voice mail entry 714 mRecordsToLoad += 1; 715 new AdnRecordLoader(mFh).loadFromEF( 716 EF_MAILBOX_CPHS, EF_EXT1, 1, 717 obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); 718 719 break; 720 } 721 722 mVoiceMailNum = adn.getNumber(); 723 mVoiceMailTag = adn.getAlphaTag(); 724 break; 725 726 case EVENT_GET_MSISDN_DONE: 727 isRecordLoadResponse = true; 728 729 ar = (AsyncResult)msg.obj; 730 731 if (ar.exception != null) { 732 log("Invalid or missing EF[MSISDN]"); 733 break; 734 } 735 736 adn = (AdnRecord)ar.result; 737 738 mMsisdn = adn.getNumber(); 739 mMsisdnTag = adn.getAlphaTag(); 740 741 log("MSISDN: " + /*mMsisdn*/ "xxxxxxx"); 742 break; 743 744 case EVENT_SET_MSISDN_DONE: 745 isRecordLoadResponse = false; 746 ar = (AsyncResult)msg.obj; 747 748 if (ar.userObj != null) { 749 AsyncResult.forMessage(((Message) ar.userObj)).exception 750 = ar.exception; 751 ((Message) ar.userObj).sendToTarget(); 752 } 753 break; 754 755 case EVENT_GET_MWIS_DONE: 756 isRecordLoadResponse = true; 757 758 ar = (AsyncResult)msg.obj; 759 data = (byte[])ar.result; 760 761 if (ar.exception != null) { 762 break; 763 } 764 765 log("EF_MWIS: " + IccUtils.bytesToHexString(data)); 766 767 mEfMWIS = data; 768 769 if ((data[0] & 0xff) == 0xff) { 770 log("Uninitialized record MWIS"); 771 break; 772 } 773 774 // Refer TS 51.011 Section 10.3.45 for the content description 775 boolean voiceMailWaiting = ((data[0] & 0x01) != 0); 776 mCountVoiceMessages = data[1] & 0xff; 777 778 if (voiceMailWaiting && mCountVoiceMessages == 0) { 779 // Unknown count = -1 780 mCountVoiceMessages = -1; 781 } 782 783 mRecordsEventsRegistrants.notifyResult(EVENT_MWI); 784 break; 785 786 case EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE: 787 isRecordLoadResponse = true; 788 789 ar = (AsyncResult)msg.obj; 790 data = (byte[])ar.result; 791 792 if (ar.exception != null) { 793 break; 794 } 795 796 mEfCPHS_MWI = data; 797 798 // Use this data if the EF[MWIS] exists and 799 // has been loaded 800 801 if (mEfMWIS == null) { 802 int indicator = data[0] & 0xf; 803 804 // Refer CPHS4_2.WW6 B4.2.3 805 if (indicator == 0xA) { 806 // Unknown count = -1 807 mCountVoiceMessages = -1; 808 } else if (indicator == 0x5) { 809 mCountVoiceMessages = 0; 810 } 811 812 mRecordsEventsRegistrants.notifyResult(EVENT_MWI); 813 } 814 break; 815 816 case EVENT_GET_ICCID_DONE: 817 isRecordLoadResponse = true; 818 819 ar = (AsyncResult)msg.obj; 820 data = (byte[])ar.result; 821 822 if (ar.exception != null) { 823 break; 824 } 825 826 mIccId = IccUtils.bcdToString(data, 0, data.length); 827 828 log("iccid: " + mIccId); 829 830 break; 831 832 833 case EVENT_GET_AD_DONE: 834 try { 835 isRecordLoadResponse = true; 836 837 ar = (AsyncResult)msg.obj; 838 data = (byte[])ar.result; 839 840 if (ar.exception != null) { 841 break; 842 } 843 844 log("EF_AD: " + IccUtils.bytesToHexString(data)); 845 846 if (data.length < 3) { 847 log("Corrupt AD data on SIM"); 848 break; 849 } 850 851 if (data.length == 3) { 852 log("MNC length not present in EF_AD"); 853 break; 854 } 855 856 mMncLength = data[3] & 0xf; 857 858 if (mMncLength == 0xf) { 859 mMncLength = UNKNOWN; 860 } 861 } finally { 862 if (((mMncLength == UNINITIALIZED) || (mMncLength == UNKNOWN) || 863 (mMncLength == 2)) && ((mImsi != null) && (mImsi.length() >= 6))) { 864 String mccmncCode = mImsi.substring(0, 6); 865 for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) { 866 if (mccmnc.equals(mccmncCode)) { 867 mMncLength = 3; 868 break; 869 } 870 } 871 } 872 873 if (mMncLength == UNKNOWN || mMncLength == UNINITIALIZED) { 874 if (mImsi != null) { 875 try { 876 int mcc = Integer.parseInt(mImsi.substring(0,3)); 877 878 mMncLength = MccTable.smallestDigitsMccForMnc(mcc); 879 } catch (NumberFormatException e) { 880 mMncLength = UNKNOWN; 881 loge("Corrupt IMSI!"); 882 } 883 } else { 884 // Indicate we got this info, but it didn't contain the length. 885 mMncLength = UNKNOWN; 886 887 log("MNC length not present in EF_AD"); 888 } 889 } 890 if (mImsi != null && mMncLength != UNKNOWN) { 891 // finally have both imsi and the length of the mnc and can parse 892 // the imsi properly 893 MccTable.updateMccMncConfiguration(mContext, 894 mImsi.substring(0, 3 + mMncLength), false); 895 } 896 } 897 break; 898 899 case EVENT_GET_SPN_DONE: 900 isRecordLoadResponse = true; 901 ar = (AsyncResult) msg.obj; 902 getSpnFsm(false, ar); 903 break; 904 905 case EVENT_GET_CFF_DONE: 906 isRecordLoadResponse = true; 907 908 ar = (AsyncResult) msg.obj; 909 data = (byte[]) ar.result; 910 911 if (ar.exception != null) { 912 break; 913 } 914 915 log("EF_CFF_CPHS: " + IccUtils.bytesToHexString(data)); 916 mEfCff = data; 917 918 // if EF_CFIS is valid, prefer it to EF_CFF_CPHS 919 if (!validEfCfis(mEfCfis)) { 920 mCallForwardingEnabled = 921 ((data[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE); 922 923 mRecordsEventsRegistrants.notifyResult(EVENT_CFI); 924 } else { 925 log("EVENT_GET_CFF_DONE: EF_CFIS is valid, ignoring EF_CFF_CPHS"); 926 } 927 break; 928 929 case EVENT_GET_SPDI_DONE: 930 isRecordLoadResponse = true; 931 932 ar = (AsyncResult)msg.obj; 933 data = (byte[])ar.result; 934 935 if (ar.exception != null) { 936 break; 937 } 938 939 parseEfSpdi(data); 940 break; 941 942 case EVENT_UPDATE_DONE: 943 ar = (AsyncResult)msg.obj; 944 if (ar.exception != null) { 945 logw("update failed. ", ar.exception); 946 } 947 break; 948 949 case EVENT_GET_PNN_DONE: 950 isRecordLoadResponse = true; 951 952 ar = (AsyncResult)msg.obj; 953 data = (byte[])ar.result; 954 955 if (ar.exception != null) { 956 break; 957 } 958 959 SimTlv tlv = new SimTlv(data, 0, data.length); 960 961 for ( ; tlv.isValidObject() ; tlv.nextObject()) { 962 if (tlv.getTag() == TAG_FULL_NETWORK_NAME) { 963 mPnnHomeName 964 = IccUtils.networkNameToString( 965 tlv.getData(), 0, tlv.getData().length); 966 break; 967 } 968 } 969 break; 970 971 case EVENT_GET_ALL_SMS_DONE: 972 isRecordLoadResponse = true; 973 974 ar = (AsyncResult)msg.obj; 975 if (ar.exception != null) 976 break; 977 978 handleSmses((ArrayList<byte []>) ar.result); 979 break; 980 981 case EVENT_MARK_SMS_READ_DONE: 982 Rlog.i("ENF", "marked read: sms " + msg.arg1); 983 break; 984 985 986 case EVENT_SMS_ON_SIM: 987 isRecordLoadResponse = false; 988 989 ar = (AsyncResult)msg.obj; 990 991 int[] index = (int[])ar.result; 992 993 if (ar.exception != null || index.length != 1) { 994 loge("Error on SMS_ON_SIM with exp " 995 + ar.exception + " length " + index.length); 996 } else { 997 log("READ EF_SMS RECORD index=" + index[0]); 998 mFh.loadEFLinearFixed(EF_SMS,index[0], 999 obtainMessage(EVENT_GET_SMS_DONE)); 1000 } 1001 break; 1002 1003 case EVENT_GET_SMS_DONE: 1004 isRecordLoadResponse = false; 1005 ar = (AsyncResult)msg.obj; 1006 if (ar.exception == null) { 1007 handleSms((byte[])ar.result); 1008 } else { 1009 loge("Error on GET_SMS with exp " + ar.exception); 1010 } 1011 break; 1012 case EVENT_GET_SST_DONE: 1013 isRecordLoadResponse = true; 1014 1015 ar = (AsyncResult)msg.obj; 1016 data = (byte[])ar.result; 1017 1018 if (ar.exception != null) { 1019 break; 1020 } 1021 1022 mUsimServiceTable = new UsimServiceTable(data); 1023 if (DBG) log("SST: " + mUsimServiceTable); 1024 break; 1025 1026 case EVENT_GET_INFO_CPHS_DONE: 1027 isRecordLoadResponse = true; 1028 1029 ar = (AsyncResult)msg.obj; 1030 1031 if (ar.exception != null) { 1032 break; 1033 } 1034 1035 mCphsInfo = (byte[])ar.result; 1036 1037 if (DBG) log("iCPHS: " + IccUtils.bytesToHexString(mCphsInfo)); 1038 break; 1039 1040 case EVENT_SET_MBDN_DONE: 1041 isRecordLoadResponse = false; 1042 ar = (AsyncResult)msg.obj; 1043 1044 if (ar.exception == null) { 1045 mVoiceMailNum = mNewVoiceMailNum; 1046 mVoiceMailTag = mNewVoiceMailTag; 1047 } 1048 1049 if (isCphsMailboxEnabled()) { 1050 adn = new AdnRecord(mVoiceMailTag, mVoiceMailNum); 1051 Message onCphsCompleted = (Message) ar.userObj; 1052 1053 /* write to cphs mailbox whenever it is available but 1054 * we only need notify caller once if both updating are 1055 * successful. 1056 * 1057 * so if set_mbdn successful, notify caller here and set 1058 * onCphsCompleted to null 1059 */ 1060 if (ar.exception == null && ar.userObj != null) { 1061 AsyncResult.forMessage(((Message) ar.userObj)).exception 1062 = null; 1063 ((Message) ar.userObj).sendToTarget(); 1064 1065 if (DBG) log("Callback with MBDN successful."); 1066 1067 onCphsCompleted = null; 1068 } 1069 1070 new AdnRecordLoader(mFh). 1071 updateEF(adn, EF_MAILBOX_CPHS, EF_EXT1, 1, null, 1072 obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE, 1073 onCphsCompleted)); 1074 } else { 1075 if (ar.userObj != null) { 1076 AsyncResult.forMessage(((Message) ar.userObj)).exception 1077 = ar.exception; 1078 ((Message) ar.userObj).sendToTarget(); 1079 } 1080 } 1081 break; 1082 case EVENT_SET_CPHS_MAILBOX_DONE: 1083 isRecordLoadResponse = false; 1084 ar = (AsyncResult)msg.obj; 1085 if(ar.exception == null) { 1086 mVoiceMailNum = mNewVoiceMailNum; 1087 mVoiceMailTag = mNewVoiceMailTag; 1088 } else { 1089 if (DBG) log("Set CPHS MailBox with exception: " 1090 + ar.exception); 1091 } 1092 if (ar.userObj != null) { 1093 if (DBG) log("Callback with CPHS MB successful."); 1094 AsyncResult.forMessage(((Message) ar.userObj)).exception 1095 = ar.exception; 1096 ((Message) ar.userObj).sendToTarget(); 1097 } 1098 break; 1099 case EVENT_SIM_REFRESH: 1100 isRecordLoadResponse = false; 1101 ar = (AsyncResult)msg.obj; 1102 if (DBG) log("Sim REFRESH with exception: " + ar.exception); 1103 if (ar.exception == null) { 1104 handleSimRefresh((IccRefreshResponse)ar.result); 1105 } 1106 break; 1107 case EVENT_GET_CFIS_DONE: 1108 isRecordLoadResponse = true; 1109 1110 ar = (AsyncResult)msg.obj; 1111 data = (byte[])ar.result; 1112 1113 if (ar.exception != null) { 1114 break; 1115 } 1116 1117 log("EF_CFIS: " + IccUtils.bytesToHexString(data)); 1118 1119 if (validEfCfis(data)) { 1120 mEfCfis = data; 1121 1122 // Refer TS 51.011 Section 10.3.46 for the content description 1123 mCallForwardingEnabled = ((data[1] & 0x01) != 0); 1124 log("EF_CFIS: callForwardingEnabled=" + mCallForwardingEnabled); 1125 1126 mRecordsEventsRegistrants.notifyResult(EVENT_CFI); 1127 } else { 1128 log("EF_CFIS: invalid data=" + IccUtils.bytesToHexString(data)); 1129 } 1130 break; 1131 1132 case EVENT_GET_CSP_CPHS_DONE: 1133 isRecordLoadResponse = true; 1134 1135 ar = (AsyncResult)msg.obj; 1136 1137 if (ar.exception != null) { 1138 loge("Exception in fetching EF_CSP data " + ar.exception); 1139 break; 1140 } 1141 1142 data = (byte[])ar.result; 1143 1144 log("EF_CSP: " + IccUtils.bytesToHexString(data)); 1145 handleEfCspData(data); 1146 break; 1147 1148 case EVENT_GET_GID1_DONE: 1149 isRecordLoadResponse = true; 1150 1151 ar = (AsyncResult)msg.obj; 1152 data =(byte[])ar.result; 1153 1154 if (ar.exception != null) { 1155 loge("Exception in get GID1 " + ar.exception); 1156 mGid1 = null; 1157 break; 1158 } 1159 mGid1 = IccUtils.bytesToHexString(data); 1160 log("GID1: " + mGid1); 1161 1162 break; 1163 1164 default: 1165 super.handleMessage(msg); // IccRecords handles generic record load responses 1166 1167 }}catch (RuntimeException exc) { 1168 // I don't want these exceptions to be fatal 1169 logw("Exception parsing SIM record", exc); 1170 } finally { 1171 // Count up record load responses even if they are fails 1172 if (isRecordLoadResponse) { 1173 onRecordLoaded(); 1174 } 1175 } 1176 } 1177 1178 private void handleFileUpdate(int efid) { 1179 switch(efid) { 1180 case EF_MBDN: 1181 mRecordsToLoad++; 1182 new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6, 1183 mMailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE)); 1184 break; 1185 case EF_MAILBOX_CPHS: 1186 mRecordsToLoad++; 1187 new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1, 1188 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); 1189 break; 1190 case EF_CSP_CPHS: 1191 mRecordsToLoad++; 1192 log("[CSP] SIM Refresh for EF_CSP_CPHS"); 1193 mFh.loadEFTransparent(EF_CSP_CPHS, 1194 obtainMessage(EVENT_GET_CSP_CPHS_DONE)); 1195 break; 1196 case EF_FDN: 1197 if (DBG) log("SIM Refresh called for EF_FDN"); 1198 mParentApp.queryFdn(); 1199 break; 1200 default: 1201 // For now, fetch all records if this is not a 1202 // voicemail number. 1203 // TODO: Handle other cases, instead of fetching all. 1204 mAdnCache.reset(); 1205 fetchSimRecords(); 1206 break; 1207 } 1208 } 1209 1210 private void handleSimRefresh(IccRefreshResponse refreshResponse){ 1211 if (refreshResponse == null) { 1212 if (DBG) log("handleSimRefresh received without input"); 1213 return; 1214 } 1215 1216 if (refreshResponse.aid != null && 1217 !refreshResponse.aid.equals(mParentApp.getAid())) { 1218 // This is for different app. Ignore. 1219 return; 1220 } 1221 1222 switch (refreshResponse.refreshResult) { 1223 case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE: 1224 if (DBG) log("handleSimRefresh with SIM_FILE_UPDATED"); 1225 handleFileUpdate(refreshResponse.efId); 1226 break; 1227 case IccRefreshResponse.REFRESH_RESULT_INIT: 1228 if (DBG) log("handleSimRefresh with SIM_REFRESH_INIT"); 1229 // need to reload all files (that we care about) 1230 onIccRefreshInit(); 1231 break; 1232 case IccRefreshResponse.REFRESH_RESULT_RESET: 1233 if (DBG) log("handleSimRefresh with SIM_REFRESH_RESET"); 1234 mCi.setRadioPower(false, null); 1235 /* Note: no need to call setRadioPower(true). Assuming the desired 1236 * radio power state is still ON (as tracked by ServiceStateTracker), 1237 * ServiceStateTracker will call setRadioPower when it receives the 1238 * RADIO_STATE_CHANGED notification for the power off. And if the 1239 * desired power state has changed in the interim, we don't want to 1240 * override it with an unconditional power on. 1241 */ 1242 mAdnCache.reset(); 1243 break; 1244 default: 1245 // unknown refresh operation 1246 if (DBG) log("handleSimRefresh with unknown operation"); 1247 break; 1248 } 1249 } 1250 1251 /** 1252 * Dispatch 3GPP format message to registrant ({@code GSMPhone} or {@code CDMALTEPhone}) 1253 * to pass to the 3GPP SMS dispatcher for delivery. 1254 */ 1255 private int dispatchGsmMessage(SmsMessage message) { 1256 mNewSmsRegistrants.notifyResult(message); 1257 return 0; 1258 } 1259 1260 private void handleSms(byte[] ba) { 1261 if (ba[0] != 0) 1262 Rlog.d("ENF", "status : " + ba[0]); 1263 1264 // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 1265 // 3 == "received by MS from network; message to be read" 1266 if (ba[0] == 3) { 1267 int n = ba.length; 1268 1269 // Note: Data may include trailing FF's. That's OK; message 1270 // should still parse correctly. 1271 byte[] pdu = new byte[n - 1]; 1272 System.arraycopy(ba, 1, pdu, 0, n - 1); 1273 SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP); 1274 1275 dispatchGsmMessage(message); 1276 } 1277 } 1278 1279 1280 private void handleSmses(ArrayList<byte[]> messages) { 1281 int count = messages.size(); 1282 1283 for (int i = 0; i < count; i++) { 1284 byte[] ba = messages.get(i); 1285 1286 if (ba[0] != 0) 1287 Rlog.i("ENF", "status " + i + ": " + ba[0]); 1288 1289 // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 1290 // 3 == "received by MS from network; message to be read" 1291 1292 if (ba[0] == 3) { 1293 int n = ba.length; 1294 1295 // Note: Data may include trailing FF's. That's OK; message 1296 // should still parse correctly. 1297 byte[] pdu = new byte[n - 1]; 1298 System.arraycopy(ba, 1, pdu, 0, n - 1); 1299 SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP); 1300 1301 dispatchGsmMessage(message); 1302 1303 // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 1304 // 1 == "received by MS from network; message read" 1305 1306 ba[0] = 1; 1307 1308 if (false) { // FIXME: writing seems to crash RdoServD 1309 mFh.updateEFLinearFixed(EF_SMS, 1310 i, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, i)); 1311 } 1312 } 1313 } 1314 } 1315 1316 @Override 1317 protected void onRecordLoaded() { 1318 // One record loaded successfully or failed, In either case 1319 // we need to update the recordsToLoad count 1320 mRecordsToLoad -= 1; 1321 if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested); 1322 1323 if (mRecordsToLoad == 0 && mRecordsRequested == true) { 1324 onAllRecordsLoaded(); 1325 } else if (mRecordsToLoad < 0) { 1326 loge("recordsToLoad <0, programmer error suspected"); 1327 mRecordsToLoad = 0; 1328 } 1329 } 1330 1331 @Override 1332 protected void onAllRecordsLoaded() { 1333 if (DBG) log("record load complete"); 1334 1335 // Some fields require more than one SIM record to set 1336 1337 String operator = getOperatorNumeric(); 1338 if (!TextUtils.isEmpty(operator)) { 1339 log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" + 1340 operator + "'"); 1341 SystemProperties.set(PROPERTY_ICC_OPERATOR_NUMERIC, operator); 1342 } else { 1343 log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping"); 1344 } 1345 1346 if (!TextUtils.isEmpty(mImsi)) { 1347 log("onAllRecordsLoaded set mcc imsi=" + mImsi); 1348 SystemProperties.set(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, 1349 MccTable.countryCodeForMcc(Integer.parseInt(mImsi.substring(0,3)))); 1350 } else { 1351 log("onAllRecordsLoaded empty imsi skipping setting mcc"); 1352 } 1353 1354 setVoiceMailByCountry(operator); 1355 setSpnFromConfig(operator); 1356 1357 mRecordsLoadedRegistrants.notifyRegistrants( 1358 new AsyncResult(null, null, null)); 1359 } 1360 1361 //***** Private methods 1362 1363 private void setSpnFromConfig(String carrier) { 1364 if (mSpnOverride.containsCarrier(carrier)) { 1365 mSpn = mSpnOverride.getSpn(carrier); 1366 } 1367 } 1368 1369 1370 private void setVoiceMailByCountry (String spn) { 1371 if (mVmConfig.containsCarrier(spn)) { 1372 mIsVoiceMailFixed = true; 1373 mVoiceMailNum = mVmConfig.getVoiceMailNumber(spn); 1374 mVoiceMailTag = mVmConfig.getVoiceMailTag(spn); 1375 } 1376 } 1377 1378 @Override 1379 public void onReady() { 1380 fetchSimRecords(); 1381 } 1382 1383 protected void fetchSimRecords() { 1384 mRecordsRequested = true; 1385 1386 if (DBG) log("fetchSimRecords " + mRecordsToLoad); 1387 1388 mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE)); 1389 mRecordsToLoad++; 1390 1391 mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE)); 1392 mRecordsToLoad++; 1393 1394 // FIXME should examine EF[MSISDN]'s capability configuration 1395 // to determine which is the voice/data/fax line 1396 new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, EF_EXT1, 1, 1397 obtainMessage(EVENT_GET_MSISDN_DONE)); 1398 mRecordsToLoad++; 1399 1400 // Record number is subscriber profile 1401 mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE)); 1402 mRecordsToLoad++; 1403 1404 mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE)); 1405 mRecordsToLoad++; 1406 1407 // Record number is subscriber profile 1408 mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE)); 1409 mRecordsToLoad++; 1410 1411 1412 // Also load CPHS-style voice mail indicator, which stores 1413 // the same info as EF[MWIS]. If both exist, both are updated 1414 // but the EF[MWIS] data is preferred 1415 // Please note this must be loaded after EF[MWIS] 1416 mFh.loadEFTransparent( 1417 EF_VOICE_MAIL_INDICATOR_CPHS, 1418 obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE)); 1419 mRecordsToLoad++; 1420 1421 // Same goes for Call Forward Status indicator: fetch both 1422 // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred. 1423 mFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE)); 1424 mRecordsToLoad++; 1425 mFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE)); 1426 mRecordsToLoad++; 1427 1428 1429 getSpnFsm(true, null); 1430 1431 mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE)); 1432 mRecordsToLoad++; 1433 1434 mFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE)); 1435 mRecordsToLoad++; 1436 1437 mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE)); 1438 mRecordsToLoad++; 1439 1440 mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE)); 1441 mRecordsToLoad++; 1442 1443 mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE)); 1444 mRecordsToLoad++; 1445 1446 mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE)); 1447 mRecordsToLoad++; 1448 1449 // XXX should seek instead of examining them all 1450 if (false) { // XXX 1451 mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE)); 1452 mRecordsToLoad++; 1453 } 1454 1455 if (CRASH_RIL) { 1456 String sms = "0107912160130310f20404d0110041007030208054832b0120" 1457 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1458 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1459 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1460 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1461 + "ffffffffffffffffffffffffffffff"; 1462 byte[] ba = IccUtils.hexStringToBytes(sms); 1463 1464 mFh.updateEFLinearFixed(EF_SMS, 1, ba, null, 1465 obtainMessage(EVENT_MARK_SMS_READ_DONE, 1)); 1466 } 1467 if (DBG) log("fetchSimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested); 1468 } 1469 1470 /** 1471 * Returns the SpnDisplayRule based on settings on the SIM and the 1472 * specified plmn (currently-registered PLMN). See TS 22.101 Annex A 1473 * and TS 51.011 10.3.11 for details. 1474 * 1475 * If the SPN is not found on the SIM or is empty, the rule is 1476 * always PLMN_ONLY. 1477 */ 1478 @Override 1479 public int getDisplayRule(String plmn) { 1480 int rule; 1481 if (TextUtils.isEmpty(mSpn) || mSpnDisplayCondition == -1) { 1482 // No EF_SPN content was found on the SIM, or not yet loaded. Just show ONS. 1483 rule = SPN_RULE_SHOW_PLMN; 1484 } else if (isOnMatchingPlmn(plmn)) { 1485 rule = SPN_RULE_SHOW_SPN; 1486 if ((mSpnDisplayCondition & 0x01) == 0x01) { 1487 // ONS required when registered to HPLMN or PLMN in EF_SPDI 1488 rule |= SPN_RULE_SHOW_PLMN; 1489 } 1490 } else { 1491 rule = SPN_RULE_SHOW_PLMN; 1492 if ((mSpnDisplayCondition & 0x02) == 0x00) { 1493 // SPN required if not registered to HPLMN or PLMN in EF_SPDI 1494 rule |= SPN_RULE_SHOW_SPN; 1495 } 1496 } 1497 return rule; 1498 } 1499 1500 /** 1501 * Checks if plmn is HPLMN or on the spdiNetworks list. 1502 */ 1503 private boolean isOnMatchingPlmn(String plmn) { 1504 if (plmn == null) return false; 1505 1506 if (plmn.equals(getOperatorNumeric())) { 1507 return true; 1508 } 1509 1510 if (mSpdiNetworks != null) { 1511 for (String spdiNet : mSpdiNetworks) { 1512 if (plmn.equals(spdiNet)) { 1513 return true; 1514 } 1515 } 1516 } 1517 return false; 1518 } 1519 1520 /** 1521 * States of Get SPN Finite State Machine which only used by getSpnFsm() 1522 */ 1523 private enum GetSpnFsmState { 1524 IDLE, // No initialized 1525 INIT, // Start FSM 1526 READ_SPN_3GPP, // Load EF_SPN firstly 1527 READ_SPN_CPHS, // Load EF_SPN_CPHS secondly 1528 READ_SPN_SHORT_CPHS // Load EF_SPN_SHORT_CPHS last 1529 } 1530 1531 /** 1532 * Finite State Machine to load Service Provider Name , which can be stored 1533 * in either EF_SPN (3GPP), EF_SPN_CPHS, or EF_SPN_SHORT_CPHS (CPHS4.2) 1534 * 1535 * After starting, FSM will search SPN EFs in order and stop after finding 1536 * the first valid SPN 1537 * 1538 * If the FSM gets restart while waiting for one of 1539 * SPN EFs results (i.e. a SIM refresh occurs after issuing 1540 * read EF_CPHS_SPN), it will re-initialize only after 1541 * receiving and discarding the unfinished SPN EF result. 1542 * 1543 * @param start set true only for initialize loading 1544 * @param ar the AsyncResult from loadEFTransparent 1545 * ar.exception holds exception in error 1546 * ar.result is byte[] for data in success 1547 */ 1548 private void getSpnFsm(boolean start, AsyncResult ar) { 1549 byte[] data; 1550 1551 if (start) { 1552 // Check previous state to see if there is outstanding 1553 // SPN read 1554 if(mSpnState == GetSpnFsmState.READ_SPN_3GPP || 1555 mSpnState == GetSpnFsmState.READ_SPN_CPHS || 1556 mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS || 1557 mSpnState == GetSpnFsmState.INIT) { 1558 // Set INIT then return so the INIT code 1559 // will run when the outstanding read done. 1560 mSpnState = GetSpnFsmState.INIT; 1561 return; 1562 } else { 1563 mSpnState = GetSpnFsmState.INIT; 1564 } 1565 } 1566 1567 switch(mSpnState){ 1568 case INIT: 1569 mSpn = null; 1570 1571 mFh.loadEFTransparent(EF_SPN, 1572 obtainMessage(EVENT_GET_SPN_DONE)); 1573 mRecordsToLoad++; 1574 1575 mSpnState = GetSpnFsmState.READ_SPN_3GPP; 1576 break; 1577 case READ_SPN_3GPP: 1578 if (ar != null && ar.exception == null) { 1579 data = (byte[]) ar.result; 1580 mSpnDisplayCondition = 0xff & data[0]; 1581 mSpn = IccUtils.adnStringFieldToString(data, 1, data.length - 1); 1582 1583 if (DBG) log("Load EF_SPN: " + mSpn 1584 + " spnDisplayCondition: " + mSpnDisplayCondition); 1585 SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, mSpn); 1586 1587 mSpnState = GetSpnFsmState.IDLE; 1588 } else { 1589 mFh.loadEFTransparent( EF_SPN_CPHS, 1590 obtainMessage(EVENT_GET_SPN_DONE)); 1591 mRecordsToLoad++; 1592 1593 mSpnState = GetSpnFsmState.READ_SPN_CPHS; 1594 1595 // See TS 51.011 10.3.11. Basically, default to 1596 // show PLMN always, and SPN also if roaming. 1597 mSpnDisplayCondition = -1; 1598 } 1599 break; 1600 case READ_SPN_CPHS: 1601 if (ar != null && ar.exception == null) { 1602 data = (byte[]) ar.result; 1603 mSpn = IccUtils.adnStringFieldToString(data, 0, data.length); 1604 1605 if (DBG) log("Load EF_SPN_CPHS: " + mSpn); 1606 SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, mSpn); 1607 1608 mSpnState = GetSpnFsmState.IDLE; 1609 } else { 1610 mFh.loadEFTransparent( 1611 EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE)); 1612 mRecordsToLoad++; 1613 1614 mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS; 1615 } 1616 break; 1617 case READ_SPN_SHORT_CPHS: 1618 if (ar != null && ar.exception == null) { 1619 data = (byte[]) ar.result; 1620 mSpn = IccUtils.adnStringFieldToString(data, 0, data.length); 1621 1622 if (DBG) log("Load EF_SPN_SHORT_CPHS: " + mSpn); 1623 SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, mSpn); 1624 }else { 1625 if (DBG) log("No SPN loaded in either CHPS or 3GPP"); 1626 } 1627 1628 mSpnState = GetSpnFsmState.IDLE; 1629 break; 1630 default: 1631 mSpnState = GetSpnFsmState.IDLE; 1632 } 1633 } 1634 1635 /** 1636 * Parse TS 51.011 EF[SPDI] record 1637 * This record contains the list of numeric network IDs that 1638 * are treated specially when determining SPN display 1639 */ 1640 private void 1641 parseEfSpdi(byte[] data) { 1642 SimTlv tlv = new SimTlv(data, 0, data.length); 1643 1644 byte[] plmnEntries = null; 1645 1646 for ( ; tlv.isValidObject() ; tlv.nextObject()) { 1647 // Skip SPDI tag, if existant 1648 if (tlv.getTag() == TAG_SPDI) { 1649 tlv = new SimTlv(tlv.getData(), 0, tlv.getData().length); 1650 } 1651 // There should only be one TAG_SPDI_PLMN_LIST 1652 if (tlv.getTag() == TAG_SPDI_PLMN_LIST) { 1653 plmnEntries = tlv.getData(); 1654 break; 1655 } 1656 } 1657 1658 if (plmnEntries == null) { 1659 return; 1660 } 1661 1662 mSpdiNetworks = new ArrayList<String>(plmnEntries.length / 3); 1663 1664 for (int i = 0 ; i + 2 < plmnEntries.length ; i += 3) { 1665 String plmnCode; 1666 plmnCode = IccUtils.bcdToString(plmnEntries, i, 3); 1667 1668 // Valid operator codes are 5 or 6 digits 1669 if (plmnCode.length() >= 5) { 1670 log("EF_SPDI network: " + plmnCode); 1671 mSpdiNetworks.add(plmnCode); 1672 } 1673 } 1674 } 1675 1676 /** 1677 * check to see if Mailbox Number is allocated and activated in CPHS SST 1678 */ 1679 private boolean isCphsMailboxEnabled() { 1680 if (mCphsInfo == null) return false; 1681 return ((mCphsInfo[1] & CPHS_SST_MBN_MASK) == CPHS_SST_MBN_ENABLED ); 1682 } 1683 1684 @Override 1685 protected void log(String s) { 1686 Rlog.d(LOG_TAG, "[SIMRecords] " + s); 1687 } 1688 1689 @Override 1690 protected void loge(String s) { 1691 Rlog.e(LOG_TAG, "[SIMRecords] " + s); 1692 } 1693 1694 protected void logw(String s, Throwable tr) { 1695 Rlog.w(LOG_TAG, "[SIMRecords] " + s, tr); 1696 } 1697 1698 protected void logv(String s) { 1699 Rlog.v(LOG_TAG, "[SIMRecords] " + s); 1700 } 1701 1702 /** 1703 * Return true if "Restriction of menu options for manual PLMN selection" 1704 * bit is set or EF_CSP data is unavailable, return false otherwise. 1705 */ 1706 @Override 1707 public boolean isCspPlmnEnabled() { 1708 return mCspPlmnEnabled; 1709 } 1710 1711 /** 1712 * Parse EF_CSP data and check if 1713 * "Restriction of menu options for manual PLMN selection" is 1714 * Enabled/Disabled 1715 * 1716 * @param data EF_CSP hex data. 1717 */ 1718 private void handleEfCspData(byte[] data) { 1719 // As per spec CPHS4_2.WW6, CPHS B.4.7.1, EF_CSP contains CPHS defined 1720 // 18 bytes (i.e 9 service groups info) and additional data specific to 1721 // operator. The valueAddedServicesGroup is not part of standard 1722 // services. This is operator specific and can be programmed any where. 1723 // Normally this is programmed as 10th service after the standard 1724 // services. 1725 int usedCspGroups = data.length / 2; 1726 // This is the "Service Group Number" of "Value Added Services Group". 1727 byte valueAddedServicesGroup = (byte)0xC0; 1728 1729 mCspPlmnEnabled = true; 1730 for (int i = 0; i < usedCspGroups; i++) { 1731 if (data[2 * i] == valueAddedServicesGroup) { 1732 log("[CSP] found ValueAddedServicesGroup, value " + data[(2 * i) + 1]); 1733 if ((data[(2 * i) + 1] & 0x80) == 0x80) { 1734 // Bit 8 is for 1735 // "Restriction of menu options for manual PLMN selection". 1736 // Operator Selection menu should be enabled. 1737 mCspPlmnEnabled = true; 1738 } else { 1739 mCspPlmnEnabled = false; 1740 // Operator Selection menu should be disabled. 1741 // Operator Selection Mode should be set to Automatic. 1742 log("[CSP] Set Automatic Network Selection"); 1743 mNetworkSelectionModeAutomaticRegistrants.notifyRegistrants(); 1744 } 1745 return; 1746 } 1747 } 1748 1749 log("[CSP] Value Added Service Group (0xC0), not found!"); 1750 } 1751 1752 @Override 1753 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1754 pw.println("SIMRecords: " + this); 1755 pw.println(" extends:"); 1756 super.dump(fd, pw, args); 1757 pw.println(" mVmConfig=" + mVmConfig); 1758 pw.println(" mSpnOverride=" + mSpnOverride); 1759 pw.println(" mCallForwardingEnabled=" + mCallForwardingEnabled); 1760 pw.println(" mSpnState=" + mSpnState); 1761 pw.println(" mCphsInfo=" + mCphsInfo); 1762 pw.println(" mCspPlmnEnabled=" + mCspPlmnEnabled); 1763 pw.println(" mEfMWIS[]=" + Arrays.toString(mEfMWIS)); 1764 pw.println(" mEfCPHS_MWI[]=" + Arrays.toString(mEfCPHS_MWI)); 1765 pw.println(" mEfCff[]=" + Arrays.toString(mEfCff)); 1766 pw.println(" mEfCfis[]=" + Arrays.toString(mEfCfis)); 1767 pw.println(" mSpnDisplayCondition=" + mSpnDisplayCondition); 1768 pw.println(" mSpdiNetworks[]=" + mSpdiNetworks); 1769 pw.println(" mPnnHomeName=" + mPnnHomeName); 1770 pw.println(" mUsimServiceTable=" + mUsimServiceTable); 1771 pw.println(" mGid1=" + mGid1); 1772 pw.flush(); 1773 } 1774} 1775