1 /* 2 * Copyright (C) 2012 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.uicc; 18 19 import android.app.ActivityManager; 20 import android.content.Context; 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.os.UserHandle; 28 import android.telephony.Rlog; 29 import android.telephony.ServiceState; 30 import android.telephony.SubscriptionManager; 31 import android.telephony.TelephonyManager; 32 import android.text.TextUtils; 33 34 import com.android.internal.telephony.CommandsInterface; 35 import com.android.internal.telephony.CommandsInterface.RadioState; 36 import com.android.internal.telephony.IccCard; 37 import com.android.internal.telephony.IccCardConstants; 38 import com.android.internal.telephony.IccCardConstants.State; 39 import com.android.internal.telephony.IntentBroadcaster; 40 import com.android.internal.telephony.MccTable; 41 import com.android.internal.telephony.Phone; 42 import com.android.internal.telephony.PhoneConstants; 43 import com.android.internal.telephony.RILConstants; 44 import com.android.internal.telephony.TelephonyIntents; 45 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; 46 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState; 47 import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState; 48 import com.android.internal.telephony.uicc.IccCardStatus.CardState; 49 import com.android.internal.telephony.uicc.IccCardStatus.PinState; 50 51 import java.io.FileDescriptor; 52 import java.io.PrintWriter; 53 54 /** 55 * @Deprecated use {@link UiccController}.getUiccCard instead. 56 * 57 * The Phone App assumes that there is only one icc card, and one icc application 58 * available at a time. Moreover, it assumes such object (represented with IccCard) 59 * is available all the time (whether {@link RILConstants#RIL_REQUEST_GET_SIM_STATUS} returned 60 * or not, whether card has desired application or not, whether there really is a card in the 61 * slot or not). 62 * 63 * UiccController, however, can handle multiple instances of icc objects (multiple 64 * {@link UiccCardApplication}, multiple {@link IccFileHandler}, multiple {@link IccRecords}) 65 * created and destroyed dynamically during phone operation. 66 * 67 * This class implements the IccCard interface that is always available (right after default 68 * phone object is constructed) to expose the current (based on voice radio technology) 69 * application on the uicc card, so that external apps won't break. 70 */ 71 72 public class IccCardProxy extends Handler implements IccCard { 73 private static final boolean DBG = true; 74 private static final String LOG_TAG = "IccCardProxy"; 75 76 private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 1; 77 private static final int EVENT_RADIO_ON = 2; 78 private static final int EVENT_ICC_CHANGED = 3; 79 private static final int EVENT_ICC_ABSENT = 4; 80 private static final int EVENT_ICC_LOCKED = 5; 81 private static final int EVENT_APP_READY = 6; 82 private static final int EVENT_RECORDS_LOADED = 7; 83 private static final int EVENT_IMSI_READY = 8; 84 private static final int EVENT_NETWORK_LOCKED = 9; 85 private static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 11; 86 87 private static final int EVENT_ICC_RECORD_EVENTS = 500; 88 private static final int EVENT_SUBSCRIPTION_ACTIVATED = 501; 89 private static final int EVENT_SUBSCRIPTION_DEACTIVATED = 502; 90 private static final int EVENT_CARRIER_PRIVILEGES_LOADED = 503; 91 92 private Integer mPhoneId = null; 93 94 private final Object mLock = new Object(); 95 private Context mContext; 96 private CommandsInterface mCi; 97 private TelephonyManager mTelephonyManager; 98 99 private RegistrantList mAbsentRegistrants = new RegistrantList(); 100 private RegistrantList mPinLockedRegistrants = new RegistrantList(); 101 private RegistrantList mNetworkLockedRegistrants = new RegistrantList(); 102 103 private int mCurrentAppType = UiccController.APP_FAM_3GPP; //default to 3gpp? 104 private UiccController mUiccController = null; 105 private UiccCard mUiccCard = null; 106 private UiccCardApplication mUiccApplication = null; 107 private IccRecords mIccRecords = null; 108 private CdmaSubscriptionSourceManager mCdmaSSM = null; 109 private RadioState mRadioState = RadioState.RADIO_UNAVAILABLE; 110 private boolean mQuietMode = false; // when set to true IccCardProxy will not broadcast 111 // ACTION_SIM_STATE_CHANGED intents 112 private boolean mInitialized = false; 113 private State mExternalState = State.UNKNOWN; 114 115 public static final String ACTION_INTERNAL_SIM_STATE_CHANGED = "android.intent.action.internal_sim_state_changed"; 116 117 public IccCardProxy(Context context, CommandsInterface ci, int phoneId) { 118 if (DBG) log("ctor: ci=" + ci + " phoneId=" + phoneId); 119 mContext = context; 120 mCi = ci; 121 mPhoneId = phoneId; 122 mTelephonyManager = (TelephonyManager) mContext.getSystemService( 123 Context.TELEPHONY_SERVICE); 124 mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(context, 125 ci, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null); 126 mUiccController = UiccController.getInstance(); 127 mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null); 128 ci.registerForOn(this,EVENT_RADIO_ON, null); 129 ci.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_UNAVAILABLE, null); 130 131 resetProperties(); 132 } 133 134 public void dispose() { 135 synchronized (mLock) { 136 log("Disposing"); 137 //Cleanup icc references 138 mUiccController.unregisterForIccChanged(this); 139 mUiccController = null; 140 mCi.unregisterForOn(this); 141 mCi.unregisterForOffOrNotAvailable(this); 142 mCdmaSSM.dispose(this); 143 } 144 } 145 146 /* 147 * The card application that the external world sees will be based on the 148 * voice radio technology only! 149 */ 150 public void setVoiceRadioTech(int radioTech) { 151 synchronized (mLock) { 152 if (DBG) { 153 log("Setting radio tech " + ServiceState.rilRadioTechnologyToString(radioTech)); 154 } 155 if (ServiceState.isGsm(radioTech)) { 156 mCurrentAppType = UiccController.APP_FAM_3GPP; 157 } else { 158 mCurrentAppType = UiccController.APP_FAM_3GPP2; 159 } 160 updateQuietMode(); 161 } 162 } 163 164 /** 165 * In case of 3gpp2 we need to find out if subscription used is coming from 166 * NV in which case we shouldn't broadcast any sim states changes. 167 */ 168 private void updateQuietMode() { 169 synchronized (mLock) { 170 boolean oldQuietMode = mQuietMode; 171 boolean newQuietMode; 172 int cdmaSource = Phone.CDMA_SUBSCRIPTION_UNKNOWN; 173 boolean isLteOnCdmaMode = TelephonyManager.getLteOnCdmaModeStatic() 174 == PhoneConstants.LTE_ON_CDMA_TRUE; 175 if (mCurrentAppType == UiccController.APP_FAM_3GPP) { 176 newQuietMode = false; 177 if (DBG) log("updateQuietMode: 3GPP subscription -> newQuietMode=" + newQuietMode); 178 } else { 179 if (isLteOnCdmaMode) { 180 log("updateQuietMode: is cdma/lte device, force IccCardProxy into 3gpp mode"); 181 mCurrentAppType = UiccController.APP_FAM_3GPP; 182 } 183 cdmaSource = mCdmaSSM != null ? 184 mCdmaSSM.getCdmaSubscriptionSource() : Phone.CDMA_SUBSCRIPTION_UNKNOWN; 185 186 newQuietMode = (cdmaSource == Phone.CDMA_SUBSCRIPTION_NV) 187 && (mCurrentAppType == UiccController.APP_FAM_3GPP2) 188 && !isLteOnCdmaMode; 189 if (DBG) { 190 log("updateQuietMode: cdmaSource=" + cdmaSource 191 + " mCurrentAppType=" + mCurrentAppType 192 + " isLteOnCdmaMode=" + isLteOnCdmaMode 193 + " newQuietMode=" + newQuietMode); 194 } 195 } 196 197 if (mQuietMode == false && newQuietMode == true) { 198 // Last thing to do before switching to quiet mode is 199 // broadcast ICC_READY 200 log("Switching to QuietMode."); 201 setExternalState(State.READY); 202 mQuietMode = newQuietMode; 203 } else if (mQuietMode == true && newQuietMode == false) { 204 if (DBG) { 205 log("updateQuietMode: Switching out from QuietMode." 206 + " Force broadcast of current state=" + mExternalState); 207 } 208 mQuietMode = newQuietMode; 209 setExternalState(mExternalState, true); 210 } else { 211 if (DBG) log("updateQuietMode: no changes don't setExternalState"); 212 } 213 if (DBG) { 214 log("updateQuietMode: QuietMode is " + mQuietMode + " (app_type=" 215 + mCurrentAppType + " isLteOnCdmaMode=" + isLteOnCdmaMode 216 + " cdmaSource=" + cdmaSource + ")"); 217 } 218 mInitialized = true; 219 sendMessage(obtainMessage(EVENT_ICC_CHANGED)); 220 } 221 } 222 223 @Override 224 public void handleMessage(Message msg) { 225 switch (msg.what) { 226 case EVENT_RADIO_OFF_OR_UNAVAILABLE: 227 mRadioState = mCi.getRadioState(); 228 updateExternalState(); 229 break; 230 case EVENT_RADIO_ON: 231 mRadioState = RadioState.RADIO_ON; 232 if (!mInitialized) { 233 updateQuietMode(); 234 } else { 235 // updateQuietMode() triggers ICC_CHANGED, which eventually 236 // calls updateExternalState; thus, we don't need this in the 237 // above case 238 updateExternalState(); 239 } 240 break; 241 case EVENT_ICC_CHANGED: 242 if (mInitialized) { 243 updateIccAvailability(); 244 } 245 break; 246 case EVENT_ICC_ABSENT: 247 mAbsentRegistrants.notifyRegistrants(); 248 setExternalState(State.ABSENT); 249 break; 250 case EVENT_ICC_LOCKED: 251 processLockedState(); 252 break; 253 case EVENT_APP_READY: 254 setExternalState(State.READY); 255 break; 256 case EVENT_RECORDS_LOADED: 257 // Update the MCC/MNC. 258 if (mIccRecords != null) { 259 String operator = mIccRecords.getOperatorNumeric(); 260 log("operator=" + operator + " mPhoneId=" + mPhoneId); 261 262 if (!TextUtils.isEmpty(operator)) { 263 mTelephonyManager.setSimOperatorNumericForPhone(mPhoneId, operator); 264 String countryCode = operator.substring(0,3); 265 if (countryCode != null) { 266 mTelephonyManager.setSimCountryIsoForPhone(mPhoneId, 267 MccTable.countryCodeForMcc(Integer.parseInt(countryCode))); 268 } else { 269 loge("EVENT_RECORDS_LOADED Country code is null"); 270 } 271 } else { 272 loge("EVENT_RECORDS_LOADED Operator name is null"); 273 } 274 } 275 if (mUiccCard != null && !mUiccCard.areCarrierPriviligeRulesLoaded()) { 276 mUiccCard.registerForCarrierPrivilegeRulesLoaded( 277 this, EVENT_CARRIER_PRIVILEGES_LOADED, null); 278 } else { 279 onRecordsLoaded(); 280 } 281 break; 282 case EVENT_IMSI_READY: 283 broadcastIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_IMSI, null); 284 break; 285 case EVENT_NETWORK_LOCKED: 286 mNetworkLockedRegistrants.notifyRegistrants(); 287 setExternalState(State.NETWORK_LOCKED); 288 break; 289 case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED: 290 updateQuietMode(); 291 break; 292 case EVENT_SUBSCRIPTION_ACTIVATED: 293 log("EVENT_SUBSCRIPTION_ACTIVATED"); 294 onSubscriptionActivated(); 295 break; 296 297 case EVENT_SUBSCRIPTION_DEACTIVATED: 298 log("EVENT_SUBSCRIPTION_DEACTIVATED"); 299 onSubscriptionDeactivated(); 300 break; 301 302 case EVENT_ICC_RECORD_EVENTS: 303 if ((mCurrentAppType == UiccController.APP_FAM_3GPP) && (mIccRecords != null)) { 304 AsyncResult ar = (AsyncResult)msg.obj; 305 int eventCode = (Integer) ar.result; 306 if (eventCode == SIMRecords.EVENT_SPN) { 307 mTelephonyManager.setSimOperatorNameForPhone( 308 mPhoneId, mIccRecords.getServiceProviderName()); 309 } 310 } 311 break; 312 313 case EVENT_CARRIER_PRIVILEGES_LOADED: 314 log("EVENT_CARRIER_PRIVILEGES_LOADED"); 315 if (mUiccCard != null) { 316 mUiccCard.unregisterForCarrierPrivilegeRulesLoaded(this); 317 } 318 onRecordsLoaded(); 319 break; 320 321 default: 322 loge("Unhandled message with number: " + msg.what); 323 break; 324 } 325 } 326 327 private void onSubscriptionActivated() { 328 updateIccAvailability(); 329 updateStateProperty(); 330 } 331 332 private void onSubscriptionDeactivated() { 333 resetProperties(); 334 updateIccAvailability(); 335 updateStateProperty(); 336 } 337 338 private void onRecordsLoaded() { 339 broadcastInternalIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_LOADED, null); 340 } 341 342 private void updateIccAvailability() { 343 synchronized (mLock) { 344 UiccCard newCard = mUiccController.getUiccCard(mPhoneId); 345 UiccCardApplication newApp = null; 346 IccRecords newRecords = null; 347 if (newCard != null) { 348 newApp = newCard.getApplication(mCurrentAppType); 349 if (newApp != null) { 350 newRecords = newApp.getIccRecords(); 351 } 352 } 353 354 if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) { 355 if (DBG) log("Icc changed. Reregistering."); 356 unregisterUiccCardEvents(); 357 mUiccCard = newCard; 358 mUiccApplication = newApp; 359 mIccRecords = newRecords; 360 registerUiccCardEvents(); 361 } 362 updateExternalState(); 363 } 364 } 365 366 void resetProperties() { 367 if (mCurrentAppType == UiccController.APP_FAM_3GPP) { 368 log("update icc_operator_numeric=" + ""); 369 mTelephonyManager.setSimOperatorNumericForPhone(mPhoneId, ""); 370 mTelephonyManager.setSimCountryIsoForPhone(mPhoneId, ""); 371 mTelephonyManager.setSimOperatorNameForPhone(mPhoneId, ""); 372 } 373 } 374 375 private void HandleDetectedState() { 376 // CAF_MSIM SAND 377 // setExternalState(State.DETECTED, false); 378 } 379 380 private void updateExternalState() { 381 382 // mUiccCard could be null at bootup, before valid card states have 383 // been received from UiccController. 384 if (mUiccCard == null) { 385 setExternalState(State.UNKNOWN); 386 return; 387 } 388 389 if (mUiccCard.getCardState() == CardState.CARDSTATE_ABSENT) { 390 /* 391 * Both IccCardProxy and UiccController are registered for 392 * RadioState changes. When the UiccController receives a radio 393 * state changed to Unknown it will dispose of all of the IccCard 394 * objects, which will then notify the IccCardProxy and the null 395 * object will force the state to unknown. However, because the 396 * IccCardProxy is also registered for RadioState changes, it will 397 * recieve that signal first. By triggering on radio state changes 398 * directly, we reduce the time window during which the modem is 399 * UNAVAILABLE but the IccStatus is reported as something valid. 400 * This is not ideal. 401 */ 402 if (mRadioState == RadioState.RADIO_UNAVAILABLE) { 403 setExternalState(State.UNKNOWN); 404 } else { 405 setExternalState(State.ABSENT); 406 } 407 return; 408 } 409 410 if (mUiccCard.getCardState() == CardState.CARDSTATE_ERROR) { 411 setExternalState(State.CARD_IO_ERROR); 412 return; 413 } 414 415 if (mUiccCard.getCardState() == CardState.CARDSTATE_RESTRICTED) { 416 setExternalState(State.CARD_RESTRICTED); 417 return; 418 } 419 420 if (mUiccApplication == null) { 421 setExternalState(State.NOT_READY); 422 return; 423 } 424 425 // By process of elimination, the UICC Card State = PRESENT 426 switch (mUiccApplication.getState()) { 427 case APPSTATE_UNKNOWN: 428 /* 429 * APPSTATE_UNKNOWN is a catch-all state reported whenever the app 430 * is not explicitly in one of the other states. To differentiate the 431 * case where we know that there is a card present, but the APP is not 432 * ready, we choose NOT_READY here instead of unknown. This is possible 433 * in at least two cases: 434 * 1) A transient during the process of the SIM bringup 435 * 2) There is no valid App on the SIM to load, which can be the case with an 436 * eSIM/soft SIM. 437 */ 438 setExternalState(State.NOT_READY); 439 break; 440 case APPSTATE_DETECTED: 441 HandleDetectedState(); 442 break; 443 case APPSTATE_PIN: 444 setExternalState(State.PIN_REQUIRED); 445 break; 446 case APPSTATE_PUK: 447 PinState pin1State = mUiccApplication.getPin1State(); 448 if (pin1State.isPermBlocked()) { 449 setExternalState(State.PERM_DISABLED); 450 return; 451 } 452 setExternalState(State.PUK_REQUIRED); 453 break; 454 case APPSTATE_SUBSCRIPTION_PERSO: 455 if (mUiccApplication.getPersoSubState() == 456 PersoSubState.PERSOSUBSTATE_SIM_NETWORK) { 457 setExternalState(State.NETWORK_LOCKED); 458 } 459 // Otherwise don't change external SIM state. 460 break; 461 case APPSTATE_READY: 462 setExternalState(State.READY); 463 break; 464 } 465 } 466 467 private void registerUiccCardEvents() { 468 if (mUiccCard != null) { 469 mUiccCard.registerForAbsent(this, EVENT_ICC_ABSENT, null); 470 } 471 if (mUiccApplication != null) { 472 mUiccApplication.registerForReady(this, EVENT_APP_READY, null); 473 mUiccApplication.registerForLocked(this, EVENT_ICC_LOCKED, null); 474 mUiccApplication.registerForNetworkLocked(this, EVENT_NETWORK_LOCKED, null); 475 } 476 if (mIccRecords != null) { 477 mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null); 478 mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); 479 mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null); 480 } 481 } 482 483 private void unregisterUiccCardEvents() { 484 if (mUiccCard != null) mUiccCard.unregisterForAbsent(this); 485 if (mUiccCard != null) mUiccCard.unregisterForCarrierPrivilegeRulesLoaded(this); 486 if (mUiccApplication != null) mUiccApplication.unregisterForReady(this); 487 if (mUiccApplication != null) mUiccApplication.unregisterForLocked(this); 488 if (mUiccApplication != null) mUiccApplication.unregisterForNetworkLocked(this); 489 if (mIccRecords != null) mIccRecords.unregisterForImsiReady(this); 490 if (mIccRecords != null) mIccRecords.unregisterForRecordsLoaded(this); 491 if (mIccRecords != null) mIccRecords.unregisterForRecordsEvents(this); 492 } 493 494 private void updateStateProperty() { 495 mTelephonyManager.setSimStateForPhone(mPhoneId, getState().toString()); 496 } 497 498 private void broadcastIccStateChangedIntent(String value, String reason) { 499 synchronized (mLock) { 500 if (mPhoneId == null || !SubscriptionManager.isValidSlotIndex(mPhoneId)) { 501 loge("broadcastIccStateChangedIntent: mPhoneId=" + mPhoneId 502 + " is invalid; Return!!"); 503 return; 504 } 505 506 if (mQuietMode) { 507 log("broadcastIccStateChangedIntent: QuietMode" 508 + " NOT Broadcasting intent ACTION_SIM_STATE_CHANGED " 509 + " value=" + value + " reason=" + reason); 510 return; 511 } 512 513 Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 514 // TODO - we'd like this intent to have a single snapshot of all sim state, 515 // but until then this should not use REPLACE_PENDING or we may lose 516 // information 517 // intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING 518 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 519 intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone"); 520 intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value); 521 intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason); 522 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhoneId); 523 log("broadcastIccStateChangedIntent intent ACTION_SIM_STATE_CHANGED value=" + value 524 + " reason=" + reason + " for mPhoneId=" + mPhoneId); 525 IntentBroadcaster.getInstance().broadcastStickyIntent(intent, mPhoneId); 526 } 527 } 528 529 private void broadcastInternalIccStateChangedIntent(String value, String reason) { 530 synchronized (mLock) { 531 if (mPhoneId == null) { 532 loge("broadcastInternalIccStateChangedIntent: Card Index is not set; Return!!"); 533 return; 534 } 535 536 Intent intent = new Intent(ACTION_INTERNAL_SIM_STATE_CHANGED); 537 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING 538 | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 539 intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone"); 540 intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value); 541 intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason); 542 intent.putExtra(PhoneConstants.PHONE_KEY, mPhoneId); // SubId may not be valid. 543 log("Sending intent ACTION_INTERNAL_SIM_STATE_CHANGED value=" + value 544 + " for mPhoneId : " + mPhoneId); 545 ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL); 546 } 547 } 548 549 private void setExternalState(State newState, boolean override) { 550 synchronized (mLock) { 551 if (mPhoneId == null || !SubscriptionManager.isValidSlotIndex(mPhoneId)) { 552 loge("setExternalState: mPhoneId=" + mPhoneId + " is invalid; Return!!"); 553 return; 554 } 555 556 if (!override && newState == mExternalState) { 557 log("setExternalState: !override and newstate unchanged from " + newState); 558 return; 559 } 560 mExternalState = newState; 561 log("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState); 562 mTelephonyManager.setSimStateForPhone(mPhoneId, getState().toString()); 563 564 // For locked states, we should be sending internal broadcast. 565 if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals( 566 getIccStateIntentString(mExternalState))) { 567 broadcastInternalIccStateChangedIntent(getIccStateIntentString(mExternalState), 568 getIccStateReason(mExternalState)); 569 } else { 570 broadcastIccStateChangedIntent(getIccStateIntentString(mExternalState), 571 getIccStateReason(mExternalState)); 572 } 573 // TODO: Need to notify registrants for other states as well. 574 if ( State.ABSENT == mExternalState) { 575 mAbsentRegistrants.notifyRegistrants(); 576 } 577 } 578 } 579 580 private void processLockedState() { 581 synchronized (mLock) { 582 if (mUiccApplication == null) { 583 //Don't need to do anything if non-existent application is locked 584 return; 585 } 586 PinState pin1State = mUiccApplication.getPin1State(); 587 if (pin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) { 588 setExternalState(State.PERM_DISABLED); 589 return; 590 } 591 592 AppState appState = mUiccApplication.getState(); 593 switch (appState) { 594 case APPSTATE_PIN: 595 mPinLockedRegistrants.notifyRegistrants(); 596 setExternalState(State.PIN_REQUIRED); 597 break; 598 case APPSTATE_PUK: 599 setExternalState(State.PUK_REQUIRED); 600 break; 601 case APPSTATE_DETECTED: 602 case APPSTATE_READY: 603 case APPSTATE_SUBSCRIPTION_PERSO: 604 case APPSTATE_UNKNOWN: 605 // Neither required 606 break; 607 } 608 } 609 } 610 611 private void setExternalState(State newState) { 612 setExternalState(newState, false); 613 } 614 615 public boolean getIccRecordsLoaded() { 616 synchronized (mLock) { 617 if (mIccRecords != null) { 618 return mIccRecords.getRecordsLoaded(); 619 } 620 return false; 621 } 622 } 623 624 private String getIccStateIntentString(State state) { 625 switch (state) { 626 case ABSENT: return IccCardConstants.INTENT_VALUE_ICC_ABSENT; 627 case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED; 628 case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED; 629 case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED; 630 case READY: return IccCardConstants.INTENT_VALUE_ICC_READY; 631 case NOT_READY: return IccCardConstants.INTENT_VALUE_ICC_NOT_READY; 632 case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED; 633 case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR; 634 case CARD_RESTRICTED: return IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED; 635 default: return IccCardConstants.INTENT_VALUE_ICC_UNKNOWN; 636 } 637 } 638 639 /** 640 * Locked state have a reason (PIN, PUK, NETWORK, PERM_DISABLED, CARD_IO_ERROR) 641 * @return reason 642 */ 643 private String getIccStateReason(State state) { 644 switch (state) { 645 case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN; 646 case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK; 647 case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_LOCKED_NETWORK; 648 case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED; 649 case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR; 650 case CARD_RESTRICTED: return IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED; 651 default: return null; 652 } 653 } 654 655 /* IccCard interface implementation */ 656 @Override 657 public State getState() { 658 synchronized (mLock) { 659 return mExternalState; 660 } 661 } 662 663 @Override 664 public IccRecords getIccRecords() { 665 synchronized (mLock) { 666 return mIccRecords; 667 } 668 } 669 670 @Override 671 public IccFileHandler getIccFileHandler() { 672 synchronized (mLock) { 673 if (mUiccApplication != null) { 674 return mUiccApplication.getIccFileHandler(); 675 } 676 return null; 677 } 678 } 679 680 /** 681 * Notifies handler of any transition into State.ABSENT 682 */ 683 @Override 684 public void registerForAbsent(Handler h, int what, Object obj) { 685 synchronized (mLock) { 686 Registrant r = new Registrant (h, what, obj); 687 688 mAbsentRegistrants.add(r); 689 690 if (getState() == State.ABSENT) { 691 r.notifyRegistrant(); 692 } 693 } 694 } 695 696 @Override 697 public void unregisterForAbsent(Handler h) { 698 synchronized (mLock) { 699 mAbsentRegistrants.remove(h); 700 } 701 } 702 703 /** 704 * Notifies handler of any transition into State.NETWORK_LOCKED 705 */ 706 @Override 707 public void registerForNetworkLocked(Handler h, int what, Object obj) { 708 synchronized (mLock) { 709 Registrant r = new Registrant (h, what, obj); 710 711 mNetworkLockedRegistrants.add(r); 712 713 if (getState() == State.NETWORK_LOCKED) { 714 r.notifyRegistrant(); 715 } 716 } 717 } 718 719 @Override 720 public void unregisterForNetworkLocked(Handler h) { 721 synchronized (mLock) { 722 mNetworkLockedRegistrants.remove(h); 723 } 724 } 725 726 /** 727 * Notifies handler of any transition into State.isPinLocked() 728 */ 729 @Override 730 public void registerForLocked(Handler h, int what, Object obj) { 731 synchronized (mLock) { 732 Registrant r = new Registrant (h, what, obj); 733 734 mPinLockedRegistrants.add(r); 735 736 if (getState().isPinLocked()) { 737 r.notifyRegistrant(); 738 } 739 } 740 } 741 742 @Override 743 public void unregisterForLocked(Handler h) { 744 synchronized (mLock) { 745 mPinLockedRegistrants.remove(h); 746 } 747 } 748 749 @Override 750 public void supplyPin(String pin, Message onComplete) { 751 synchronized (mLock) { 752 if (mUiccApplication != null) { 753 mUiccApplication.supplyPin(pin, onComplete); 754 } else if (onComplete != null) { 755 Exception e = new RuntimeException("ICC card is absent."); 756 AsyncResult.forMessage(onComplete).exception = e; 757 onComplete.sendToTarget(); 758 return; 759 } 760 } 761 } 762 763 @Override 764 public void supplyPuk(String puk, String newPin, Message onComplete) { 765 synchronized (mLock) { 766 if (mUiccApplication != null) { 767 mUiccApplication.supplyPuk(puk, newPin, onComplete); 768 } else if (onComplete != null) { 769 Exception e = new RuntimeException("ICC card is absent."); 770 AsyncResult.forMessage(onComplete).exception = e; 771 onComplete.sendToTarget(); 772 return; 773 } 774 } 775 } 776 777 @Override 778 public void supplyPin2(String pin2, Message onComplete) { 779 synchronized (mLock) { 780 if (mUiccApplication != null) { 781 mUiccApplication.supplyPin2(pin2, onComplete); 782 } else if (onComplete != null) { 783 Exception e = new RuntimeException("ICC card is absent."); 784 AsyncResult.forMessage(onComplete).exception = e; 785 onComplete.sendToTarget(); 786 return; 787 } 788 } 789 } 790 791 @Override 792 public void supplyPuk2(String puk2, String newPin2, Message onComplete) { 793 synchronized (mLock) { 794 if (mUiccApplication != null) { 795 mUiccApplication.supplyPuk2(puk2, newPin2, onComplete); 796 } else if (onComplete != null) { 797 Exception e = new RuntimeException("ICC card is absent."); 798 AsyncResult.forMessage(onComplete).exception = e; 799 onComplete.sendToTarget(); 800 return; 801 } 802 } 803 } 804 805 @Override 806 public void supplyNetworkDepersonalization(String pin, Message onComplete) { 807 synchronized (mLock) { 808 if (mUiccApplication != null) { 809 mUiccApplication.supplyNetworkDepersonalization(pin, onComplete); 810 } else if (onComplete != null) { 811 Exception e = new RuntimeException("CommandsInterface is not set."); 812 AsyncResult.forMessage(onComplete).exception = e; 813 onComplete.sendToTarget(); 814 return; 815 } 816 } 817 } 818 819 @Override 820 public boolean getIccLockEnabled() { 821 synchronized (mLock) { 822 /* defaults to false, if ICC is absent/deactivated */ 823 Boolean retValue = mUiccApplication != null ? 824 mUiccApplication.getIccLockEnabled() : false; 825 return retValue; 826 } 827 } 828 829 @Override 830 public boolean getIccFdnEnabled() { 831 synchronized (mLock) { 832 Boolean retValue = mUiccApplication != null ? 833 mUiccApplication.getIccFdnEnabled() : false; 834 return retValue; 835 } 836 } 837 838 public boolean getIccFdnAvailable() { 839 boolean retValue = mUiccApplication != null ? mUiccApplication.getIccFdnAvailable() : false; 840 return retValue; 841 } 842 843 public boolean getIccPin2Blocked() { 844 /* defaults to disabled */ 845 Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccPin2Blocked() : false; 846 return retValue; 847 } 848 849 public boolean getIccPuk2Blocked() { 850 /* defaults to disabled */ 851 Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccPuk2Blocked() : false; 852 return retValue; 853 } 854 855 @Override 856 public void setIccLockEnabled(boolean enabled, String password, Message onComplete) { 857 synchronized (mLock) { 858 if (mUiccApplication != null) { 859 mUiccApplication.setIccLockEnabled(enabled, password, onComplete); 860 } else if (onComplete != null) { 861 Exception e = new RuntimeException("ICC card is absent."); 862 AsyncResult.forMessage(onComplete).exception = e; 863 onComplete.sendToTarget(); 864 return; 865 } 866 } 867 } 868 869 @Override 870 public void setIccFdnEnabled(boolean enabled, String password, Message onComplete) { 871 synchronized (mLock) { 872 if (mUiccApplication != null) { 873 mUiccApplication.setIccFdnEnabled(enabled, password, onComplete); 874 } else if (onComplete != null) { 875 Exception e = new RuntimeException("ICC card is absent."); 876 AsyncResult.forMessage(onComplete).exception = e; 877 onComplete.sendToTarget(); 878 return; 879 } 880 } 881 } 882 883 @Override 884 public void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete) { 885 synchronized (mLock) { 886 if (mUiccApplication != null) { 887 mUiccApplication.changeIccLockPassword(oldPassword, newPassword, onComplete); 888 } else if (onComplete != null) { 889 Exception e = new RuntimeException("ICC card is absent."); 890 AsyncResult.forMessage(onComplete).exception = e; 891 onComplete.sendToTarget(); 892 return; 893 } 894 } 895 } 896 897 @Override 898 public void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete) { 899 synchronized (mLock) { 900 if (mUiccApplication != null) { 901 mUiccApplication.changeIccFdnPassword(oldPassword, newPassword, onComplete); 902 } else if (onComplete != null) { 903 Exception e = new RuntimeException("ICC card is absent."); 904 AsyncResult.forMessage(onComplete).exception = e; 905 onComplete.sendToTarget(); 906 return; 907 } 908 } 909 } 910 911 @Override 912 public String getServiceProviderName() { 913 synchronized (mLock) { 914 if (mIccRecords != null) { 915 return mIccRecords.getServiceProviderName(); 916 } 917 return null; 918 } 919 } 920 921 @Override 922 public boolean isApplicationOnIcc(IccCardApplicationStatus.AppType type) { 923 synchronized (mLock) { 924 Boolean retValue = mUiccCard != null ? mUiccCard.isApplicationOnIcc(type) : false; 925 return retValue; 926 } 927 } 928 929 @Override 930 public boolean hasIccCard() { 931 synchronized (mLock) { 932 if (mUiccCard != null && mUiccCard.getCardState() != CardState.CARDSTATE_ABSENT) { 933 return true; 934 } 935 return false; 936 } 937 } 938 939 private void setSystemProperty(String property, String value) { 940 TelephonyManager.setTelephonyProperty(mPhoneId, property, value); 941 } 942 943 public IccRecords getIccRecord() { 944 return mIccRecords; 945 } 946 private void log(String s) { 947 Rlog.d(LOG_TAG, s); 948 } 949 950 private void loge(String msg) { 951 Rlog.e(LOG_TAG, msg); 952 } 953 954 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 955 pw.println("IccCardProxy: " + this); 956 pw.println(" mContext=" + mContext); 957 pw.println(" mCi=" + mCi); 958 pw.println(" mAbsentRegistrants: size=" + mAbsentRegistrants.size()); 959 for (int i = 0; i < mAbsentRegistrants.size(); i++) { 960 pw.println(" mAbsentRegistrants[" + i + "]=" 961 + ((Registrant)mAbsentRegistrants.get(i)).getHandler()); 962 } 963 pw.println(" mPinLockedRegistrants: size=" + mPinLockedRegistrants.size()); 964 for (int i = 0; i < mPinLockedRegistrants.size(); i++) { 965 pw.println(" mPinLockedRegistrants[" + i + "]=" 966 + ((Registrant)mPinLockedRegistrants.get(i)).getHandler()); 967 } 968 pw.println(" mNetworkLockedRegistrants: size=" + mNetworkLockedRegistrants.size()); 969 for (int i = 0; i < mNetworkLockedRegistrants.size(); i++) { 970 pw.println(" mNetworkLockedRegistrants[" + i + "]=" 971 + ((Registrant)mNetworkLockedRegistrants.get(i)).getHandler()); 972 } 973 pw.println(" mCurrentAppType=" + mCurrentAppType); 974 pw.println(" mUiccController=" + mUiccController); 975 pw.println(" mUiccCard=" + mUiccCard); 976 pw.println(" mUiccApplication=" + mUiccApplication); 977 pw.println(" mIccRecords=" + mIccRecords); 978 pw.println(" mCdmaSSM=" + mCdmaSSM); 979 pw.println(" mRadioState=" + mRadioState); 980 pw.println(" mQuietMode=" + mQuietMode); 981 pw.println(" mInitialized=" + mInitialized); 982 pw.println(" mExternalState=" + mExternalState); 983 984 pw.flush(); 985 } 986 } 987