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