SIMRecords.java revision 5309535f4b6f83623b7d4edd9f5b1a8d53555066
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.gsm.SimTlv; 37import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState; 38import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType; 39 40import java.io.FileDescriptor; 41import java.io.PrintWriter; 42import java.util.ArrayList; 43import java.util.Arrays; 44 45/** 46 * {@hide} 47 */ 48public class SIMRecords extends IccRecords { 49 protected static final String LOG_TAG = "SIMRecords"; 50 51 private static final boolean CRASH_RIL = false; 52 53 // ***** Instance Variables 54 55 VoiceMailConstants mVmConfig; 56 57 58 SpnOverride mSpnOverride; 59 60 // ***** Cached SIM State; cleared on channel close 61 62 private int mCallForwardingStatus; 63 64 65 /** 66 * States only used by getSpnFsm FSM 67 */ 68 private GetSpnFsmState mSpnState; 69 70 /** CPHS service information (See CPHS 4.2 B.3.1.1) 71 * It will be set in onSimReady if reading GET_CPHS_INFO successfully 72 * mCphsInfo[0] is CPHS Phase 73 * mCphsInfo[1] and mCphsInfo[2] is CPHS Service Table 74 */ 75 private byte[] mCphsInfo = null; 76 boolean mCspPlmnEnabled = true; 77 78 byte[] mEfMWIS = null; 79 byte[] mEfCPHS_MWI =null; 80 byte[] mEfCff = null; 81 byte[] mEfCfis = null; 82 83 byte[] mEfLi = null; 84 byte[] mEfPl = null; 85 86 int mSpnDisplayCondition; 87 // Numeric network codes listed in TS 51.011 EF[SPDI] 88 ArrayList<String> mSpdiNetworks = null; 89 90 String mPnnHomeName = null; 91 92 UsimServiceTable mUsimServiceTable; 93 94 @Override 95 public String toString() { 96 return "SimRecords: " + super.toString() 97 + " mVmConfig" + mVmConfig 98 + " mSpnOverride=" + "mSpnOverride" 99 + " callForwardingEnabled=" + mCallForwardingStatus 100 + " spnState=" + mSpnState 101 + " mCphsInfo=" + mCphsInfo 102 + " mCspPlmnEnabled=" + mCspPlmnEnabled 103 + " efMWIS=" + mEfMWIS 104 + " efCPHS_MWI=" + mEfCPHS_MWI 105 + " mEfCff=" + mEfCff 106 + " mEfCfis=" + mEfCfis 107 + " getOperatorNumeric=" + getOperatorNumeric(); 108 } 109 110 // ***** Constants 111 112 // From TS 51.011 EF[SPDI] section 113 static final int TAG_SPDI = 0xA3; 114 static final int TAG_SPDI_PLMN_LIST = 0x80; 115 116 // Full Name IEI from TS 24.008 117 static final int TAG_FULL_NETWORK_NAME = 0x43; 118 119 // Short Name IEI from TS 24.008 120 static final int TAG_SHORT_NETWORK_NAME = 0x45; 121 122 // active CFF from CPHS 4.2 B.4.5 123 static final int CFF_UNCONDITIONAL_ACTIVE = 0x0a; 124 static final int CFF_UNCONDITIONAL_DEACTIVE = 0x05; 125 static final int CFF_LINE1_MASK = 0x0f; 126 static final int CFF_LINE1_RESET = 0xf0; 127 128 // CPHS Service Table (See CPHS 4.2 B.3.1) 129 private static final int CPHS_SST_MBN_MASK = 0x30; 130 private static final int CPHS_SST_MBN_ENABLED = 0x30; 131 132 // EF_CFIS related constants 133 // Spec reference TS 51.011 section 10.3.46. 134 private static final int CFIS_BCD_NUMBER_LENGTH_OFFSET = 2; 135 private static final int CFIS_TON_NPI_OFFSET = 3; 136 private static final int CFIS_ADN_CAPABILITY_ID_OFFSET = 14; 137 private static final int CFIS_ADN_EXTENSION_ID_OFFSET = 15; 138 139 // ***** Event Constants 140 private static final int SIM_RECORD_EVENT_BASE = 0x00; 141 private static final int EVENT_GET_IMSI_DONE = 3 + SIM_RECORD_EVENT_BASE; 142 private static final int EVENT_GET_ICCID_DONE = 4 + SIM_RECORD_EVENT_BASE; 143 private static final int EVENT_GET_MBI_DONE = 5 + SIM_RECORD_EVENT_BASE; 144 private static final int EVENT_GET_MBDN_DONE = 6 + SIM_RECORD_EVENT_BASE; 145 private static final int EVENT_GET_MWIS_DONE = 7 + SIM_RECORD_EVENT_BASE; 146 private static final int EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE = 8 + SIM_RECORD_EVENT_BASE; 147 private static final int EVENT_GET_AD_DONE = 9 + SIM_RECORD_EVENT_BASE; // Admin data on SIM 148 private static final int EVENT_GET_MSISDN_DONE = 10 + SIM_RECORD_EVENT_BASE; 149 private static final int EVENT_GET_CPHS_MAILBOX_DONE = 11 + SIM_RECORD_EVENT_BASE; 150 private static final int EVENT_GET_SPN_DONE = 12 + SIM_RECORD_EVENT_BASE; 151 private static final int EVENT_GET_SPDI_DONE = 13 + SIM_RECORD_EVENT_BASE; 152 private static final int EVENT_UPDATE_DONE = 14 + SIM_RECORD_EVENT_BASE; 153 private static final int EVENT_GET_PNN_DONE = 15 + SIM_RECORD_EVENT_BASE; 154 private static final int EVENT_GET_SST_DONE = 17 + SIM_RECORD_EVENT_BASE; 155 private static final int EVENT_GET_ALL_SMS_DONE = 18 + SIM_RECORD_EVENT_BASE; 156 private static final int EVENT_MARK_SMS_READ_DONE = 19 + SIM_RECORD_EVENT_BASE; 157 private static final int EVENT_SET_MBDN_DONE = 20 + SIM_RECORD_EVENT_BASE; 158 private static final int EVENT_SMS_ON_SIM = 21 + SIM_RECORD_EVENT_BASE; 159 private static final int EVENT_GET_SMS_DONE = 22 + SIM_RECORD_EVENT_BASE; 160 private static final int EVENT_GET_CFF_DONE = 24 + SIM_RECORD_EVENT_BASE; 161 private static final int EVENT_SET_CPHS_MAILBOX_DONE = 25 + SIM_RECORD_EVENT_BASE; 162 private static final int EVENT_GET_INFO_CPHS_DONE = 26 + SIM_RECORD_EVENT_BASE; 163 private static final int EVENT_SET_MSISDN_DONE = 30 + SIM_RECORD_EVENT_BASE; 164 private static final int EVENT_GET_CFIS_DONE = 32 + SIM_RECORD_EVENT_BASE; 165 private static final int EVENT_GET_CSP_CPHS_DONE = 33 + SIM_RECORD_EVENT_BASE; 166 private static final int EVENT_GET_GID1_DONE = 34 + SIM_RECORD_EVENT_BASE; 167 private static final int EVENT_GET_GID2_DONE = 36 + SIM_RECORD_EVENT_BASE; 168 169 // TODO: Possibly move these to IccRecords.java 170 private static final int SYSTEM_EVENT_BASE = 0x100; 171 private static final int EVENT_CARRIER_CONFIG_CHANGED = 1 + SYSTEM_EVENT_BASE; 172 private static final int EVENT_APP_LOCKED = 2 + SYSTEM_EVENT_BASE; 173 private static final int EVENT_SIM_REFRESH = 3 + SYSTEM_EVENT_BASE; 174 175 176 177 // Lookup table for carriers known to produce SIMs which incorrectly indicate MNC length. 178 179 private static final String[] MCCMNC_CODES_HAVING_3DIGITS_MNC = { 180 "302370", "302720", "310260", 181 "405025", "405026", "405027", "405028", "405029", "405030", "405031", "405032", 182 "405033", "405034", "405035", "405036", "405037", "405038", "405039", "405040", 183 "405041", "405042", "405043", "405044", "405045", "405046", "405047", "405750", 184 "405751", "405752", "405753", "405754", "405755", "405756", "405799", "405800", 185 "405801", "405802", "405803", "405804", "405805", "405806", "405807", "405808", 186 "405809", "405810", "405811", "405812", "405813", "405814", "405815", "405816", 187 "405817", "405818", "405819", "405820", "405821", "405822", "405823", "405824", 188 "405825", "405826", "405827", "405828", "405829", "405830", "405831", "405832", 189 "405833", "405834", "405835", "405836", "405837", "405838", "405839", "405840", 190 "405841", "405842", "405843", "405844", "405845", "405846", "405847", "405848", 191 "405849", "405850", "405851", "405852", "405853", "405854", "405855", "405856", 192 "405857", "405858", "405859", "405860", "405861", "405862", "405863", "405864", 193 "405865", "405866", "405867", "405868", "405869", "405870", "405871", "405872", 194 "405873", "405874", "405875", "405876", "405877", "405878", "405879", "405880", 195 "405881", "405882", "405883", "405884", "405885", "405886", "405908", "405909", 196 "405910", "405911", "405912", "405913", "405914", "405915", "405916", "405917", 197 "405918", "405919", "405920", "405921", "405922", "405923", "405924", "405925", 198 "405926", "405927", "405928", "405929", "405930", "405931", "405932", "502142", 199 "502143", "502145", "502146", "502147", "502148" 200 }; 201 202 // ***** Constructor 203 204 public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) { 205 super(app, c, ci); 206 207 mAdnCache = new AdnRecordCache(mFh); 208 209 mVmConfig = new VoiceMailConstants(); 210 mSpnOverride = new SpnOverride(); 211 212 mRecordsRequested = false; // No load request is made till SIM ready 213 214 // recordsToLoad is set to 0 because no requests are made yet 215 mRecordsToLoad = 0; 216 217 mCi.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null); 218 mCi.registerForIccRefresh(this, EVENT_SIM_REFRESH, null); 219 220 // Start off by setting empty state 221 resetRecords(); 222 mParentApp.registerForReady(this, EVENT_APP_READY, null); 223 mParentApp.registerForLocked(this, EVENT_APP_LOCKED, null); 224 if (DBG) log("SIMRecords X ctor this=" + this); 225 226 IntentFilter intentfilter = new IntentFilter(); 227 intentfilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 228 c.registerReceiver(mReceiver, intentfilter); 229 } 230 231 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 232 @Override 233 public void onReceive(Context context, Intent intent) { 234 if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { 235 sendMessage(obtainMessage(EVENT_CARRIER_CONFIG_CHANGED)); 236 } 237 } 238 }; 239 240 @Override 241 public void dispose() { 242 if (DBG) log("Disposing SIMRecords this=" + this); 243 //Unregister for all events 244 mCi.unregisterForIccRefresh(this); 245 mCi.unSetOnSmsOnSim(this); 246 mParentApp.unregisterForReady(this); 247 mParentApp.unregisterForLocked(this); 248 resetRecords(); 249 super.dispose(); 250 } 251 252 @Override 253 protected void finalize() { 254 if(DBG) log("finalized"); 255 } 256 257 protected void resetRecords() { 258 mImsi = null; 259 mMsisdn = null; 260 mVoiceMailNum = null; 261 mMncLength = UNINITIALIZED; 262 log("setting0 mMncLength" + mMncLength); 263 mIccId = null; 264 mFullIccId = null; 265 // -1 means no EF_SPN found; treat accordingly. 266 mSpnDisplayCondition = -1; 267 mEfMWIS = null; 268 mEfCPHS_MWI = null; 269 mSpdiNetworks = null; 270 mPnnHomeName = null; 271 mGid1 = null; 272 mGid2 = null; 273 274 mAdnCache.reset(); 275 276 log("SIMRecords: onRadioOffOrNotAvailable set 'gsm.sim.operator.numeric' to operator=null"); 277 log("update icc_operator_numeric=" + null); 278 mTelephonyManager.setSimOperatorNumericForPhone(mParentApp.getPhoneId(), ""); 279 mTelephonyManager.setSimOperatorNameForPhone(mParentApp.getPhoneId(), ""); 280 mTelephonyManager.setSimCountryIsoForPhone(mParentApp.getPhoneId(), ""); 281 282 // recordsRequested is set to false indicating that the SIM 283 // read requests made so far are not valid. This is set to 284 // true only when fresh set of read requests are made. 285 mRecordsRequested = false; 286 } 287 288 289 //***** Public Methods 290 291 /** 292 * {@inheritDoc} 293 */ 294 @Override 295 public String getIMSI() { 296 return mImsi; 297 } 298 299 @Override 300 public String getMsisdnNumber() { 301 return mMsisdn; 302 } 303 304 @Override 305 public String getGid1() { 306 return mGid1; 307 } 308 309 @Override 310 public String getGid2() { 311 return mGid2; 312 } 313 314 @Override 315 public UsimServiceTable getUsimServiceTable() { 316 return mUsimServiceTable; 317 } 318 319 private int getExtFromEf(int ef) { 320 int ext; 321 switch (ef) { 322 case EF_MSISDN: 323 /* For USIM apps use EXT5. (TS 31.102 Section 4.2.37) */ 324 if (mParentApp.getType() == AppType.APPTYPE_USIM) { 325 ext = EF_EXT5; 326 } else { 327 ext = EF_EXT1; 328 } 329 break; 330 default: 331 ext = EF_EXT1; 332 } 333 return ext; 334 } 335 336 /** 337 * Set subscriber number to SIM record 338 * 339 * The subscriber number is stored in EF_MSISDN (TS 51.011) 340 * 341 * When the operation is complete, onComplete will be sent to its handler 342 * 343 * @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters) 344 * @param number dailing nubmer (up to 20 digits) 345 * if the number starts with '+', then set to international TOA 346 * @param onComplete 347 * onComplete.obj will be an AsyncResult 348 * ((AsyncResult)onComplete.obj).exception == null on success 349 * ((AsyncResult)onComplete.obj).exception != null on fail 350 */ 351 @Override 352 public void setMsisdnNumber(String alphaTag, String number, 353 Message onComplete) { 354 355 // If the SIM card is locked by PIN, we will set EF_MSISDN fail. 356 // In that case, msisdn and msisdnTag should not be update. 357 mNewMsisdn = number; 358 mNewMsisdnTag = alphaTag; 359 360 if(DBG) log("Set MSISDN: " + mNewMsisdnTag + " " + /*mNewMsisdn*/ 361 Rlog.pii(LOG_TAG, mNewMsisdn)); 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 f1 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 logv("EF_CFIS: updating cf number, " + Rlog.pii(LOG_TAG, 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) + Rlog.pii(LOG_TAG, mImsi.substring(6))); 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*/ Rlog.pii(LOG_TAG, mMsisdn)); 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 mAdnCache.reset(); 1315 break; 1316 case EF_MSISDN: 1317 mRecordsToLoad++; 1318 log("SIM Refresh called for EF_MSISDN"); 1319 new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, getExtFromEf(EF_MSISDN), 1, 1320 obtainMessage(EVENT_GET_MSISDN_DONE)); 1321 break; 1322 case EF_CFIS: 1323 case EF_CFF_CPHS: 1324 log("SIM Refresh called for EF_CFIS or EF_CFF_CPHS"); 1325 loadCallForwardingRecords(); 1326 break; 1327 default: 1328 // For now, fetch all records if this is not a 1329 // voicemail number. 1330 // TODO: Handle other cases, instead of fetching all. 1331 mAdnCache.reset(); 1332 fetchSimRecords(); 1333 break; 1334 } 1335 } 1336 1337 private void handleSimRefresh(IccRefreshResponse refreshResponse){ 1338 if (refreshResponse == null) { 1339 if (DBG) log("handleSimRefresh received without input"); 1340 return; 1341 } 1342 1343 if (refreshResponse.aid != null && 1344 !refreshResponse.aid.equals(mParentApp.getAid())) { 1345 // This is for different app. Ignore. 1346 return; 1347 } 1348 1349 switch (refreshResponse.refreshResult) { 1350 case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE: 1351 if (DBG) log("handleSimRefresh with SIM_FILE_UPDATED"); 1352 handleFileUpdate(refreshResponse.efId); 1353 break; 1354 case IccRefreshResponse.REFRESH_RESULT_INIT: 1355 if (DBG) log("handleSimRefresh with SIM_REFRESH_INIT"); 1356 // need to reload all files (that we care about) 1357 onIccRefreshInit(); 1358 break; 1359 case IccRefreshResponse.REFRESH_RESULT_RESET: 1360 // Refresh reset is handled by the UiccCard object. 1361 if (DBG) log("handleSimRefresh with SIM_REFRESH_RESET"); 1362 break; 1363 default: 1364 // unknown refresh operation 1365 if (DBG) log("handleSimRefresh with unknown operation"); 1366 break; 1367 } 1368 } 1369 1370 /** 1371 * Dispatch 3GPP format message to registrant ({@code GsmCdmaPhone}) to pass to the 3GPP SMS 1372 * dispatcher for delivery. 1373 */ 1374 private int dispatchGsmMessage(SmsMessage message) { 1375 mNewSmsRegistrants.notifyResult(message); 1376 return 0; 1377 } 1378 1379 private void handleSms(byte[] ba) { 1380 if (ba[0] != 0) 1381 Rlog.d("ENF", "status : " + ba[0]); 1382 1383 // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 1384 // 3 == "received by MS from network; message to be read" 1385 if (ba[0] == 3) { 1386 int n = ba.length; 1387 1388 // Note: Data may include trailing FF's. That's OK; message 1389 // should still parse correctly. 1390 byte[] pdu = new byte[n - 1]; 1391 System.arraycopy(ba, 1, pdu, 0, n - 1); 1392 SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP); 1393 1394 dispatchGsmMessage(message); 1395 } 1396 } 1397 1398 1399 private void handleSmses(ArrayList<byte[]> messages) { 1400 int count = messages.size(); 1401 1402 for (int i = 0; i < count; i++) { 1403 byte[] ba = messages.get(i); 1404 1405 if (ba[0] != 0) 1406 Rlog.i("ENF", "status " + i + ": " + ba[0]); 1407 1408 // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 1409 // 3 == "received by MS from network; message to be read" 1410 1411 if (ba[0] == 3) { 1412 int n = ba.length; 1413 1414 // Note: Data may include trailing FF's. That's OK; message 1415 // should still parse correctly. 1416 byte[] pdu = new byte[n - 1]; 1417 System.arraycopy(ba, 1, pdu, 0, n - 1); 1418 SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP); 1419 1420 dispatchGsmMessage(message); 1421 1422 // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 1423 // 1 == "received by MS from network; message read" 1424 1425 ba[0] = 1; 1426 1427 if (false) { // FIXME: writing seems to crash RdoServD 1428 mFh.updateEFLinearFixed(EF_SMS, 1429 i, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, i)); 1430 } 1431 } 1432 } 1433 } 1434 1435 @Override 1436 protected void onRecordLoaded() { 1437 // One record loaded successfully or failed, In either case 1438 // we need to update the recordsToLoad count 1439 mRecordsToLoad -= 1; 1440 if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested); 1441 1442 if (mRecordsToLoad == 0 && mRecordsRequested == true) { 1443 onAllRecordsLoaded(); 1444 } else if (mRecordsToLoad < 0) { 1445 loge("recordsToLoad <0, programmer error suspected"); 1446 mRecordsToLoad = 0; 1447 } 1448 } 1449 1450 private void setVoiceCallForwardingFlagFromSimRecords() { 1451 if (validEfCfis(mEfCfis)) { 1452 // Refer TS 51.011 Section 10.3.46 for the content description 1453 mCallForwardingStatus = (mEfCfis[1] & 0x01); 1454 log("EF_CFIS: callForwardingEnabled=" + mCallForwardingStatus); 1455 } else if (mEfCff != null) { 1456 mCallForwardingStatus = 1457 ((mEfCff[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE) ? 1458 CALL_FORWARDING_STATUS_ENABLED : CALL_FORWARDING_STATUS_DISABLED; 1459 log("EF_CFF: callForwardingEnabled=" + mCallForwardingStatus); 1460 } else { 1461 mCallForwardingStatus = CALL_FORWARDING_STATUS_UNKNOWN; 1462 log("EF_CFIS and EF_CFF not valid. callForwardingEnabled=" + mCallForwardingStatus); 1463 } 1464 } 1465 1466 @Override 1467 protected void onAllRecordsLoaded() { 1468 if (DBG) log("record load complete"); 1469 1470 Resources resource = Resources.getSystem(); 1471 if (resource.getBoolean(com.android.internal.R.bool.config_use_sim_language_file)) { 1472 setSimLanguage(mEfLi, mEfPl); 1473 } else { 1474 if (DBG) log ("Not using EF LI/EF PL"); 1475 } 1476 1477 setVoiceCallForwardingFlagFromSimRecords(); 1478 1479 if (mParentApp.getState() == AppState.APPSTATE_PIN || 1480 mParentApp.getState() == AppState.APPSTATE_PUK) { 1481 // reset recordsRequested, since sim is not loaded really 1482 mRecordsRequested = false; 1483 // lock state, only update language 1484 return ; 1485 } 1486 1487 // Some fields require more than one SIM record to set 1488 1489 String operator = getOperatorNumeric(); 1490 if (!TextUtils.isEmpty(operator)) { 1491 log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" + 1492 operator + "'"); 1493 mTelephonyManager.setSimOperatorNumericForPhone( 1494 mParentApp.getPhoneId(), operator); 1495 } else { 1496 log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping"); 1497 } 1498 1499 if (!TextUtils.isEmpty(mImsi)) { 1500 log("onAllRecordsLoaded set mcc imsi" + (VDBG ? ("=" + mImsi) : "")); 1501 mTelephonyManager.setSimCountryIsoForPhone( 1502 mParentApp.getPhoneId(), MccTable.countryCodeForMcc( 1503 Integer.parseInt(mImsi.substring(0,3)))); 1504 } else { 1505 log("onAllRecordsLoaded empty imsi skipping setting mcc"); 1506 } 1507 1508 setVoiceMailByCountry(operator); 1509 1510 mRecordsLoadedRegistrants.notifyRegistrants( 1511 new AsyncResult(null, null, null)); 1512 } 1513 1514 //***** Private methods 1515 1516 private void handleCarrierNameOverride() { 1517 CarrierConfigManager configLoader = (CarrierConfigManager) 1518 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); 1519 if (configLoader != null && configLoader.getConfig().getBoolean( 1520 CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL)) { 1521 String carrierName = configLoader.getConfig().getString( 1522 CarrierConfigManager.KEY_CARRIER_NAME_STRING); 1523 setServiceProviderName(carrierName); 1524 mTelephonyManager.setSimOperatorNameForPhone(mParentApp.getPhoneId(), 1525 carrierName); 1526 } else { 1527 setSpnFromConfig(getOperatorNumeric()); 1528 } 1529 } 1530 1531 private void setSpnFromConfig(String carrier) { 1532 if (mSpnOverride.containsCarrier(carrier)) { 1533 setServiceProviderName(mSpnOverride.getSpn(carrier)); 1534 mTelephonyManager.setSimOperatorNameForPhone( 1535 mParentApp.getPhoneId(), getServiceProviderName()); 1536 } 1537 } 1538 1539 1540 private void setVoiceMailByCountry (String spn) { 1541 if (mVmConfig.containsCarrier(spn)) { 1542 mIsVoiceMailFixed = true; 1543 mVoiceMailNum = mVmConfig.getVoiceMailNumber(spn); 1544 mVoiceMailTag = mVmConfig.getVoiceMailTag(spn); 1545 } 1546 } 1547 1548 @Override 1549 public void onReady() { 1550 fetchSimRecords(); 1551 } 1552 1553 private void onLocked() { 1554 if (DBG) log("only fetch EF_LI and EF_PL in lock state"); 1555 loadEfLiAndEfPl(); 1556 } 1557 1558 private void loadEfLiAndEfPl() { 1559 if (mParentApp.getType() == AppType.APPTYPE_USIM) { 1560 mRecordsRequested = true; 1561 mFh.loadEFTransparent(EF_LI, 1562 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfUsimLiLoaded())); 1563 mRecordsToLoad++; 1564 1565 mFh.loadEFTransparent(EF_PL, 1566 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfPlLoaded())); 1567 mRecordsToLoad++; 1568 } 1569 } 1570 1571 private void loadCallForwardingRecords() { 1572 mRecordsRequested = true; 1573 mFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE)); 1574 mRecordsToLoad++; 1575 mFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE)); 1576 mRecordsToLoad++; 1577 } 1578 1579 protected void fetchSimRecords() { 1580 mRecordsRequested = true; 1581 1582 if (DBG) log("fetchSimRecords " + mRecordsToLoad); 1583 1584 mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE)); 1585 mRecordsToLoad++; 1586 1587 mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE)); 1588 mRecordsToLoad++; 1589 1590 // FIXME should examine EF[MSISDN]'s capability configuration 1591 // to determine which is the voice/data/fax line 1592 new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, getExtFromEf(EF_MSISDN), 1, 1593 obtainMessage(EVENT_GET_MSISDN_DONE)); 1594 mRecordsToLoad++; 1595 1596 // Record number is subscriber profile 1597 mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE)); 1598 mRecordsToLoad++; 1599 1600 mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE)); 1601 mRecordsToLoad++; 1602 1603 // Record number is subscriber profile 1604 mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE)); 1605 mRecordsToLoad++; 1606 1607 1608 // Also load CPHS-style voice mail indicator, which stores 1609 // the same info as EF[MWIS]. If both exist, both are updated 1610 // but the EF[MWIS] data is preferred 1611 // Please note this must be loaded after EF[MWIS] 1612 mFh.loadEFTransparent( 1613 EF_VOICE_MAIL_INDICATOR_CPHS, 1614 obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE)); 1615 mRecordsToLoad++; 1616 1617 // Same goes for Call Forward Status indicator: fetch both 1618 // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred. 1619 loadCallForwardingRecords(); 1620 1621 getSpnFsm(true, null); 1622 1623 mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE)); 1624 mRecordsToLoad++; 1625 1626 mFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE)); 1627 mRecordsToLoad++; 1628 1629 mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE)); 1630 mRecordsToLoad++; 1631 1632 mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE)); 1633 mRecordsToLoad++; 1634 1635 mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE)); 1636 mRecordsToLoad++; 1637 1638 mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE)); 1639 mRecordsToLoad++; 1640 1641 mFh.loadEFTransparent(EF_GID2, obtainMessage(EVENT_GET_GID2_DONE)); 1642 mRecordsToLoad++; 1643 1644 loadEfLiAndEfPl(); 1645 1646 // XXX should seek instead of examining them all 1647 if (false) { // XXX 1648 mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE)); 1649 mRecordsToLoad++; 1650 } 1651 1652 if (CRASH_RIL) { 1653 String sms = "0107912160130310f20404d0110041007030208054832b0120" 1654 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1655 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1656 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1657 + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 1658 + "ffffffffffffffffffffffffffffff"; 1659 byte[] ba = IccUtils.hexStringToBytes(sms); 1660 1661 mFh.updateEFLinearFixed(EF_SMS, 1, ba, null, 1662 obtainMessage(EVENT_MARK_SMS_READ_DONE, 1)); 1663 } 1664 if (DBG) log("fetchSimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested); 1665 } 1666 1667 /** 1668 * Returns the SpnDisplayRule based on settings on the SIM and the 1669 * specified plmn (currently-registered PLMN). See TS 22.101 Annex A 1670 * and TS 51.011 10.3.11 for details. 1671 * 1672 * If the SPN is not found on the SIM or is empty, the rule is 1673 * always PLMN_ONLY. 1674 */ 1675 @Override 1676 public int getDisplayRule(String plmn) { 1677 int rule; 1678 1679 if (mParentApp != null && mParentApp.getUiccCard() != null && 1680 mParentApp.getUiccCard().getOperatorBrandOverride() != null) { 1681 // If the operator has been overridden, treat it as the SPN file on the SIM did not exist. 1682 rule = SPN_RULE_SHOW_PLMN; 1683 } else if (TextUtils.isEmpty(getServiceProviderName()) || mSpnDisplayCondition == -1) { 1684 // No EF_SPN content was found on the SIM, or not yet loaded. Just show ONS. 1685 rule = SPN_RULE_SHOW_PLMN; 1686 } else if (isOnMatchingPlmn(plmn)) { 1687 rule = SPN_RULE_SHOW_SPN; 1688 if ((mSpnDisplayCondition & 0x01) == 0x01) { 1689 // ONS required when registered to HPLMN or PLMN in EF_SPDI 1690 rule |= SPN_RULE_SHOW_PLMN; 1691 } 1692 } else { 1693 rule = SPN_RULE_SHOW_PLMN; 1694 if ((mSpnDisplayCondition & 0x02) == 0x00) { 1695 // SPN required if not registered to HPLMN or PLMN in EF_SPDI 1696 rule |= SPN_RULE_SHOW_SPN; 1697 } 1698 } 1699 return rule; 1700 } 1701 1702 /** 1703 * Checks if plmn is HPLMN or on the spdiNetworks list. 1704 */ 1705 private boolean isOnMatchingPlmn(String plmn) { 1706 if (plmn == null) return false; 1707 1708 if (plmn.equals(getOperatorNumeric())) { 1709 return true; 1710 } 1711 1712 if (mSpdiNetworks != null) { 1713 for (String spdiNet : mSpdiNetworks) { 1714 if (plmn.equals(spdiNet)) { 1715 return true; 1716 } 1717 } 1718 } 1719 return false; 1720 } 1721 1722 /** 1723 * States of Get SPN Finite State Machine which only used by getSpnFsm() 1724 */ 1725 private enum GetSpnFsmState { 1726 IDLE, // No initialized 1727 INIT, // Start FSM 1728 READ_SPN_3GPP, // Load EF_SPN firstly 1729 READ_SPN_CPHS, // Load EF_SPN_CPHS secondly 1730 READ_SPN_SHORT_CPHS // Load EF_SPN_SHORT_CPHS last 1731 } 1732 1733 /** 1734 * Finite State Machine to load Service Provider Name , which can be stored 1735 * in either EF_SPN (3GPP), EF_SPN_CPHS, or EF_SPN_SHORT_CPHS (CPHS4.2) 1736 * 1737 * After starting, FSM will search SPN EFs in order and stop after finding 1738 * the first valid SPN 1739 * 1740 * If the FSM gets restart while waiting for one of 1741 * SPN EFs results (i.e. a SIM refresh occurs after issuing 1742 * read EF_CPHS_SPN), it will re-initialize only after 1743 * receiving and discarding the unfinished SPN EF result. 1744 * 1745 * @param start set true only for initialize loading 1746 * @param ar the AsyncResult from loadEFTransparent 1747 * ar.exception holds exception in error 1748 * ar.result is byte[] for data in success 1749 */ 1750 private void getSpnFsm(boolean start, AsyncResult ar) { 1751 byte[] data; 1752 1753 if (start) { 1754 // Check previous state to see if there is outstanding 1755 // SPN read 1756 if(mSpnState == GetSpnFsmState.READ_SPN_3GPP || 1757 mSpnState == GetSpnFsmState.READ_SPN_CPHS || 1758 mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS || 1759 mSpnState == GetSpnFsmState.INIT) { 1760 // Set INIT then return so the INIT code 1761 // will run when the outstanding read done. 1762 mSpnState = GetSpnFsmState.INIT; 1763 return; 1764 } else { 1765 mSpnState = GetSpnFsmState.INIT; 1766 } 1767 } 1768 1769 switch(mSpnState){ 1770 case INIT: 1771 setServiceProviderName(null); 1772 1773 mFh.loadEFTransparent(EF_SPN, 1774 obtainMessage(EVENT_GET_SPN_DONE)); 1775 mRecordsToLoad++; 1776 1777 mSpnState = GetSpnFsmState.READ_SPN_3GPP; 1778 break; 1779 case READ_SPN_3GPP: 1780 if (ar != null && ar.exception == null) { 1781 data = (byte[]) ar.result; 1782 mSpnDisplayCondition = 0xff & data[0]; 1783 1784 setServiceProviderName(IccUtils.adnStringFieldToString( 1785 data, 1, data.length - 1)); 1786 // for card double-check and brand override 1787 // we have to do this: 1788 final String spn = getServiceProviderName(); 1789 1790 if (spn == null || spn.length() == 0) { 1791 mSpnState = GetSpnFsmState.READ_SPN_CPHS; 1792 } else { 1793 if (DBG) log("Load EF_SPN: " + spn 1794 + " spnDisplayCondition: " + mSpnDisplayCondition); 1795 mTelephonyManager.setSimOperatorNameForPhone( 1796 mParentApp.getPhoneId(), spn); 1797 1798 mSpnState = GetSpnFsmState.IDLE; 1799 } 1800 } else { 1801 mSpnState = GetSpnFsmState.READ_SPN_CPHS; 1802 } 1803 1804 if (mSpnState == GetSpnFsmState.READ_SPN_CPHS) { 1805 mFh.loadEFTransparent( EF_SPN_CPHS, 1806 obtainMessage(EVENT_GET_SPN_DONE)); 1807 mRecordsToLoad++; 1808 1809 // See TS 51.011 10.3.11. Basically, default to 1810 // show PLMN always, and SPN also if roaming. 1811 mSpnDisplayCondition = -1; 1812 } 1813 break; 1814 case READ_SPN_CPHS: 1815 if (ar != null && ar.exception == null) { 1816 data = (byte[]) ar.result; 1817 1818 setServiceProviderName(IccUtils.adnStringFieldToString( 1819 data, 0, data.length)); 1820 // for card double-check and brand override 1821 // we have to do this: 1822 final String spn = getServiceProviderName(); 1823 1824 if (spn == null || spn.length() == 0) { 1825 mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS; 1826 } else { 1827 // Display CPHS Operator Name only when not roaming 1828 mSpnDisplayCondition = 2; 1829 1830 if (DBG) log("Load EF_SPN_CPHS: " + spn); 1831 mTelephonyManager.setSimOperatorNameForPhone( 1832 mParentApp.getPhoneId(), spn); 1833 1834 mSpnState = GetSpnFsmState.IDLE; 1835 } 1836 } else { 1837 mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS; 1838 } 1839 1840 if (mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS) { 1841 mFh.loadEFTransparent( 1842 EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE)); 1843 mRecordsToLoad++; 1844 } 1845 break; 1846 case READ_SPN_SHORT_CPHS: 1847 if (ar != null && ar.exception == null) { 1848 data = (byte[]) ar.result; 1849 1850 setServiceProviderName(IccUtils.adnStringFieldToString( 1851 data, 0, data.length)); 1852 // for card double-check and brand override 1853 // we have to do this: 1854 final String spn = getServiceProviderName(); 1855 1856 if (spn == null || spn.length() == 0) { 1857 if (DBG) log("No SPN loaded in either CHPS or 3GPP"); 1858 } else { 1859 // Display CPHS Operator Name only when not roaming 1860 mSpnDisplayCondition = 2; 1861 1862 if (DBG) log("Load EF_SPN_SHORT_CPHS: " + spn); 1863 mTelephonyManager.setSimOperatorNameForPhone( 1864 mParentApp.getPhoneId(), spn); 1865 } 1866 } else { 1867 setServiceProviderName(null); 1868 if (DBG) log("No SPN loaded in either CHPS or 3GPP"); 1869 } 1870 1871 mSpnState = GetSpnFsmState.IDLE; 1872 break; 1873 default: 1874 mSpnState = GetSpnFsmState.IDLE; 1875 } 1876 } 1877 1878 /** 1879 * Parse TS 51.011 EF[SPDI] record 1880 * This record contains the list of numeric network IDs that 1881 * are treated specially when determining SPN display 1882 */ 1883 private void 1884 parseEfSpdi(byte[] data) { 1885 SimTlv tlv = new SimTlv(data, 0, data.length); 1886 1887 byte[] plmnEntries = null; 1888 1889 for ( ; tlv.isValidObject() ; tlv.nextObject()) { 1890 // Skip SPDI tag, if existant 1891 if (tlv.getTag() == TAG_SPDI) { 1892 tlv = new SimTlv(tlv.getData(), 0, tlv.getData().length); 1893 } 1894 // There should only be one TAG_SPDI_PLMN_LIST 1895 if (tlv.getTag() == TAG_SPDI_PLMN_LIST) { 1896 plmnEntries = tlv.getData(); 1897 break; 1898 } 1899 } 1900 1901 if (plmnEntries == null) { 1902 return; 1903 } 1904 1905 mSpdiNetworks = new ArrayList<String>(plmnEntries.length / 3); 1906 1907 for (int i = 0 ; i + 2 < plmnEntries.length ; i += 3) { 1908 String plmnCode; 1909 plmnCode = IccUtils.bcdToString(plmnEntries, i, 3); 1910 1911 // Valid operator codes are 5 or 6 digits 1912 if (plmnCode.length() >= 5) { 1913 log("EF_SPDI network: " + plmnCode); 1914 mSpdiNetworks.add(plmnCode); 1915 } 1916 } 1917 } 1918 1919 /** 1920 * check to see if Mailbox Number is allocated and activated in CPHS SST 1921 */ 1922 private boolean isCphsMailboxEnabled() { 1923 if (mCphsInfo == null) return false; 1924 return ((mCphsInfo[1] & CPHS_SST_MBN_MASK) == CPHS_SST_MBN_ENABLED ); 1925 } 1926 1927 @Override 1928 protected void log(String s) { 1929 Rlog.d(LOG_TAG, "[SIMRecords] " + s); 1930 } 1931 1932 @Override 1933 protected void loge(String s) { 1934 Rlog.e(LOG_TAG, "[SIMRecords] " + s); 1935 } 1936 1937 protected void logw(String s, Throwable tr) { 1938 Rlog.w(LOG_TAG, "[SIMRecords] " + s, tr); 1939 } 1940 1941 protected void logv(String s) { 1942 Rlog.v(LOG_TAG, "[SIMRecords] " + s); 1943 } 1944 1945 /** 1946 * Return true if "Restriction of menu options for manual PLMN selection" 1947 * bit is set or EF_CSP data is unavailable, return false otherwise. 1948 */ 1949 @Override 1950 public boolean isCspPlmnEnabled() { 1951 return mCspPlmnEnabled; 1952 } 1953 1954 /** 1955 * Parse EF_CSP data and check if 1956 * "Restriction of menu options for manual PLMN selection" is 1957 * Enabled/Disabled 1958 * 1959 * @param data EF_CSP hex data. 1960 */ 1961 private void handleEfCspData(byte[] data) { 1962 // As per spec CPHS4_2.WW6, CPHS B.4.7.1, EF_CSP contains CPHS defined 1963 // 18 bytes (i.e 9 service groups info) and additional data specific to 1964 // operator. The valueAddedServicesGroup is not part of standard 1965 // services. This is operator specific and can be programmed any where. 1966 // Normally this is programmed as 10th service after the standard 1967 // services. 1968 int usedCspGroups = data.length / 2; 1969 // This is the "Service Group Number" of "Value Added Services Group". 1970 byte valueAddedServicesGroup = (byte)0xC0; 1971 1972 mCspPlmnEnabled = true; 1973 for (int i = 0; i < usedCspGroups; i++) { 1974 if (data[2 * i] == valueAddedServicesGroup) { 1975 log("[CSP] found ValueAddedServicesGroup, value " + data[(2 * i) + 1]); 1976 if ((data[(2 * i) + 1] & 0x80) == 0x80) { 1977 // Bit 8 is for 1978 // "Restriction of menu options for manual PLMN selection". 1979 // Operator Selection menu should be enabled. 1980 mCspPlmnEnabled = true; 1981 } else { 1982 mCspPlmnEnabled = false; 1983 // Operator Selection menu should be disabled. 1984 // Operator Selection Mode should be set to Automatic. 1985 log("[CSP] Set Automatic Network Selection"); 1986 mNetworkSelectionModeAutomaticRegistrants.notifyRegistrants(); 1987 } 1988 return; 1989 } 1990 } 1991 1992 log("[CSP] Value Added Service Group (0xC0), not found!"); 1993 } 1994 1995 @Override 1996 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1997 pw.println("SIMRecords: " + this); 1998 pw.println(" extends:"); 1999 super.dump(fd, pw, args); 2000 pw.println(" mVmConfig=" + mVmConfig); 2001 pw.println(" mSpnOverride=" + mSpnOverride); 2002 pw.println(" mCallForwardingStatus=" + mCallForwardingStatus); 2003 pw.println(" mSpnState=" + mSpnState); 2004 pw.println(" mCphsInfo=" + mCphsInfo); 2005 pw.println(" mCspPlmnEnabled=" + mCspPlmnEnabled); 2006 pw.println(" mEfMWIS[]=" + Arrays.toString(mEfMWIS)); 2007 pw.println(" mEfCPHS_MWI[]=" + Arrays.toString(mEfCPHS_MWI)); 2008 pw.println(" mEfCff[]=" + Arrays.toString(mEfCff)); 2009 pw.println(" mEfCfis[]=" + Arrays.toString(mEfCfis)); 2010 pw.println(" mSpnDisplayCondition=" + mSpnDisplayCondition); 2011 pw.println(" mSpdiNetworks[]=" + mSpdiNetworks); 2012 pw.println(" mPnnHomeName=" + mPnnHomeName); 2013 pw.println(" mUsimServiceTable=" + mUsimServiceTable); 2014 pw.println(" mGid1=" + mGid1); 2015 pw.println(" mGid2=" + mGid2); 2016 pw.flush(); 2017 } 2018} 2019