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