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