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