SIMRecords.java revision 6bc4098827f3070a44b5e51508b455d7c7be9c07
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 // If the SIM card is locked by PIN, we will set EF_MSISDN fail. 301 // In that case, msisdn and msisdnTag should not be update. 302 mNewMsisdn = number; 303 mNewMsisdnTag = alphaTag; 304 305 if(DBG) log("Set MSISDN: " + mNewMsisdnTag + " " + /*mNewMsisdn*/ "xxxxxxx"); 306 307 308 AdnRecord adn = new AdnRecord(mNewMsisdnTag, mNewMsisdn); 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.exception == null) { 758 mMsisdn = mNewMsisdn; 759 mMsisdnTag = mNewMsisdnTag; 760 log("Success to update EF[MSISDN]"); 761 } 762 763 if (ar.userObj != null) { 764 AsyncResult.forMessage(((Message) ar.userObj)).exception 765 = ar.exception; 766 ((Message) ar.userObj).sendToTarget(); 767 } 768 break; 769 770 case EVENT_GET_MWIS_DONE: 771 isRecordLoadResponse = true; 772 773 ar = (AsyncResult)msg.obj; 774 data = (byte[])ar.result; 775 776 if (ar.exception != null) { 777 break; 778 } 779 780 log("EF_MWIS: " + IccUtils.bytesToHexString(data)); 781 782 mEfMWIS = data; 783 784 if ((data[0] & 0xff) == 0xff) { 785 log("Uninitialized record MWIS"); 786 break; 787 } 788 789 // Refer TS 51.011 Section 10.3.45 for the content description 790 boolean voiceMailWaiting = ((data[0] & 0x01) != 0); 791 mCountVoiceMessages = data[1] & 0xff; 792 793 if (voiceMailWaiting && mCountVoiceMessages == 0) { 794 // Unknown count = -1 795 mCountVoiceMessages = -1; 796 } 797 798 mRecordsEventsRegistrants.notifyResult(EVENT_MWI); 799 break; 800 801 case EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE: 802 isRecordLoadResponse = true; 803 804 ar = (AsyncResult)msg.obj; 805 data = (byte[])ar.result; 806 807 if (ar.exception != null) { 808 break; 809 } 810 811 mEfCPHS_MWI = data; 812 813 // Use this data if the EF[MWIS] exists and 814 // has been loaded 815 816 if (mEfMWIS == null) { 817 int indicator = data[0] & 0xf; 818 819 // Refer CPHS4_2.WW6 B4.2.3 820 if (indicator == 0xA) { 821 // Unknown count = -1 822 mCountVoiceMessages = -1; 823 } else if (indicator == 0x5) { 824 mCountVoiceMessages = 0; 825 } 826 827 mRecordsEventsRegistrants.notifyResult(EVENT_MWI); 828 } 829 break; 830 831 case EVENT_GET_ICCID_DONE: 832 isRecordLoadResponse = true; 833 834 ar = (AsyncResult)msg.obj; 835 data = (byte[])ar.result; 836 837 if (ar.exception != null) { 838 break; 839 } 840 841 mIccId = IccUtils.bcdToString(data, 0, data.length); 842 843 log("iccid: " + mIccId); 844 845 break; 846 847 848 case EVENT_GET_AD_DONE: 849 try { 850 isRecordLoadResponse = true; 851 852 ar = (AsyncResult)msg.obj; 853 data = (byte[])ar.result; 854 855 if (ar.exception != null) { 856 break; 857 } 858 859 log("EF_AD: " + IccUtils.bytesToHexString(data)); 860 861 if (data.length < 3) { 862 log("Corrupt AD data on SIM"); 863 break; 864 } 865 866 if (data.length == 3) { 867 log("MNC length not present in EF_AD"); 868 break; 869 } 870 871 mMncLength = data[3] & 0xf; 872 log("setting4 mMncLength=" + mMncLength); 873 874 if (mMncLength == 0xf) { 875 mMncLength = UNKNOWN; 876 log("setting5 mMncLength=" + mMncLength); 877 } 878 } finally { 879 if (((mMncLength == UNINITIALIZED) || (mMncLength == UNKNOWN) || 880 (mMncLength == 2)) && ((mImsi != null) && (mImsi.length() >= 6))) { 881 String mccmncCode = mImsi.substring(0, 6); 882 log("mccmncCode=" + mccmncCode); 883 for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) { 884 if (mccmnc.equals(mccmncCode)) { 885 mMncLength = 3; 886 log("setting6 mMncLength=" + mMncLength); 887 break; 888 } 889 } 890 } 891 892 if (mMncLength == UNKNOWN || mMncLength == UNINITIALIZED) { 893 if (mImsi != null) { 894 try { 895 int mcc = Integer.parseInt(mImsi.substring(0,3)); 896 897 mMncLength = MccTable.smallestDigitsMccForMnc(mcc); 898 log("setting7 mMncLength=" + mMncLength); 899 } catch (NumberFormatException e) { 900 mMncLength = UNKNOWN; 901 loge("Corrupt IMSI! setting8 mMncLength=" + mMncLength); 902 } 903 } else { 904 // Indicate we got this info, but it didn't contain the length. 905 mMncLength = UNKNOWN; 906 log("MNC length not present in EF_AD setting9 mMncLength=" + mMncLength); 907 } 908 } 909 if (mImsi != null && mMncLength != UNKNOWN) { 910 // finally have both imsi and the length of the mnc and can parse 911 // the imsi properly 912 log("update mccmnc=" + mImsi.substring(0, 3 + mMncLength)); 913 MccTable.updateMccMncConfiguration(mContext, 914 mImsi.substring(0, 3 + mMncLength), false); 915 } 916 } 917 break; 918 919 case EVENT_GET_SPN_DONE: 920 isRecordLoadResponse = true; 921 ar = (AsyncResult) msg.obj; 922 getSpnFsm(false, ar); 923 break; 924 925 case EVENT_GET_CFF_DONE: 926 isRecordLoadResponse = true; 927 928 ar = (AsyncResult) msg.obj; 929 data = (byte[]) ar.result; 930 931 if (ar.exception != null) { 932 break; 933 } 934 935 log("EF_CFF_CPHS: " + IccUtils.bytesToHexString(data)); 936 mEfCff = data; 937 938 // if EF_CFIS is valid, prefer it to EF_CFF_CPHS 939 if (!validEfCfis(mEfCfis)) { 940 mCallForwardingEnabled = 941 ((data[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE); 942 943 mRecordsEventsRegistrants.notifyResult(EVENT_CFI); 944 } else { 945 log("EVENT_GET_CFF_DONE: EF_CFIS is valid, ignoring EF_CFF_CPHS"); 946 } 947 break; 948 949 case EVENT_GET_SPDI_DONE: 950 isRecordLoadResponse = true; 951 952 ar = (AsyncResult)msg.obj; 953 data = (byte[])ar.result; 954 955 if (ar.exception != null) { 956 break; 957 } 958 959 parseEfSpdi(data); 960 break; 961 962 case EVENT_UPDATE_DONE: 963 ar = (AsyncResult)msg.obj; 964 if (ar.exception != null) { 965 logw("update failed. ", ar.exception); 966 } 967 break; 968 969 case EVENT_GET_PNN_DONE: 970 isRecordLoadResponse = true; 971 972 ar = (AsyncResult)msg.obj; 973 data = (byte[])ar.result; 974 975 if (ar.exception != null) { 976 break; 977 } 978 979 SimTlv tlv = new SimTlv(data, 0, data.length); 980 981 for ( ; tlv.isValidObject() ; tlv.nextObject()) { 982 if (tlv.getTag() == TAG_FULL_NETWORK_NAME) { 983 mPnnHomeName 984 = IccUtils.networkNameToString( 985 tlv.getData(), 0, tlv.getData().length); 986 break; 987 } 988 } 989 break; 990 991 case EVENT_GET_ALL_SMS_DONE: 992 isRecordLoadResponse = true; 993 994 ar = (AsyncResult)msg.obj; 995 if (ar.exception != null) 996 break; 997 998 handleSmses((ArrayList<byte []>) ar.result); 999 break; 1000 1001 case EVENT_MARK_SMS_READ_DONE: 1002 Rlog.i("ENF", "marked read: sms " + msg.arg1); 1003 break; 1004 1005 1006 case EVENT_SMS_ON_SIM: 1007 isRecordLoadResponse = false; 1008 1009 ar = (AsyncResult)msg.obj; 1010 1011 int[] index = (int[])ar.result; 1012 1013 if (ar.exception != null || index.length != 1) { 1014 loge("Error on SMS_ON_SIM with exp " 1015 + ar.exception + " length " + index.length); 1016 } else { 1017 log("READ EF_SMS RECORD index=" + index[0]); 1018 mFh.loadEFLinearFixed(EF_SMS,index[0], 1019 obtainMessage(EVENT_GET_SMS_DONE)); 1020 } 1021 break; 1022 1023 case EVENT_GET_SMS_DONE: 1024 isRecordLoadResponse = false; 1025 ar = (AsyncResult)msg.obj; 1026 if (ar.exception == null) { 1027 handleSms((byte[])ar.result); 1028 } else { 1029 loge("Error on GET_SMS with exp " + ar.exception); 1030 } 1031 break; 1032 case EVENT_GET_SST_DONE: 1033 isRecordLoadResponse = true; 1034 1035 ar = (AsyncResult)msg.obj; 1036 data = (byte[])ar.result; 1037 1038 if (ar.exception != null) { 1039 break; 1040 } 1041 1042 mUsimServiceTable = new UsimServiceTable(data); 1043 if (DBG) log("SST: " + mUsimServiceTable); 1044 break; 1045 1046 case EVENT_GET_INFO_CPHS_DONE: 1047 isRecordLoadResponse = true; 1048 1049 ar = (AsyncResult)msg.obj; 1050 1051 if (ar.exception != null) { 1052 break; 1053 } 1054 1055 mCphsInfo = (byte[])ar.result; 1056 1057 if (DBG) log("iCPHS: " + IccUtils.bytesToHexString(mCphsInfo)); 1058 break; 1059 1060 case EVENT_SET_MBDN_DONE: 1061 isRecordLoadResponse = false; 1062 ar = (AsyncResult)msg.obj; 1063 1064 if (ar.exception == null) { 1065 mVoiceMailNum = mNewVoiceMailNum; 1066 mVoiceMailTag = mNewVoiceMailTag; 1067 } 1068 1069 if (isCphsMailboxEnabled()) { 1070 adn = new AdnRecord(mVoiceMailTag, mVoiceMailNum); 1071 Message onCphsCompleted = (Message) ar.userObj; 1072 1073 /* write to cphs mailbox whenever it is available but 1074 * we only need notify caller once if both updating are 1075 * successful. 1076 * 1077 * so if set_mbdn successful, notify caller here and set 1078 * onCphsCompleted to null 1079 */ 1080 if (ar.exception == null && ar.userObj != null) { 1081 AsyncResult.forMessage(((Message) ar.userObj)).exception 1082 = null; 1083 ((Message) ar.userObj).sendToTarget(); 1084 1085 if (DBG) log("Callback with MBDN successful."); 1086 1087 onCphsCompleted = null; 1088 } 1089 1090 new AdnRecordLoader(mFh). 1091 updateEF(adn, EF_MAILBOX_CPHS, EF_EXT1, 1, null, 1092 obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE, 1093 onCphsCompleted)); 1094 } else { 1095 if (ar.userObj != null) { 1096 AsyncResult.forMessage(((Message) ar.userObj)).exception 1097 = ar.exception; 1098 ((Message) ar.userObj).sendToTarget(); 1099 } 1100 } 1101 break; 1102 case EVENT_SET_CPHS_MAILBOX_DONE: 1103 isRecordLoadResponse = false; 1104 ar = (AsyncResult)msg.obj; 1105 if(ar.exception == null) { 1106 mVoiceMailNum = mNewVoiceMailNum; 1107 mVoiceMailTag = mNewVoiceMailTag; 1108 } else { 1109 if (DBG) log("Set CPHS MailBox with exception: " 1110 + ar.exception); 1111 } 1112 if (ar.userObj != null) { 1113 if (DBG) log("Callback with CPHS MB successful."); 1114 AsyncResult.forMessage(((Message) ar.userObj)).exception 1115 = ar.exception; 1116 ((Message) ar.userObj).sendToTarget(); 1117 } 1118 break; 1119 case EVENT_SIM_REFRESH: 1120 isRecordLoadResponse = false; 1121 ar = (AsyncResult)msg.obj; 1122 if (DBG) log("Sim REFRESH with exception: " + ar.exception); 1123 if (ar.exception == null) { 1124 handleSimRefresh((IccRefreshResponse)ar.result); 1125 } 1126 break; 1127 case EVENT_GET_CFIS_DONE: 1128 isRecordLoadResponse = true; 1129 1130 ar = (AsyncResult)msg.obj; 1131 data = (byte[])ar.result; 1132 1133 if (ar.exception != null) { 1134 break; 1135 } 1136 1137 log("EF_CFIS: " + IccUtils.bytesToHexString(data)); 1138 1139 if (validEfCfis(data)) { 1140 mEfCfis = data; 1141 1142 // Refer TS 51.011 Section 10.3.46 for the content description 1143 mCallForwardingEnabled = ((data[1] & 0x01) != 0); 1144 log("EF_CFIS: callForwardingEnabled=" + mCallForwardingEnabled); 1145 1146 mRecordsEventsRegistrants.notifyResult(EVENT_CFI); 1147 } else { 1148 log("EF_CFIS: invalid data=" + IccUtils.bytesToHexString(data)); 1149 } 1150 break; 1151 1152 case EVENT_GET_CSP_CPHS_DONE: 1153 isRecordLoadResponse = true; 1154 1155 ar = (AsyncResult)msg.obj; 1156 1157 if (ar.exception != null) { 1158 loge("Exception in fetching EF_CSP data " + ar.exception); 1159 break; 1160 } 1161 1162 data = (byte[])ar.result; 1163 1164 log("EF_CSP: " + IccUtils.bytesToHexString(data)); 1165 handleEfCspData(data); 1166 break; 1167 1168 case EVENT_GET_GID1_DONE: 1169 isRecordLoadResponse = true; 1170 1171 ar = (AsyncResult)msg.obj; 1172 data =(byte[])ar.result; 1173 1174 if (ar.exception != null) { 1175 loge("Exception in get GID1 " + ar.exception); 1176 mGid1 = null; 1177 break; 1178 } 1179 mGid1 = IccUtils.bytesToHexString(data); 1180 log("GID1: " + mGid1); 1181 1182 break; 1183 1184 default: 1185 super.handleMessage(msg); // IccRecords handles generic record load responses 1186 1187 }}catch (RuntimeException exc) { 1188 // I don't want these exceptions to be fatal 1189 logw("Exception parsing SIM record", exc); 1190 } finally { 1191 // Count up record load responses even if they are fails 1192 if (isRecordLoadResponse) { 1193 onRecordLoaded(); 1194 } 1195 } 1196 } 1197 1198 private void handleFileUpdate(int efid) { 1199 switch(efid) { 1200 case EF_MBDN: 1201 mRecordsToLoad++; 1202 new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6, 1203 mMailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE)); 1204 break; 1205 case EF_MAILBOX_CPHS: 1206 mRecordsToLoad++; 1207 new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1, 1208 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); 1209 break; 1210 case EF_CSP_CPHS: 1211 mRecordsToLoad++; 1212 log("[CSP] SIM Refresh for EF_CSP_CPHS"); 1213 mFh.loadEFTransparent(EF_CSP_CPHS, 1214 obtainMessage(EVENT_GET_CSP_CPHS_DONE)); 1215 break; 1216 case EF_FDN: 1217 if (DBG) log("SIM Refresh called for EF_FDN"); 1218 mParentApp.queryFdn(); 1219 break; 1220 default: 1221 // For now, fetch all records if this is not a 1222 // voicemail number. 1223 // TODO: Handle other cases, instead of fetching all. 1224 mAdnCache.reset(); 1225 fetchSimRecords(); 1226 break; 1227 } 1228 } 1229 1230 private void handleSimRefresh(IccRefreshResponse refreshResponse){ 1231 if (refreshResponse == null) { 1232 if (DBG) log("handleSimRefresh received without input"); 1233 return; 1234 } 1235 1236 if (refreshResponse.aid != null && 1237 !refreshResponse.aid.equals(mParentApp.getAid())) { 1238 // This is for different app. Ignore. 1239 return; 1240 } 1241 1242 switch (refreshResponse.refreshResult) { 1243 case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE: 1244 if (DBG) log("handleSimRefresh with SIM_FILE_UPDATED"); 1245 handleFileUpdate(refreshResponse.efId); 1246 break; 1247 case IccRefreshResponse.REFRESH_RESULT_INIT: 1248 if (DBG) log("handleSimRefresh with SIM_REFRESH_INIT"); 1249 // need to reload all files (that we care about) 1250 onIccRefreshInit(); 1251 break; 1252 case IccRefreshResponse.REFRESH_RESULT_RESET: 1253 if (DBG) log("handleSimRefresh with SIM_REFRESH_RESET"); 1254 mCi.setRadioPower(false, null); 1255 /* Note: no need to call setRadioPower(true). Assuming the desired 1256 * radio power state is still ON (as tracked by ServiceStateTracker), 1257 * ServiceStateTracker will call setRadioPower when it receives the 1258 * RADIO_STATE_CHANGED notification for the power off. And if the 1259 * desired power state has changed in the interim, we don't want to 1260 * override it with an unconditional power on. 1261 */ 1262 mAdnCache.reset(); 1263 break; 1264 default: 1265 // unknown refresh operation 1266 if (DBG) log("handleSimRefresh with unknown operation"); 1267 break; 1268 } 1269 } 1270 1271 /** 1272 * Dispatch 3GPP format message to registrant ({@code GSMPhone} or {@code CDMALTEPhone}) 1273 * to pass to the 3GPP SMS dispatcher for delivery. 1274 */ 1275 private int dispatchGsmMessage(SmsMessage message) { 1276 mNewSmsRegistrants.notifyResult(message); 1277 return 0; 1278 } 1279 1280 private void handleSms(byte[] ba) { 1281 if (ba[0] != 0) 1282 Rlog.d("ENF", "status : " + ba[0]); 1283 1284 // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 1285 // 3 == "received by MS from network; message to be read" 1286 if (ba[0] == 3) { 1287 int n = ba.length; 1288 1289 // Note: Data may include trailing FF's. That's OK; message 1290 // should still parse correctly. 1291 byte[] pdu = new byte[n - 1]; 1292 System.arraycopy(ba, 1, pdu, 0, n - 1); 1293 SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP); 1294 1295 dispatchGsmMessage(message); 1296 } 1297 } 1298 1299 1300 private void handleSmses(ArrayList<byte[]> messages) { 1301 int count = messages.size(); 1302 1303 for (int i = 0; i < count; i++) { 1304 byte[] ba = messages.get(i); 1305 1306 if (ba[0] != 0) 1307 Rlog.i("ENF", "status " + i + ": " + ba[0]); 1308 1309 // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 1310 // 3 == "received by MS from network; message to be read" 1311 1312 if (ba[0] == 3) { 1313 int n = ba.length; 1314 1315 // Note: Data may include trailing FF's. That's OK; message 1316 // should still parse correctly. 1317 byte[] pdu = new byte[n - 1]; 1318 System.arraycopy(ba, 1, pdu, 0, n - 1); 1319 SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP); 1320 1321 dispatchGsmMessage(message); 1322 1323 // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 1324 // 1 == "received by MS from network; message read" 1325 1326 ba[0] = 1; 1327 1328 if (false) { // FIXME: writing seems to crash RdoServD 1329 mFh.updateEFLinearFixed(EF_SMS, 1330 i, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, i)); 1331 } 1332 } 1333 } 1334 } 1335 1336 @Override 1337 protected void onRecordLoaded() { 1338 // One record loaded successfully or failed, In either case 1339 // we need to update the recordsToLoad count 1340 mRecordsToLoad -= 1; 1341 if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested); 1342 1343 if (mRecordsToLoad == 0 && mRecordsRequested == true) { 1344 onAllRecordsLoaded(); 1345 } else if (mRecordsToLoad < 0) { 1346 loge("recordsToLoad <0, programmer error suspected"); 1347 mRecordsToLoad = 0; 1348 } 1349 } 1350 1351 @Override 1352 protected void onAllRecordsLoaded() { 1353 if (DBG) log("record load complete"); 1354 1355 // Some fields require more than one SIM record to set 1356 1357 String operator = getOperatorNumeric(); 1358 if (!TextUtils.isEmpty(operator)) { 1359 log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" + 1360 operator + "'"); 1361 log("update icc_operator_numeric=" + operator); 1362 setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, operator); 1363 } else { 1364 log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping"); 1365 } 1366 1367 if (!TextUtils.isEmpty(mImsi)) { 1368 log("onAllRecordsLoaded set mcc imsi=" + mImsi); 1369 setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, 1370 MccTable.countryCodeForMcc(Integer.parseInt(mImsi.substring(0,3)))); 1371 } else { 1372 log("onAllRecordsLoaded empty imsi skipping setting mcc"); 1373 } 1374 1375 setVoiceMailByCountry(operator); 1376 setSpnFromConfig(operator); 1377 1378 mRecordsLoadedRegistrants.notifyRegistrants( 1379 new AsyncResult(null, null, null)); 1380 } 1381 1382 //***** Private methods 1383 1384 private void setSpnFromConfig(String carrier) { 1385 if (mSpnOverride.containsCarrier(carrier)) { 1386 setServiceProviderName(mSpnOverride.getSpn(carrier)); 1387 } 1388 } 1389 1390 1391 private void setVoiceMailByCountry (String spn) { 1392 if (mVmConfig.containsCarrier(spn)) { 1393 mIsVoiceMailFixed = true; 1394 mVoiceMailNum = mVmConfig.getVoiceMailNumber(spn); 1395 mVoiceMailTag = mVmConfig.getVoiceMailTag(spn); 1396 } 1397 } 1398 1399 @Override 1400 public void onReady() { 1401 fetchSimRecords(); 1402 } 1403 1404 protected void fetchSimRecords() { 1405 mRecordsRequested = true; 1406 1407 if (DBG) log("fetchSimRecords " + mRecordsToLoad); 1408 1409 mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE)); 1410 mRecordsToLoad++; 1411 1412 mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE)); 1413 mRecordsToLoad++; 1414 1415 // FIXME should examine EF[MSISDN]'s capability configuration 1416 // to determine which is the voice/data/fax line 1417 new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, EF_EXT1, 1, 1418 obtainMessage(EVENT_GET_MSISDN_DONE)); 1419 mRecordsToLoad++; 1420 1421 // Record number is subscriber profile 1422 mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE)); 1423 mRecordsToLoad++; 1424 1425 mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE)); 1426 mRecordsToLoad++; 1427 1428 // Record number is subscriber profile 1429 mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE)); 1430 mRecordsToLoad++; 1431 1432 1433 // Also load CPHS-style voice mail indicator, which stores 1434 // the same info as EF[MWIS]. If both exist, both are updated 1435 // but the EF[MWIS] data is preferred 1436 // Please note this must be loaded after EF[MWIS] 1437 mFh.loadEFTransparent( 1438 EF_VOICE_MAIL_INDICATOR_CPHS, 1439 obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE)); 1440 mRecordsToLoad++; 1441 1442 // Same goes for Call Forward Status indicator: fetch both 1443 // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred. 1444 mFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE)); 1445 mRecordsToLoad++; 1446 mFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE)); 1447 mRecordsToLoad++; 1448 1449 1450 getSpnFsm(true, null); 1451 1452 mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE)); 1453 mRecordsToLoad++; 1454 1455 mFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE)); 1456 mRecordsToLoad++; 1457 1458 mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE)); 1459 mRecordsToLoad++; 1460 1461 mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE)); 1462 mRecordsToLoad++; 1463 1464 mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE)); 1465 mRecordsToLoad++; 1466 1467 mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE)); 1468 mRecordsToLoad++; 1469 1470 // XXX should seek instead of examining them all 1471 if (false) { // XXX 1472 mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE)); 1473 mRecordsToLoad++; 1474 } 1475 1476 if (CRASH_RIL) { 1477 String sms = "0107912160130310f20404d0110041007030208054832b0120" 1478 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1479 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1480 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1481 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1482 + "ffffffffffffffffffffffffffffff"; 1483 byte[] ba = IccUtils.hexStringToBytes(sms); 1484 1485 mFh.updateEFLinearFixed(EF_SMS, 1, ba, null, 1486 obtainMessage(EVENT_MARK_SMS_READ_DONE, 1)); 1487 } 1488 if (DBG) log("fetchSimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested); 1489 } 1490 1491 /** 1492 * Returns the SpnDisplayRule based on settings on the SIM and the 1493 * specified plmn (currently-registered PLMN). See TS 22.101 Annex A 1494 * and TS 51.011 10.3.11 for details. 1495 * 1496 * If the SPN is not found on the SIM or is empty, the rule is 1497 * always PLMN_ONLY. 1498 */ 1499 @Override 1500 public int getDisplayRule(String plmn) { 1501 int rule; 1502 1503 if (mParentApp.getUiccCard() != null && 1504 mParentApp.getUiccCard().getOperatorBrandOverride() != null) { 1505 // If the operator has been overridden, treat it as the SPN file on the SIM did not exist. 1506 rule = SPN_RULE_SHOW_PLMN; 1507 } else if (TextUtils.isEmpty(getServiceProviderName()) || mSpnDisplayCondition == -1) { 1508 // No EF_SPN content was found on the SIM, or not yet loaded. Just show ONS. 1509 rule = SPN_RULE_SHOW_PLMN; 1510 } else if (isOnMatchingPlmn(plmn)) { 1511 rule = SPN_RULE_SHOW_SPN; 1512 if ((mSpnDisplayCondition & 0x01) == 0x01) { 1513 // ONS required when registered to HPLMN or PLMN in EF_SPDI 1514 rule |= SPN_RULE_SHOW_PLMN; 1515 } 1516 } else { 1517 rule = SPN_RULE_SHOW_PLMN; 1518 if ((mSpnDisplayCondition & 0x02) == 0x00) { 1519 // SPN required if not registered to HPLMN or PLMN in EF_SPDI 1520 rule |= SPN_RULE_SHOW_SPN; 1521 } 1522 } 1523 return rule; 1524 } 1525 1526 /** 1527 * Checks if plmn is HPLMN or on the spdiNetworks list. 1528 */ 1529 private boolean isOnMatchingPlmn(String plmn) { 1530 if (plmn == null) return false; 1531 1532 if (plmn.equals(getOperatorNumeric())) { 1533 return true; 1534 } 1535 1536 if (mSpdiNetworks != null) { 1537 for (String spdiNet : mSpdiNetworks) { 1538 if (plmn.equals(spdiNet)) { 1539 return true; 1540 } 1541 } 1542 } 1543 return false; 1544 } 1545 1546 /** 1547 * States of Get SPN Finite State Machine which only used by getSpnFsm() 1548 */ 1549 private enum GetSpnFsmState { 1550 IDLE, // No initialized 1551 INIT, // Start FSM 1552 READ_SPN_3GPP, // Load EF_SPN firstly 1553 READ_SPN_CPHS, // Load EF_SPN_CPHS secondly 1554 READ_SPN_SHORT_CPHS // Load EF_SPN_SHORT_CPHS last 1555 } 1556 1557 /** 1558 * Finite State Machine to load Service Provider Name , which can be stored 1559 * in either EF_SPN (3GPP), EF_SPN_CPHS, or EF_SPN_SHORT_CPHS (CPHS4.2) 1560 * 1561 * After starting, FSM will search SPN EFs in order and stop after finding 1562 * the first valid SPN 1563 * 1564 * If the FSM gets restart while waiting for one of 1565 * SPN EFs results (i.e. a SIM refresh occurs after issuing 1566 * read EF_CPHS_SPN), it will re-initialize only after 1567 * receiving and discarding the unfinished SPN EF result. 1568 * 1569 * @param start set true only for initialize loading 1570 * @param ar the AsyncResult from loadEFTransparent 1571 * ar.exception holds exception in error 1572 * ar.result is byte[] for data in success 1573 */ 1574 private void getSpnFsm(boolean start, AsyncResult ar) { 1575 byte[] data; 1576 1577 if (start) { 1578 // Check previous state to see if there is outstanding 1579 // SPN read 1580 if(mSpnState == GetSpnFsmState.READ_SPN_3GPP || 1581 mSpnState == GetSpnFsmState.READ_SPN_CPHS || 1582 mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS || 1583 mSpnState == GetSpnFsmState.INIT) { 1584 // Set INIT then return so the INIT code 1585 // will run when the outstanding read done. 1586 mSpnState = GetSpnFsmState.INIT; 1587 return; 1588 } else { 1589 mSpnState = GetSpnFsmState.INIT; 1590 } 1591 } 1592 1593 switch(mSpnState){ 1594 case INIT: 1595 setServiceProviderName(null); 1596 1597 mFh.loadEFTransparent(EF_SPN, 1598 obtainMessage(EVENT_GET_SPN_DONE)); 1599 mRecordsToLoad++; 1600 1601 mSpnState = GetSpnFsmState.READ_SPN_3GPP; 1602 break; 1603 case READ_SPN_3GPP: 1604 if (ar != null && ar.exception == null) { 1605 data = (byte[]) ar.result; 1606 mSpnDisplayCondition = 0xff & data[0]; 1607 setServiceProviderName(IccUtils.adnStringFieldToString( 1608 data, 1, data.length - 1)); 1609 1610 if (DBG) log("Load EF_SPN: " + getServiceProviderName() 1611 + " spnDisplayCondition: " + mSpnDisplayCondition); 1612 setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, getServiceProviderName()); 1613 1614 mSpnState = GetSpnFsmState.IDLE; 1615 } else { 1616 mFh.loadEFTransparent( EF_SPN_CPHS, 1617 obtainMessage(EVENT_GET_SPN_DONE)); 1618 mRecordsToLoad++; 1619 1620 mSpnState = GetSpnFsmState.READ_SPN_CPHS; 1621 1622 // See TS 51.011 10.3.11. Basically, default to 1623 // show PLMN always, and SPN also if roaming. 1624 mSpnDisplayCondition = -1; 1625 } 1626 break; 1627 case READ_SPN_CPHS: 1628 if (ar != null && ar.exception == null) { 1629 data = (byte[]) ar.result; 1630 setServiceProviderName(IccUtils.adnStringFieldToString(data, 0, data.length)); 1631 1632 if (DBG) log("Load EF_SPN_CPHS: " + getServiceProviderName()); 1633 setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, getServiceProviderName()); 1634 1635 mSpnState = GetSpnFsmState.IDLE; 1636 } else { 1637 mFh.loadEFTransparent( 1638 EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE)); 1639 mRecordsToLoad++; 1640 1641 mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS; 1642 } 1643 break; 1644 case READ_SPN_SHORT_CPHS: 1645 if (ar != null && ar.exception == null) { 1646 data = (byte[]) ar.result; 1647 setServiceProviderName(IccUtils.adnStringFieldToString(data, 0, data.length)); 1648 1649 if (DBG) log("Load EF_SPN_SHORT_CPHS: " + getServiceProviderName()); 1650 setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, getServiceProviderName()); 1651 }else { 1652 if (DBG) log("No SPN loaded in either CHPS or 3GPP"); 1653 } 1654 1655 mSpnState = GetSpnFsmState.IDLE; 1656 break; 1657 default: 1658 mSpnState = GetSpnFsmState.IDLE; 1659 } 1660 } 1661 1662 /** 1663 * Parse TS 51.011 EF[SPDI] record 1664 * This record contains the list of numeric network IDs that 1665 * are treated specially when determining SPN display 1666 */ 1667 private void 1668 parseEfSpdi(byte[] data) { 1669 SimTlv tlv = new SimTlv(data, 0, data.length); 1670 1671 byte[] plmnEntries = null; 1672 1673 for ( ; tlv.isValidObject() ; tlv.nextObject()) { 1674 // Skip SPDI tag, if existant 1675 if (tlv.getTag() == TAG_SPDI) { 1676 tlv = new SimTlv(tlv.getData(), 0, tlv.getData().length); 1677 } 1678 // There should only be one TAG_SPDI_PLMN_LIST 1679 if (tlv.getTag() == TAG_SPDI_PLMN_LIST) { 1680 plmnEntries = tlv.getData(); 1681 break; 1682 } 1683 } 1684 1685 if (plmnEntries == null) { 1686 return; 1687 } 1688 1689 mSpdiNetworks = new ArrayList<String>(plmnEntries.length / 3); 1690 1691 for (int i = 0 ; i + 2 < plmnEntries.length ; i += 3) { 1692 String plmnCode; 1693 plmnCode = IccUtils.bcdToString(plmnEntries, i, 3); 1694 1695 // Valid operator codes are 5 or 6 digits 1696 if (plmnCode.length() >= 5) { 1697 log("EF_SPDI network: " + plmnCode); 1698 mSpdiNetworks.add(plmnCode); 1699 } 1700 } 1701 } 1702 1703 /** 1704 * check to see if Mailbox Number is allocated and activated in CPHS SST 1705 */ 1706 private boolean isCphsMailboxEnabled() { 1707 if (mCphsInfo == null) return false; 1708 return ((mCphsInfo[1] & CPHS_SST_MBN_MASK) == CPHS_SST_MBN_ENABLED ); 1709 } 1710 1711 @Override 1712 protected void log(String s) { 1713 Rlog.d(LOG_TAG, "[SIMRecords] " + s); 1714 } 1715 1716 @Override 1717 protected void loge(String s) { 1718 Rlog.e(LOG_TAG, "[SIMRecords] " + s); 1719 } 1720 1721 protected void logw(String s, Throwable tr) { 1722 Rlog.w(LOG_TAG, "[SIMRecords] " + s, tr); 1723 } 1724 1725 protected void logv(String s) { 1726 Rlog.v(LOG_TAG, "[SIMRecords] " + s); 1727 } 1728 1729 /** 1730 * Return true if "Restriction of menu options for manual PLMN selection" 1731 * bit is set or EF_CSP data is unavailable, return false otherwise. 1732 */ 1733 @Override 1734 public boolean isCspPlmnEnabled() { 1735 return mCspPlmnEnabled; 1736 } 1737 1738 /** 1739 * Parse EF_CSP data and check if 1740 * "Restriction of menu options for manual PLMN selection" is 1741 * Enabled/Disabled 1742 * 1743 * @param data EF_CSP hex data. 1744 */ 1745 private void handleEfCspData(byte[] data) { 1746 // As per spec CPHS4_2.WW6, CPHS B.4.7.1, EF_CSP contains CPHS defined 1747 // 18 bytes (i.e 9 service groups info) and additional data specific to 1748 // operator. The valueAddedServicesGroup is not part of standard 1749 // services. This is operator specific and can be programmed any where. 1750 // Normally this is programmed as 10th service after the standard 1751 // services. 1752 int usedCspGroups = data.length / 2; 1753 // This is the "Service Group Number" of "Value Added Services Group". 1754 byte valueAddedServicesGroup = (byte)0xC0; 1755 1756 mCspPlmnEnabled = true; 1757 for (int i = 0; i < usedCspGroups; i++) { 1758 if (data[2 * i] == valueAddedServicesGroup) { 1759 log("[CSP] found ValueAddedServicesGroup, value " + data[(2 * i) + 1]); 1760 if ((data[(2 * i) + 1] & 0x80) == 0x80) { 1761 // Bit 8 is for 1762 // "Restriction of menu options for manual PLMN selection". 1763 // Operator Selection menu should be enabled. 1764 mCspPlmnEnabled = true; 1765 } else { 1766 mCspPlmnEnabled = false; 1767 // Operator Selection menu should be disabled. 1768 // Operator Selection Mode should be set to Automatic. 1769 log("[CSP] Set Automatic Network Selection"); 1770 mNetworkSelectionModeAutomaticRegistrants.notifyRegistrants(); 1771 } 1772 return; 1773 } 1774 } 1775 1776 log("[CSP] Value Added Service Group (0xC0), not found!"); 1777 } 1778 1779 @Override 1780 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1781 pw.println("SIMRecords: " + this); 1782 pw.println(" extends:"); 1783 super.dump(fd, pw, args); 1784 pw.println(" mVmConfig=" + mVmConfig); 1785 pw.println(" mSpnOverride=" + mSpnOverride); 1786 pw.println(" mCallForwardingEnabled=" + mCallForwardingEnabled); 1787 pw.println(" mSpnState=" + mSpnState); 1788 pw.println(" mCphsInfo=" + mCphsInfo); 1789 pw.println(" mCspPlmnEnabled=" + mCspPlmnEnabled); 1790 pw.println(" mEfMWIS[]=" + Arrays.toString(mEfMWIS)); 1791 pw.println(" mEfCPHS_MWI[]=" + Arrays.toString(mEfCPHS_MWI)); 1792 pw.println(" mEfCff[]=" + Arrays.toString(mEfCff)); 1793 pw.println(" mEfCfis[]=" + Arrays.toString(mEfCfis)); 1794 pw.println(" mSpnDisplayCondition=" + mSpnDisplayCondition); 1795 pw.println(" mSpdiNetworks[]=" + mSpdiNetworks); 1796 pw.println(" mPnnHomeName=" + mPnnHomeName); 1797 pw.println(" mUsimServiceTable=" + mUsimServiceTable); 1798 pw.println(" mGid1=" + mGid1); 1799 pw.flush(); 1800 } 1801} 1802