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