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