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