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