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