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