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