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