RuimRecords.java revision 0764b3df0fdd465c260fc2180b0243194e7b1f31
1/* 2 * Copyright (C) 2008 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 19 20import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY; 21import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC; 22 23import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA; 24import static com.android.internal.telephony.TelephonyProperties.PROPERTY_TEST_CSIM; 25 26import java.io.FileDescriptor; 27import java.io.PrintWriter; 28import java.util.ArrayList; 29import java.util.Arrays; 30import java.util.Locale; 31import android.content.Context; 32import android.os.AsyncResult; 33import android.os.Message; 34import android.os.SystemProperties; 35import android.telephony.Rlog; 36import android.text.TextUtils; 37 38import com.android.internal.telephony.CommandsInterface; 39import com.android.internal.telephony.GsmAlphabet; 40import com.android.internal.telephony.MccTable; 41 42import com.android.internal.telephony.cdma.sms.UserData; 43import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType; 44 45 46/** 47 * {@hide} 48 */ 49public final class RuimRecords extends IccRecords { 50 static final String LOG_TAG = "RuimRecords"; 51 52 private boolean mOtaCommited=false; 53 54 // ***** Instance Variables 55 56 private String mMyMobileNumber; 57 private String mMin2Min1; 58 59 private String mPrlVersion; 60 // From CSIM application 61 private byte[] mEFpl = null; 62 private byte[] mEFli = null; 63 boolean mCsimSpnDisplayCondition = false; 64 private String mMdn; 65 private String mMin; 66 private String mHomeSystemId; 67 private String mHomeNetworkId; 68 69 @Override 70 public String toString() { 71 return "RuimRecords: " + super.toString() 72 + " m_ota_commited" + mOtaCommited 73 + " mMyMobileNumber=" + "xxxx" 74 + " mMin2Min1=" + mMin2Min1 75 + " mPrlVersion=" + mPrlVersion 76 + " mEFpl=" + mEFpl 77 + " mEFli=" + mEFli 78 + " mCsimSpnDisplayCondition=" + mCsimSpnDisplayCondition 79 + " mMdn=" + mMdn 80 + " mMin=" + mMin 81 + " mHomeSystemId=" + mHomeSystemId 82 + " mHomeNetworkId=" + mHomeNetworkId; 83 } 84 85 // ***** Event Constants 86 private static final int EVENT_GET_IMSI_DONE = 3; 87 private static final int EVENT_GET_DEVICE_IDENTITY_DONE = 4; 88 private static final int EVENT_GET_ICCID_DONE = 5; 89 private static final int EVENT_GET_CDMA_SUBSCRIPTION_DONE = 10; 90 private static final int EVENT_UPDATE_DONE = 14; 91 private static final int EVENT_GET_SST_DONE = 17; 92 private static final int EVENT_GET_ALL_SMS_DONE = 18; 93 private static final int EVENT_MARK_SMS_READ_DONE = 19; 94 95 private static final int EVENT_SMS_ON_RUIM = 21; 96 private static final int EVENT_GET_SMS_DONE = 22; 97 98 private static final int EVENT_RUIM_REFRESH = 31; 99 100 public RuimRecords(UiccCardApplication app, Context c, CommandsInterface ci) { 101 super(app, c, ci); 102 103 mAdnCache = new AdnRecordCache(mFh); 104 105 mRecordsRequested = false; // No load request is made till SIM ready 106 107 // recordsToLoad is set to 0 because no requests are made yet 108 mRecordsToLoad = 0; 109 110 // NOTE the EVENT_SMS_ON_RUIM is not registered 111 mCi.registerForIccRefresh(this, EVENT_RUIM_REFRESH, null); 112 113 // Start off by setting empty state 114 resetRecords(); 115 116 mParentApp.registerForReady(this, EVENT_APP_READY, null); 117 if (DBG) log("RuimRecords X ctor this=" + this); 118 } 119 120 @Override 121 public void dispose() { 122 if (DBG) log("Disposing RuimRecords " + this); 123 //Unregister for all events 124 mCi.unregisterForIccRefresh(this); 125 mParentApp.unregisterForReady(this); 126 resetRecords(); 127 super.dispose(); 128 } 129 130 @Override 131 protected void finalize() { 132 if(DBG) log("RuimRecords finalized"); 133 } 134 135 protected void resetRecords() { 136 mCountVoiceMessages = 0; 137 mMncLength = UNINITIALIZED; 138 mIccId = null; 139 140 mAdnCache.reset(); 141 142 // Don't clean up PROPERTY_ICC_OPERATOR_ISO_COUNTRY and 143 // PROPERTY_ICC_OPERATOR_NUMERIC here. Since not all CDMA 144 // devices have RUIM, these properties should keep the original 145 // values, e.g. build time settings, when there is no RUIM but 146 // set new values when RUIM is available and loaded. 147 148 // recordsRequested is set to false indicating that the SIM 149 // read requests made so far are not valid. This is set to 150 // true only when fresh set of read requests are made. 151 mRecordsRequested = false; 152 } 153 154 @Override 155 public String getIMSI() { 156 return mImsi; 157 } 158 159 public String getMdnNumber() { 160 return mMyMobileNumber; 161 } 162 163 public String getCdmaMin() { 164 return mMin2Min1; 165 } 166 167 /** Returns null if RUIM is not yet ready */ 168 public String getPrlVersion() { 169 return mPrlVersion; 170 } 171 172 @Override 173 public void setVoiceMailNumber(String alphaTag, String voiceNumber, Message onComplete){ 174 // In CDMA this is Operator/OEM dependent 175 AsyncResult.forMessage((onComplete)).exception = 176 new IccException("setVoiceMailNumber not implemented"); 177 onComplete.sendToTarget(); 178 loge("method setVoiceMailNumber is not implemented"); 179 } 180 181 /** 182 * Called by CCAT Service when REFRESH is received. 183 * @param fileChanged indicates whether any files changed 184 * @param fileList if non-null, a list of EF files that changed 185 */ 186 @Override 187 public void onRefresh(boolean fileChanged, int[] fileList) { 188 if (fileChanged) { 189 // A future optimization would be to inspect fileList and 190 // only reload those files that we care about. For now, 191 // just re-fetch all RUIM records that we cache. 192 fetchRuimRecords(); 193 } 194 } 195 196 private int adjstMinDigits (int digits) { 197 // Per C.S0005 section 2.3.1. 198 digits += 111; 199 digits = (digits % 10 == 0)?(digits - 10):digits; 200 digits = ((digits / 10) % 10 == 0)?(digits - 100):digits; 201 digits = ((digits / 100) % 10 == 0)?(digits - 1000):digits; 202 return digits; 203 } 204 205 /** 206 * Returns the 5 or 6 digit MCC/MNC of the operator that 207 * provided the RUIM card. Returns null of RUIM is not yet ready 208 */ 209 public String getRUIMOperatorNumeric() { 210 if (mImsi == null) { 211 return null; 212 } 213 214 if (mMncLength != UNINITIALIZED && mMncLength != UNKNOWN) { 215 // Length = length of MCC + length of MNC 216 // length of mcc = 3 (3GPP2 C.S0005 - Section 2.3) 217 return mImsi.substring(0, 3 + mMncLength); 218 } 219 220 // Guess the MNC length based on the MCC if we don't 221 // have a valid value in ef[ad] 222 223 int mcc = Integer.parseInt(mImsi.substring(0,3)); 224 return mImsi.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc)); 225 } 226 227 // Refer to ETSI TS 102.221 228 private class EfPlLoaded implements IccRecordLoaded { 229 @Override 230 public String getEfName() { 231 return "EF_PL"; 232 } 233 234 @Override 235 public void onRecordLoaded(AsyncResult ar) { 236 mEFpl = (byte[]) ar.result; 237 if (DBG) log("EF_PL=" + IccUtils.bytesToHexString(mEFpl)); 238 } 239 } 240 241 // Refer to C.S0065 5.2.26 242 private class EfCsimLiLoaded implements IccRecordLoaded { 243 @Override 244 public String getEfName() { 245 return "EF_CSIM_LI"; 246 } 247 248 @Override 249 public void onRecordLoaded(AsyncResult ar) { 250 mEFli = (byte[]) ar.result; 251 // convert csim efli data to iso 639 format 252 for (int i = 0; i < mEFli.length; i+=2) { 253 switch(mEFli[i+1]) { 254 case 0x01: mEFli[i] = 'e'; mEFli[i+1] = 'n';break; 255 case 0x02: mEFli[i] = 'f'; mEFli[i+1] = 'r';break; 256 case 0x03: mEFli[i] = 'e'; mEFli[i+1] = 's';break; 257 case 0x04: mEFli[i] = 'j'; mEFli[i+1] = 'a';break; 258 case 0x05: mEFli[i] = 'k'; mEFli[i+1] = 'o';break; 259 case 0x06: mEFli[i] = 'z'; mEFli[i+1] = 'h';break; 260 case 0x07: mEFli[i] = 'h'; mEFli[i+1] = 'e';break; 261 default: mEFli[i] = ' '; mEFli[i+1] = ' '; 262 } 263 } 264 265 if (DBG) log("EF_LI=" + IccUtils.bytesToHexString(mEFli)); 266 } 267 } 268 269 // Refer to C.S0065 5.2.32 270 private class EfCsimSpnLoaded implements IccRecordLoaded { 271 @Override 272 public String getEfName() { 273 return "EF_CSIM_SPN"; 274 } 275 276 @Override 277 public void onRecordLoaded(AsyncResult ar) { 278 byte[] data = (byte[]) ar.result; 279 if (DBG) log("CSIM_SPN=" + 280 IccUtils.bytesToHexString(data)); 281 282 // C.S0065 for EF_SPN decoding 283 mCsimSpnDisplayCondition = ((0x01 & data[0]) != 0); 284 285 int encoding = data[1]; 286 int language = data[2]; 287 byte[] spnData = new byte[32]; 288 int len = ((data.length - 3) < 32) ? (data.length - 3) : 32; 289 System.arraycopy(data, 3, spnData, 0, len); 290 291 int numBytes; 292 for (numBytes = 0; numBytes < spnData.length; numBytes++) { 293 if ((spnData[numBytes] & 0xFF) == 0xFF) break; 294 } 295 296 if (numBytes == 0) { 297 mSpn = ""; 298 return; 299 } 300 try { 301 switch (encoding) { 302 case UserData.ENCODING_OCTET: 303 case UserData.ENCODING_LATIN: 304 mSpn = new String(spnData, 0, numBytes, "ISO-8859-1"); 305 break; 306 case UserData.ENCODING_IA5: 307 case UserData.ENCODING_GSM_7BIT_ALPHABET: 308 mSpn = GsmAlphabet.gsm7BitPackedToString(spnData, 0, (numBytes*8)/7); 309 break; 310 case UserData.ENCODING_7BIT_ASCII: 311 mSpn = new String(spnData, 0, numBytes, "US-ASCII"); 312 break; 313 case UserData.ENCODING_UNICODE_16: 314 mSpn = new String(spnData, 0, numBytes, "utf-16"); 315 break; 316 default: 317 log("SPN encoding not supported"); 318 } 319 } catch(Exception e) { 320 log("spn decode error: " + e); 321 } 322 if (DBG) log("spn=" + mSpn); 323 if (DBG) log("spnCondition=" + mCsimSpnDisplayCondition); 324 SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, mSpn); 325 } 326 } 327 328 private class EfCsimMdnLoaded implements IccRecordLoaded { 329 @Override 330 public String getEfName() { 331 return "EF_CSIM_MDN"; 332 } 333 334 @Override 335 public void onRecordLoaded(AsyncResult ar) { 336 byte[] data = (byte[]) ar.result; 337 if (DBG) log("CSIM_MDN=" + IccUtils.bytesToHexString(data)); 338 // Refer to C.S0065 5.2.35 339 int mdnDigitsNum = 0x0F & data[0]; 340 mMdn = IccUtils.cdmaBcdToString(data, 1, mdnDigitsNum); 341 if (DBG) log("CSIM MDN=" + mMdn); 342 } 343 } 344 345 private class EfCsimImsimLoaded implements IccRecordLoaded { 346 @Override 347 public String getEfName() { 348 return "EF_CSIM_IMSIM"; 349 } 350 351 @Override 352 public void onRecordLoaded(AsyncResult ar) { 353 byte[] data = (byte[]) ar.result; 354 if (DBG) log("CSIM_IMSIM=" + IccUtils.bytesToHexString(data)); 355 // C.S0065 section 5.2.2 for IMSI_M encoding 356 // C.S0005 section 2.3.1 for MIN encoding in IMSI_M. 357 boolean provisioned = ((data[7] & 0x80) == 0x80); 358 359 if (provisioned) { 360 int first3digits = ((0x03 & data[2]) << 8) + (0xFF & data[1]); 361 int second3digits = (((0xFF & data[5]) << 8) | (0xFF & data[4])) >> 6; 362 int digit7 = 0x0F & (data[4] >> 2); 363 if (digit7 > 0x09) digit7 = 0; 364 int last3digits = ((0x03 & data[4]) << 8) | (0xFF & data[3]); 365 first3digits = adjstMinDigits(first3digits); 366 second3digits = adjstMinDigits(second3digits); 367 last3digits = adjstMinDigits(last3digits); 368 369 StringBuilder builder = new StringBuilder(); 370 builder.append(String.format(Locale.US, "%03d", first3digits)); 371 builder.append(String.format(Locale.US, "%03d", second3digits)); 372 builder.append(String.format(Locale.US, "%d", digit7)); 373 builder.append(String.format(Locale.US, "%03d", last3digits)); 374 mMin = builder.toString(); 375 if (DBG) log("min present=" + mMin); 376 } else { 377 if (DBG) log("min not present"); 378 } 379 } 380 } 381 382 private class EfCsimCdmaHomeLoaded implements IccRecordLoaded { 383 @Override 384 public String getEfName() { 385 return "EF_CSIM_CDMAHOME"; 386 } 387 388 @Override 389 public void onRecordLoaded(AsyncResult ar) { 390 // Per C.S0065 section 5.2.8 391 ArrayList<byte[]> dataList = (ArrayList<byte[]>) ar.result; 392 if (DBG) log("CSIM_CDMAHOME data size=" + dataList.size()); 393 if (dataList.isEmpty()) { 394 return; 395 } 396 StringBuilder sidBuf = new StringBuilder(); 397 StringBuilder nidBuf = new StringBuilder(); 398 399 for (byte[] data : dataList) { 400 if (data.length == 5) { 401 int sid = ((data[1] & 0xFF) << 8) | (data[0] & 0xFF); 402 int nid = ((data[3] & 0xFF) << 8) | (data[2] & 0xFF); 403 sidBuf.append(sid).append(','); 404 nidBuf.append(nid).append(','); 405 } 406 } 407 // remove trailing "," 408 sidBuf.setLength(sidBuf.length()-1); 409 nidBuf.setLength(nidBuf.length()-1); 410 411 mHomeSystemId = sidBuf.toString(); 412 mHomeNetworkId = nidBuf.toString(); 413 } 414 } 415 416 private class EfCsimEprlLoaded implements IccRecordLoaded { 417 @Override 418 public String getEfName() { 419 return "EF_CSIM_EPRL"; 420 } 421 @Override 422 public void onRecordLoaded(AsyncResult ar) { 423 onGetCSimEprlDone(ar); 424 } 425 } 426 427 private void onGetCSimEprlDone(AsyncResult ar) { 428 // C.S0065 section 5.2.57 for EFeprl encoding 429 // C.S0016 section 3.5.5 for PRL format. 430 byte[] data = (byte[]) ar.result; 431 if (DBG) log("CSIM_EPRL=" + IccUtils.bytesToHexString(data)); 432 433 // Only need the first 4 bytes of record 434 if (data.length > 3) { 435 int prlId = ((data[2] & 0xFF) << 8) | (data[3] & 0xFF); 436 mPrlVersion = Integer.toString(prlId); 437 } 438 if (DBG) log("CSIM PRL version=" + mPrlVersion); 439 } 440 441 @Override 442 public void handleMessage(Message msg) { 443 AsyncResult ar; 444 445 byte data[]; 446 447 boolean isRecordLoadResponse = false; 448 449 if (mDestroyed.get()) { 450 loge("Received message " + msg + 451 "[" + msg.what + "] while being destroyed. Ignoring."); 452 return; 453 } 454 455 try { switch (msg.what) { 456 case EVENT_APP_READY: 457 onReady(); 458 break; 459 460 case EVENT_GET_DEVICE_IDENTITY_DONE: 461 log("Event EVENT_GET_DEVICE_IDENTITY_DONE Received"); 462 break; 463 464 /* IO events */ 465 case EVENT_GET_IMSI_DONE: 466 isRecordLoadResponse = true; 467 468 ar = (AsyncResult)msg.obj; 469 if (ar.exception != null) { 470 loge("Exception querying IMSI, Exception:" + ar.exception); 471 break; 472 } 473 474 mImsi = (String) ar.result; 475 476 // IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more 477 // than 15 (and usually 15). 478 if (mImsi != null && (mImsi.length() < 6 || mImsi.length() > 15)) { 479 loge("invalid IMSI " + mImsi); 480 mImsi = null; 481 } 482 483 log("IMSI: " + mImsi.substring(0, 6) + "xxxxxxxxx"); 484 485 String operatorNumeric = getRUIMOperatorNumeric(); 486 if (operatorNumeric != null) { 487 if(operatorNumeric.length() <= 6){ 488 MccTable.updateMccMncConfiguration(mContext, operatorNumeric, false); 489 } 490 } 491 break; 492 493 case EVENT_GET_CDMA_SUBSCRIPTION_DONE: 494 ar = (AsyncResult)msg.obj; 495 String localTemp[] = (String[])ar.result; 496 if (ar.exception != null) { 497 break; 498 } 499 500 mMyMobileNumber = localTemp[0]; 501 mMin2Min1 = localTemp[3]; 502 mPrlVersion = localTemp[4]; 503 504 log("MDN: " + mMyMobileNumber + " MIN: " + mMin2Min1); 505 506 break; 507 508 case EVENT_GET_ICCID_DONE: 509 isRecordLoadResponse = true; 510 511 ar = (AsyncResult)msg.obj; 512 data = (byte[])ar.result; 513 514 if (ar.exception != null) { 515 break; 516 } 517 518 mIccId = IccUtils.bcdToString(data, 0, data.length); 519 520 log("iccid: " + mIccId); 521 522 break; 523 524 case EVENT_UPDATE_DONE: 525 ar = (AsyncResult)msg.obj; 526 if (ar.exception != null) { 527 Rlog.i(LOG_TAG, "RuimRecords update failed", ar.exception); 528 } 529 break; 530 531 case EVENT_GET_ALL_SMS_DONE: 532 case EVENT_MARK_SMS_READ_DONE: 533 case EVENT_SMS_ON_RUIM: 534 case EVENT_GET_SMS_DONE: 535 Rlog.w(LOG_TAG, "Event not supported: " + msg.what); 536 break; 537 538 // TODO: probably EF_CST should be read instead 539 case EVENT_GET_SST_DONE: 540 log("Event EVENT_GET_SST_DONE Received"); 541 break; 542 543 case EVENT_RUIM_REFRESH: 544 isRecordLoadResponse = false; 545 ar = (AsyncResult)msg.obj; 546 if (ar.exception == null) { 547 handleRuimRefresh((IccRefreshResponse)ar.result); 548 } 549 break; 550 551 default: 552 super.handleMessage(msg); // IccRecords handles generic record load responses 553 554 }}catch (RuntimeException exc) { 555 // I don't want these exceptions to be fatal 556 Rlog.w(LOG_TAG, "Exception parsing RUIM record", exc); 557 } finally { 558 // Count up record load responses even if they are fails 559 if (isRecordLoadResponse) { 560 onRecordLoaded(); 561 } 562 } 563 } 564 565 private String findBestLanguage(byte[] languages) { 566 String bestMatch = null; 567 String[] locales = mContext.getAssets().getLocales(); 568 569 if ((languages == null) || (locales == null)) return null; 570 571 // Each 2-bytes consists of one language 572 for (int i = 0; (i + 1) < languages.length; i += 2) { 573 try { 574 String lang = new String(languages, i, 2, "ISO-8859-1"); 575 for (int j = 0; j < locales.length; j++) { 576 if (locales[j] != null && locales[j].length() >= 2 && 577 locales[j].substring(0, 2).equals(lang)) { 578 return lang; 579 } 580 } 581 if (bestMatch != null) break; 582 } catch(java.io.UnsupportedEncodingException e) { 583 log ("Failed to parse SIM language records"); 584 } 585 } 586 // no match found. return null 587 return null; 588 } 589 590 private void setLocaleFromCsim() { 591 String prefLang = null; 592 // check EFli then EFpl 593 prefLang = findBestLanguage(mEFli); 594 595 if (prefLang == null) { 596 prefLang = findBestLanguage(mEFpl); 597 } 598 599 if (prefLang != null) { 600 // check country code from SIM 601 String imsi = getIMSI(); 602 String country = null; 603 if (imsi != null) { 604 country = MccTable.countryCodeForMcc( 605 Integer.parseInt(imsi.substring(0,3))); 606 } 607 log("Setting locale to " + prefLang + "_" + country); 608 MccTable.setSystemLocale(mContext, prefLang, country); 609 } else { 610 log ("No suitable CSIM selected locale"); 611 } 612 } 613 614 @Override 615 protected void onRecordLoaded() { 616 // One record loaded successfully or failed, In either case 617 // we need to update the recordsToLoad count 618 mRecordsToLoad -= 1; 619 if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested); 620 621 if (mRecordsToLoad == 0 && mRecordsRequested == true) { 622 onAllRecordsLoaded(); 623 } else if (mRecordsToLoad < 0) { 624 loge("recordsToLoad <0, programmer error suspected"); 625 mRecordsToLoad = 0; 626 } 627 } 628 629 @Override 630 protected void onAllRecordsLoaded() { 631 if (DBG) log("record load complete"); 632 633 // Further records that can be inserted are Operator/OEM dependent 634 635 String operator = getRUIMOperatorNumeric(); 636 if (!TextUtils.isEmpty(operator)) { 637 log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" + 638 operator + "'"); 639 SystemProperties.set(PROPERTY_ICC_OPERATOR_NUMERIC, operator); 640 } else { 641 log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping"); 642 } 643 644 if (!TextUtils.isEmpty(mImsi)) { 645 log("onAllRecordsLoaded set mcc imsi=" + mImsi); 646 SystemProperties.set(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, 647 MccTable.countryCodeForMcc(Integer.parseInt(mImsi.substring(0,3)))); 648 } else { 649 log("onAllRecordsLoaded empty imsi skipping setting mcc"); 650 } 651 652 setLocaleFromCsim(); 653 mRecordsLoadedRegistrants.notifyRegistrants( 654 new AsyncResult(null, null, null)); 655 } 656 657 @Override 658 public void onReady() { 659 fetchRuimRecords(); 660 661 mCi.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE)); 662 } 663 664 665 private void fetchRuimRecords() { 666 mRecordsRequested = true; 667 668 if (DBG) log("fetchRuimRecords " + mRecordsToLoad); 669 670 mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE)); 671 mRecordsToLoad++; 672 673 mFh.loadEFTransparent(EF_ICCID, 674 obtainMessage(EVENT_GET_ICCID_DONE)); 675 mRecordsToLoad++; 676 677 mFh.loadEFTransparent(EF_PL, 678 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfPlLoaded())); 679 mRecordsToLoad++; 680 681 mFh.loadEFTransparent(EF_CSIM_LI, 682 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimLiLoaded())); 683 mRecordsToLoad++; 684 685 mFh.loadEFTransparent(EF_CSIM_SPN, 686 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimSpnLoaded())); 687 mRecordsToLoad++; 688 689 mFh.loadEFLinearFixed(EF_CSIM_MDN, 1, 690 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimMdnLoaded())); 691 mRecordsToLoad++; 692 693 mFh.loadEFTransparent(EF_CSIM_IMSIM, 694 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimImsimLoaded())); 695 mRecordsToLoad++; 696 697 mFh.loadEFLinearFixedAll(EF_CSIM_CDMAHOME, 698 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimCdmaHomeLoaded())); 699 mRecordsToLoad++; 700 701 // Entire PRL could be huge. We are only interested in 702 // the first 4 bytes of the record. 703 mFh.loadEFTransparent(EF_CSIM_EPRL, 4, 704 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimEprlLoaded())); 705 mRecordsToLoad++; 706 707 if (DBG) log("fetchRuimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested); 708 // Further records that can be inserted are Operator/OEM dependent 709 } 710 711 /** 712 * {@inheritDoc} 713 * 714 * No Display rule for RUIMs yet. 715 */ 716 @Override 717 public int getDisplayRule(String plmn) { 718 // TODO together with spn 719 return 0; 720 } 721 722 @Override 723 public boolean isProvisioned() { 724 // If UICC card has CSIM app, look for MDN and MIN field 725 // to determine if the SIM is provisioned. Otherwise, 726 // consider the SIM is provisioned. (for case of ordinal 727 // USIM only UICC.) 728 // If PROPERTY_TEST_CSIM is defined, bypess provision check 729 // and consider the SIM is provisioned. 730 if (SystemProperties.getBoolean(PROPERTY_TEST_CSIM, false)) { 731 return true; 732 } 733 734 if (mParentApp == null) { 735 return false; 736 } 737 738 if (mParentApp.getType() == AppType.APPTYPE_CSIM && 739 ((mMdn == null) || (mMin == null))) { 740 return false; 741 } 742 return true; 743 } 744 745 @Override 746 public void setVoiceMessageWaiting(int line, int countWaiting) { 747 if (line != 1) { 748 // only profile 1 is supported 749 return; 750 } 751 752 // range check 753 if (countWaiting < 0) { 754 countWaiting = -1; 755 } else if (countWaiting > 0xff) { 756 // C.S0015-B v2, 4.5.12 757 // range: 0-99 758 countWaiting = 0xff; 759 } 760 mCountVoiceMessages = countWaiting; 761 762 mRecordsEventsRegistrants.notifyResult(EVENT_MWI); 763 } 764 765 private void handleRuimRefresh(IccRefreshResponse refreshResponse) { 766 if (refreshResponse == null) { 767 if (DBG) log("handleRuimRefresh received without input"); 768 return; 769 } 770 771 if (refreshResponse.aid != null && 772 !refreshResponse.aid.equals(mParentApp.getAid())) { 773 // This is for different app. Ignore. 774 return; 775 } 776 777 switch (refreshResponse.refreshResult) { 778 case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE: 779 if (DBG) log("handleRuimRefresh with SIM_REFRESH_FILE_UPDATED"); 780 mAdnCache.reset(); 781 fetchRuimRecords(); 782 break; 783 case IccRefreshResponse.REFRESH_RESULT_INIT: 784 if (DBG) log("handleRuimRefresh with SIM_REFRESH_INIT"); 785 // need to reload all files (that we care about) 786 onIccRefreshInit(); 787 break; 788 case IccRefreshResponse.REFRESH_RESULT_RESET: 789 if (DBG) log("handleRuimRefresh with SIM_REFRESH_RESET"); 790 mCi.setRadioPower(false, null); 791 /* Note: no need to call setRadioPower(true). Assuming the desired 792 * radio power state is still ON (as tracked by ServiceStateTracker), 793 * ServiceStateTracker will call setRadioPower when it receives the 794 * RADIO_STATE_CHANGED notification for the power off. And if the 795 * desired power state has changed in the interim, we don't want to 796 * override it with an unconditional power on. 797 */ 798 break; 799 default: 800 // unknown refresh operation 801 if (DBG) log("handleRuimRefresh with unknown operation"); 802 break; 803 } 804 } 805 806 public String getMdn() { 807 return mMdn; 808 } 809 810 public String getMin() { 811 return mMin; 812 } 813 814 public String getSid() { 815 return mHomeSystemId; 816 } 817 818 public String getNid() { 819 return mHomeNetworkId; 820 } 821 822 public boolean getCsimSpnDisplayCondition() { 823 return mCsimSpnDisplayCondition; 824 } 825 @Override 826 protected void log(String s) { 827 Rlog.d(LOG_TAG, "[RuimRecords] " + s); 828 } 829 830 @Override 831 protected void loge(String s) { 832 Rlog.e(LOG_TAG, "[RuimRecords] " + s); 833 } 834 835 @Override 836 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 837 pw.println("RuimRecords: " + this); 838 pw.println(" extends:"); 839 super.dump(fd, pw, args); 840 pw.println(" mOtaCommited=" + mOtaCommited); 841 pw.println(" mMyMobileNumber=" + mMyMobileNumber); 842 pw.println(" mMin2Min1=" + mMin2Min1); 843 pw.println(" mPrlVersion=" + mPrlVersion); 844 pw.println(" mEFpl[]=" + Arrays.toString(mEFpl)); 845 pw.println(" mEFli[]=" + Arrays.toString(mEFli)); 846 pw.println(" mCsimSpnDisplayCondition=" + mCsimSpnDisplayCondition); 847 pw.println(" mMdn=" + mMdn); 848 pw.println(" mMin=" + mMin); 849 pw.println(" mHomeSystemId=" + mHomeSystemId); 850 pw.println(" mHomeNetworkId=" + mHomeNetworkId); 851 pw.flush(); 852 } 853} 854