1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony; 18 19 import static android.Manifest.permission.READ_PHONE_STATE; 20 import android.app.ActivityManagerNative; 21 import android.content.Intent; 22 import android.os.AsyncResult; 23 import android.os.Handler; 24 import android.os.Message; 25 import android.os.Registrant; 26 import android.os.RegistrantList; 27 import android.util.Log; 28 29 import com.android.internal.telephony.PhoneBase; 30 import com.android.internal.telephony.CommandsInterface.RadioState; 31 32 /** 33 * {@hide} 34 */ 35 public abstract class IccCard { 36 protected String mLogTag; 37 protected boolean mDbg; 38 39 private IccCardStatus mIccCardStatus = null; 40 protected State mState = null; 41 protected PhoneBase mPhone; 42 private RegistrantList mAbsentRegistrants = new RegistrantList(); 43 private RegistrantList mPinLockedRegistrants = new RegistrantList(); 44 private RegistrantList mNetworkLockedRegistrants = new RegistrantList(); 45 46 private boolean mDesiredPinLocked; 47 private boolean mDesiredFdnEnabled; 48 private boolean mIccPinLocked = true; // Default to locked 49 private boolean mIccFdnEnabled = false; // Default to disabled. 50 // Will be updated when SIM_READY. 51 52 53 /* The extra data for broacasting intent INTENT_ICC_STATE_CHANGE */ 54 static public final String INTENT_KEY_ICC_STATE = "ss"; 55 /* NOT_READY means the ICC interface is not ready (eg, radio is off or powering on) */ 56 static public final String INTENT_VALUE_ICC_NOT_READY = "NOT_READY"; 57 /* ABSENT means ICC is missing */ 58 static public final String INTENT_VALUE_ICC_ABSENT = "ABSENT"; 59 /* LOCKED means ICC is locked by pin or by network */ 60 static public final String INTENT_VALUE_ICC_LOCKED = "LOCKED"; 61 /* READY means ICC is ready to access */ 62 static public final String INTENT_VALUE_ICC_READY = "READY"; 63 /* IMSI means ICC IMSI is ready in property */ 64 static public final String INTENT_VALUE_ICC_IMSI = "IMSI"; 65 /* LOADED means all ICC records, including IMSI, are loaded */ 66 static public final String INTENT_VALUE_ICC_LOADED = "LOADED"; 67 /* The extra data for broacasting intent INTENT_ICC_STATE_CHANGE */ 68 static public final String INTENT_KEY_LOCKED_REASON = "reason"; 69 /* PIN means ICC is locked on PIN1 */ 70 static public final String INTENT_VALUE_LOCKED_ON_PIN = "PIN"; 71 /* PUK means ICC is locked on PUK1 */ 72 static public final String INTENT_VALUE_LOCKED_ON_PUK = "PUK"; 73 /* NETWORK means ICC is locked on NETWORK PERSONALIZATION */ 74 static public final String INTENT_VALUE_LOCKED_NETWORK = "NETWORK"; 75 76 protected static final int EVENT_ICC_LOCKED_OR_ABSENT = 1; 77 private static final int EVENT_GET_ICC_STATUS_DONE = 2; 78 protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3; 79 private static final int EVENT_PINPUK_DONE = 4; 80 private static final int EVENT_REPOLL_STATUS_DONE = 5; 81 protected static final int EVENT_ICC_READY = 6; 82 private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7; 83 private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8; 84 private static final int EVENT_CHANGE_ICC_PASSWORD_DONE = 9; 85 private static final int EVENT_QUERY_FACILITY_FDN_DONE = 10; 86 private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11; 87 88 /* 89 UNKNOWN is a transient state, for example, after uesr inputs ICC pin under 90 PIN_REQUIRED state, the query for ICC status returns UNKNOWN before it 91 turns to READY 92 */ 93 public enum State { 94 UNKNOWN, 95 ABSENT, 96 PIN_REQUIRED, 97 PUK_REQUIRED, 98 NETWORK_LOCKED, 99 READY, 100 NOT_READY; 101 102 public boolean isPinLocked() { 103 return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED)); 104 } 105 } 106 107 public State getState() { 108 if (mState == null) { 109 switch(mPhone.mCM.getRadioState()) { 110 /* This switch block must not return anything in 111 * State.isLocked() or State.ABSENT. 112 * If it does, handleSimStatus() may break 113 */ 114 case RADIO_OFF: 115 case RADIO_UNAVAILABLE: 116 case SIM_NOT_READY: 117 case RUIM_NOT_READY: 118 return State.UNKNOWN; 119 case SIM_LOCKED_OR_ABSENT: 120 case RUIM_LOCKED_OR_ABSENT: 121 //this should be transient-only 122 return State.UNKNOWN; 123 case SIM_READY: 124 case RUIM_READY: 125 case NV_READY: 126 return State.READY; 127 case NV_NOT_READY: 128 return State.ABSENT; 129 } 130 } else { 131 return mState; 132 } 133 134 Log.e(mLogTag, "IccCard.getState(): case should never be reached"); 135 return State.UNKNOWN; 136 } 137 138 public IccCard(PhoneBase phone, String logTag, Boolean dbg) { 139 mPhone = phone; 140 mLogTag = logTag; 141 mDbg = dbg; 142 } 143 144 abstract public void dispose(); 145 146 protected void finalize() { 147 if(mDbg) Log.d(mLogTag, "IccCard finalized"); 148 } 149 150 /** 151 * Notifies handler of any transition into State.ABSENT 152 */ 153 public void registerForAbsent(Handler h, int what, Object obj) { 154 Registrant r = new Registrant (h, what, obj); 155 156 mAbsentRegistrants.add(r); 157 158 if (getState() == State.ABSENT) { 159 r.notifyRegistrant(); 160 } 161 } 162 163 public void unregisterForAbsent(Handler h) { 164 mAbsentRegistrants.remove(h); 165 } 166 167 /** 168 * Notifies handler of any transition into State.NETWORK_LOCKED 169 */ 170 public void registerForNetworkLocked(Handler h, int what, Object obj) { 171 Registrant r = new Registrant (h, what, obj); 172 173 mNetworkLockedRegistrants.add(r); 174 175 if (getState() == State.NETWORK_LOCKED) { 176 r.notifyRegistrant(); 177 } 178 } 179 180 public void unregisterForNetworkLocked(Handler h) { 181 mNetworkLockedRegistrants.remove(h); 182 } 183 184 /** 185 * Notifies handler of any transition into State.isPinLocked() 186 */ 187 public void registerForLocked(Handler h, int what, Object obj) { 188 Registrant r = new Registrant (h, what, obj); 189 190 mPinLockedRegistrants.add(r); 191 192 if (getState().isPinLocked()) { 193 r.notifyRegistrant(); 194 } 195 } 196 197 public void unregisterForLocked(Handler h) { 198 mPinLockedRegistrants.remove(h); 199 } 200 201 202 /** 203 * Supply the ICC PIN to the ICC 204 * 205 * When the operation is complete, onComplete will be sent to its 206 * Handler. 207 * 208 * onComplete.obj will be an AsyncResult 209 * 210 * ((AsyncResult)onComplete.obj).exception == null on success 211 * ((AsyncResult)onComplete.obj).exception != null on fail 212 * 213 * If the supplied PIN is incorrect: 214 * ((AsyncResult)onComplete.obj).exception != null 215 * && ((AsyncResult)onComplete.obj).exception 216 * instanceof com.android.internal.telephony.gsm.CommandException) 217 * && ((CommandException)(((AsyncResult)onComplete.obj).exception)) 218 * .getCommandError() == CommandException.Error.PASSWORD_INCORRECT 219 * 220 * 221 */ 222 223 public void supplyPin (String pin, Message onComplete) { 224 mPhone.mCM.supplyIccPin(pin, mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); 225 } 226 227 public void supplyPuk (String puk, String newPin, Message onComplete) { 228 mPhone.mCM.supplyIccPuk(puk, newPin, 229 mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); 230 } 231 232 public void supplyPin2 (String pin2, Message onComplete) { 233 mPhone.mCM.supplyIccPin2(pin2, 234 mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); 235 } 236 237 public void supplyPuk2 (String puk2, String newPin2, Message onComplete) { 238 mPhone.mCM.supplyIccPuk2(puk2, newPin2, 239 mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); 240 } 241 242 public void supplyNetworkDepersonalization (String pin, Message onComplete) { 243 if(mDbg) log("Network Despersonalization: " + pin); 244 mPhone.mCM.supplyNetworkDepersonalization(pin, 245 mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); 246 } 247 248 /** 249 * Check whether ICC pin lock is enabled 250 * This is a sync call which returns the cached pin enabled state 251 * 252 * @return true for ICC locked enabled 253 * false for ICC locked disabled 254 */ 255 public boolean getIccLockEnabled() { 256 return mIccPinLocked; 257 } 258 259 /** 260 * Check whether ICC fdn (fixed dialing number) is enabled 261 * This is a sync call which returns the cached pin enabled state 262 * 263 * @return true for ICC fdn enabled 264 * false for ICC fdn disabled 265 */ 266 public boolean getIccFdnEnabled() { 267 return mIccFdnEnabled; 268 } 269 270 /** 271 * Set the ICC pin lock enabled or disabled 272 * When the operation is complete, onComplete will be sent to its handler 273 * 274 * @param enabled "true" for locked "false" for unlocked. 275 * @param password needed to change the ICC pin state, aka. Pin1 276 * @param onComplete 277 * onComplete.obj will be an AsyncResult 278 * ((AsyncResult)onComplete.obj).exception == null on success 279 * ((AsyncResult)onComplete.obj).exception != null on fail 280 */ 281 public void setIccLockEnabled (boolean enabled, 282 String password, Message onComplete) { 283 int serviceClassX; 284 serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + 285 CommandsInterface.SERVICE_CLASS_DATA + 286 CommandsInterface.SERVICE_CLASS_FAX; 287 288 mDesiredPinLocked = enabled; 289 290 mPhone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM, 291 enabled, password, serviceClassX, 292 mHandler.obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete)); 293 } 294 295 /** 296 * Set the ICC fdn enabled or disabled 297 * When the operation is complete, onComplete will be sent to its handler 298 * 299 * @param enabled "true" for locked "false" for unlocked. 300 * @param password needed to change the ICC fdn enable, aka Pin2 301 * @param onComplete 302 * onComplete.obj will be an AsyncResult 303 * ((AsyncResult)onComplete.obj).exception == null on success 304 * ((AsyncResult)onComplete.obj).exception != null on fail 305 */ 306 public void setIccFdnEnabled (boolean enabled, 307 String password, Message onComplete) { 308 int serviceClassX; 309 serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + 310 CommandsInterface.SERVICE_CLASS_DATA + 311 CommandsInterface.SERVICE_CLASS_FAX + 312 CommandsInterface.SERVICE_CLASS_SMS; 313 314 mDesiredFdnEnabled = enabled; 315 316 mPhone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD, 317 enabled, password, serviceClassX, 318 mHandler.obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete)); 319 } 320 321 /** 322 * Change the ICC password used in ICC pin lock 323 * When the operation is complete, onComplete will be sent to its handler 324 * 325 * @param oldPassword is the old password 326 * @param newPassword is the new password 327 * @param onComplete 328 * onComplete.obj will be an AsyncResult 329 * ((AsyncResult)onComplete.obj).exception == null on success 330 * ((AsyncResult)onComplete.obj).exception != null on fail 331 */ 332 public void changeIccLockPassword(String oldPassword, String newPassword, 333 Message onComplete) { 334 if(mDbg) log("Change Pin1 old: " + oldPassword + " new: " + newPassword); 335 mPhone.mCM.changeIccPin(oldPassword, newPassword, 336 mHandler.obtainMessage(EVENT_CHANGE_ICC_PASSWORD_DONE, onComplete)); 337 338 } 339 340 /** 341 * Change the ICC password used in ICC fdn enable 342 * When the operation is complete, onComplete will be sent to its handler 343 * 344 * @param oldPassword is the old password 345 * @param newPassword is the new password 346 * @param onComplete 347 * onComplete.obj will be an AsyncResult 348 * ((AsyncResult)onComplete.obj).exception == null on success 349 * ((AsyncResult)onComplete.obj).exception != null on fail 350 */ 351 public void changeIccFdnPassword(String oldPassword, String newPassword, 352 Message onComplete) { 353 if(mDbg) log("Change Pin2 old: " + oldPassword + " new: " + newPassword); 354 mPhone.mCM.changeIccPin2(oldPassword, newPassword, 355 mHandler.obtainMessage(EVENT_CHANGE_ICC_PASSWORD_DONE, onComplete)); 356 357 } 358 359 360 /** 361 * Returns service provider name stored in ICC card. 362 * If there is no service provider name associated or the record is not 363 * yet available, null will be returned <p> 364 * 365 * Please use this value when display Service Provider Name in idle mode <p> 366 * 367 * Usage of this provider name in the UI is a common carrier requirement. 368 * 369 * Also available via Android property "gsm.sim.operator.alpha" 370 * 371 * @return Service Provider Name stored in ICC card 372 * null if no service provider name associated or the record is not 373 * yet available 374 * 375 */ 376 public abstract String getServiceProviderName(); 377 378 protected void updateStateProperty() { 379 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_SIM_STATE, getState().toString()); 380 } 381 382 private void getIccCardStatusDone(AsyncResult ar) { 383 if (ar.exception != null) { 384 Log.e(mLogTag,"Error getting ICC status. " 385 + "RIL_REQUEST_GET_ICC_STATUS should " 386 + "never return an error", ar.exception); 387 return; 388 } 389 handleIccCardStatus((IccCardStatus) ar.result); 390 } 391 392 private void handleIccCardStatus(IccCardStatus newCardStatus) { 393 boolean transitionedIntoPinLocked; 394 boolean transitionedIntoAbsent; 395 boolean transitionedIntoNetworkLocked; 396 397 State oldState, newState; 398 399 oldState = mState; 400 mIccCardStatus = newCardStatus; 401 newState = getIccCardState(); 402 mState = newState; 403 404 updateStateProperty(); 405 406 transitionedIntoPinLocked = ( 407 (oldState != State.PIN_REQUIRED && newState == State.PIN_REQUIRED) 408 || (oldState != State.PUK_REQUIRED && newState == State.PUK_REQUIRED)); 409 transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT); 410 transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED 411 && newState == State.NETWORK_LOCKED); 412 413 if (transitionedIntoPinLocked) { 414 if(mDbg) log("Notify SIM pin or puk locked."); 415 mPinLockedRegistrants.notifyRegistrants(); 416 broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED, 417 (newState == State.PIN_REQUIRED) ? 418 INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK); 419 } else if (transitionedIntoAbsent) { 420 if(mDbg) log("Notify SIM missing."); 421 mAbsentRegistrants.notifyRegistrants(); 422 broadcastIccStateChangedIntent(INTENT_VALUE_ICC_ABSENT, null); 423 } else if (transitionedIntoNetworkLocked) { 424 if(mDbg) log("Notify SIM network locked."); 425 mNetworkLockedRegistrants.notifyRegistrants(); 426 broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED, 427 INTENT_VALUE_LOCKED_NETWORK); 428 } 429 } 430 431 /** 432 * Interperate EVENT_QUERY_FACILITY_LOCK_DONE 433 * @param ar is asyncResult of Query_Facility_Locked 434 */ 435 private void onQueryFdnEnabled(AsyncResult ar) { 436 if(ar.exception != null) { 437 if(mDbg) log("Error in querying facility lock:" + ar.exception); 438 return; 439 } 440 441 int[] ints = (int[])ar.result; 442 if(ints.length != 0) { 443 mIccFdnEnabled = (0!=ints[0]); 444 if(mDbg) log("Query facility lock : " + mIccFdnEnabled); 445 } else { 446 Log.e(mLogTag, "[IccCard] Bogus facility lock response"); 447 } 448 } 449 450 /** 451 * Interperate EVENT_QUERY_FACILITY_LOCK_DONE 452 * @param ar is asyncResult of Query_Facility_Locked 453 */ 454 private void onQueryFacilityLock(AsyncResult ar) { 455 if(ar.exception != null) { 456 if (mDbg) log("Error in querying facility lock:" + ar.exception); 457 return; 458 } 459 460 int[] ints = (int[])ar.result; 461 if(ints.length != 0) { 462 mIccPinLocked = (0!=ints[0]); 463 if(mDbg) log("Query facility lock : " + mIccPinLocked); 464 } else { 465 Log.e(mLogTag, "[IccCard] Bogus facility lock response"); 466 } 467 } 468 469 public void broadcastIccStateChangedIntent(String value, String reason) { 470 Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 471 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 472 intent.putExtra(Phone.PHONE_NAME_KEY, mPhone.getPhoneName()); 473 intent.putExtra(INTENT_KEY_ICC_STATE, value); 474 intent.putExtra(INTENT_KEY_LOCKED_REASON, reason); 475 if(mDbg) log("Broadcasting intent ACTION_SIM_STATE_CHANGED " + value 476 + " reason " + reason); 477 ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE); 478 } 479 480 protected Handler mHandler = new Handler() { 481 @Override 482 public void handleMessage(Message msg){ 483 AsyncResult ar; 484 int serviceClassX; 485 486 serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + 487 CommandsInterface.SERVICE_CLASS_DATA + 488 CommandsInterface.SERVICE_CLASS_FAX; 489 490 switch (msg.what) { 491 case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: 492 mState = null; 493 updateStateProperty(); 494 broadcastIccStateChangedIntent(INTENT_VALUE_ICC_NOT_READY, null); 495 break; 496 case EVENT_ICC_READY: 497 //TODO: put facility read in SIM_READY now, maybe in REG_NW 498 mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE)); 499 mPhone.mCM.queryFacilityLock ( 500 CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, 501 obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); 502 mPhone.mCM.queryFacilityLock ( 503 CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX, 504 obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE)); 505 break; 506 case EVENT_ICC_LOCKED_OR_ABSENT: 507 mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE)); 508 mPhone.mCM.queryFacilityLock ( 509 CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, 510 obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); 511 break; 512 case EVENT_GET_ICC_STATUS_DONE: 513 ar = (AsyncResult)msg.obj; 514 515 getIccCardStatusDone(ar); 516 break; 517 case EVENT_PINPUK_DONE: 518 // a PIN/PUK/PIN2/PUK2/Network Personalization 519 // request has completed. ar.userObj is the response Message 520 // Repoll before returning 521 ar = (AsyncResult)msg.obj; 522 // TODO should abstract these exceptions 523 AsyncResult.forMessage(((Message)ar.userObj)).exception 524 = ar.exception; 525 mPhone.mCM.getIccCardStatus( 526 obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj)); 527 break; 528 case EVENT_REPOLL_STATUS_DONE: 529 // Finished repolling status after PIN operation 530 // ar.userObj is the response messaeg 531 // ar.userObj.obj is already an AsyncResult with an 532 // appropriate exception filled in if applicable 533 534 ar = (AsyncResult)msg.obj; 535 getIccCardStatusDone(ar); 536 ((Message)ar.userObj).sendToTarget(); 537 break; 538 case EVENT_QUERY_FACILITY_LOCK_DONE: 539 ar = (AsyncResult)msg.obj; 540 onQueryFacilityLock(ar); 541 break; 542 case EVENT_QUERY_FACILITY_FDN_DONE: 543 ar = (AsyncResult)msg.obj; 544 onQueryFdnEnabled(ar); 545 break; 546 case EVENT_CHANGE_FACILITY_LOCK_DONE: 547 ar = (AsyncResult)msg.obj; 548 if (ar.exception == null) { 549 mIccPinLocked = mDesiredPinLocked; 550 if (mDbg) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " + 551 "mIccPinLocked= " + mIccPinLocked); 552 } else { 553 Log.e(mLogTag, "Error change facility lock with exception " 554 + ar.exception); 555 } 556 AsyncResult.forMessage(((Message)ar.userObj)).exception 557 = ar.exception; 558 ((Message)ar.userObj).sendToTarget(); 559 break; 560 case EVENT_CHANGE_FACILITY_FDN_DONE: 561 ar = (AsyncResult)msg.obj; 562 563 if (ar.exception == null) { 564 mIccFdnEnabled = mDesiredFdnEnabled; 565 if (mDbg) log("EVENT_CHANGE_FACILITY_FDN_DONE: " + 566 "mIccFdnEnabled=" + mIccFdnEnabled); 567 } else { 568 Log.e(mLogTag, "Error change facility fdn with exception " 569 + ar.exception); 570 } 571 AsyncResult.forMessage(((Message)ar.userObj)).exception 572 = ar.exception; 573 ((Message)ar.userObj).sendToTarget(); 574 break; 575 case EVENT_CHANGE_ICC_PASSWORD_DONE: 576 ar = (AsyncResult)msg.obj; 577 if(ar.exception != null) { 578 Log.e(mLogTag, "Error in change sim password with exception" 579 + ar.exception); 580 } 581 AsyncResult.forMessage(((Message)ar.userObj)).exception 582 = ar.exception; 583 ((Message)ar.userObj).sendToTarget(); 584 break; 585 default: 586 Log.e(mLogTag, "[IccCard] Unknown Event " + msg.what); 587 } 588 } 589 }; 590 591 public State getIccCardState() { 592 if (mIccCardStatus == null) { 593 Log.e(mLogTag, "[IccCard] IccCardStatus is null"); 594 return IccCard.State.ABSENT; 595 } 596 597 // this is common for all radio technologies 598 if (!mIccCardStatus.getCardState().isCardPresent()) { 599 return IccCard.State.ABSENT; 600 } 601 602 RadioState currentRadioState = mPhone.mCM.getRadioState(); 603 // check radio technology 604 if( currentRadioState == RadioState.RADIO_OFF || 605 currentRadioState == RadioState.RADIO_UNAVAILABLE || 606 currentRadioState == RadioState.SIM_NOT_READY || 607 currentRadioState == RadioState.RUIM_NOT_READY || 608 currentRadioState == RadioState.NV_NOT_READY || 609 currentRadioState == RadioState.NV_READY) { 610 return IccCard.State.NOT_READY; 611 } 612 613 if( currentRadioState == RadioState.SIM_LOCKED_OR_ABSENT || 614 currentRadioState == RadioState.SIM_READY || 615 currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT || 616 currentRadioState == RadioState.RUIM_READY) { 617 618 int index; 619 620 // check for CDMA radio technology 621 if (currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT || 622 currentRadioState == RadioState.RUIM_READY) { 623 index = mIccCardStatus.getCdmaSubscriptionAppIndex(); 624 } 625 else { 626 index = mIccCardStatus.getGsmUmtsSubscriptionAppIndex(); 627 } 628 629 IccCardApplication app = mIccCardStatus.getApplication(index); 630 631 if (app == null) { 632 Log.e(mLogTag, "[IccCard] Subscription Application in not present"); 633 return IccCard.State.ABSENT; 634 } 635 636 // check if PIN required 637 if (app.app_state.isPinRequired()) { 638 return IccCard.State.PIN_REQUIRED; 639 } 640 if (app.app_state.isPukRequired()) { 641 return IccCard.State.PUK_REQUIRED; 642 } 643 if (app.app_state.isSubscriptionPersoEnabled()) { 644 return IccCard.State.NETWORK_LOCKED; 645 } 646 if (app.app_state.isAppReady()) { 647 return IccCard.State.READY; 648 } 649 if (app.app_state.isAppNotReady()) { 650 return IccCard.State.NOT_READY; 651 } 652 return IccCard.State.NOT_READY; 653 } 654 655 return IccCard.State.ABSENT; 656 } 657 658 659 public boolean isApplicationOnIcc(IccCardApplication.AppType type) { 660 if (mIccCardStatus == null) return false; 661 662 for (int i = 0 ; i < mIccCardStatus.getNumApplications(); i++) { 663 IccCardApplication app = mIccCardStatus.getApplication(i); 664 if (app != null && app.app_type == type) { 665 return true; 666 } 667 } 668 return false; 669 } 670 671 /** 672 * @return true if a ICC card is present 673 */ 674 public boolean hasIccCard() { 675 boolean isIccPresent; 676 if (mPhone.getPhoneName().equals("GSM")) { 677 return mIccCardStatus.getCardState().isCardPresent(); 678 } else { 679 // TODO: Make work with a CDMA device with a RUIM card. 680 return false; 681 } 682 } 683 684 private void log(String msg) { 685 Log.d(mLogTag, "[IccCard] " + msg); 686 } 687 } 688