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             updateExternalState();
366         }
367     }
368 
resetProperties()369     void resetProperties() {
370         if (mCurrentAppType == UiccController.APP_FAM_3GPP) {
371             log("update icc_operator_numeric=" + "");
372             mTelephonyManager.setSimOperatorNumericForPhone(mPhoneId, "");
373             mTelephonyManager.setSimCountryIsoForPhone(mPhoneId, "");
374             mTelephonyManager.setSimOperatorNameForPhone(mPhoneId, "");
375          }
376     }
377 
HandleDetectedState()378     private void HandleDetectedState() {
379     // CAF_MSIM SAND
380 //        setExternalState(State.DETECTED, false);
381     }
382 
updateExternalState()383     private void updateExternalState() {
384 
385         // mUiccCard could be null at bootup, before valid card states have
386         // been received from UiccController.
387         if (mUiccCard == null) {
388             setExternalState(State.NOT_READY);
389             return;
390         }
391 
392         if (mUiccCard.getCardState() == CardState.CARDSTATE_ABSENT) {
393             if (mRadioOn) {
394                 setExternalState(State.ABSENT);
395             } else {
396                 setExternalState(State.NOT_READY);
397             }
398             return;
399         }
400 
401         if (mUiccCard.getCardState() == CardState.CARDSTATE_ERROR) {
402             setExternalState(State.CARD_IO_ERROR);
403             return;
404         }
405 
406         if (mUiccApplication == null) {
407             setExternalState(State.NOT_READY);
408             return;
409         }
410 
411         switch (mUiccApplication.getState()) {
412             case APPSTATE_UNKNOWN:
413                 setExternalState(State.UNKNOWN);
414                 break;
415             case APPSTATE_DETECTED:
416                 HandleDetectedState();
417                 break;
418             case APPSTATE_PIN:
419                 setExternalState(State.PIN_REQUIRED);
420                 break;
421             case APPSTATE_PUK:
422                 setExternalState(State.PUK_REQUIRED);
423                 break;
424             case APPSTATE_SUBSCRIPTION_PERSO:
425                 if (mUiccApplication.getPersoSubState() ==
426                         PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
427                     setExternalState(State.NETWORK_LOCKED);
428                 } else {
429                     setExternalState(State.UNKNOWN);
430                 }
431                 break;
432             case APPSTATE_READY:
433                 setExternalState(State.READY);
434                 break;
435         }
436     }
437 
registerUiccCardEvents()438     private void registerUiccCardEvents() {
439         if (mUiccCard != null) {
440             mUiccCard.registerForAbsent(this, EVENT_ICC_ABSENT, null);
441         }
442         if (mUiccApplication != null) {
443             mUiccApplication.registerForReady(this, EVENT_APP_READY, null);
444             mUiccApplication.registerForLocked(this, EVENT_ICC_LOCKED, null);
445             mUiccApplication.registerForNetworkLocked(this, EVENT_NETWORK_LOCKED, null);
446         }
447         if (mIccRecords != null) {
448             mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null);
449             mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
450             mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
451         }
452     }
453 
unregisterUiccCardEvents()454     private void unregisterUiccCardEvents() {
455         if (mUiccCard != null) mUiccCard.unregisterForAbsent(this);
456         if (mUiccApplication != null) mUiccApplication.unregisterForReady(this);
457         if (mUiccApplication != null) mUiccApplication.unregisterForLocked(this);
458         if (mUiccApplication != null) mUiccApplication.unregisterForNetworkLocked(this);
459         if (mIccRecords != null) mIccRecords.unregisterForImsiReady(this);
460         if (mIccRecords != null) mIccRecords.unregisterForRecordsLoaded(this);
461         if (mIccRecords != null) mIccRecords.unregisterForRecordsEvents(this);
462     }
463 
updateStateProperty()464     private void updateStateProperty() {
465         mTelephonyManager.setSimStateForPhone(mPhoneId, getState().toString());
466     }
467 
broadcastIccStateChangedIntent(String value, String reason)468     private void broadcastIccStateChangedIntent(String value, String reason) {
469         synchronized (mLock) {
470             if (mPhoneId == null || !SubscriptionManager.isValidSlotId(mPhoneId)) {
471                 loge("broadcastIccStateChangedIntent: mPhoneId=" + mPhoneId
472                         + " is invalid; Return!!");
473                 return;
474             }
475 
476             if (mQuietMode) {
477                 log("broadcastIccStateChangedIntent: QuietMode"
478                         + " NOT Broadcasting intent ACTION_SIM_STATE_CHANGED "
479                         + " value=" +  value + " reason=" + reason);
480                 return;
481             }
482 
483             Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
484             // TODO - we'd like this intent to have a single snapshot of all sim state,
485             // but until then this should not use REPLACE_PENDING or we may lose
486             // information
487             // intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
488             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
489             intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
490             intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
491             intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
492             SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhoneId);
493             log("broadcastIccStateChangedIntent intent ACTION_SIM_STATE_CHANGED value=" + value
494                 + " reason=" + reason + " for mPhoneId=" + mPhoneId);
495             ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
496                     UserHandle.USER_ALL);
497         }
498     }
499 
broadcastInternalIccStateChangedIntent(String value, String reason)500     private void broadcastInternalIccStateChangedIntent(String value, String reason) {
501         synchronized (mLock) {
502             if (mPhoneId == null) {
503                 loge("broadcastInternalIccStateChangedIntent: Card Index is not set; Return!!");
504                 return;
505             }
506 
507             Intent intent = new Intent(ACTION_INTERNAL_SIM_STATE_CHANGED);
508             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
509                     | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
510             intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
511             intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
512             intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
513             intent.putExtra(PhoneConstants.PHONE_KEY, mPhoneId);  // SubId may not be valid.
514             log("Sending intent ACTION_INTERNAL_SIM_STATE_CHANGED" + " for mPhoneId : " + mPhoneId);
515             ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
516         }
517     }
518 
setExternalState(State newState, boolean override)519     private void setExternalState(State newState, boolean override) {
520         synchronized (mLock) {
521             if (mPhoneId == null || !SubscriptionManager.isValidSlotId(mPhoneId)) {
522                 loge("setExternalState: mPhoneId=" + mPhoneId + " is invalid; Return!!");
523                 return;
524             }
525 
526             if (!override && newState == mExternalState) {
527                 loge("setExternalState: !override and newstate unchanged from " + newState);
528                 return;
529             }
530             mExternalState = newState;
531             loge("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState);
532             mTelephonyManager.setSimStateForPhone(mPhoneId, getState().toString());
533 
534             // For locked states, we should be sending internal broadcast.
535             if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(getIccStateIntentString(mExternalState))) {
536                 broadcastInternalIccStateChangedIntent(getIccStateIntentString(mExternalState),
537                         getIccStateReason(mExternalState));
538             } else {
539                 broadcastIccStateChangedIntent(getIccStateIntentString(mExternalState),
540                         getIccStateReason(mExternalState));
541             }
542             // TODO: Need to notify registrants for other states as well.
543             if ( State.ABSENT == mExternalState) {
544                 mAbsentRegistrants.notifyRegistrants();
545             }
546         }
547     }
548 
processLockedState()549     private void processLockedState() {
550         synchronized (mLock) {
551             if (mUiccApplication == null) {
552                 //Don't need to do anything if non-existent application is locked
553                 return;
554             }
555             PinState pin1State = mUiccApplication.getPin1State();
556             if (pin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
557                 setExternalState(State.PERM_DISABLED);
558                 return;
559             }
560 
561             AppState appState = mUiccApplication.getState();
562             switch (appState) {
563                 case APPSTATE_PIN:
564                     mPinLockedRegistrants.notifyRegistrants();
565                     setExternalState(State.PIN_REQUIRED);
566                     break;
567                 case APPSTATE_PUK:
568                     setExternalState(State.PUK_REQUIRED);
569                     break;
570                 case APPSTATE_DETECTED:
571                 case APPSTATE_READY:
572                 case APPSTATE_SUBSCRIPTION_PERSO:
573                 case APPSTATE_UNKNOWN:
574                     // Neither required
575                     break;
576             }
577         }
578     }
579 
setExternalState(State newState)580     private void setExternalState(State newState) {
581         setExternalState(newState, false);
582     }
583 
getIccRecordsLoaded()584     public boolean getIccRecordsLoaded() {
585         synchronized (mLock) {
586             if (mIccRecords != null) {
587                 return mIccRecords.getRecordsLoaded();
588             }
589             return false;
590         }
591     }
592 
getIccStateIntentString(State state)593     private String getIccStateIntentString(State state) {
594         switch (state) {
595             case ABSENT: return IccCardConstants.INTENT_VALUE_ICC_ABSENT;
596             case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
597             case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
598             case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
599             case READY: return IccCardConstants.INTENT_VALUE_ICC_READY;
600             case NOT_READY: return IccCardConstants.INTENT_VALUE_ICC_NOT_READY;
601             case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
602             case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR;
603             default: return IccCardConstants.INTENT_VALUE_ICC_UNKNOWN;
604         }
605     }
606 
607     /**
608      * Locked state have a reason (PIN, PUK, NETWORK, PERM_DISABLED, CARD_IO_ERROR)
609      * @return reason
610      */
getIccStateReason(State state)611     private String getIccStateReason(State state) {
612         switch (state) {
613             case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN;
614             case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK;
615             case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_LOCKED_NETWORK;
616             case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED;
617             case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR;
618             default: return null;
619        }
620     }
621 
622     /* IccCard interface implementation */
623     @Override
getState()624     public State getState() {
625         synchronized (mLock) {
626             return mExternalState;
627         }
628     }
629 
630     @Override
getIccRecords()631     public IccRecords getIccRecords() {
632         synchronized (mLock) {
633             return mIccRecords;
634         }
635     }
636 
637     @Override
getIccFileHandler()638     public IccFileHandler getIccFileHandler() {
639         synchronized (mLock) {
640             if (mUiccApplication != null) {
641                 return mUiccApplication.getIccFileHandler();
642             }
643             return null;
644         }
645     }
646 
647     /**
648      * Notifies handler of any transition into State.ABSENT
649      */
650     @Override
registerForAbsent(Handler h, int what, Object obj)651     public void registerForAbsent(Handler h, int what, Object obj) {
652         synchronized (mLock) {
653             Registrant r = new Registrant (h, what, obj);
654 
655             mAbsentRegistrants.add(r);
656 
657             if (getState() == State.ABSENT) {
658                 r.notifyRegistrant();
659             }
660         }
661     }
662 
663     @Override
unregisterForAbsent(Handler h)664     public void unregisterForAbsent(Handler h) {
665         synchronized (mLock) {
666             mAbsentRegistrants.remove(h);
667         }
668     }
669 
670     /**
671      * Notifies handler of any transition into State.NETWORK_LOCKED
672      */
673     @Override
registerForNetworkLocked(Handler h, int what, Object obj)674     public void registerForNetworkLocked(Handler h, int what, Object obj) {
675         synchronized (mLock) {
676             Registrant r = new Registrant (h, what, obj);
677 
678             mNetworkLockedRegistrants.add(r);
679 
680             if (getState() == State.NETWORK_LOCKED) {
681                 r.notifyRegistrant();
682             }
683         }
684     }
685 
686     @Override
unregisterForNetworkLocked(Handler h)687     public void unregisterForNetworkLocked(Handler h) {
688         synchronized (mLock) {
689             mNetworkLockedRegistrants.remove(h);
690         }
691     }
692 
693     /**
694      * Notifies handler of any transition into State.isPinLocked()
695      */
696     @Override
registerForLocked(Handler h, int what, Object obj)697     public void registerForLocked(Handler h, int what, Object obj) {
698         synchronized (mLock) {
699             Registrant r = new Registrant (h, what, obj);
700 
701             mPinLockedRegistrants.add(r);
702 
703             if (getState().isPinLocked()) {
704                 r.notifyRegistrant();
705             }
706         }
707     }
708 
709     @Override
unregisterForLocked(Handler h)710     public void unregisterForLocked(Handler h) {
711         synchronized (mLock) {
712             mPinLockedRegistrants.remove(h);
713         }
714     }
715 
716     @Override
supplyPin(String pin, Message onComplete)717     public void supplyPin(String pin, Message onComplete) {
718         synchronized (mLock) {
719             if (mUiccApplication != null) {
720                 mUiccApplication.supplyPin(pin, onComplete);
721             } else if (onComplete != null) {
722                 Exception e = new RuntimeException("ICC card is absent.");
723                 AsyncResult.forMessage(onComplete).exception = e;
724                 onComplete.sendToTarget();
725                 return;
726             }
727         }
728     }
729 
730     @Override
supplyPuk(String puk, String newPin, Message onComplete)731     public void supplyPuk(String puk, String newPin, Message onComplete) {
732         synchronized (mLock) {
733             if (mUiccApplication != null) {
734                 mUiccApplication.supplyPuk(puk, newPin, onComplete);
735             } else if (onComplete != null) {
736                 Exception e = new RuntimeException("ICC card is absent.");
737                 AsyncResult.forMessage(onComplete).exception = e;
738                 onComplete.sendToTarget();
739                 return;
740             }
741         }
742     }
743 
744     @Override
supplyPin2(String pin2, Message onComplete)745     public void supplyPin2(String pin2, Message onComplete) {
746         synchronized (mLock) {
747             if (mUiccApplication != null) {
748                 mUiccApplication.supplyPin2(pin2, onComplete);
749             } else if (onComplete != null) {
750                 Exception e = new RuntimeException("ICC card is absent.");
751                 AsyncResult.forMessage(onComplete).exception = e;
752                 onComplete.sendToTarget();
753                 return;
754             }
755         }
756     }
757 
758     @Override
supplyPuk2(String puk2, String newPin2, Message onComplete)759     public void supplyPuk2(String puk2, String newPin2, Message onComplete) {
760         synchronized (mLock) {
761             if (mUiccApplication != null) {
762                 mUiccApplication.supplyPuk2(puk2, newPin2, onComplete);
763             } else if (onComplete != null) {
764                 Exception e = new RuntimeException("ICC card is absent.");
765                 AsyncResult.forMessage(onComplete).exception = e;
766                 onComplete.sendToTarget();
767                 return;
768             }
769         }
770     }
771 
772     @Override
supplyNetworkDepersonalization(String pin, Message onComplete)773     public void supplyNetworkDepersonalization(String pin, Message onComplete) {
774         synchronized (mLock) {
775             if (mUiccApplication != null) {
776                 mUiccApplication.supplyNetworkDepersonalization(pin, onComplete);
777             } else if (onComplete != null) {
778                 Exception e = new RuntimeException("CommandsInterface is not set.");
779                 AsyncResult.forMessage(onComplete).exception = e;
780                 onComplete.sendToTarget();
781                 return;
782             }
783         }
784     }
785 
786     @Override
getIccLockEnabled()787     public boolean getIccLockEnabled() {
788         synchronized (mLock) {
789             /* defaults to false, if ICC is absent/deactivated */
790             Boolean retValue = mUiccApplication != null ?
791                     mUiccApplication.getIccLockEnabled() : false;
792             return retValue;
793         }
794     }
795 
796     @Override
getIccFdnEnabled()797     public boolean getIccFdnEnabled() {
798         synchronized (mLock) {
799             Boolean retValue = mUiccApplication != null ?
800                     mUiccApplication.getIccFdnEnabled() : false;
801             return retValue;
802         }
803     }
804 
getIccFdnAvailable()805     public boolean getIccFdnAvailable() {
806         boolean retValue = mUiccApplication != null ? mUiccApplication.getIccFdnAvailable() : false;
807         return retValue;
808     }
809 
getIccPin2Blocked()810     public boolean getIccPin2Blocked() {
811         /* defaults to disabled */
812         Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccPin2Blocked() : false;
813         return retValue;
814     }
815 
getIccPuk2Blocked()816     public boolean getIccPuk2Blocked() {
817         /* defaults to disabled */
818         Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccPuk2Blocked() : false;
819         return retValue;
820     }
821 
822     @Override
setIccLockEnabled(boolean enabled, String password, Message onComplete)823     public void setIccLockEnabled(boolean enabled, String password, Message onComplete) {
824         synchronized (mLock) {
825             if (mUiccApplication != null) {
826                 mUiccApplication.setIccLockEnabled(enabled, password, onComplete);
827             } else if (onComplete != null) {
828                 Exception e = new RuntimeException("ICC card is absent.");
829                 AsyncResult.forMessage(onComplete).exception = e;
830                 onComplete.sendToTarget();
831                 return;
832             }
833         }
834     }
835 
836     @Override
setIccFdnEnabled(boolean enabled, String password, Message onComplete)837     public void setIccFdnEnabled(boolean enabled, String password, Message onComplete) {
838         synchronized (mLock) {
839             if (mUiccApplication != null) {
840                 mUiccApplication.setIccFdnEnabled(enabled, password, onComplete);
841             } else if (onComplete != null) {
842                 Exception e = new RuntimeException("ICC card is absent.");
843                 AsyncResult.forMessage(onComplete).exception = e;
844                 onComplete.sendToTarget();
845                 return;
846             }
847         }
848     }
849 
850     @Override
changeIccLockPassword(String oldPassword, String newPassword, Message onComplete)851     public void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete) {
852         synchronized (mLock) {
853             if (mUiccApplication != null) {
854                 mUiccApplication.changeIccLockPassword(oldPassword, newPassword, onComplete);
855             } else if (onComplete != null) {
856                 Exception e = new RuntimeException("ICC card is absent.");
857                 AsyncResult.forMessage(onComplete).exception = e;
858                 onComplete.sendToTarget();
859                 return;
860             }
861         }
862     }
863 
864     @Override
changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete)865     public void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete) {
866         synchronized (mLock) {
867             if (mUiccApplication != null) {
868                 mUiccApplication.changeIccFdnPassword(oldPassword, newPassword, onComplete);
869             } else if (onComplete != null) {
870                 Exception e = new RuntimeException("ICC card is absent.");
871                 AsyncResult.forMessage(onComplete).exception = e;
872                 onComplete.sendToTarget();
873                 return;
874             }
875         }
876     }
877 
878     @Override
getServiceProviderName()879     public String getServiceProviderName() {
880         synchronized (mLock) {
881             if (mIccRecords != null) {
882                 return mIccRecords.getServiceProviderName();
883             }
884             return null;
885         }
886     }
887 
888     @Override
isApplicationOnIcc(IccCardApplicationStatus.AppType type)889     public boolean isApplicationOnIcc(IccCardApplicationStatus.AppType type) {
890         synchronized (mLock) {
891             Boolean retValue = mUiccCard != null ? mUiccCard.isApplicationOnIcc(type) : false;
892             return retValue;
893         }
894     }
895 
896     @Override
hasIccCard()897     public boolean hasIccCard() {
898         synchronized (mLock) {
899             if (mUiccCard != null && mUiccCard.getCardState() != CardState.CARDSTATE_ABSENT) {
900                 return true;
901             }
902             return false;
903         }
904     }
905 
setSystemProperty(String property, String value)906     private void setSystemProperty(String property, String value) {
907         TelephonyManager.setTelephonyProperty(mPhoneId, property, value);
908     }
909 
getIccRecord()910     public IccRecords getIccRecord() {
911         return mIccRecords;
912     }
log(String s)913     private void log(String s) {
914         Rlog.d(LOG_TAG, s);
915     }
916 
loge(String msg)917     private void loge(String msg) {
918         Rlog.e(LOG_TAG, msg);
919     }
920 
dump(FileDescriptor fd, PrintWriter pw, String[] args)921     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
922         pw.println("IccCardProxy: " + this);
923         pw.println(" mContext=" + mContext);
924         pw.println(" mCi=" + mCi);
925         pw.println(" mAbsentRegistrants: size=" + mAbsentRegistrants.size());
926         for (int i = 0; i < mAbsentRegistrants.size(); i++) {
927             pw.println("  mAbsentRegistrants[" + i + "]="
928                     + ((Registrant)mAbsentRegistrants.get(i)).getHandler());
929         }
930         pw.println(" mPinLockedRegistrants: size=" + mPinLockedRegistrants.size());
931         for (int i = 0; i < mPinLockedRegistrants.size(); i++) {
932             pw.println("  mPinLockedRegistrants[" + i + "]="
933                     + ((Registrant)mPinLockedRegistrants.get(i)).getHandler());
934         }
935         pw.println(" mNetworkLockedRegistrants: size=" + mNetworkLockedRegistrants.size());
936         for (int i = 0; i < mNetworkLockedRegistrants.size(); i++) {
937             pw.println("  mNetworkLockedRegistrants[" + i + "]="
938                     + ((Registrant)mNetworkLockedRegistrants.get(i)).getHandler());
939         }
940         pw.println(" mCurrentAppType=" + mCurrentAppType);
941         pw.println(" mUiccController=" + mUiccController);
942         pw.println(" mUiccCard=" + mUiccCard);
943         pw.println(" mUiccApplication=" + mUiccApplication);
944         pw.println(" mIccRecords=" + mIccRecords);
945         pw.println(" mCdmaSSM=" + mCdmaSSM);
946         pw.println(" mRadioOn=" + mRadioOn);
947         pw.println(" mQuietMode=" + mQuietMode);
948         pw.println(" mInitialized=" + mInitialized);
949         pw.println(" mExternalState=" + mExternalState);
950 
951         pw.flush();
952     }
953 }
954