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