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