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