SIMRecords.java revision 200014f52acfbff467ab92910247f81e369da7e6
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 } else if (mMncLength != 2 && mMncLength != 3) { 905 mMncLength = UNINITIALIZED; 906 log("setting5 mMncLength=" + mMncLength); 907 } 908 } finally { 909 if (((mMncLength == UNINITIALIZED) || (mMncLength == UNKNOWN) || 910 (mMncLength == 2)) && ((mImsi != null) && (mImsi.length() >= 6))) { 911 String mccmncCode = mImsi.substring(0, 6); 912 log("mccmncCode=" + mccmncCode); 913 for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) { 914 if (mccmnc.equals(mccmncCode)) { 915 mMncLength = 3; 916 log("setting6 mMncLength=" + mMncLength); 917 break; 918 } 919 } 920 } 921 922 if (mMncLength == UNKNOWN || mMncLength == UNINITIALIZED) { 923 if (mImsi != null) { 924 try { 925 int mcc = Integer.parseInt(mImsi.substring(0,3)); 926 927 mMncLength = MccTable.smallestDigitsMccForMnc(mcc); 928 log("setting7 mMncLength=" + mMncLength); 929 } catch (NumberFormatException e) { 930 mMncLength = UNKNOWN; 931 loge("Corrupt IMSI! setting8 mMncLength=" + mMncLength); 932 } 933 } else { 934 // Indicate we got this info, but it didn't contain the length. 935 mMncLength = UNKNOWN; 936 log("MNC length not present in EF_AD setting9 mMncLength=" + mMncLength); 937 } 938 } 939 if (mImsi != null && mMncLength != UNKNOWN) { 940 // finally have both imsi and the length of the mnc and can parse 941 // the imsi properly 942 log("update mccmnc=" + mImsi.substring(0, 3 + mMncLength)); 943 MccTable.updateMccMncConfiguration(mContext, 944 mImsi.substring(0, 3 + mMncLength), false); 945 } 946 } 947 break; 948 949 case EVENT_GET_SPN_DONE: 950 isRecordLoadResponse = true; 951 ar = (AsyncResult) msg.obj; 952 getSpnFsm(false, ar); 953 break; 954 955 case EVENT_GET_CFF_DONE: 956 isRecordLoadResponse = true; 957 958 ar = (AsyncResult) msg.obj; 959 data = (byte[]) ar.result; 960 961 if (ar.exception != null) { 962 break; 963 } 964 965 log("EF_CFF_CPHS: " + IccUtils.bytesToHexString(data)); 966 mEfCff = data; 967 968 // if EF_CFIS is valid, prefer it to EF_CFF_CPHS 969 if (!validEfCfis(mEfCfis)) { 970 mCallForwardingEnabled = 971 ((data[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE); 972 973 mRecordsEventsRegistrants.notifyResult(EVENT_CFI); 974 } else { 975 log("EVENT_GET_CFF_DONE: EF_CFIS is valid, ignoring EF_CFF_CPHS"); 976 } 977 break; 978 979 case EVENT_GET_SPDI_DONE: 980 isRecordLoadResponse = true; 981 982 ar = (AsyncResult)msg.obj; 983 data = (byte[])ar.result; 984 985 if (ar.exception != null) { 986 break; 987 } 988 989 parseEfSpdi(data); 990 break; 991 992 case EVENT_UPDATE_DONE: 993 ar = (AsyncResult)msg.obj; 994 if (ar.exception != null) { 995 logw("update failed. ", ar.exception); 996 } 997 break; 998 999 case EVENT_GET_PNN_DONE: 1000 isRecordLoadResponse = true; 1001 1002 ar = (AsyncResult)msg.obj; 1003 data = (byte[])ar.result; 1004 1005 if (ar.exception != null) { 1006 break; 1007 } 1008 1009 SimTlv tlv = new SimTlv(data, 0, data.length); 1010 1011 for ( ; tlv.isValidObject() ; tlv.nextObject()) { 1012 if (tlv.getTag() == TAG_FULL_NETWORK_NAME) { 1013 mPnnHomeName 1014 = IccUtils.networkNameToString( 1015 tlv.getData(), 0, tlv.getData().length); 1016 break; 1017 } 1018 } 1019 break; 1020 1021 case EVENT_GET_ALL_SMS_DONE: 1022 isRecordLoadResponse = true; 1023 1024 ar = (AsyncResult)msg.obj; 1025 if (ar.exception != null) 1026 break; 1027 1028 handleSmses((ArrayList<byte []>) ar.result); 1029 break; 1030 1031 case EVENT_MARK_SMS_READ_DONE: 1032 Rlog.i("ENF", "marked read: sms " + msg.arg1); 1033 break; 1034 1035 1036 case EVENT_SMS_ON_SIM: 1037 isRecordLoadResponse = false; 1038 1039 ar = (AsyncResult)msg.obj; 1040 1041 int[] index = (int[])ar.result; 1042 1043 if (ar.exception != null || index.length != 1) { 1044 loge("Error on SMS_ON_SIM with exp " 1045 + ar.exception + " length " + index.length); 1046 } else { 1047 log("READ EF_SMS RECORD index=" + index[0]); 1048 mFh.loadEFLinearFixed(EF_SMS,index[0], 1049 obtainMessage(EVENT_GET_SMS_DONE)); 1050 } 1051 break; 1052 1053 case EVENT_GET_SMS_DONE: 1054 isRecordLoadResponse = false; 1055 ar = (AsyncResult)msg.obj; 1056 if (ar.exception == null) { 1057 handleSms((byte[])ar.result); 1058 } else { 1059 loge("Error on GET_SMS with exp " + ar.exception); 1060 } 1061 break; 1062 case EVENT_GET_SST_DONE: 1063 isRecordLoadResponse = true; 1064 1065 ar = (AsyncResult)msg.obj; 1066 data = (byte[])ar.result; 1067 1068 if (ar.exception != null) { 1069 break; 1070 } 1071 1072 mUsimServiceTable = new UsimServiceTable(data); 1073 if (DBG) log("SST: " + mUsimServiceTable); 1074 break; 1075 1076 case EVENT_GET_INFO_CPHS_DONE: 1077 isRecordLoadResponse = true; 1078 1079 ar = (AsyncResult)msg.obj; 1080 1081 if (ar.exception != null) { 1082 break; 1083 } 1084 1085 mCphsInfo = (byte[])ar.result; 1086 1087 if (DBG) log("iCPHS: " + IccUtils.bytesToHexString(mCphsInfo)); 1088 break; 1089 1090 case EVENT_SET_MBDN_DONE: 1091 isRecordLoadResponse = false; 1092 ar = (AsyncResult)msg.obj; 1093 1094 if (DBG) log("EVENT_SET_MBDN_DONE ex:" + ar.exception); 1095 if (ar.exception == null) { 1096 mVoiceMailNum = mNewVoiceMailNum; 1097 mVoiceMailTag = mNewVoiceMailTag; 1098 } 1099 1100 if (isCphsMailboxEnabled()) { 1101 adn = new AdnRecord(mVoiceMailTag, mVoiceMailNum); 1102 Message onCphsCompleted = (Message) ar.userObj; 1103 1104 /* write to cphs mailbox whenever it is available but 1105 * we only need notify caller once if both updating are 1106 * successful. 1107 * 1108 * so if set_mbdn successful, notify caller here and set 1109 * onCphsCompleted to null 1110 */ 1111 if (ar.exception == null && ar.userObj != null) { 1112 AsyncResult.forMessage(((Message) ar.userObj)).exception 1113 = null; 1114 ((Message) ar.userObj).sendToTarget(); 1115 1116 if (DBG) log("Callback with MBDN successful."); 1117 1118 onCphsCompleted = null; 1119 } 1120 1121 new AdnRecordLoader(mFh). 1122 updateEF(adn, EF_MAILBOX_CPHS, EF_EXT1, 1, null, 1123 obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE, 1124 onCphsCompleted)); 1125 } else { 1126 if (ar.userObj != null) { 1127 Resources resource = Resources.getSystem(); 1128 if (ar.exception != null && resource.getBoolean(com.android.internal. 1129 R.bool.editable_voicemailnumber)) { 1130 // GSMPhone will store vm number on device 1131 // when IccVmNotSupportedException occurred 1132 AsyncResult.forMessage(((Message) ar.userObj)).exception 1133 = new IccVmNotSupportedException( 1134 "Update SIM voice mailbox error"); 1135 } else { 1136 AsyncResult.forMessage(((Message) ar.userObj)).exception 1137 = ar.exception; 1138 } 1139 ((Message) ar.userObj).sendToTarget(); 1140 } 1141 } 1142 break; 1143 case EVENT_SET_CPHS_MAILBOX_DONE: 1144 isRecordLoadResponse = false; 1145 ar = (AsyncResult)msg.obj; 1146 if(ar.exception == null) { 1147 mVoiceMailNum = mNewVoiceMailNum; 1148 mVoiceMailTag = mNewVoiceMailTag; 1149 } else { 1150 if (DBG) log("Set CPHS MailBox with exception: " 1151 + ar.exception); 1152 } 1153 if (ar.userObj != null) { 1154 if (DBG) log("Callback with CPHS MB successful."); 1155 AsyncResult.forMessage(((Message) ar.userObj)).exception 1156 = ar.exception; 1157 ((Message) ar.userObj).sendToTarget(); 1158 } 1159 break; 1160 case EVENT_SIM_REFRESH: 1161 isRecordLoadResponse = false; 1162 ar = (AsyncResult)msg.obj; 1163 if (DBG) log("Sim REFRESH with exception: " + ar.exception); 1164 if (ar.exception == null) { 1165 handleSimRefresh((IccRefreshResponse)ar.result); 1166 } 1167 break; 1168 case EVENT_GET_CFIS_DONE: 1169 isRecordLoadResponse = true; 1170 1171 ar = (AsyncResult)msg.obj; 1172 data = (byte[])ar.result; 1173 1174 if (ar.exception != null) { 1175 break; 1176 } 1177 1178 log("EF_CFIS: " + IccUtils.bytesToHexString(data)); 1179 1180 if (validEfCfis(data)) { 1181 mEfCfis = data; 1182 1183 // Refer TS 51.011 Section 10.3.46 for the content description 1184 mCallForwardingEnabled = ((data[1] & 0x01) != 0); 1185 log("EF_CFIS: callForwardingEnabled=" + mCallForwardingEnabled); 1186 1187 mRecordsEventsRegistrants.notifyResult(EVENT_CFI); 1188 } else { 1189 log("EF_CFIS: invalid data=" + IccUtils.bytesToHexString(data)); 1190 } 1191 break; 1192 1193 case EVENT_GET_CSP_CPHS_DONE: 1194 isRecordLoadResponse = true; 1195 1196 ar = (AsyncResult)msg.obj; 1197 1198 if (ar.exception != null) { 1199 loge("Exception in fetching EF_CSP data " + ar.exception); 1200 break; 1201 } 1202 1203 data = (byte[])ar.result; 1204 1205 log("EF_CSP: " + IccUtils.bytesToHexString(data)); 1206 handleEfCspData(data); 1207 break; 1208 1209 case EVENT_GET_GID1_DONE: 1210 isRecordLoadResponse = true; 1211 1212 ar = (AsyncResult)msg.obj; 1213 data =(byte[])ar.result; 1214 1215 if (ar.exception != null) { 1216 loge("Exception in get GID1 " + ar.exception); 1217 mGid1 = null; 1218 break; 1219 } 1220 mGid1 = IccUtils.bytesToHexString(data); 1221 log("GID1: " + mGid1); 1222 1223 break; 1224 1225 case EVENT_GET_GID2_DONE: 1226 isRecordLoadResponse = true; 1227 1228 ar = (AsyncResult)msg.obj; 1229 data =(byte[])ar.result; 1230 1231 if (ar.exception != null) { 1232 loge("Exception in get GID2 " + ar.exception); 1233 mGid2 = null; 1234 break; 1235 } 1236 mGid2 = IccUtils.bytesToHexString(data); 1237 log("GID2: " + mGid2); 1238 1239 break; 1240 1241 default: 1242 super.handleMessage(msg); // IccRecords handles generic record load responses 1243 1244 }}catch (RuntimeException exc) { 1245 // I don't want these exceptions to be fatal 1246 logw("Exception parsing SIM record", exc); 1247 } finally { 1248 // Count up record load responses even if they are fails 1249 if (isRecordLoadResponse) { 1250 onRecordLoaded(); 1251 } 1252 } 1253 } 1254 1255 private class EfPlLoaded implements IccRecordLoaded { 1256 public String getEfName() { 1257 return "EF_PL"; 1258 } 1259 1260 public void onRecordLoaded(AsyncResult ar) { 1261 mEfPl = (byte[]) ar.result; 1262 if (DBG) log("EF_PL=" + IccUtils.bytesToHexString(mEfPl)); 1263 } 1264 } 1265 1266 private class EfUsimLiLoaded implements IccRecordLoaded { 1267 public String getEfName() { 1268 return "EF_LI"; 1269 } 1270 1271 public void onRecordLoaded(AsyncResult ar) { 1272 mEfLi = (byte[]) ar.result; 1273 if (DBG) log("EF_LI=" + IccUtils.bytesToHexString(mEfLi)); 1274 } 1275 } 1276 1277 private void handleFileUpdate(int efid) { 1278 switch(efid) { 1279 case EF_MBDN: 1280 mRecordsToLoad++; 1281 new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6, 1282 mMailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE)); 1283 break; 1284 case EF_MAILBOX_CPHS: 1285 mRecordsToLoad++; 1286 new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1, 1287 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); 1288 break; 1289 case EF_CSP_CPHS: 1290 mRecordsToLoad++; 1291 log("[CSP] SIM Refresh for EF_CSP_CPHS"); 1292 mFh.loadEFTransparent(EF_CSP_CPHS, 1293 obtainMessage(EVENT_GET_CSP_CPHS_DONE)); 1294 break; 1295 case EF_FDN: 1296 if (DBG) log("SIM Refresh called for EF_FDN"); 1297 mParentApp.queryFdn(); 1298 break; 1299 case EF_MSISDN: 1300 mRecordsToLoad++; 1301 log("SIM Refresh called for EF_MSISDN"); 1302 new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, getExtFromEf(EF_MSISDN), 1, 1303 obtainMessage(EVENT_GET_MSISDN_DONE)); 1304 break; 1305 case EF_CFIS: 1306 mRecordsToLoad++; 1307 log("SIM Refresh called for EF_CFIS"); 1308 mFh.loadEFLinearFixed(EF_CFIS, 1309 1, obtainMessage(EVENT_GET_CFIS_DONE)); 1310 break; 1311 case EF_CFF_CPHS: 1312 mRecordsToLoad++; 1313 log("SIM Refresh called for EF_CFF_CPHS"); 1314 mFh.loadEFTransparent(EF_CFF_CPHS, 1315 obtainMessage(EVENT_GET_CFF_DONE)); 1316 break; 1317 default: 1318 // For now, fetch all records if this is not a 1319 // voicemail number. 1320 // TODO: Handle other cases, instead of fetching all. 1321 mAdnCache.reset(); 1322 fetchSimRecords(); 1323 break; 1324 } 1325 } 1326 1327 private void handleSimRefresh(IccRefreshResponse refreshResponse){ 1328 if (refreshResponse == null) { 1329 if (DBG) log("handleSimRefresh received without input"); 1330 return; 1331 } 1332 1333 if (refreshResponse.aid != null && 1334 !refreshResponse.aid.equals(mParentApp.getAid())) { 1335 // This is for different app. Ignore. 1336 return; 1337 } 1338 1339 switch (refreshResponse.refreshResult) { 1340 case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE: 1341 if (DBG) log("handleSimRefresh with SIM_FILE_UPDATED"); 1342 handleFileUpdate(refreshResponse.efId); 1343 break; 1344 case IccRefreshResponse.REFRESH_RESULT_INIT: 1345 if (DBG) log("handleSimRefresh with SIM_REFRESH_INIT"); 1346 // need to reload all files (that we care about) 1347 onIccRefreshInit(); 1348 break; 1349 case IccRefreshResponse.REFRESH_RESULT_RESET: 1350 // Refresh reset is handled by the UiccCard object. 1351 if (DBG) log("handleSimRefresh with SIM_REFRESH_RESET"); 1352 break; 1353 default: 1354 // unknown refresh operation 1355 if (DBG) log("handleSimRefresh with unknown operation"); 1356 break; 1357 } 1358 } 1359 1360 /** 1361 * Dispatch 3GPP format message to registrant ({@code GSMPhone} or {@code CDMALTEPhone}) 1362 * to pass to the 3GPP SMS dispatcher for delivery. 1363 */ 1364 private int dispatchGsmMessage(SmsMessage message) { 1365 mNewSmsRegistrants.notifyResult(message); 1366 return 0; 1367 } 1368 1369 private void handleSms(byte[] ba) { 1370 if (ba[0] != 0) 1371 Rlog.d("ENF", "status : " + ba[0]); 1372 1373 // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 1374 // 3 == "received by MS from network; message to be read" 1375 if (ba[0] == 3) { 1376 int n = ba.length; 1377 1378 // Note: Data may include trailing FF's. That's OK; message 1379 // should still parse correctly. 1380 byte[] pdu = new byte[n - 1]; 1381 System.arraycopy(ba, 1, pdu, 0, n - 1); 1382 SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP); 1383 1384 dispatchGsmMessage(message); 1385 } 1386 } 1387 1388 1389 private void handleSmses(ArrayList<byte[]> messages) { 1390 int count = messages.size(); 1391 1392 for (int i = 0; i < count; i++) { 1393 byte[] ba = messages.get(i); 1394 1395 if (ba[0] != 0) 1396 Rlog.i("ENF", "status " + i + ": " + ba[0]); 1397 1398 // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 1399 // 3 == "received by MS from network; message to be read" 1400 1401 if (ba[0] == 3) { 1402 int n = ba.length; 1403 1404 // Note: Data may include trailing FF's. That's OK; message 1405 // should still parse correctly. 1406 byte[] pdu = new byte[n - 1]; 1407 System.arraycopy(ba, 1, pdu, 0, n - 1); 1408 SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP); 1409 1410 dispatchGsmMessage(message); 1411 1412 // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 1413 // 1 == "received by MS from network; message read" 1414 1415 ba[0] = 1; 1416 1417 if (false) { // FIXME: writing seems to crash RdoServD 1418 mFh.updateEFLinearFixed(EF_SMS, 1419 i, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, i)); 1420 } 1421 } 1422 } 1423 } 1424 1425 @Override 1426 protected void onRecordLoaded() { 1427 // One record loaded successfully or failed, In either case 1428 // we need to update the recordsToLoad count 1429 mRecordsToLoad -= 1; 1430 if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested); 1431 1432 if (mRecordsToLoad == 0 && mRecordsRequested == true) { 1433 onAllRecordsLoaded(); 1434 } else if (mRecordsToLoad < 0) { 1435 loge("recordsToLoad <0, programmer error suspected"); 1436 mRecordsToLoad = 0; 1437 } 1438 } 1439 1440 @Override 1441 protected void onAllRecordsLoaded() { 1442 if (DBG) log("record load complete"); 1443 1444 Resources resource = Resources.getSystem(); 1445 if (resource.getBoolean(com.android.internal.R.bool.config_use_sim_language_file)) { 1446 setSimLanguage(mEfLi, mEfPl); 1447 } else { 1448 if (DBG) log ("Not using EF LI/EF PL"); 1449 } 1450 1451 if (mParentApp.getState() == AppState.APPSTATE_PIN || 1452 mParentApp.getState() == AppState.APPSTATE_PUK) { 1453 // reset recordsRequested, since sim is not loaded really 1454 mRecordsRequested = false; 1455 // lock state, only update language 1456 return ; 1457 } 1458 1459 // Some fields require more than one SIM record to set 1460 1461 String operator = getOperatorNumeric(); 1462 if (!TextUtils.isEmpty(operator)) { 1463 log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" + 1464 operator + "'"); 1465 log("update icc_operator_numeric=" + operator); 1466 mTelephonyManager.setSimOperatorNumericForPhone( 1467 mParentApp.getPhoneId(), operator); 1468 final SubscriptionController subController = SubscriptionController.getInstance(); 1469 subController.setMccMnc(operator, subController.getDefaultSmsSubId()); 1470 } else { 1471 log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping"); 1472 } 1473 1474 if (!TextUtils.isEmpty(mImsi)) { 1475 log("onAllRecordsLoaded set mcc imsi" + (VDBG ? ("=" + mImsi) : "")); 1476 mTelephonyManager.setSimCountryIsoForPhone( 1477 mParentApp.getPhoneId(), MccTable.countryCodeForMcc( 1478 Integer.parseInt(mImsi.substring(0,3)))); 1479 } else { 1480 log("onAllRecordsLoaded empty imsi skipping setting mcc"); 1481 } 1482 1483 setVoiceMailByCountry(operator); 1484 setSpnFromConfig(operator); 1485 1486 mRecordsLoadedRegistrants.notifyRegistrants( 1487 new AsyncResult(null, null, null)); 1488 } 1489 1490 //***** Private methods 1491 1492 private void setSpnFromConfig(String carrier) { 1493 if (mSpnOverride.containsCarrier(carrier)) { 1494 setServiceProviderName(mSpnOverride.getSpn(carrier)); 1495 mTelephonyManager.setSimOperatorNameForPhone( 1496 mParentApp.getPhoneId(), getServiceProviderName()); 1497 } 1498 } 1499 1500 1501 private void setVoiceMailByCountry (String spn) { 1502 if (mVmConfig.containsCarrier(spn)) { 1503 mIsVoiceMailFixed = true; 1504 mVoiceMailNum = mVmConfig.getVoiceMailNumber(spn); 1505 mVoiceMailTag = mVmConfig.getVoiceMailTag(spn); 1506 } 1507 } 1508 1509 @Override 1510 public void onReady() { 1511 fetchSimRecords(); 1512 } 1513 1514 private void onLocked() { 1515 if (DBG) log("only fetch EF_LI and EF_PL in lock state"); 1516 loadEfLiAndEfPl(); 1517 } 1518 1519 private void loadEfLiAndEfPl() { 1520 if (mParentApp.getType() == AppType.APPTYPE_USIM) { 1521 mRecordsRequested = true; 1522 mFh.loadEFTransparent(EF_LI, 1523 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfUsimLiLoaded())); 1524 mRecordsToLoad++; 1525 1526 mFh.loadEFTransparent(EF_PL, 1527 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfPlLoaded())); 1528 mRecordsToLoad++; 1529 } 1530 } 1531 1532 protected void fetchSimRecords() { 1533 mRecordsRequested = true; 1534 1535 if (DBG) log("fetchSimRecords " + mRecordsToLoad); 1536 1537 mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE)); 1538 mRecordsToLoad++; 1539 1540 mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE)); 1541 mRecordsToLoad++; 1542 1543 // FIXME should examine EF[MSISDN]'s capability configuration 1544 // to determine which is the voice/data/fax line 1545 new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, getExtFromEf(EF_MSISDN), 1, 1546 obtainMessage(EVENT_GET_MSISDN_DONE)); 1547 mRecordsToLoad++; 1548 1549 // Record number is subscriber profile 1550 mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE)); 1551 mRecordsToLoad++; 1552 1553 mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE)); 1554 mRecordsToLoad++; 1555 1556 // Record number is subscriber profile 1557 mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE)); 1558 mRecordsToLoad++; 1559 1560 1561 // Also load CPHS-style voice mail indicator, which stores 1562 // the same info as EF[MWIS]. If both exist, both are updated 1563 // but the EF[MWIS] data is preferred 1564 // Please note this must be loaded after EF[MWIS] 1565 mFh.loadEFTransparent( 1566 EF_VOICE_MAIL_INDICATOR_CPHS, 1567 obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE)); 1568 mRecordsToLoad++; 1569 1570 // Same goes for Call Forward Status indicator: fetch both 1571 // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred. 1572 mFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE)); 1573 mRecordsToLoad++; 1574 mFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE)); 1575 mRecordsToLoad++; 1576 1577 1578 getSpnFsm(true, null); 1579 1580 mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE)); 1581 mRecordsToLoad++; 1582 1583 mFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE)); 1584 mRecordsToLoad++; 1585 1586 mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE)); 1587 mRecordsToLoad++; 1588 1589 mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE)); 1590 mRecordsToLoad++; 1591 1592 mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE)); 1593 mRecordsToLoad++; 1594 1595 mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE)); 1596 mRecordsToLoad++; 1597 1598 mFh.loadEFTransparent(EF_GID2, obtainMessage(EVENT_GET_GID2_DONE)); 1599 mRecordsToLoad++; 1600 1601 loadEfLiAndEfPl(); 1602 1603 // XXX should seek instead of examining them all 1604 if (false) { // XXX 1605 mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE)); 1606 mRecordsToLoad++; 1607 } 1608 1609 if (CRASH_RIL) { 1610 String sms = "0107912160130310f20404d0110041007030208054832b0120" 1611 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1612 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1613 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1614 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1615 + "ffffffffffffffffffffffffffffff"; 1616 byte[] ba = IccUtils.hexStringToBytes(sms); 1617 1618 mFh.updateEFLinearFixed(EF_SMS, 1, ba, null, 1619 obtainMessage(EVENT_MARK_SMS_READ_DONE, 1)); 1620 } 1621 if (DBG) log("fetchSimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested); 1622 } 1623 1624 /** 1625 * Returns the SpnDisplayRule based on settings on the SIM and the 1626 * specified plmn (currently-registered PLMN). See TS 22.101 Annex A 1627 * and TS 51.011 10.3.11 for details. 1628 * 1629 * If the SPN is not found on the SIM or is empty, the rule is 1630 * always PLMN_ONLY. 1631 */ 1632 @Override 1633 public int getDisplayRule(String plmn) { 1634 int rule; 1635 1636 if (mParentApp != null && mParentApp.getUiccCard() != null && 1637 mParentApp.getUiccCard().getOperatorBrandOverride() != null) { 1638 // If the operator has been overridden, treat it as the SPN file on the SIM did not exist. 1639 rule = SPN_RULE_SHOW_PLMN; 1640 } else if (TextUtils.isEmpty(getServiceProviderName()) || mSpnDisplayCondition == -1) { 1641 // No EF_SPN content was found on the SIM, or not yet loaded. Just show ONS. 1642 rule = SPN_RULE_SHOW_PLMN; 1643 } else if (isOnMatchingPlmn(plmn)) { 1644 rule = SPN_RULE_SHOW_SPN; 1645 if ((mSpnDisplayCondition & 0x01) == 0x01) { 1646 // ONS required when registered to HPLMN or PLMN in EF_SPDI 1647 rule |= SPN_RULE_SHOW_PLMN; 1648 } 1649 } else { 1650 rule = SPN_RULE_SHOW_PLMN; 1651 if ((mSpnDisplayCondition & 0x02) == 0x00) { 1652 // SPN required if not registered to HPLMN or PLMN in EF_SPDI 1653 rule |= SPN_RULE_SHOW_SPN; 1654 } 1655 } 1656 return rule; 1657 } 1658 1659 /** 1660 * Checks if plmn is HPLMN or on the spdiNetworks list. 1661 */ 1662 private boolean isOnMatchingPlmn(String plmn) { 1663 if (plmn == null) return false; 1664 1665 if (plmn.equals(getOperatorNumeric())) { 1666 return true; 1667 } 1668 1669 if (mSpdiNetworks != null) { 1670 for (String spdiNet : mSpdiNetworks) { 1671 if (plmn.equals(spdiNet)) { 1672 return true; 1673 } 1674 } 1675 } 1676 return false; 1677 } 1678 1679 /** 1680 * States of Get SPN Finite State Machine which only used by getSpnFsm() 1681 */ 1682 private enum GetSpnFsmState { 1683 IDLE, // No initialized 1684 INIT, // Start FSM 1685 READ_SPN_3GPP, // Load EF_SPN firstly 1686 READ_SPN_CPHS, // Load EF_SPN_CPHS secondly 1687 READ_SPN_SHORT_CPHS // Load EF_SPN_SHORT_CPHS last 1688 } 1689 1690 /** 1691 * Finite State Machine to load Service Provider Name , which can be stored 1692 * in either EF_SPN (3GPP), EF_SPN_CPHS, or EF_SPN_SHORT_CPHS (CPHS4.2) 1693 * 1694 * After starting, FSM will search SPN EFs in order and stop after finding 1695 * the first valid SPN 1696 * 1697 * If the FSM gets restart while waiting for one of 1698 * SPN EFs results (i.e. a SIM refresh occurs after issuing 1699 * read EF_CPHS_SPN), it will re-initialize only after 1700 * receiving and discarding the unfinished SPN EF result. 1701 * 1702 * @param start set true only for initialize loading 1703 * @param ar the AsyncResult from loadEFTransparent 1704 * ar.exception holds exception in error 1705 * ar.result is byte[] for data in success 1706 */ 1707 private void getSpnFsm(boolean start, AsyncResult ar) { 1708 byte[] data; 1709 1710 if (start) { 1711 // Check previous state to see if there is outstanding 1712 // SPN read 1713 if(mSpnState == GetSpnFsmState.READ_SPN_3GPP || 1714 mSpnState == GetSpnFsmState.READ_SPN_CPHS || 1715 mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS || 1716 mSpnState == GetSpnFsmState.INIT) { 1717 // Set INIT then return so the INIT code 1718 // will run when the outstanding read done. 1719 mSpnState = GetSpnFsmState.INIT; 1720 return; 1721 } else { 1722 mSpnState = GetSpnFsmState.INIT; 1723 } 1724 } 1725 1726 switch(mSpnState){ 1727 case INIT: 1728 setServiceProviderName(null); 1729 1730 mFh.loadEFTransparent(EF_SPN, 1731 obtainMessage(EVENT_GET_SPN_DONE)); 1732 mRecordsToLoad++; 1733 1734 mSpnState = GetSpnFsmState.READ_SPN_3GPP; 1735 break; 1736 case READ_SPN_3GPP: 1737 if (ar != null && ar.exception == null) { 1738 data = (byte[]) ar.result; 1739 mSpnDisplayCondition = 0xff & data[0]; 1740 setServiceProviderName(IccUtils.adnStringFieldToString( 1741 data, 1, data.length - 1)); 1742 1743 if (DBG) log("Load EF_SPN: " + getServiceProviderName() 1744 + " spnDisplayCondition: " + mSpnDisplayCondition); 1745 mTelephonyManager.setSimOperatorNameForPhone( 1746 mParentApp.getPhoneId(), getServiceProviderName()); 1747 1748 mSpnState = GetSpnFsmState.IDLE; 1749 } else { 1750 mFh.loadEFTransparent( EF_SPN_CPHS, 1751 obtainMessage(EVENT_GET_SPN_DONE)); 1752 mRecordsToLoad++; 1753 1754 mSpnState = GetSpnFsmState.READ_SPN_CPHS; 1755 1756 // See TS 51.011 10.3.11. Basically, default to 1757 // show PLMN always, and SPN also if roaming. 1758 mSpnDisplayCondition = -1; 1759 } 1760 break; 1761 case READ_SPN_CPHS: 1762 if (ar != null && ar.exception == null) { 1763 data = (byte[]) ar.result; 1764 setServiceProviderName(IccUtils.adnStringFieldToString(data, 0, data.length)); 1765 1766 if (DBG) log("Load EF_SPN_CPHS: " + getServiceProviderName()); 1767 mTelephonyManager.setSimOperatorNameForPhone( 1768 mParentApp.getPhoneId(), getServiceProviderName()); 1769 1770 mSpnState = GetSpnFsmState.IDLE; 1771 } else { 1772 mFh.loadEFTransparent( 1773 EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE)); 1774 mRecordsToLoad++; 1775 1776 mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS; 1777 } 1778 break; 1779 case READ_SPN_SHORT_CPHS: 1780 if (ar != null && ar.exception == null) { 1781 data = (byte[]) ar.result; 1782 setServiceProviderName(IccUtils.adnStringFieldToString(data, 0, data.length)); 1783 1784 if (DBG) log("Load EF_SPN_SHORT_CPHS: " + getServiceProviderName()); 1785 mTelephonyManager.setSimOperatorNameForPhone( 1786 mParentApp.getPhoneId(), getServiceProviderName()); 1787 }else { 1788 if (DBG) log("No SPN loaded in either CHPS or 3GPP"); 1789 } 1790 1791 mSpnState = GetSpnFsmState.IDLE; 1792 break; 1793 default: 1794 mSpnState = GetSpnFsmState.IDLE; 1795 } 1796 } 1797 1798 /** 1799 * Parse TS 51.011 EF[SPDI] record 1800 * This record contains the list of numeric network IDs that 1801 * are treated specially when determining SPN display 1802 */ 1803 private void 1804 parseEfSpdi(byte[] data) { 1805 SimTlv tlv = new SimTlv(data, 0, data.length); 1806 1807 byte[] plmnEntries = null; 1808 1809 for ( ; tlv.isValidObject() ; tlv.nextObject()) { 1810 // Skip SPDI tag, if existant 1811 if (tlv.getTag() == TAG_SPDI) { 1812 tlv = new SimTlv(tlv.getData(), 0, tlv.getData().length); 1813 } 1814 // There should only be one TAG_SPDI_PLMN_LIST 1815 if (tlv.getTag() == TAG_SPDI_PLMN_LIST) { 1816 plmnEntries = tlv.getData(); 1817 break; 1818 } 1819 } 1820 1821 if (plmnEntries == null) { 1822 return; 1823 } 1824 1825 mSpdiNetworks = new ArrayList<String>(plmnEntries.length / 3); 1826 1827 for (int i = 0 ; i + 2 < plmnEntries.length ; i += 3) { 1828 String plmnCode; 1829 plmnCode = IccUtils.bcdToString(plmnEntries, i, 3); 1830 1831 // Valid operator codes are 5 or 6 digits 1832 if (plmnCode.length() >= 5) { 1833 log("EF_SPDI network: " + plmnCode); 1834 mSpdiNetworks.add(plmnCode); 1835 } 1836 } 1837 } 1838 1839 /** 1840 * check to see if Mailbox Number is allocated and activated in CPHS SST 1841 */ 1842 private boolean isCphsMailboxEnabled() { 1843 if (mCphsInfo == null) return false; 1844 return ((mCphsInfo[1] & CPHS_SST_MBN_MASK) == CPHS_SST_MBN_ENABLED ); 1845 } 1846 1847 @Override 1848 protected void log(String s) { 1849 Rlog.d(LOG_TAG, "[SIMRecords] " + s); 1850 } 1851 1852 @Override 1853 protected void loge(String s) { 1854 Rlog.e(LOG_TAG, "[SIMRecords] " + s); 1855 } 1856 1857 protected void logw(String s, Throwable tr) { 1858 Rlog.w(LOG_TAG, "[SIMRecords] " + s, tr); 1859 } 1860 1861 protected void logv(String s) { 1862 Rlog.v(LOG_TAG, "[SIMRecords] " + s); 1863 } 1864 1865 /** 1866 * Return true if "Restriction of menu options for manual PLMN selection" 1867 * bit is set or EF_CSP data is unavailable, return false otherwise. 1868 */ 1869 @Override 1870 public boolean isCspPlmnEnabled() { 1871 return mCspPlmnEnabled; 1872 } 1873 1874 /** 1875 * Parse EF_CSP data and check if 1876 * "Restriction of menu options for manual PLMN selection" is 1877 * Enabled/Disabled 1878 * 1879 * @param data EF_CSP hex data. 1880 */ 1881 private void handleEfCspData(byte[] data) { 1882 // As per spec CPHS4_2.WW6, CPHS B.4.7.1, EF_CSP contains CPHS defined 1883 // 18 bytes (i.e 9 service groups info) and additional data specific to 1884 // operator. The valueAddedServicesGroup is not part of standard 1885 // services. This is operator specific and can be programmed any where. 1886 // Normally this is programmed as 10th service after the standard 1887 // services. 1888 int usedCspGroups = data.length / 2; 1889 // This is the "Service Group Number" of "Value Added Services Group". 1890 byte valueAddedServicesGroup = (byte)0xC0; 1891 1892 mCspPlmnEnabled = true; 1893 for (int i = 0; i < usedCspGroups; i++) { 1894 if (data[2 * i] == valueAddedServicesGroup) { 1895 log("[CSP] found ValueAddedServicesGroup, value " + data[(2 * i) + 1]); 1896 if ((data[(2 * i) + 1] & 0x80) == 0x80) { 1897 // Bit 8 is for 1898 // "Restriction of menu options for manual PLMN selection". 1899 // Operator Selection menu should be enabled. 1900 mCspPlmnEnabled = true; 1901 } else { 1902 mCspPlmnEnabled = false; 1903 // Operator Selection menu should be disabled. 1904 // Operator Selection Mode should be set to Automatic. 1905 log("[CSP] Set Automatic Network Selection"); 1906 mNetworkSelectionModeAutomaticRegistrants.notifyRegistrants(); 1907 } 1908 return; 1909 } 1910 } 1911 1912 log("[CSP] Value Added Service Group (0xC0), not found!"); 1913 } 1914 1915 @Override 1916 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1917 pw.println("SIMRecords: " + this); 1918 pw.println(" extends:"); 1919 super.dump(fd, pw, args); 1920 pw.println(" mVmConfig=" + mVmConfig); 1921 pw.println(" mSpnOverride=" + mSpnOverride); 1922 pw.println(" mCallForwardingEnabled=" + mCallForwardingEnabled); 1923 pw.println(" mSpnState=" + mSpnState); 1924 pw.println(" mCphsInfo=" + mCphsInfo); 1925 pw.println(" mCspPlmnEnabled=" + mCspPlmnEnabled); 1926 pw.println(" mEfMWIS[]=" + Arrays.toString(mEfMWIS)); 1927 pw.println(" mEfCPHS_MWI[]=" + Arrays.toString(mEfCPHS_MWI)); 1928 pw.println(" mEfCff[]=" + Arrays.toString(mEfCff)); 1929 pw.println(" mEfCfis[]=" + Arrays.toString(mEfCfis)); 1930 pw.println(" mSpnDisplayCondition=" + mSpnDisplayCondition); 1931 pw.println(" mSpdiNetworks[]=" + mSpdiNetworks); 1932 pw.println(" mPnnHomeName=" + mPnnHomeName); 1933 pw.println(" mUsimServiceTable=" + mUsimServiceTable); 1934 pw.println(" mGid1=" + mGid1); 1935 pw.println(" mGid2=" + mGid2); 1936 pw.flush(); 1937 } 1938} 1939