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