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