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