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