SIMRecords.java revision c3e37a01b74d28ebf10572bb0811c8a01916d941
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 if (requirePowerOffOnSimRefreshReset()) { 1247 mCi.setRadioPower(false, null); 1248 /* Note: no need to call setRadioPower(true). Assuming the desired 1249 * radio power state is still ON (as tracked by ServiceStateTracker), 1250 * ServiceStateTracker will call setRadioPower when it receives the 1251 * RADIO_STATE_CHANGED notification for the power off. And if the 1252 * desired power state has changed in the interim, we don't want to 1253 * override it with an unconditional power on. 1254 */ 1255 } 1256 mAdnCache.reset(); 1257 break; 1258 default: 1259 // unknown refresh operation 1260 if (DBG) log("handleSimRefresh with unknown operation"); 1261 break; 1262 } 1263 } 1264 1265 /** 1266 * Dispatch 3GPP format message to registrant ({@code GSMPhone} or {@code CDMALTEPhone}) 1267 * to pass to the 3GPP SMS dispatcher for delivery. 1268 */ 1269 private int dispatchGsmMessage(SmsMessage message) { 1270 mNewSmsRegistrants.notifyResult(message); 1271 return 0; 1272 } 1273 1274 private void handleSms(byte[] ba) { 1275 if (ba[0] != 0) 1276 Rlog.d("ENF", "status : " + ba[0]); 1277 1278 // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 1279 // 3 == "received by MS from network; message to be read" 1280 if (ba[0] == 3) { 1281 int n = ba.length; 1282 1283 // Note: Data may include trailing FF's. That's OK; message 1284 // should still parse correctly. 1285 byte[] pdu = new byte[n - 1]; 1286 System.arraycopy(ba, 1, pdu, 0, n - 1); 1287 SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP); 1288 1289 dispatchGsmMessage(message); 1290 } 1291 } 1292 1293 1294 private void handleSmses(ArrayList<byte[]> messages) { 1295 int count = messages.size(); 1296 1297 for (int i = 0; i < count; i++) { 1298 byte[] ba = messages.get(i); 1299 1300 if (ba[0] != 0) 1301 Rlog.i("ENF", "status " + i + ": " + ba[0]); 1302 1303 // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 1304 // 3 == "received by MS from network; message to be read" 1305 1306 if (ba[0] == 3) { 1307 int n = ba.length; 1308 1309 // Note: Data may include trailing FF's. That's OK; message 1310 // should still parse correctly. 1311 byte[] pdu = new byte[n - 1]; 1312 System.arraycopy(ba, 1, pdu, 0, n - 1); 1313 SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP); 1314 1315 dispatchGsmMessage(message); 1316 1317 // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 1318 // 1 == "received by MS from network; message read" 1319 1320 ba[0] = 1; 1321 1322 if (false) { // FIXME: writing seems to crash RdoServD 1323 mFh.updateEFLinearFixed(EF_SMS, 1324 i, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, i)); 1325 } 1326 } 1327 } 1328 } 1329 1330 @Override 1331 protected void onRecordLoaded() { 1332 // One record loaded successfully or failed, In either case 1333 // we need to update the recordsToLoad count 1334 mRecordsToLoad -= 1; 1335 if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested); 1336 1337 if (mRecordsToLoad == 0 && mRecordsRequested == true) { 1338 onAllRecordsLoaded(); 1339 } else if (mRecordsToLoad < 0) { 1340 loge("recordsToLoad <0, programmer error suspected"); 1341 mRecordsToLoad = 0; 1342 } 1343 } 1344 1345 @Override 1346 protected void onAllRecordsLoaded() { 1347 if (DBG) log("record load complete"); 1348 1349 // Some fields require more than one SIM record to set 1350 1351 String operator = getOperatorNumeric(); 1352 if (!TextUtils.isEmpty(operator)) { 1353 log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" + 1354 operator + "'"); 1355 log("update icc_operator_numeric=" + operator); 1356 setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, operator); 1357 } else { 1358 log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping"); 1359 } 1360 1361 if (!TextUtils.isEmpty(mImsi)) { 1362 log("onAllRecordsLoaded set mcc imsi=" + mImsi); 1363 setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, 1364 MccTable.countryCodeForMcc(Integer.parseInt(mImsi.substring(0,3)))); 1365 } else { 1366 log("onAllRecordsLoaded empty imsi skipping setting mcc"); 1367 } 1368 1369 setVoiceMailByCountry(operator); 1370 setSpnFromConfig(operator); 1371 1372 mRecordsLoadedRegistrants.notifyRegistrants( 1373 new AsyncResult(null, null, null)); 1374 } 1375 1376 //***** Private methods 1377 1378 private void setSpnFromConfig(String carrier) { 1379 if (mSpnOverride.containsCarrier(carrier)) { 1380 setServiceProviderName(mSpnOverride.getSpn(carrier)); 1381 } 1382 } 1383 1384 1385 private void setVoiceMailByCountry (String spn) { 1386 if (mVmConfig.containsCarrier(spn)) { 1387 mIsVoiceMailFixed = true; 1388 mVoiceMailNum = mVmConfig.getVoiceMailNumber(spn); 1389 mVoiceMailTag = mVmConfig.getVoiceMailTag(spn); 1390 } 1391 } 1392 1393 @Override 1394 public void onReady() { 1395 fetchSimRecords(); 1396 } 1397 1398 protected void fetchSimRecords() { 1399 mRecordsRequested = true; 1400 1401 if (DBG) log("fetchSimRecords " + mRecordsToLoad); 1402 1403 mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE)); 1404 mRecordsToLoad++; 1405 1406 mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE)); 1407 mRecordsToLoad++; 1408 1409 // FIXME should examine EF[MSISDN]'s capability configuration 1410 // to determine which is the voice/data/fax line 1411 new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, EF_EXT1, 1, 1412 obtainMessage(EVENT_GET_MSISDN_DONE)); 1413 mRecordsToLoad++; 1414 1415 // Record number is subscriber profile 1416 mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE)); 1417 mRecordsToLoad++; 1418 1419 mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE)); 1420 mRecordsToLoad++; 1421 1422 // Record number is subscriber profile 1423 mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE)); 1424 mRecordsToLoad++; 1425 1426 1427 // Also load CPHS-style voice mail indicator, which stores 1428 // the same info as EF[MWIS]. If both exist, both are updated 1429 // but the EF[MWIS] data is preferred 1430 // Please note this must be loaded after EF[MWIS] 1431 mFh.loadEFTransparent( 1432 EF_VOICE_MAIL_INDICATOR_CPHS, 1433 obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE)); 1434 mRecordsToLoad++; 1435 1436 // Same goes for Call Forward Status indicator: fetch both 1437 // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred. 1438 mFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE)); 1439 mRecordsToLoad++; 1440 mFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE)); 1441 mRecordsToLoad++; 1442 1443 1444 getSpnFsm(true, null); 1445 1446 mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE)); 1447 mRecordsToLoad++; 1448 1449 mFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE)); 1450 mRecordsToLoad++; 1451 1452 mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE)); 1453 mRecordsToLoad++; 1454 1455 mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE)); 1456 mRecordsToLoad++; 1457 1458 mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE)); 1459 mRecordsToLoad++; 1460 1461 mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE)); 1462 mRecordsToLoad++; 1463 1464 // XXX should seek instead of examining them all 1465 if (false) { // XXX 1466 mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE)); 1467 mRecordsToLoad++; 1468 } 1469 1470 if (CRASH_RIL) { 1471 String sms = "0107912160130310f20404d0110041007030208054832b0120" 1472 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1473 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1474 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1475 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1476 + "ffffffffffffffffffffffffffffff"; 1477 byte[] ba = IccUtils.hexStringToBytes(sms); 1478 1479 mFh.updateEFLinearFixed(EF_SMS, 1, ba, null, 1480 obtainMessage(EVENT_MARK_SMS_READ_DONE, 1)); 1481 } 1482 if (DBG) log("fetchSimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested); 1483 } 1484 1485 /** 1486 * Returns the SpnDisplayRule based on settings on the SIM and the 1487 * specified plmn (currently-registered PLMN). See TS 22.101 Annex A 1488 * and TS 51.011 10.3.11 for details. 1489 * 1490 * If the SPN is not found on the SIM or is empty, the rule is 1491 * always PLMN_ONLY. 1492 */ 1493 @Override 1494 public int getDisplayRule(String plmn) { 1495 int rule; 1496 1497 if (mParentApp.getUiccCard() != null && 1498 mParentApp.getUiccCard().getOperatorBrandOverride() != null) { 1499 // If the operator has been overridden, treat it as the SPN file on the SIM did not exist. 1500 rule = SPN_RULE_SHOW_PLMN; 1501 } else if (TextUtils.isEmpty(getServiceProviderName()) || mSpnDisplayCondition == -1) { 1502 // No EF_SPN content was found on the SIM, or not yet loaded. Just show ONS. 1503 rule = SPN_RULE_SHOW_PLMN; 1504 } else if (isOnMatchingPlmn(plmn)) { 1505 rule = SPN_RULE_SHOW_SPN; 1506 if ((mSpnDisplayCondition & 0x01) == 0x01) { 1507 // ONS required when registered to HPLMN or PLMN in EF_SPDI 1508 rule |= SPN_RULE_SHOW_PLMN; 1509 } 1510 } else { 1511 rule = SPN_RULE_SHOW_PLMN; 1512 if ((mSpnDisplayCondition & 0x02) == 0x00) { 1513 // SPN required if not registered to HPLMN or PLMN in EF_SPDI 1514 rule |= SPN_RULE_SHOW_SPN; 1515 } 1516 } 1517 return rule; 1518 } 1519 1520 /** 1521 * Checks if plmn is HPLMN or on the spdiNetworks list. 1522 */ 1523 private boolean isOnMatchingPlmn(String plmn) { 1524 if (plmn == null) return false; 1525 1526 if (plmn.equals(getOperatorNumeric())) { 1527 return true; 1528 } 1529 1530 if (mSpdiNetworks != null) { 1531 for (String spdiNet : mSpdiNetworks) { 1532 if (plmn.equals(spdiNet)) { 1533 return true; 1534 } 1535 } 1536 } 1537 return false; 1538 } 1539 1540 /** 1541 * States of Get SPN Finite State Machine which only used by getSpnFsm() 1542 */ 1543 private enum GetSpnFsmState { 1544 IDLE, // No initialized 1545 INIT, // Start FSM 1546 READ_SPN_3GPP, // Load EF_SPN firstly 1547 READ_SPN_CPHS, // Load EF_SPN_CPHS secondly 1548 READ_SPN_SHORT_CPHS // Load EF_SPN_SHORT_CPHS last 1549 } 1550 1551 /** 1552 * Finite State Machine to load Service Provider Name , which can be stored 1553 * in either EF_SPN (3GPP), EF_SPN_CPHS, or EF_SPN_SHORT_CPHS (CPHS4.2) 1554 * 1555 * After starting, FSM will search SPN EFs in order and stop after finding 1556 * the first valid SPN 1557 * 1558 * If the FSM gets restart while waiting for one of 1559 * SPN EFs results (i.e. a SIM refresh occurs after issuing 1560 * read EF_CPHS_SPN), it will re-initialize only after 1561 * receiving and discarding the unfinished SPN EF result. 1562 * 1563 * @param start set true only for initialize loading 1564 * @param ar the AsyncResult from loadEFTransparent 1565 * ar.exception holds exception in error 1566 * ar.result is byte[] for data in success 1567 */ 1568 private void getSpnFsm(boolean start, AsyncResult ar) { 1569 byte[] data; 1570 1571 if (start) { 1572 // Check previous state to see if there is outstanding 1573 // SPN read 1574 if(mSpnState == GetSpnFsmState.READ_SPN_3GPP || 1575 mSpnState == GetSpnFsmState.READ_SPN_CPHS || 1576 mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS || 1577 mSpnState == GetSpnFsmState.INIT) { 1578 // Set INIT then return so the INIT code 1579 // will run when the outstanding read done. 1580 mSpnState = GetSpnFsmState.INIT; 1581 return; 1582 } else { 1583 mSpnState = GetSpnFsmState.INIT; 1584 } 1585 } 1586 1587 switch(mSpnState){ 1588 case INIT: 1589 setServiceProviderName(null); 1590 1591 mFh.loadEFTransparent(EF_SPN, 1592 obtainMessage(EVENT_GET_SPN_DONE)); 1593 mRecordsToLoad++; 1594 1595 mSpnState = GetSpnFsmState.READ_SPN_3GPP; 1596 break; 1597 case READ_SPN_3GPP: 1598 if (ar != null && ar.exception == null) { 1599 data = (byte[]) ar.result; 1600 mSpnDisplayCondition = 0xff & data[0]; 1601 setServiceProviderName(IccUtils.adnStringFieldToString( 1602 data, 1, data.length - 1)); 1603 1604 if (DBG) log("Load EF_SPN: " + getServiceProviderName() 1605 + " spnDisplayCondition: " + mSpnDisplayCondition); 1606 setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, getServiceProviderName()); 1607 1608 mSpnState = GetSpnFsmState.IDLE; 1609 } else { 1610 mFh.loadEFTransparent( EF_SPN_CPHS, 1611 obtainMessage(EVENT_GET_SPN_DONE)); 1612 mRecordsToLoad++; 1613 1614 mSpnState = GetSpnFsmState.READ_SPN_CPHS; 1615 1616 // See TS 51.011 10.3.11. Basically, default to 1617 // show PLMN always, and SPN also if roaming. 1618 mSpnDisplayCondition = -1; 1619 } 1620 break; 1621 case READ_SPN_CPHS: 1622 if (ar != null && ar.exception == null) { 1623 data = (byte[]) ar.result; 1624 setServiceProviderName(IccUtils.adnStringFieldToString(data, 0, data.length)); 1625 1626 if (DBG) log("Load EF_SPN_CPHS: " + getServiceProviderName()); 1627 setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, getServiceProviderName()); 1628 1629 mSpnState = GetSpnFsmState.IDLE; 1630 } else { 1631 mFh.loadEFTransparent( 1632 EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE)); 1633 mRecordsToLoad++; 1634 1635 mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS; 1636 } 1637 break; 1638 case READ_SPN_SHORT_CPHS: 1639 if (ar != null && ar.exception == null) { 1640 data = (byte[]) ar.result; 1641 setServiceProviderName(IccUtils.adnStringFieldToString(data, 0, data.length)); 1642 1643 if (DBG) log("Load EF_SPN_SHORT_CPHS: " + getServiceProviderName()); 1644 setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, getServiceProviderName()); 1645 }else { 1646 if (DBG) log("No SPN loaded in either CHPS or 3GPP"); 1647 } 1648 1649 mSpnState = GetSpnFsmState.IDLE; 1650 break; 1651 default: 1652 mSpnState = GetSpnFsmState.IDLE; 1653 } 1654 } 1655 1656 /** 1657 * Parse TS 51.011 EF[SPDI] record 1658 * This record contains the list of numeric network IDs that 1659 * are treated specially when determining SPN display 1660 */ 1661 private void 1662 parseEfSpdi(byte[] data) { 1663 SimTlv tlv = new SimTlv(data, 0, data.length); 1664 1665 byte[] plmnEntries = null; 1666 1667 for ( ; tlv.isValidObject() ; tlv.nextObject()) { 1668 // Skip SPDI tag, if existant 1669 if (tlv.getTag() == TAG_SPDI) { 1670 tlv = new SimTlv(tlv.getData(), 0, tlv.getData().length); 1671 } 1672 // There should only be one TAG_SPDI_PLMN_LIST 1673 if (tlv.getTag() == TAG_SPDI_PLMN_LIST) { 1674 plmnEntries = tlv.getData(); 1675 break; 1676 } 1677 } 1678 1679 if (plmnEntries == null) { 1680 return; 1681 } 1682 1683 mSpdiNetworks = new ArrayList<String>(plmnEntries.length / 3); 1684 1685 for (int i = 0 ; i + 2 < plmnEntries.length ; i += 3) { 1686 String plmnCode; 1687 plmnCode = IccUtils.bcdToString(plmnEntries, i, 3); 1688 1689 // Valid operator codes are 5 or 6 digits 1690 if (plmnCode.length() >= 5) { 1691 log("EF_SPDI network: " + plmnCode); 1692 mSpdiNetworks.add(plmnCode); 1693 } 1694 } 1695 } 1696 1697 /** 1698 * check to see if Mailbox Number is allocated and activated in CPHS SST 1699 */ 1700 private boolean isCphsMailboxEnabled() { 1701 if (mCphsInfo == null) return false; 1702 return ((mCphsInfo[1] & CPHS_SST_MBN_MASK) == CPHS_SST_MBN_ENABLED ); 1703 } 1704 1705 @Override 1706 protected void log(String s) { 1707 Rlog.d(LOG_TAG, "[SIMRecords] " + s); 1708 } 1709 1710 @Override 1711 protected void loge(String s) { 1712 Rlog.e(LOG_TAG, "[SIMRecords] " + s); 1713 } 1714 1715 protected void logw(String s, Throwable tr) { 1716 Rlog.w(LOG_TAG, "[SIMRecords] " + s, tr); 1717 } 1718 1719 protected void logv(String s) { 1720 Rlog.v(LOG_TAG, "[SIMRecords] " + s); 1721 } 1722 1723 /** 1724 * Return true if "Restriction of menu options for manual PLMN selection" 1725 * bit is set or EF_CSP data is unavailable, return false otherwise. 1726 */ 1727 @Override 1728 public boolean isCspPlmnEnabled() { 1729 return mCspPlmnEnabled; 1730 } 1731 1732 /** 1733 * Parse EF_CSP data and check if 1734 * "Restriction of menu options for manual PLMN selection" is 1735 * Enabled/Disabled 1736 * 1737 * @param data EF_CSP hex data. 1738 */ 1739 private void handleEfCspData(byte[] data) { 1740 // As per spec CPHS4_2.WW6, CPHS B.4.7.1, EF_CSP contains CPHS defined 1741 // 18 bytes (i.e 9 service groups info) and additional data specific to 1742 // operator. The valueAddedServicesGroup is not part of standard 1743 // services. This is operator specific and can be programmed any where. 1744 // Normally this is programmed as 10th service after the standard 1745 // services. 1746 int usedCspGroups = data.length / 2; 1747 // This is the "Service Group Number" of "Value Added Services Group". 1748 byte valueAddedServicesGroup = (byte)0xC0; 1749 1750 mCspPlmnEnabled = true; 1751 for (int i = 0; i < usedCspGroups; i++) { 1752 if (data[2 * i] == valueAddedServicesGroup) { 1753 log("[CSP] found ValueAddedServicesGroup, value " + data[(2 * i) + 1]); 1754 if ((data[(2 * i) + 1] & 0x80) == 0x80) { 1755 // Bit 8 is for 1756 // "Restriction of menu options for manual PLMN selection". 1757 // Operator Selection menu should be enabled. 1758 mCspPlmnEnabled = true; 1759 } else { 1760 mCspPlmnEnabled = false; 1761 // Operator Selection menu should be disabled. 1762 // Operator Selection Mode should be set to Automatic. 1763 log("[CSP] Set Automatic Network Selection"); 1764 mNetworkSelectionModeAutomaticRegistrants.notifyRegistrants(); 1765 } 1766 return; 1767 } 1768 } 1769 1770 log("[CSP] Value Added Service Group (0xC0), not found!"); 1771 } 1772 1773 @Override 1774 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1775 pw.println("SIMRecords: " + this); 1776 pw.println(" extends:"); 1777 super.dump(fd, pw, args); 1778 pw.println(" mVmConfig=" + mVmConfig); 1779 pw.println(" mSpnOverride=" + mSpnOverride); 1780 pw.println(" mCallForwardingEnabled=" + mCallForwardingEnabled); 1781 pw.println(" mSpnState=" + mSpnState); 1782 pw.println(" mCphsInfo=" + mCphsInfo); 1783 pw.println(" mCspPlmnEnabled=" + mCspPlmnEnabled); 1784 pw.println(" mEfMWIS[]=" + Arrays.toString(mEfMWIS)); 1785 pw.println(" mEfCPHS_MWI[]=" + Arrays.toString(mEfCPHS_MWI)); 1786 pw.println(" mEfCff[]=" + Arrays.toString(mEfCff)); 1787 pw.println(" mEfCfis[]=" + Arrays.toString(mEfCfis)); 1788 pw.println(" mSpnDisplayCondition=" + mSpnDisplayCondition); 1789 pw.println(" mSpdiNetworks[]=" + mSpdiNetworks); 1790 pw.println(" mPnnHomeName=" + mPnnHomeName); 1791 pw.println(" mUsimServiceTable=" + mUsimServiceTable); 1792 pw.println(" mGid1=" + mGid1); 1793 pw.flush(); 1794 } 1795 1796 private void setSystemProperty(String key, String val) { 1797 // Update the system properties only in case NON-DSDS. 1798 // TODO: Shall have a better approach! 1799 if (!TelephonyManager.getDefault().isMultiSimEnabled()) { 1800 SystemProperties.set(key, val); 1801 } 1802 } 1803} 1804