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