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