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