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