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 17package com.android.internal.telephony; 18 19import static android.Manifest.permission.READ_PHONE_STATE; 20import android.app.ActivityManagerNative; 21import android.app.AlertDialog; 22import android.content.Context; 23import android.content.DialogInterface; 24import android.content.Intent; 25import android.content.res.Resources; 26import android.os.AsyncResult; 27import android.os.Handler; 28import android.os.Message; 29import android.os.PowerManager; 30import android.os.Registrant; 31import android.os.RegistrantList; 32import android.util.Log; 33import android.view.WindowManager; 34 35import com.android.internal.telephony.PhoneBase; 36import com.android.internal.telephony.CommandsInterface.RadioState; 37import com.android.internal.telephony.gsm.SIMFileHandler; 38import com.android.internal.telephony.gsm.SIMRecords; 39import com.android.internal.telephony.cat.CatService; 40import com.android.internal.telephony.cdma.CDMALTEPhone; 41import com.android.internal.telephony.cdma.CdmaLteUiccFileHandler; 42import com.android.internal.telephony.cdma.CdmaLteUiccRecords; 43import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; 44import com.android.internal.telephony.cdma.RuimFileHandler; 45import com.android.internal.telephony.cdma.RuimRecords; 46 47import android.os.SystemProperties; 48 49import com.android.internal.R; 50 51/** 52 * {@hide} 53 */ 54public class IccCard { 55 protected String mLogTag; 56 protected boolean mDbg; 57 58 protected IccCardStatus mIccCardStatus = null; 59 protected State mState = null; 60 private final Object mStateMonitor = new Object(); 61 62 protected boolean is3gpp = true; 63 protected boolean isSubscriptionFromIccCard = true; 64 protected CdmaSubscriptionSourceManager mCdmaSSM = null; 65 protected PhoneBase mPhone; 66 private IccRecords mIccRecords; 67 private IccFileHandler mIccFileHandler; 68 private CatService mCatService; 69 70 private RegistrantList mAbsentRegistrants = new RegistrantList(); 71 private RegistrantList mPinLockedRegistrants = new RegistrantList(); 72 private RegistrantList mNetworkLockedRegistrants = new RegistrantList(); 73 protected RegistrantList mReadyRegistrants = new RegistrantList(); 74 protected RegistrantList mRuimReadyRegistrants = new RegistrantList(); 75 76 private boolean mDesiredPinLocked; 77 private boolean mDesiredFdnEnabled; 78 private boolean mIccPinLocked = true; // Default to locked 79 private boolean mIccFdnEnabled = false; // Default to disabled. 80 // Will be updated when SIM_READY. 81 82 /* Parameter is3gpp's values to be passed to constructor */ 83 public final static boolean CARD_IS_3GPP = true; 84 public final static boolean CARD_IS_NOT_3GPP = false; 85 86 87 /* The extra data for broacasting intent INTENT_ICC_STATE_CHANGE */ 88 static public final String INTENT_KEY_ICC_STATE = "ss"; 89 /* NOT_READY means the ICC interface is not ready (eg, radio is off or powering on) */ 90 static public final String INTENT_VALUE_ICC_NOT_READY = "NOT_READY"; 91 /* ABSENT means ICC is missing */ 92 static public final String INTENT_VALUE_ICC_ABSENT = "ABSENT"; 93 /* LOCKED means ICC is locked by pin or by network */ 94 static public final String INTENT_VALUE_ICC_LOCKED = "LOCKED"; 95 /* READY means ICC is ready to access */ 96 static public final String INTENT_VALUE_ICC_READY = "READY"; 97 /* IMSI means ICC IMSI is ready in property */ 98 static public final String INTENT_VALUE_ICC_IMSI = "IMSI"; 99 /* LOADED means all ICC records, including IMSI, are loaded */ 100 static public final String INTENT_VALUE_ICC_LOADED = "LOADED"; 101 /* The extra data for broacasting intent INTENT_ICC_STATE_CHANGE */ 102 static public final String INTENT_KEY_LOCKED_REASON = "reason"; 103 /* PIN means ICC is locked on PIN1 */ 104 static public final String INTENT_VALUE_LOCKED_ON_PIN = "PIN"; 105 /* PUK means ICC is locked on PUK1 */ 106 static public final String INTENT_VALUE_LOCKED_ON_PUK = "PUK"; 107 /* NETWORK means ICC is locked on NETWORK PERSONALIZATION */ 108 static public final String INTENT_VALUE_LOCKED_NETWORK = "NETWORK"; 109 /* PERM_DISABLED means ICC is permanently disabled due to puk fails */ 110 static public final String INTENT_VALUE_ABSENT_ON_PERM_DISABLED = "PERM_DISABLED"; 111 112 113 protected static final int EVENT_ICC_LOCKED = 1; 114 private static final int EVENT_GET_ICC_STATUS_DONE = 2; 115 protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3; 116 private static final int EVENT_PINPUK_DONE = 4; 117 private static final int EVENT_REPOLL_STATUS_DONE = 5; 118 protected static final int EVENT_ICC_READY = 6; 119 private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7; 120 private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8; 121 private static final int EVENT_CHANGE_ICC_PASSWORD_DONE = 9; 122 private static final int EVENT_QUERY_FACILITY_FDN_DONE = 10; 123 private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11; 124 private static final int EVENT_ICC_STATUS_CHANGED = 12; 125 private static final int EVENT_CARD_REMOVED = 13; 126 private static final int EVENT_CARD_ADDED = 14; 127 protected static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 15; 128 protected static final int EVENT_RADIO_ON = 16; 129 130 /* 131 UNKNOWN is a transient state, for example, after uesr inputs ICC pin under 132 PIN_REQUIRED state, the query for ICC status returns UNKNOWN before it 133 turns to READY 134 */ 135 public enum State { 136 UNKNOWN, 137 ABSENT, 138 PIN_REQUIRED, 139 PUK_REQUIRED, 140 NETWORK_LOCKED, 141 READY, 142 NOT_READY, 143 PERM_DISABLED; 144 145 public boolean isPinLocked() { 146 return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED)); 147 } 148 149 public boolean iccCardExist() { 150 return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED) 151 || (this == NETWORK_LOCKED) || (this == READY) 152 || (this == PERM_DISABLED)); 153 } 154 } 155 156 public State getState() { 157 if (mState == null) { 158 switch(mPhone.mCM.getRadioState()) { 159 /* This switch block must not return anything in 160 * State.isLocked() or State.ABSENT. 161 * If it does, handleSimStatus() may break 162 */ 163 case RADIO_OFF: 164 case RADIO_UNAVAILABLE: 165 return State.UNKNOWN; 166 default: 167 if (!is3gpp && !isSubscriptionFromIccCard) { 168 // CDMA can get subscription from NV. In that case, 169 // subscription is ready as soon as Radio is ON. 170 return State.READY; 171 } 172 } 173 } else { 174 return mState; 175 } 176 177 return State.UNKNOWN; 178 } 179 180 public IccCard(PhoneBase phone, String logTag, Boolean is3gpp, Boolean dbg) { 181 mLogTag = logTag; 182 mDbg = dbg; 183 if (mDbg) log("[IccCard] Creating card type " + (is3gpp ? "3gpp" : "3gpp2")); 184 mPhone = phone; 185 this.is3gpp = is3gpp; 186 mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(mPhone.getContext(), 187 mPhone.mCM, mHandler, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null); 188 if (phone.mCM.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE 189 && phone instanceof CDMALTEPhone) { 190 mIccFileHandler = new CdmaLteUiccFileHandler(this, "", mPhone.mCM); 191 mIccRecords = new CdmaLteUiccRecords(this, mPhone.mContext, mPhone.mCM); 192 } else { 193 // Correct aid will be set later (when GET_SIM_STATUS returns) 194 mIccFileHandler = is3gpp ? new SIMFileHandler(this, "", mPhone.mCM) : 195 new RuimFileHandler(this, "", mPhone.mCM); 196 mIccRecords = is3gpp ? new SIMRecords(this, mPhone.mContext, mPhone.mCM) : 197 new RuimRecords(this, mPhone.mContext, mPhone.mCM); 198 } 199 mCatService = CatService.getInstance(mPhone.mCM, mIccRecords, 200 mPhone.mContext, mIccFileHandler, this); 201 mPhone.mCM.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); 202 mPhone.mCM.registerForOn(mHandler, EVENT_RADIO_ON, null); 203 mPhone.mCM.registerForIccStatusChanged(mHandler, EVENT_ICC_STATUS_CHANGED, null); 204 } 205 206 public void dispose() { 207 if (mDbg) log("[IccCard] Disposing card type " + (is3gpp ? "3gpp" : "3gpp2")); 208 mPhone.mCM.unregisterForIccStatusChanged(mHandler); 209 mPhone.mCM.unregisterForOffOrNotAvailable(mHandler); 210 mPhone.mCM.unregisterForOn(mHandler); 211 mCatService.dispose(); 212 mCdmaSSM.dispose(mHandler); 213 mIccRecords.dispose(); 214 mIccFileHandler.dispose(); 215 } 216 217 protected void finalize() { 218 if (mDbg) log("[IccCard] Finalized card type " + (is3gpp ? "3gpp" : "3gpp2")); 219 } 220 221 public IccRecords getIccRecords() { 222 return mIccRecords; 223 } 224 225 public IccFileHandler getIccFileHandler() { 226 return mIccFileHandler; 227 } 228 229 /** 230 * Notifies handler of any transition into State.ABSENT 231 */ 232 public void registerForAbsent(Handler h, int what, Object obj) { 233 Registrant r = new Registrant (h, what, obj); 234 235 mAbsentRegistrants.add(r); 236 237 if (getState() == State.ABSENT) { 238 r.notifyRegistrant(); 239 } 240 } 241 242 public void unregisterForAbsent(Handler h) { 243 mAbsentRegistrants.remove(h); 244 } 245 246 /** 247 * Notifies handler of any transition into State.NETWORK_LOCKED 248 */ 249 public void registerForNetworkLocked(Handler h, int what, Object obj) { 250 Registrant r = new Registrant (h, what, obj); 251 252 mNetworkLockedRegistrants.add(r); 253 254 if (getState() == State.NETWORK_LOCKED) { 255 r.notifyRegistrant(); 256 } 257 } 258 259 public void unregisterForNetworkLocked(Handler h) { 260 mNetworkLockedRegistrants.remove(h); 261 } 262 263 /** 264 * Notifies handler of any transition into State.isPinLocked() 265 */ 266 public void registerForLocked(Handler h, int what, Object obj) { 267 Registrant r = new Registrant (h, what, obj); 268 269 mPinLockedRegistrants.add(r); 270 271 if (getState().isPinLocked()) { 272 r.notifyRegistrant(); 273 } 274 } 275 276 public void unregisterForLocked(Handler h) { 277 mPinLockedRegistrants.remove(h); 278 } 279 280 public void registerForReady(Handler h, int what, Object obj) { 281 Registrant r = new Registrant (h, what, obj); 282 283 synchronized (mStateMonitor) { 284 mReadyRegistrants.add(r); 285 286 if (getState() == State.READY) { 287 r.notifyRegistrant(new AsyncResult(null, null, null)); 288 } 289 } 290 } 291 292 public void unregisterForReady(Handler h) { 293 synchronized (mStateMonitor) { 294 mReadyRegistrants.remove(h); 295 } 296 } 297 298 public State getRuimState() { 299 if(mIccCardStatus != null) { 300 return getAppState(mIccCardStatus.getCdmaSubscriptionAppIndex()); 301 } else { 302 return State.UNKNOWN; 303 } 304 } 305 306 public void registerForRuimReady(Handler h, int what, Object obj) { 307 Registrant r = new Registrant (h, what, obj); 308 309 synchronized (mStateMonitor) { 310 mRuimReadyRegistrants.add(r); 311 312 if (getState() == State.READY && getRuimState() == State.READY ) { 313 r.notifyRegistrant(new AsyncResult(null, null, null)); 314 } 315 } 316 } 317 318 public void unregisterForRuimReady(Handler h) { 319 synchronized (mStateMonitor) { 320 mRuimReadyRegistrants.remove(h); 321 } 322 } 323 324 /** 325 * Supply the ICC PIN to the ICC 326 * 327 * When the operation is complete, onComplete will be sent to its 328 * Handler. 329 * 330 * onComplete.obj will be an AsyncResult 331 * 332 * ((AsyncResult)onComplete.obj).exception == null on success 333 * ((AsyncResult)onComplete.obj).exception != null on fail 334 * 335 * If the supplied PIN is incorrect: 336 * ((AsyncResult)onComplete.obj).exception != null 337 * && ((AsyncResult)onComplete.obj).exception 338 * instanceof com.android.internal.telephony.gsm.CommandException) 339 * && ((CommandException)(((AsyncResult)onComplete.obj).exception)) 340 * .getCommandError() == CommandException.Error.PASSWORD_INCORRECT 341 * 342 * 343 */ 344 345 public void supplyPin (String pin, Message onComplete) { 346 mPhone.mCM.supplyIccPin(pin, mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); 347 } 348 349 public void supplyPuk (String puk, String newPin, Message onComplete) { 350 mPhone.mCM.supplyIccPuk(puk, newPin, 351 mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); 352 } 353 354 public void supplyPin2 (String pin2, Message onComplete) { 355 mPhone.mCM.supplyIccPin2(pin2, 356 mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); 357 } 358 359 public void supplyPuk2 (String puk2, String newPin2, Message onComplete) { 360 mPhone.mCM.supplyIccPuk2(puk2, newPin2, 361 mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); 362 } 363 364 public void supplyNetworkDepersonalization (String pin, Message onComplete) { 365 mPhone.mCM.supplyNetworkDepersonalization(pin, 366 mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); 367 } 368 369 /** 370 * Check whether ICC pin lock is enabled 371 * This is a sync call which returns the cached pin enabled state 372 * 373 * @return true for ICC locked enabled 374 * false for ICC locked disabled 375 */ 376 public boolean getIccLockEnabled() { 377 return mIccPinLocked; 378 } 379 380 /** 381 * Check whether ICC fdn (fixed dialing number) is enabled 382 * This is a sync call which returns the cached pin enabled state 383 * 384 * @return true for ICC fdn enabled 385 * false for ICC fdn disabled 386 */ 387 public boolean getIccFdnEnabled() { 388 return mIccFdnEnabled; 389 } 390 391 /** 392 * Set the ICC pin lock enabled or disabled 393 * When the operation is complete, onComplete will be sent to its handler 394 * 395 * @param enabled "true" for locked "false" for unlocked. 396 * @param password needed to change the ICC pin state, aka. Pin1 397 * @param onComplete 398 * onComplete.obj will be an AsyncResult 399 * ((AsyncResult)onComplete.obj).exception == null on success 400 * ((AsyncResult)onComplete.obj).exception != null on fail 401 */ 402 public void setIccLockEnabled (boolean enabled, 403 String password, Message onComplete) { 404 int serviceClassX; 405 serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + 406 CommandsInterface.SERVICE_CLASS_DATA + 407 CommandsInterface.SERVICE_CLASS_FAX; 408 409 mDesiredPinLocked = enabled; 410 411 mPhone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM, 412 enabled, password, serviceClassX, 413 mHandler.obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete)); 414 } 415 416 /** 417 * Set the ICC fdn enabled or disabled 418 * When the operation is complete, onComplete will be sent to its handler 419 * 420 * @param enabled "true" for locked "false" for unlocked. 421 * @param password needed to change the ICC fdn enable, aka Pin2 422 * @param onComplete 423 * onComplete.obj will be an AsyncResult 424 * ((AsyncResult)onComplete.obj).exception == null on success 425 * ((AsyncResult)onComplete.obj).exception != null on fail 426 */ 427 public void setIccFdnEnabled (boolean enabled, 428 String password, Message onComplete) { 429 int serviceClassX; 430 serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + 431 CommandsInterface.SERVICE_CLASS_DATA + 432 CommandsInterface.SERVICE_CLASS_FAX + 433 CommandsInterface.SERVICE_CLASS_SMS; 434 435 mDesiredFdnEnabled = enabled; 436 437 mPhone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD, 438 enabled, password, serviceClassX, 439 mHandler.obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete)); 440 } 441 442 /** 443 * Change the ICC password used in ICC pin lock 444 * When the operation is complete, onComplete will be sent to its handler 445 * 446 * @param oldPassword is the old password 447 * @param newPassword is the new password 448 * @param onComplete 449 * onComplete.obj will be an AsyncResult 450 * ((AsyncResult)onComplete.obj).exception == null on success 451 * ((AsyncResult)onComplete.obj).exception != null on fail 452 */ 453 public void changeIccLockPassword(String oldPassword, String newPassword, 454 Message onComplete) { 455 mPhone.mCM.changeIccPin(oldPassword, newPassword, 456 mHandler.obtainMessage(EVENT_CHANGE_ICC_PASSWORD_DONE, onComplete)); 457 458 } 459 460 /** 461 * Change the ICC password used in ICC fdn enable 462 * When the operation is complete, onComplete will be sent to its handler 463 * 464 * @param oldPassword is the old password 465 * @param newPassword is the new password 466 * @param onComplete 467 * onComplete.obj will be an AsyncResult 468 * ((AsyncResult)onComplete.obj).exception == null on success 469 * ((AsyncResult)onComplete.obj).exception != null on fail 470 */ 471 public void changeIccFdnPassword(String oldPassword, String newPassword, 472 Message onComplete) { 473 mPhone.mCM.changeIccPin2(oldPassword, newPassword, 474 mHandler.obtainMessage(EVENT_CHANGE_ICC_PASSWORD_DONE, onComplete)); 475 476 } 477 478 479 /** 480 * Returns service provider name stored in ICC card. 481 * If there is no service provider name associated or the record is not 482 * yet available, null will be returned <p> 483 * 484 * Please use this value when display Service Provider Name in idle mode <p> 485 * 486 * Usage of this provider name in the UI is a common carrier requirement. 487 * 488 * Also available via Android property "gsm.sim.operator.alpha" 489 * 490 * @return Service Provider Name stored in ICC card 491 * null if no service provider name associated or the record is not 492 * yet available 493 * 494 */ 495 public String getServiceProviderName () { 496 return mPhone.mIccRecords.getServiceProviderName(); 497 } 498 499 protected void updateStateProperty() { 500 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_SIM_STATE, getState().toString()); 501 } 502 503 private void getIccCardStatusDone(AsyncResult ar) { 504 if (ar.exception != null) { 505 Log.e(mLogTag,"Error getting ICC status. " 506 + "RIL_REQUEST_GET_ICC_STATUS should " 507 + "never return an error", ar.exception); 508 return; 509 } 510 handleIccCardStatus((IccCardStatus) ar.result); 511 } 512 513 private void handleIccCardStatus(IccCardStatus newCardStatus) { 514 boolean transitionedIntoPinLocked; 515 boolean transitionedIntoAbsent; 516 boolean transitionedIntoNetworkLocked; 517 boolean transitionedIntoPermBlocked; 518 boolean isIccCardRemoved; 519 boolean isIccCardAdded; 520 521 State oldState, newState; 522 State oldRuimState = getRuimState(); 523 524 oldState = mState; 525 mIccCardStatus = newCardStatus; 526 newState = getIccCardState(); 527 528 synchronized (mStateMonitor) { 529 mState = newState; 530 updateStateProperty(); 531 if (oldState != State.READY && newState == State.READY) { 532 mHandler.sendMessage(mHandler.obtainMessage(EVENT_ICC_READY)); 533 mReadyRegistrants.notifyRegistrants(); 534 } else if (newState.isPinLocked()) { 535 mHandler.sendMessage(mHandler.obtainMessage(EVENT_ICC_LOCKED)); 536 } 537 if (oldRuimState != State.READY && getRuimState() == State.READY) { 538 mRuimReadyRegistrants.notifyRegistrants(); 539 } 540 } 541 542 transitionedIntoPinLocked = ( 543 (oldState != State.PIN_REQUIRED && newState == State.PIN_REQUIRED) 544 || (oldState != State.PUK_REQUIRED && newState == State.PUK_REQUIRED)); 545 transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT); 546 transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED 547 && newState == State.NETWORK_LOCKED); 548 transitionedIntoPermBlocked = (oldState != State.PERM_DISABLED 549 && newState == State.PERM_DISABLED); 550 isIccCardRemoved = (oldState != null && 551 oldState.iccCardExist() && newState == State.ABSENT); 552 isIccCardAdded = (oldState == State.ABSENT && 553 newState != null && newState.iccCardExist()); 554 555 if (transitionedIntoPinLocked) { 556 if (mDbg) log("Notify SIM pin or puk locked."); 557 mPinLockedRegistrants.notifyRegistrants(); 558 broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED, 559 (newState == State.PIN_REQUIRED) ? 560 INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK); 561 } else if (transitionedIntoAbsent) { 562 if (mDbg) log("Notify SIM missing."); 563 mAbsentRegistrants.notifyRegistrants(); 564 broadcastIccStateChangedIntent(INTENT_VALUE_ICC_ABSENT, null); 565 } else if (transitionedIntoNetworkLocked) { 566 if (mDbg) log("Notify SIM network locked."); 567 mNetworkLockedRegistrants.notifyRegistrants(); 568 broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED, 569 INTENT_VALUE_LOCKED_NETWORK); 570 } else if (transitionedIntoPermBlocked) { 571 if (mDbg) log("Notify SIM permanently disabled."); 572 broadcastIccStateChangedIntent(INTENT_VALUE_ICC_ABSENT, 573 INTENT_VALUE_ABSENT_ON_PERM_DISABLED); 574 } 575 576 if (isIccCardRemoved) { 577 mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_REMOVED, null)); 578 } else if (isIccCardAdded) { 579 mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_ADDED, null)); 580 } 581 582 // Call onReady Record(s) on the IccCard becomes ready (not NV) 583 if (oldState != State.READY && newState == State.READY && 584 (is3gpp || isSubscriptionFromIccCard)) { 585 if (!(mIccFileHandler instanceof CdmaLteUiccFileHandler)) { 586 // CdmaLteUicc File Handler deals with both USIM and CSIM. 587 // Do not lock onto one AID for now. 588 mIccFileHandler.setAid(getAid()); 589 } 590 mIccRecords.onReady(); 591 } 592 } 593 594 private void onIccSwap(boolean isAdded) { 595 // TODO: Here we assume the device can't handle SIM hot-swap 596 // and has to reboot. We may want to add a property, 597 // e.g. REBOOT_ON_SIM_SWAP, to indicate if modem support 598 // hot-swap. 599 DialogInterface.OnClickListener listener = null; 600 601 602 // TODO: SimRecords is not reset while SIM ABSENT (only reset while 603 // Radio_off_or_not_available). Have to reset in both both 604 // added or removed situation. 605 listener = new DialogInterface.OnClickListener() { 606 @Override 607 public void onClick(DialogInterface dialog, int which) { 608 if (which == DialogInterface.BUTTON_POSITIVE) { 609 if (mDbg) log("Reboot due to SIM swap"); 610 PowerManager pm = (PowerManager) mPhone.getContext() 611 .getSystemService(Context.POWER_SERVICE); 612 pm.reboot("SIM is added."); 613 } 614 } 615 616 }; 617 618 Resources r = Resources.getSystem(); 619 620 String title = (isAdded) ? r.getString(R.string.sim_added_title) : 621 r.getString(R.string.sim_removed_title); 622 String message = (isAdded) ? r.getString(R.string.sim_added_message) : 623 r.getString(R.string.sim_removed_message); 624 String buttonTxt = r.getString(R.string.sim_restart_button); 625 626 AlertDialog dialog = new AlertDialog.Builder(mPhone.getContext()) 627 .setTitle(title) 628 .setMessage(message) 629 .setPositiveButton(buttonTxt, listener) 630 .create(); 631 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 632 dialog.show(); 633 } 634 635 /** 636 * Interperate EVENT_QUERY_FACILITY_LOCK_DONE 637 * @param ar is asyncResult of Query_Facility_Locked 638 */ 639 private void onQueryFdnEnabled(AsyncResult ar) { 640 if(ar.exception != null) { 641 if(mDbg) log("Error in querying facility lock:" + ar.exception); 642 return; 643 } 644 645 int[] ints = (int[])ar.result; 646 if(ints.length != 0) { 647 mIccFdnEnabled = (0!=ints[0]); 648 if(mDbg) log("Query facility lock : " + mIccFdnEnabled); 649 } else { 650 Log.e(mLogTag, "[IccCard] Bogus facility lock response"); 651 } 652 } 653 654 /** 655 * Interperate EVENT_QUERY_FACILITY_LOCK_DONE 656 * @param ar is asyncResult of Query_Facility_Locked 657 */ 658 private void onQueryFacilityLock(AsyncResult ar) { 659 if(ar.exception != null) { 660 if (mDbg) log("Error in querying facility lock:" + ar.exception); 661 return; 662 } 663 664 int[] ints = (int[])ar.result; 665 if(ints.length != 0) { 666 mIccPinLocked = (0!=ints[0]); 667 if(mDbg) log("Query facility lock : " + mIccPinLocked); 668 } else { 669 Log.e(mLogTag, "[IccCard] Bogus facility lock response"); 670 } 671 } 672 673 public void broadcastIccStateChangedIntent(String value, String reason) { 674 Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 675 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 676 intent.putExtra(Phone.PHONE_NAME_KEY, mPhone.getPhoneName()); 677 intent.putExtra(INTENT_KEY_ICC_STATE, value); 678 intent.putExtra(INTENT_KEY_LOCKED_REASON, reason); 679 if(mDbg) log("Broadcasting intent ACTION_SIM_STATE_CHANGED " + value 680 + " reason " + reason); 681 ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE); 682 } 683 684 protected Handler mHandler = new Handler() { 685 @Override 686 public void handleMessage(Message msg){ 687 AsyncResult ar; 688 int serviceClassX; 689 690 serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + 691 CommandsInterface.SERVICE_CLASS_DATA + 692 CommandsInterface.SERVICE_CLASS_FAX; 693 694 if (!mPhone.mIsTheCurrentActivePhone) { 695 Log.e(mLogTag, "Received message " + msg + "[" + msg.what 696 + "] while being destroyed. Ignoring."); 697 return; 698 } 699 700 switch (msg.what) { 701 case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: 702 mState = null; 703 updateStateProperty(); 704 broadcastIccStateChangedIntent(INTENT_VALUE_ICC_NOT_READY, null); 705 break; 706 case EVENT_RADIO_ON: 707 if (!is3gpp) { 708 handleCdmaSubscriptionSource(); 709 } 710 mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE)); 711 break; 712 case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED: 713 handleCdmaSubscriptionSource(); 714 break; 715 case EVENT_ICC_READY: 716 if(isSubscriptionFromIccCard) { 717 mPhone.mCM.queryFacilityLock ( 718 CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, 719 obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); 720 mPhone.mCM.queryFacilityLock ( 721 CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX, 722 obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE)); 723 } 724 break; 725 case EVENT_ICC_LOCKED: 726 mPhone.mCM.queryFacilityLock ( 727 CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, 728 obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); 729 break; 730 case EVENT_GET_ICC_STATUS_DONE: 731 ar = (AsyncResult)msg.obj; 732 733 getIccCardStatusDone(ar); 734 break; 735 case EVENT_PINPUK_DONE: 736 // a PIN/PUK/PIN2/PUK2/Network Personalization 737 // request has completed. ar.userObj is the response Message 738 // Repoll before returning 739 ar = (AsyncResult)msg.obj; 740 // TODO should abstract these exceptions 741 AsyncResult.forMessage(((Message)ar.userObj)).exception 742 = ar.exception; 743 mPhone.mCM.getIccCardStatus( 744 obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj)); 745 break; 746 case EVENT_REPOLL_STATUS_DONE: 747 // Finished repolling status after PIN operation 748 // ar.userObj is the response messaeg 749 // ar.userObj.obj is already an AsyncResult with an 750 // appropriate exception filled in if applicable 751 752 ar = (AsyncResult)msg.obj; 753 getIccCardStatusDone(ar); 754 ((Message)ar.userObj).sendToTarget(); 755 break; 756 case EVENT_QUERY_FACILITY_LOCK_DONE: 757 ar = (AsyncResult)msg.obj; 758 onQueryFacilityLock(ar); 759 break; 760 case EVENT_QUERY_FACILITY_FDN_DONE: 761 ar = (AsyncResult)msg.obj; 762 onQueryFdnEnabled(ar); 763 break; 764 case EVENT_CHANGE_FACILITY_LOCK_DONE: 765 ar = (AsyncResult)msg.obj; 766 if (ar.exception == null) { 767 mIccPinLocked = mDesiredPinLocked; 768 if (mDbg) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " + 769 "mIccPinLocked= " + mIccPinLocked); 770 } else { 771 Log.e(mLogTag, "Error change facility lock with exception " 772 + ar.exception); 773 } 774 AsyncResult.forMessage(((Message)ar.userObj)).exception 775 = ar.exception; 776 ((Message)ar.userObj).sendToTarget(); 777 break; 778 case EVENT_CHANGE_FACILITY_FDN_DONE: 779 ar = (AsyncResult)msg.obj; 780 781 if (ar.exception == null) { 782 mIccFdnEnabled = mDesiredFdnEnabled; 783 if (mDbg) log("EVENT_CHANGE_FACILITY_FDN_DONE: " + 784 "mIccFdnEnabled=" + mIccFdnEnabled); 785 } else { 786 Log.e(mLogTag, "Error change facility fdn with exception " 787 + ar.exception); 788 } 789 AsyncResult.forMessage(((Message)ar.userObj)).exception 790 = ar.exception; 791 ((Message)ar.userObj).sendToTarget(); 792 break; 793 case EVENT_CHANGE_ICC_PASSWORD_DONE: 794 ar = (AsyncResult)msg.obj; 795 if(ar.exception != null) { 796 Log.e(mLogTag, "Error in change sim password with exception" 797 + ar.exception); 798 } 799 AsyncResult.forMessage(((Message)ar.userObj)).exception 800 = ar.exception; 801 ((Message)ar.userObj).sendToTarget(); 802 break; 803 case EVENT_ICC_STATUS_CHANGED: 804 Log.d(mLogTag, "Received Event EVENT_ICC_STATUS_CHANGED"); 805 mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE)); 806 break; 807 case EVENT_CARD_REMOVED: 808 onIccSwap(false); 809 break; 810 case EVENT_CARD_ADDED: 811 onIccSwap(true); 812 break; 813 default: 814 Log.e(mLogTag, "[IccCard] Unknown Event " + msg.what); 815 } 816 } 817 }; 818 819 private void handleCdmaSubscriptionSource() { 820 if(mCdmaSSM != null) { 821 int newSubscriptionSource = mCdmaSSM.getCdmaSubscriptionSource(); 822 823 Log.d(mLogTag, "Received Cdma subscription source: " + newSubscriptionSource); 824 825 boolean isNewSubFromRuim = 826 (newSubscriptionSource == CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_RUIM); 827 828 if (isNewSubFromRuim != isSubscriptionFromIccCard) { 829 isSubscriptionFromIccCard = isNewSubFromRuim; 830 // Parse the Stored IccCardStatus Message to set mState correctly. 831 handleIccCardStatus(mIccCardStatus); 832 } 833 } 834 } 835 836 public State getIccCardState() { 837 if(!is3gpp && !isSubscriptionFromIccCard) { 838 // CDMA can get subscription from NV. In that case, 839 // subscription is ready as soon as Radio is ON. 840 return State.READY; 841 } 842 843 if (mIccCardStatus == null) { 844 Log.e(mLogTag, "[IccCard] IccCardStatus is null"); 845 return IccCard.State.ABSENT; 846 } 847 848 // this is common for all radio technologies 849 if (!mIccCardStatus.getCardState().isCardPresent()) { 850 return IccCard.State.ABSENT; 851 } 852 853 RadioState currentRadioState = mPhone.mCM.getRadioState(); 854 // check radio technology 855 if( currentRadioState == RadioState.RADIO_OFF || 856 currentRadioState == RadioState.RADIO_UNAVAILABLE) { 857 return IccCard.State.NOT_READY; 858 } 859 860 if( currentRadioState == RadioState.RADIO_ON ) { 861 State csimState = 862 getAppState(mIccCardStatus.getCdmaSubscriptionAppIndex()); 863 State usimState = 864 getAppState(mIccCardStatus.getGsmUmtsSubscriptionAppIndex()); 865 866 if(mDbg) log("USIM=" + usimState + " CSIM=" + csimState); 867 868 if (mPhone.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE) { 869 // UICC card contains both USIM and CSIM 870 // Return consolidated status 871 return getConsolidatedState(csimState, usimState, csimState); 872 } 873 874 // check for CDMA radio technology 875 if (!is3gpp) { 876 return csimState; 877 } 878 return usimState; 879 } 880 881 return IccCard.State.ABSENT; 882 } 883 884 private State getAppState(int appIndex) { 885 IccCardApplication app; 886 if (appIndex >= 0 && appIndex < IccCardStatus.CARD_MAX_APPS) { 887 app = mIccCardStatus.getApplication(appIndex); 888 } else { 889 Log.e(mLogTag, "[IccCard] Invalid Subscription Application index:" + appIndex); 890 return IccCard.State.ABSENT; 891 } 892 893 if (app == null) { 894 Log.e(mLogTag, "[IccCard] Subscription Application in not present"); 895 return IccCard.State.ABSENT; 896 } 897 898 // check if PIN required 899 if (app.pin1.isPermBlocked()) { 900 return IccCard.State.PERM_DISABLED; 901 } 902 if (app.app_state.isPinRequired()) { 903 return IccCard.State.PIN_REQUIRED; 904 } 905 if (app.app_state.isPukRequired()) { 906 return IccCard.State.PUK_REQUIRED; 907 } 908 if (app.app_state.isSubscriptionPersoEnabled()) { 909 return IccCard.State.NETWORK_LOCKED; 910 } 911 if (app.app_state.isAppReady()) { 912 return IccCard.State.READY; 913 } 914 if (app.app_state.isAppNotReady()) { 915 return IccCard.State.NOT_READY; 916 } 917 return IccCard.State.NOT_READY; 918 } 919 920 private State getConsolidatedState(State left, State right, State preferredState) { 921 // Check if either is absent. 922 if (right == IccCard.State.ABSENT) return left; 923 if (left == IccCard.State.ABSENT) return right; 924 925 // Only if both are ready, return ready 926 if ((left == IccCard.State.READY) && (right == IccCard.State.READY)) { 927 return State.READY; 928 } 929 930 // Case one is ready, but the other is not. 931 if (((right == IccCard.State.NOT_READY) && (left == IccCard.State.READY)) || 932 ((left == IccCard.State.NOT_READY) && (right == IccCard.State.READY))) { 933 return IccCard.State.NOT_READY; 934 } 935 936 // At this point, the other state is assumed to be one of locked state 937 if (right == IccCard.State.NOT_READY) return left; 938 if (left == IccCard.State.NOT_READY) return right; 939 940 // At this point, FW currently just assumes the status will be 941 // consistent across the applications... 942 return preferredState; 943 } 944 945 public boolean isApplicationOnIcc(IccCardApplication.AppType type) { 946 if (mIccCardStatus == null) return false; 947 948 for (int i = 0 ; i < mIccCardStatus.getNumApplications(); i++) { 949 IccCardApplication app = mIccCardStatus.getApplication(i); 950 if (app != null && app.app_type == type) { 951 return true; 952 } 953 } 954 return false; 955 } 956 957 /** 958 * @return true if a ICC card is present 959 */ 960 public boolean hasIccCard() { 961 if (mIccCardStatus == null) { 962 return false; 963 } else { 964 // Returns ICC card status for both GSM and CDMA mode 965 return mIccCardStatus.getCardState().isCardPresent(); 966 } 967 } 968 969 private void log(String msg) { 970 Log.d(mLogTag, "[IccCard] " + msg); 971 } 972 973 protected int getCurrentApplicationIndex() { 974 if (is3gpp) { 975 return mIccCardStatus.getGsmUmtsSubscriptionAppIndex(); 976 } else { 977 return mIccCardStatus.getCdmaSubscriptionAppIndex(); 978 } 979 } 980 981 public String getAid() { 982 String aid = ""; 983 if (mIccCardStatus == null) { 984 return aid; 985 } 986 987 int appIndex = getCurrentApplicationIndex(); 988 989 if (appIndex >= 0 && appIndex < IccCardStatus.CARD_MAX_APPS) { 990 IccCardApplication app = mIccCardStatus.getApplication(appIndex); 991 if (app != null) { 992 aid = app.aid; 993 } else { 994 Log.e(mLogTag, "[IccCard] getAid: no current application index=" + appIndex); 995 } 996 } else { 997 Log.e(mLogTag, "[IccCard] getAid: Invalid Subscription Application index=" + appIndex); 998 } 999 1000 return aid; 1001 } 1002} 1003