SIMRecords.java revision 75b33cb5b1f46ba3f3e8b0cb47d47d3f87c5e4f4
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", "405854", "405855", "405856", 187 "405857", "405858", "405859", "405860", "405861", "405862", "405863", "405864", 188 "405865", "405866", "405867", "405868", "405869", "405870", "405871", "405872", 189 "405873", "405874", "405875", "405876", "405877", "405878", "405879", "405880", 190 "405881", "405882", "405883", "405884", "405885", "405886", "405908", "405909", 191 "405910", "405911", "405912", "405913", "405914", "405915", "405916", "405917", 192 "405918", "405919", "405920", "405921", "405922", "405923", "405924", "405925", 193 "405926", "405927", "405928", "405929", "405930", "405931", "405932", "502142", 194 "502143", "502145", "502146", "502147", "502148" 195 }; 196 197 // ***** Constructor 198 199 public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) { 200 super(app, c, ci); 201 202 mAdnCache = new AdnRecordCache(mFh); 203 204 mVmConfig = new VoiceMailConstants(); 205 mSpnOverride = new SpnOverride(); 206 207 mRecordsRequested = false; // No load request is made till SIM ready 208 209 // recordsToLoad is set to 0 because no requests are made yet 210 mRecordsToLoad = 0; 211 212 mCi.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null); 213 mCi.registerForIccRefresh(this, EVENT_SIM_REFRESH, null); 214 215 // Start off by setting empty state 216 resetRecords(); 217 mParentApp.registerForReady(this, EVENT_APP_READY, null); 218 mParentApp.registerForLocked(this, EVENT_APP_LOCKED, null); 219 if (DBG) log("SIMRecords X ctor this=" + this); 220 221 IntentFilter intentfilter = new IntentFilter(); 222 intentfilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 223 c.registerReceiver(mReceiver, intentfilter); 224 } 225 226 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 227 @Override 228 public void onReceive(Context context, Intent intent) { 229 if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { 230 sendMessage(obtainMessage(EVENT_CARRIER_CONFIG_CHANGED)); 231 } 232 } 233 }; 234 235 @Override 236 public void dispose() { 237 if (DBG) log("Disposing SIMRecords this=" + this); 238 //Unregister for all events 239 mCi.unregisterForIccRefresh(this); 240 mCi.unSetOnSmsOnSim(this); 241 mParentApp.unregisterForReady(this); 242 mParentApp.unregisterForLocked(this); 243 resetRecords(); 244 super.dispose(); 245 } 246 247 @Override 248 protected void finalize() { 249 if(DBG) log("finalized"); 250 } 251 252 protected void resetRecords() { 253 mImsi = null; 254 mMsisdn = null; 255 mVoiceMailNum = null; 256 mMncLength = UNINITIALIZED; 257 log("setting0 mMncLength" + mMncLength); 258 mIccId = null; 259 mFullIccId = null; 260 // -1 means no EF_SPN found; treat accordingly. 261 mSpnDisplayCondition = -1; 262 mEfMWIS = null; 263 mEfCPHS_MWI = null; 264 mSpdiNetworks = null; 265 mPnnHomeName = null; 266 mGid1 = null; 267 mGid2 = null; 268 269 mAdnCache.reset(); 270 271 log("SIMRecords: onRadioOffOrNotAvailable set 'gsm.sim.operator.numeric' to operator=null"); 272 log("update icc_operator_numeric=" + null); 273 mTelephonyManager.setSimOperatorNumericForPhone(mParentApp.getPhoneId(), ""); 274 mTelephonyManager.setSimOperatorNameForPhone(mParentApp.getPhoneId(), ""); 275 mTelephonyManager.setSimCountryIsoForPhone(mParentApp.getPhoneId(), ""); 276 277 // recordsRequested is set to false indicating that the SIM 278 // read requests made so far are not valid. This is set to 279 // true only when fresh set of read requests are made. 280 mRecordsRequested = false; 281 } 282 283 284 //***** Public Methods 285 286 /** 287 * {@inheritDoc} 288 */ 289 @Override 290 public String getIMSI() { 291 return mImsi; 292 } 293 294 @Override 295 public String getMsisdnNumber() { 296 return mMsisdn; 297 } 298 299 @Override 300 public String getGid1() { 301 return mGid1; 302 } 303 304 @Override 305 public String getGid2() { 306 return mGid2; 307 } 308 309 @Override 310 public UsimServiceTable getUsimServiceTable() { 311 return mUsimServiceTable; 312 } 313 314 private int getExtFromEf(int ef) { 315 int ext; 316 switch (ef) { 317 case EF_MSISDN: 318 /* For USIM apps use EXT5. (TS 31.102 Section 4.2.37) */ 319 if (mParentApp.getType() == AppType.APPTYPE_USIM) { 320 ext = EF_EXT5; 321 } else { 322 ext = EF_EXT1; 323 } 324 break; 325 default: 326 ext = EF_EXT1; 327 } 328 return ext; 329 } 330 331 /** 332 * Set subscriber number to SIM record 333 * 334 * The subscriber number is stored in EF_MSISDN (TS 51.011) 335 * 336 * When the operation is complete, onComplete will be sent to its handler 337 * 338 * @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters) 339 * @param number dailing nubmer (up to 20 digits) 340 * if the number starts with '+', then set to international TOA 341 * @param onComplete 342 * onComplete.obj will be an AsyncResult 343 * ((AsyncResult)onComplete.obj).exception == null on success 344 * ((AsyncResult)onComplete.obj).exception != null on fail 345 */ 346 @Override 347 public void setMsisdnNumber(String alphaTag, String number, 348 Message onComplete) { 349 350 // If the SIM card is locked by PIN, we will set EF_MSISDN fail. 351 // In that case, msisdn and msisdnTag should not be update. 352 mNewMsisdn = number; 353 mNewMsisdnTag = alphaTag; 354 355 if(DBG) log("Set MSISDN: " + mNewMsisdnTag + " " + /*mNewMsisdn*/ "xxxxxxx"); 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 1 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 log("EF_CFIS: updating cf number, " + 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) + "xxxxxxx"); 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*/ "xxxxxxx"); 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 log("update icc_operator_numeric=" + operator); 1486 mTelephonyManager.setSimOperatorNumericForPhone( 1487 mParentApp.getPhoneId(), operator); 1488 final SubscriptionController subController = SubscriptionController.getInstance(); 1489 subController.setMccMnc(operator, subController.getDefaultSubId()); 1490 } else { 1491 log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping"); 1492 } 1493 1494 if (!TextUtils.isEmpty(mImsi)) { 1495 log("onAllRecordsLoaded set mcc imsi" + (VDBG ? ("=" + mImsi) : "")); 1496 mTelephonyManager.setSimCountryIsoForPhone( 1497 mParentApp.getPhoneId(), MccTable.countryCodeForMcc( 1498 Integer.parseInt(mImsi.substring(0,3)))); 1499 } else { 1500 log("onAllRecordsLoaded empty imsi skipping setting mcc"); 1501 } 1502 1503 setVoiceMailByCountry(operator); 1504 1505 mRecordsLoadedRegistrants.notifyRegistrants( 1506 new AsyncResult(null, null, null)); 1507 } 1508 1509 //***** Private methods 1510 1511 private void handleCarrierNameOverride() { 1512 CarrierConfigManager configLoader = (CarrierConfigManager) 1513 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); 1514 if (configLoader != null && configLoader.getConfig().getBoolean( 1515 CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL)) { 1516 String carrierName = configLoader.getConfig().getString( 1517 CarrierConfigManager.KEY_CARRIER_NAME_STRING); 1518 setServiceProviderName(carrierName); 1519 mTelephonyManager.setSimOperatorNameForPhone(mParentApp.getPhoneId(), 1520 carrierName); 1521 } else { 1522 setSpnFromConfig(getOperatorNumeric()); 1523 } 1524 } 1525 1526 private void setSpnFromConfig(String carrier) { 1527 if (mSpnOverride.containsCarrier(carrier)) { 1528 setServiceProviderName(mSpnOverride.getSpn(carrier)); 1529 mTelephonyManager.setSimOperatorNameForPhone( 1530 mParentApp.getPhoneId(), getServiceProviderName()); 1531 } 1532 } 1533 1534 1535 private void setVoiceMailByCountry (String spn) { 1536 if (mVmConfig.containsCarrier(spn)) { 1537 mIsVoiceMailFixed = true; 1538 mVoiceMailNum = mVmConfig.getVoiceMailNumber(spn); 1539 mVoiceMailTag = mVmConfig.getVoiceMailTag(spn); 1540 } 1541 } 1542 1543 @Override 1544 public void onReady() { 1545 fetchSimRecords(); 1546 } 1547 1548 private void onLocked() { 1549 if (DBG) log("only fetch EF_LI and EF_PL in lock state"); 1550 loadEfLiAndEfPl(); 1551 } 1552 1553 private void loadEfLiAndEfPl() { 1554 if (mParentApp.getType() == AppType.APPTYPE_USIM) { 1555 mRecordsRequested = true; 1556 mFh.loadEFTransparent(EF_LI, 1557 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfUsimLiLoaded())); 1558 mRecordsToLoad++; 1559 1560 mFh.loadEFTransparent(EF_PL, 1561 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfPlLoaded())); 1562 mRecordsToLoad++; 1563 } 1564 } 1565 1566 private void loadCallForwardingRecords() { 1567 mRecordsRequested = true; 1568 mFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE)); 1569 mRecordsToLoad++; 1570 mFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE)); 1571 mRecordsToLoad++; 1572 } 1573 1574 protected void fetchSimRecords() { 1575 mRecordsRequested = true; 1576 1577 if (DBG) log("fetchSimRecords " + mRecordsToLoad); 1578 1579 mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE)); 1580 mRecordsToLoad++; 1581 1582 mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE)); 1583 mRecordsToLoad++; 1584 1585 // FIXME should examine EF[MSISDN]'s capability configuration 1586 // to determine which is the voice/data/fax line 1587 new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, getExtFromEf(EF_MSISDN), 1, 1588 obtainMessage(EVENT_GET_MSISDN_DONE)); 1589 mRecordsToLoad++; 1590 1591 // Record number is subscriber profile 1592 mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE)); 1593 mRecordsToLoad++; 1594 1595 mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE)); 1596 mRecordsToLoad++; 1597 1598 // Record number is subscriber profile 1599 mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE)); 1600 mRecordsToLoad++; 1601 1602 1603 // Also load CPHS-style voice mail indicator, which stores 1604 // the same info as EF[MWIS]. If both exist, both are updated 1605 // but the EF[MWIS] data is preferred 1606 // Please note this must be loaded after EF[MWIS] 1607 mFh.loadEFTransparent( 1608 EF_VOICE_MAIL_INDICATOR_CPHS, 1609 obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE)); 1610 mRecordsToLoad++; 1611 1612 // Same goes for Call Forward Status indicator: fetch both 1613 // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred. 1614 loadCallForwardingRecords(); 1615 1616 getSpnFsm(true, null); 1617 1618 mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE)); 1619 mRecordsToLoad++; 1620 1621 mFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE)); 1622 mRecordsToLoad++; 1623 1624 mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE)); 1625 mRecordsToLoad++; 1626 1627 mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE)); 1628 mRecordsToLoad++; 1629 1630 mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE)); 1631 mRecordsToLoad++; 1632 1633 mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE)); 1634 mRecordsToLoad++; 1635 1636 mFh.loadEFTransparent(EF_GID2, obtainMessage(EVENT_GET_GID2_DONE)); 1637 mRecordsToLoad++; 1638 1639 loadEfLiAndEfPl(); 1640 1641 // XXX should seek instead of examining them all 1642 if (false) { // XXX 1643 mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE)); 1644 mRecordsToLoad++; 1645 } 1646 1647 if (CRASH_RIL) { 1648 String sms = "0107912160130310f20404d0110041007030208054832b0120" 1649 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1650 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1651 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1652 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1653 + "ffffffffffffffffffffffffffffff"; 1654 byte[] ba = IccUtils.hexStringToBytes(sms); 1655 1656 mFh.updateEFLinearFixed(EF_SMS, 1, ba, null, 1657 obtainMessage(EVENT_MARK_SMS_READ_DONE, 1)); 1658 } 1659 if (DBG) log("fetchSimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested); 1660 } 1661 1662 /** 1663 * Returns the SpnDisplayRule based on settings on the SIM and the 1664 * specified plmn (currently-registered PLMN). See TS 22.101 Annex A 1665 * and TS 51.011 10.3.11 for details. 1666 * 1667 * If the SPN is not found on the SIM or is empty, the rule is 1668 * always PLMN_ONLY. 1669 */ 1670 @Override 1671 public int getDisplayRule(String plmn) { 1672 int rule; 1673 1674 if (mParentApp != null && mParentApp.getUiccCard() != null && 1675 mParentApp.getUiccCard().getOperatorBrandOverride() != null) { 1676 // If the operator has been overridden, treat it as the SPN file on the SIM did not exist. 1677 rule = SPN_RULE_SHOW_PLMN; 1678 } else if (TextUtils.isEmpty(getServiceProviderName()) || mSpnDisplayCondition == -1) { 1679 // No EF_SPN content was found on the SIM, or not yet loaded. Just show ONS. 1680 rule = SPN_RULE_SHOW_PLMN; 1681 } else if (isOnMatchingPlmn(plmn)) { 1682 rule = SPN_RULE_SHOW_SPN; 1683 if ((mSpnDisplayCondition & 0x01) == 0x01) { 1684 // ONS required when registered to HPLMN or PLMN in EF_SPDI 1685 rule |= SPN_RULE_SHOW_PLMN; 1686 } 1687 } else { 1688 rule = SPN_RULE_SHOW_PLMN; 1689 if ((mSpnDisplayCondition & 0x02) == 0x00) { 1690 // SPN required if not registered to HPLMN or PLMN in EF_SPDI 1691 rule |= SPN_RULE_SHOW_SPN; 1692 } 1693 } 1694 return rule; 1695 } 1696 1697 /** 1698 * Checks if plmn is HPLMN or on the spdiNetworks list. 1699 */ 1700 private boolean isOnMatchingPlmn(String plmn) { 1701 if (plmn == null) return false; 1702 1703 if (plmn.equals(getOperatorNumeric())) { 1704 return true; 1705 } 1706 1707 if (mSpdiNetworks != null) { 1708 for (String spdiNet : mSpdiNetworks) { 1709 if (plmn.equals(spdiNet)) { 1710 return true; 1711 } 1712 } 1713 } 1714 return false; 1715 } 1716 1717 /** 1718 * States of Get SPN Finite State Machine which only used by getSpnFsm() 1719 */ 1720 private enum GetSpnFsmState { 1721 IDLE, // No initialized 1722 INIT, // Start FSM 1723 READ_SPN_3GPP, // Load EF_SPN firstly 1724 READ_SPN_CPHS, // Load EF_SPN_CPHS secondly 1725 READ_SPN_SHORT_CPHS // Load EF_SPN_SHORT_CPHS last 1726 } 1727 1728 /** 1729 * Finite State Machine to load Service Provider Name , which can be stored 1730 * in either EF_SPN (3GPP), EF_SPN_CPHS, or EF_SPN_SHORT_CPHS (CPHS4.2) 1731 * 1732 * After starting, FSM will search SPN EFs in order and stop after finding 1733 * the first valid SPN 1734 * 1735 * If the FSM gets restart while waiting for one of 1736 * SPN EFs results (i.e. a SIM refresh occurs after issuing 1737 * read EF_CPHS_SPN), it will re-initialize only after 1738 * receiving and discarding the unfinished SPN EF result. 1739 * 1740 * @param start set true only for initialize loading 1741 * @param ar the AsyncResult from loadEFTransparent 1742 * ar.exception holds exception in error 1743 * ar.result is byte[] for data in success 1744 */ 1745 private void getSpnFsm(boolean start, AsyncResult ar) { 1746 byte[] data; 1747 1748 if (start) { 1749 // Check previous state to see if there is outstanding 1750 // SPN read 1751 if(mSpnState == GetSpnFsmState.READ_SPN_3GPP || 1752 mSpnState == GetSpnFsmState.READ_SPN_CPHS || 1753 mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS || 1754 mSpnState == GetSpnFsmState.INIT) { 1755 // Set INIT then return so the INIT code 1756 // will run when the outstanding read done. 1757 mSpnState = GetSpnFsmState.INIT; 1758 return; 1759 } else { 1760 mSpnState = GetSpnFsmState.INIT; 1761 } 1762 } 1763 1764 switch(mSpnState){ 1765 case INIT: 1766 setServiceProviderName(null); 1767 1768 mFh.loadEFTransparent(EF_SPN, 1769 obtainMessage(EVENT_GET_SPN_DONE)); 1770 mRecordsToLoad++; 1771 1772 mSpnState = GetSpnFsmState.READ_SPN_3GPP; 1773 break; 1774 case READ_SPN_3GPP: 1775 if (ar != null && ar.exception == null) { 1776 data = (byte[]) ar.result; 1777 mSpnDisplayCondition = 0xff & data[0]; 1778 1779 setServiceProviderName(IccUtils.adnStringFieldToString( 1780 data, 1, data.length - 1)); 1781 // for card double-check and brand override 1782 // we have to do this: 1783 final String spn = getServiceProviderName(); 1784 1785 if (spn == null || spn.length() == 0) { 1786 mSpnState = GetSpnFsmState.READ_SPN_CPHS; 1787 } else { 1788 if (DBG) log("Load EF_SPN: " + spn 1789 + " spnDisplayCondition: " + mSpnDisplayCondition); 1790 mTelephonyManager.setSimOperatorNameForPhone( 1791 mParentApp.getPhoneId(), spn); 1792 1793 mSpnState = GetSpnFsmState.IDLE; 1794 } 1795 } else { 1796 mSpnState = GetSpnFsmState.READ_SPN_CPHS; 1797 } 1798 1799 if (mSpnState == GetSpnFsmState.READ_SPN_CPHS) { 1800 mFh.loadEFTransparent( EF_SPN_CPHS, 1801 obtainMessage(EVENT_GET_SPN_DONE)); 1802 mRecordsToLoad++; 1803 1804 // See TS 51.011 10.3.11. Basically, default to 1805 // show PLMN always, and SPN also if roaming. 1806 mSpnDisplayCondition = -1; 1807 } 1808 break; 1809 case READ_SPN_CPHS: 1810 if (ar != null && ar.exception == null) { 1811 data = (byte[]) ar.result; 1812 1813 setServiceProviderName(IccUtils.adnStringFieldToString( 1814 data, 0, data.length)); 1815 // for card double-check and brand override 1816 // we have to do this: 1817 final String spn = getServiceProviderName(); 1818 1819 if (spn == null || spn.length() == 0) { 1820 mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS; 1821 } else { 1822 // Display CPHS Operator Name only when not roaming 1823 mSpnDisplayCondition = 2; 1824 1825 if (DBG) log("Load EF_SPN_CPHS: " + spn); 1826 mTelephonyManager.setSimOperatorNameForPhone( 1827 mParentApp.getPhoneId(), spn); 1828 1829 mSpnState = GetSpnFsmState.IDLE; 1830 } 1831 } else { 1832 mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS; 1833 } 1834 1835 if (mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS) { 1836 mFh.loadEFTransparent( 1837 EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE)); 1838 mRecordsToLoad++; 1839 } 1840 break; 1841 case READ_SPN_SHORT_CPHS: 1842 if (ar != null && ar.exception == null) { 1843 data = (byte[]) ar.result; 1844 1845 setServiceProviderName(IccUtils.adnStringFieldToString( 1846 data, 0, data.length)); 1847 // for card double-check and brand override 1848 // we have to do this: 1849 final String spn = getServiceProviderName(); 1850 1851 if (spn == null || spn.length() == 0) { 1852 if (DBG) log("No SPN loaded in either CHPS or 3GPP"); 1853 } else { 1854 // Display CPHS Operator Name only when not roaming 1855 mSpnDisplayCondition = 2; 1856 1857 if (DBG) log("Load EF_SPN_SHORT_CPHS: " + spn); 1858 mTelephonyManager.setSimOperatorNameForPhone( 1859 mParentApp.getPhoneId(), spn); 1860 } 1861 } else { 1862 setServiceProviderName(null); 1863 if (DBG) log("No SPN loaded in either CHPS or 3GPP"); 1864 } 1865 1866 mSpnState = GetSpnFsmState.IDLE; 1867 break; 1868 default: 1869 mSpnState = GetSpnFsmState.IDLE; 1870 } 1871 } 1872 1873 /** 1874 * Parse TS 51.011 EF[SPDI] record 1875 * This record contains the list of numeric network IDs that 1876 * are treated specially when determining SPN display 1877 */ 1878 private void 1879 parseEfSpdi(byte[] data) { 1880 SimTlv tlv = new SimTlv(data, 0, data.length); 1881 1882 byte[] plmnEntries = null; 1883 1884 for ( ; tlv.isValidObject() ; tlv.nextObject()) { 1885 // Skip SPDI tag, if existant 1886 if (tlv.getTag() == TAG_SPDI) { 1887 tlv = new SimTlv(tlv.getData(), 0, tlv.getData().length); 1888 } 1889 // There should only be one TAG_SPDI_PLMN_LIST 1890 if (tlv.getTag() == TAG_SPDI_PLMN_LIST) { 1891 plmnEntries = tlv.getData(); 1892 break; 1893 } 1894 } 1895 1896 if (plmnEntries == null) { 1897 return; 1898 } 1899 1900 mSpdiNetworks = new ArrayList<String>(plmnEntries.length / 3); 1901 1902 for (int i = 0 ; i + 2 < plmnEntries.length ; i += 3) { 1903 String plmnCode; 1904 plmnCode = IccUtils.bcdToString(plmnEntries, i, 3); 1905 1906 // Valid operator codes are 5 or 6 digits 1907 if (plmnCode.length() >= 5) { 1908 log("EF_SPDI network: " + plmnCode); 1909 mSpdiNetworks.add(plmnCode); 1910 } 1911 } 1912 } 1913 1914 /** 1915 * check to see if Mailbox Number is allocated and activated in CPHS SST 1916 */ 1917 private boolean isCphsMailboxEnabled() { 1918 if (mCphsInfo == null) return false; 1919 return ((mCphsInfo[1] & CPHS_SST_MBN_MASK) == CPHS_SST_MBN_ENABLED ); 1920 } 1921 1922 @Override 1923 protected void log(String s) { 1924 Rlog.d(LOG_TAG, "[SIMRecords] " + s); 1925 } 1926 1927 @Override 1928 protected void loge(String s) { 1929 Rlog.e(LOG_TAG, "[SIMRecords] " + s); 1930 } 1931 1932 protected void logw(String s, Throwable tr) { 1933 Rlog.w(LOG_TAG, "[SIMRecords] " + s, tr); 1934 } 1935 1936 protected void logv(String s) { 1937 Rlog.v(LOG_TAG, "[SIMRecords] " + s); 1938 } 1939 1940 /** 1941 * Return true if "Restriction of menu options for manual PLMN selection" 1942 * bit is set or EF_CSP data is unavailable, return false otherwise. 1943 */ 1944 @Override 1945 public boolean isCspPlmnEnabled() { 1946 return mCspPlmnEnabled; 1947 } 1948 1949 /** 1950 * Parse EF_CSP data and check if 1951 * "Restriction of menu options for manual PLMN selection" is 1952 * Enabled/Disabled 1953 * 1954 * @param data EF_CSP hex data. 1955 */ 1956 private void handleEfCspData(byte[] data) { 1957 // As per spec CPHS4_2.WW6, CPHS B.4.7.1, EF_CSP contains CPHS defined 1958 // 18 bytes (i.e 9 service groups info) and additional data specific to 1959 // operator. The valueAddedServicesGroup is not part of standard 1960 // services. This is operator specific and can be programmed any where. 1961 // Normally this is programmed as 10th service after the standard 1962 // services. 1963 int usedCspGroups = data.length / 2; 1964 // This is the "Service Group Number" of "Value Added Services Group". 1965 byte valueAddedServicesGroup = (byte)0xC0; 1966 1967 mCspPlmnEnabled = true; 1968 for (int i = 0; i < usedCspGroups; i++) { 1969 if (data[2 * i] == valueAddedServicesGroup) { 1970 log("[CSP] found ValueAddedServicesGroup, value " + data[(2 * i) + 1]); 1971 if ((data[(2 * i) + 1] & 0x80) == 0x80) { 1972 // Bit 8 is for 1973 // "Restriction of menu options for manual PLMN selection". 1974 // Operator Selection menu should be enabled. 1975 mCspPlmnEnabled = true; 1976 } else { 1977 mCspPlmnEnabled = false; 1978 // Operator Selection menu should be disabled. 1979 // Operator Selection Mode should be set to Automatic. 1980 log("[CSP] Set Automatic Network Selection"); 1981 mNetworkSelectionModeAutomaticRegistrants.notifyRegistrants(); 1982 } 1983 return; 1984 } 1985 } 1986 1987 log("[CSP] Value Added Service Group (0xC0), not found!"); 1988 } 1989 1990 @Override 1991 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1992 pw.println("SIMRecords: " + this); 1993 pw.println(" extends:"); 1994 super.dump(fd, pw, args); 1995 pw.println(" mVmConfig=" + mVmConfig); 1996 pw.println(" mSpnOverride=" + mSpnOverride); 1997 pw.println(" mCallForwardingStatus=" + mCallForwardingStatus); 1998 pw.println(" mSpnState=" + mSpnState); 1999 pw.println(" mCphsInfo=" + mCphsInfo); 2000 pw.println(" mCspPlmnEnabled=" + mCspPlmnEnabled); 2001 pw.println(" mEfMWIS[]=" + Arrays.toString(mEfMWIS)); 2002 pw.println(" mEfCPHS_MWI[]=" + Arrays.toString(mEfCPHS_MWI)); 2003 pw.println(" mEfCff[]=" + Arrays.toString(mEfCff)); 2004 pw.println(" mEfCfis[]=" + Arrays.toString(mEfCfis)); 2005 pw.println(" mSpnDisplayCondition=" + mSpnDisplayCondition); 2006 pw.println(" mSpdiNetworks[]=" + mSpdiNetworks); 2007 pw.println(" mPnnHomeName=" + mPnnHomeName); 2008 pw.println(" mUsimServiceTable=" + mUsimServiceTable); 2009 pw.println(" mGid1=" + mGid1); 2010 pw.println(" mGid2=" + mGid2); 2011 pw.flush(); 2012 } 2013} 2014