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