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