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