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