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