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