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