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