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