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