• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 newQuietMode;
174             int cdmaSource = Phone.CDMA_SUBSCRIPTION_UNKNOWN;
175             if (mCurrentAppType == UiccController.APP_FAM_3GPP) {
176                 newQuietMode = false;
177                 if (DBG) log("updateQuietMode: 3GPP subscription -> newQuietMode=" + newQuietMode);
178             } else {
179                 cdmaSource = mCdmaSSM != null ?
180                         mCdmaSSM.getCdmaSubscriptionSource() : Phone.CDMA_SUBSCRIPTION_UNKNOWN;
181 
182                 newQuietMode = (cdmaSource == Phone.CDMA_SUBSCRIPTION_NV)
183                         && (mCurrentAppType == UiccController.APP_FAM_3GPP2);
184             }
185 
186             if (mQuietMode == false && newQuietMode == true) {
187                 // Last thing to do before switching to quiet mode is
188                 // broadcast ICC_READY
189                 log("Switching to QuietMode.");
190                 setExternalState(State.READY);
191                 mQuietMode = newQuietMode;
192             } else if (mQuietMode == true && newQuietMode == false) {
193                 if (DBG) {
194                     log("updateQuietMode: Switching out from QuietMode."
195                             + " Force broadcast of current state=" + mExternalState);
196                 }
197                 mQuietMode = newQuietMode;
198                 setExternalState(mExternalState, true);
199             } else {
200                 if (DBG) log("updateQuietMode: no changes don't setExternalState");
201             }
202             if (DBG) {
203                 log("updateQuietMode: QuietMode is " + mQuietMode + " (app_type="
204                     + mCurrentAppType + " cdmaSource=" + cdmaSource + ")");
205             }
206             mInitialized = true;
207             sendMessage(obtainMessage(EVENT_ICC_CHANGED));
208         }
209     }
210 
211     @Override
handleMessage(Message msg)212     public void handleMessage(Message msg) {
213         switch (msg.what) {
214             case EVENT_RADIO_OFF_OR_UNAVAILABLE:
215                 mRadioOn = false;
216                 if (CommandsInterface.RadioState.RADIO_UNAVAILABLE == mCi.getRadioState()) {
217                     setExternalState(State.NOT_READY);
218                 }
219                 break;
220             case EVENT_RADIO_ON:
221                 mRadioOn = true;
222                 if (!mInitialized) {
223                     updateQuietMode();
224                 }
225                 break;
226             case EVENT_ICC_CHANGED:
227                 if (mInitialized) {
228                     updateIccAvailability();
229                 }
230                 break;
231             case EVENT_ICC_ABSENT:
232                 mAbsentRegistrants.notifyRegistrants();
233                 setExternalState(State.ABSENT);
234                 break;
235             case EVENT_ICC_LOCKED:
236                 processLockedState();
237                 break;
238             case EVENT_APP_READY:
239                 setExternalState(State.READY);
240                 break;
241             case EVENT_RECORDS_LOADED:
242                 // Update the MCC/MNC.
243                 if (mIccRecords != null) {
244                     String operator = mIccRecords.getOperatorNumeric();
245                     log("operator=" + operator + " mPhoneId=" + mPhoneId);
246 
247                     if (operator != null) {
248                         mTelephonyManager.setSimOperatorNumericForPhone(mPhoneId, operator);
249                         String countryCode = operator.substring(0,3);
250                         if (countryCode != null) {
251                             mTelephonyManager.setSimCountryIsoForPhone(mPhoneId,
252                                     MccTable.countryCodeForMcc(Integer.parseInt(countryCode)));
253                         } else {
254                             loge("EVENT_RECORDS_LOADED Country code is null");
255                         }
256                     } else {
257                         loge("EVENT_RECORDS_LOADED Operator name is null");
258                     }
259                 }
260                 if (mUiccCard != null && !mUiccCard.areCarrierPriviligeRulesLoaded()) {
261                     mUiccCard.registerForCarrierPrivilegeRulesLoaded(
262                         this, EVENT_CARRIER_PRIVILIGES_LOADED, null);
263                 } else {
264                     onRecordsLoaded();
265                 }
266                 break;
267             case EVENT_IMSI_READY:
268                 broadcastIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_IMSI, null);
269                 break;
270             case EVENT_NETWORK_LOCKED:
271                 mNetworkLockedRegistrants.notifyRegistrants();
272                 setExternalState(State.NETWORK_LOCKED);
273                 break;
274             case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
275                 updateQuietMode();
276                 break;
277             case EVENT_SUBSCRIPTION_ACTIVATED:
278                 log("EVENT_SUBSCRIPTION_ACTIVATED");
279                 onSubscriptionActivated();
280                 break;
281 
282             case EVENT_SUBSCRIPTION_DEACTIVATED:
283                 log("EVENT_SUBSCRIPTION_DEACTIVATED");
284                 onSubscriptionDeactivated();
285                 break;
286 
287             case EVENT_ICC_RECORD_EVENTS:
288                 if ((mCurrentAppType == UiccController.APP_FAM_3GPP) && (mIccRecords != null)) {
289                     AsyncResult ar = (AsyncResult)msg.obj;
290                     int eventCode = (Integer) ar.result;
291                     if (eventCode == SIMRecords.EVENT_SPN) {
292                         mTelephonyManager.setSimOperatorNameForPhone(
293                                 mPhoneId, mIccRecords.getServiceProviderName());
294                     }
295                 }
296                 break;
297 
298             case EVENT_CARRIER_PRIVILIGES_LOADED:
299                 log("EVENT_CARRIER_PRIVILEGES_LOADED");
300                 if (mUiccCard != null) {
301                     mUiccCard.unregisterForCarrierPrivilegeRulesLoaded(this);
302                 }
303                 onRecordsLoaded();
304                 break;
305 
306             default:
307                 loge("Unhandled message with number: " + msg.what);
308                 break;
309         }
310     }
311 
onSubscriptionActivated()312     private void onSubscriptionActivated() {
313         updateIccAvailability();
314         updateStateProperty();
315     }
316 
onSubscriptionDeactivated()317     private void onSubscriptionDeactivated() {
318         resetProperties();
319         updateIccAvailability();
320         updateStateProperty();
321     }
322 
onRecordsLoaded()323     private void onRecordsLoaded() {
324         broadcastInternalIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
325     }
326 
updateIccAvailability()327     private void updateIccAvailability() {
328         synchronized (mLock) {
329             UiccCard newCard = mUiccController.getUiccCard(mPhoneId);
330             CardState state = CardState.CARDSTATE_ABSENT;
331             UiccCardApplication newApp = null;
332             IccRecords newRecords = null;
333             if (newCard != null) {
334                 state = newCard.getCardState();
335                 newApp = newCard.getApplication(mCurrentAppType);
336                 if (newApp != null) {
337                     newRecords = newApp.getIccRecords();
338                 }
339             }
340 
341             if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) {
342                 if (DBG) log("Icc changed. Reregestering.");
343                 unregisterUiccCardEvents();
344                 mUiccCard = newCard;
345                 mUiccApplication = newApp;
346                 mIccRecords = newRecords;
347                 registerUiccCardEvents();
348             }
349             updateExternalState();
350         }
351     }
352 
resetProperties()353     void resetProperties() {
354         if (mCurrentAppType == UiccController.APP_FAM_3GPP) {
355             log("update icc_operator_numeric=" + "");
356             mTelephonyManager.setSimOperatorNumericForPhone(mPhoneId, "");
357             mTelephonyManager.setSimCountryIsoForPhone(mPhoneId, "");
358             mTelephonyManager.setSimOperatorNameForPhone(mPhoneId, "");
359          }
360     }
361 
HandleDetectedState()362     private void HandleDetectedState() {
363     // CAF_MSIM SAND
364 //        setExternalState(State.DETECTED, false);
365     }
366 
updateExternalState()367     private void updateExternalState() {
368 
369         // mUiccCard could be null at bootup, before valid card states have
370         // been received from UiccController.
371         if (mUiccCard == null) {
372             setExternalState(State.NOT_READY);
373             return;
374         }
375 
376         if (mUiccCard.getCardState() == CardState.CARDSTATE_ABSENT) {
377             if (mRadioOn) {
378                 setExternalState(State.ABSENT);
379             } else {
380                 setExternalState(State.NOT_READY);
381             }
382             return;
383         }
384 
385         if (mUiccCard.getCardState() == CardState.CARDSTATE_ERROR) {
386             setExternalState(State.CARD_IO_ERROR);
387             return;
388         }
389 
390         if (mUiccCard.getCardState() == CardState.CARDSTATE_RESTRICTED) {
391             setExternalState(State.CARD_RESTRICTED);
392             return;
393         }
394 
395         if (mUiccApplication == null) {
396             setExternalState(State.NOT_READY);
397             return;
398         }
399 
400         switch (mUiccApplication.getState()) {
401             case APPSTATE_UNKNOWN:
402                 setExternalState(State.UNKNOWN);
403                 break;
404             case APPSTATE_DETECTED:
405                 HandleDetectedState();
406                 break;
407             case APPSTATE_PIN:
408                 setExternalState(State.PIN_REQUIRED);
409                 break;
410             case APPSTATE_PUK:
411                 setExternalState(State.PUK_REQUIRED);
412                 break;
413             case APPSTATE_SUBSCRIPTION_PERSO:
414                 if (mUiccApplication.getPersoSubState() ==
415                         PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
416                     setExternalState(State.NETWORK_LOCKED);
417                 } else {
418                     setExternalState(State.UNKNOWN);
419                 }
420                 break;
421             case APPSTATE_READY:
422                 setExternalState(State.READY);
423                 break;
424         }
425     }
426 
registerUiccCardEvents()427     private void registerUiccCardEvents() {
428         if (mUiccCard != null) {
429             mUiccCard.registerForAbsent(this, EVENT_ICC_ABSENT, null);
430         }
431         if (mUiccApplication != null) {
432             mUiccApplication.registerForReady(this, EVENT_APP_READY, null);
433             mUiccApplication.registerForLocked(this, EVENT_ICC_LOCKED, null);
434             mUiccApplication.registerForNetworkLocked(this, EVENT_NETWORK_LOCKED, null);
435         }
436         if (mIccRecords != null) {
437             mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null);
438             mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
439             mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
440         }
441     }
442 
unregisterUiccCardEvents()443     private void unregisterUiccCardEvents() {
444         if (mUiccCard != null) mUiccCard.unregisterForAbsent(this);
445         if (mUiccApplication != null) mUiccApplication.unregisterForReady(this);
446         if (mUiccApplication != null) mUiccApplication.unregisterForLocked(this);
447         if (mUiccApplication != null) mUiccApplication.unregisterForNetworkLocked(this);
448         if (mIccRecords != null) mIccRecords.unregisterForImsiReady(this);
449         if (mIccRecords != null) mIccRecords.unregisterForRecordsLoaded(this);
450         if (mIccRecords != null) mIccRecords.unregisterForRecordsEvents(this);
451     }
452 
updateStateProperty()453     private void updateStateProperty() {
454         mTelephonyManager.setSimStateForPhone(mPhoneId, getState().toString());
455     }
456 
broadcastIccStateChangedIntent(String value, String reason)457     private void broadcastIccStateChangedIntent(String value, String reason) {
458         synchronized (mLock) {
459             if (mPhoneId == null || !SubscriptionManager.isValidSlotId(mPhoneId)) {
460                 loge("broadcastIccStateChangedIntent: mPhoneId=" + mPhoneId
461                         + " is invalid; Return!!");
462                 return;
463             }
464 
465             if (mQuietMode) {
466                 log("broadcastIccStateChangedIntent: QuietMode"
467                         + " NOT Broadcasting intent ACTION_SIM_STATE_CHANGED "
468                         + " value=" +  value + " reason=" + reason);
469                 return;
470             }
471 
472             Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
473             // TODO - we'd like this intent to have a single snapshot of all sim state,
474             // but until then this should not use REPLACE_PENDING or we may lose
475             // information
476             // intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
477             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
478             intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
479             intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
480             intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
481             SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhoneId);
482             log("broadcastIccStateChangedIntent intent ACTION_SIM_STATE_CHANGED value=" + value
483                 + " reason=" + reason + " for mPhoneId=" + mPhoneId);
484             ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
485                     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             ActivityManagerNative.broadcastStickyIntent(intent, null, 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.isValidSlotId(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