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