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