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