IccCardProxy.java revision 5d8e4457b03d166aa249989916b66a85df898516
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                if (CommandsInterface.RadioState.RADIO_UNAVAILABLE == mCi.getRadioState()) {
234                    setExternalState(State.NOT_READY);
235                }
236                break;
237            case EVENT_RADIO_ON:
238                mRadioOn = true;
239                if (!mInitialized) {
240                    updateQuietMode();
241                }
242                break;
243            case EVENT_ICC_CHANGED:
244                if (mInitialized) {
245                    updateIccAvailability();
246                }
247                break;
248            case EVENT_ICC_ABSENT:
249                mAbsentRegistrants.notifyRegistrants();
250                setExternalState(State.ABSENT);
251                break;
252            case EVENT_ICC_LOCKED:
253                processLockedState();
254                break;
255            case EVENT_APP_READY:
256                setExternalState(State.READY);
257                break;
258            case EVENT_RECORDS_LOADED:
259                if (mIccRecords != null) {
260                    String operator = mIccRecords.getOperatorNumeric();
261                    int slotId = mCardIndex;
262
263                    log("operator = " + operator + " slotId = " + slotId);
264
265                    if (operator != null) {
266                        log("update icc_operator_numeric=" + operator);
267                        setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, slotId, operator);
268                        String countryCode = operator.substring(0,3);
269                        if (countryCode != null) {
270                            setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, slotId,
271                                    MccTable.countryCodeForMcc(Integer.parseInt(countryCode)));
272                        } else {
273                            loge("EVENT_RECORDS_LOADED Country code is null");
274                        }
275
276                        long[] subId = SubscriptionController.getInstance().getSubId(slotId);
277                        // Update MCC MNC device configuration information only for default sub.
278                        if (subId[0] == SubscriptionController.getInstance().getDefaultSubId()) {
279                            log("update mccmnc=" + operator + " config for default subscription.");
280                            MccTable.updateMccMncConfiguration(mContext, operator, false);
281                        }
282                        SubscriptionController.getInstance().setMccMnc(operator, subId[0]);
283                    } else {
284                        loge("EVENT_RECORDS_LOADED Operator name is null");
285                    }
286                }
287                if (mUiccCard != null && !mUiccCard.areCarrierPriviligeRulesLoaded()) {
288                    mUiccCard.registerForCarrierPrivilegeRulesLoaded(
289                        this, EVENT_CARRIER_PRIVILIGES_LOADED, null);
290                } else {
291                    onRecordsLoaded();
292                }
293                break;
294            case EVENT_IMSI_READY:
295                broadcastIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_IMSI, null);
296                break;
297            case EVENT_NETWORK_LOCKED:
298                mNetworkLockedRegistrants.notifyRegistrants();
299                setExternalState(State.NETWORK_LOCKED);
300                break;
301            case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
302                updateQuietMode();
303                break;
304            case EVENT_SUBSCRIPTION_ACTIVATED:
305                log("EVENT_SUBSCRIPTION_ACTIVATED");
306                onSubscriptionActivated();
307                break;
308
309            case EVENT_SUBSCRIPTION_DEACTIVATED:
310                log("EVENT_SUBSCRIPTION_DEACTIVATED");
311                onSubscriptionDeactivated();
312                break;
313
314            case EVENT_ICC_RECORD_EVENTS:
315                if ((mCurrentAppType == UiccController.APP_FAM_3GPP) && (mIccRecords != null)) {
316                    int slotId = mCardIndex;
317                    AsyncResult ar = (AsyncResult)msg.obj;
318                    int eventCode = (Integer) ar.result;
319                    if (eventCode == SIMRecords.EVENT_SPN) {
320                        setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, slotId,
321                                mIccRecords.getServiceProviderName());
322                    }
323                }
324                break;
325
326            case EVENT_CARRIER_PRIVILIGES_LOADED:
327                log("EVENT_CARRIER_PRIVILEGES_LOADED");
328                if (mUiccCard != null) {
329                    mUiccCard.unregisterForCarrierPrivilegeRulesLoaded(this);
330                }
331                onRecordsLoaded();
332                break;
333
334            default:
335                loge("Unhandled message with number: " + msg.what);
336                break;
337        }
338    }
339
340    private void onSubscriptionActivated() {
341        //mSubscriptionData = SubscriptionManager.getCurrentSubscription(mCardIndex);
342
343        updateIccAvailability();
344        updateStateProperty();
345    }
346
347    private void onSubscriptionDeactivated() {
348        resetProperties();
349        mSubscriptionData = null;
350        updateIccAvailability();
351        updateStateProperty();
352    }
353
354    private void onRecordsLoaded() {
355        broadcastIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
356    }
357
358    private void updateIccAvailability() {
359        synchronized (mLock) {
360            UiccCard newCard = mUiccController.getUiccCard(mCardIndex);
361            CardState state = CardState.CARDSTATE_ABSENT;
362            UiccCardApplication newApp = null;
363            IccRecords newRecords = null;
364            if (newCard != null) {
365                state = newCard.getCardState();
366                newApp = newCard.getApplication(mCurrentAppType);
367                if (newApp != null) {
368                    newRecords = newApp.getIccRecords();
369                }
370            }
371
372            if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) {
373                if (DBG) log("Icc changed. Reregestering.");
374                unregisterUiccCardEvents();
375                mUiccCard = newCard;
376                mUiccApplication = newApp;
377                mIccRecords = newRecords;
378                registerUiccCardEvents();
379            }
380
381            updateExternalState();
382        }
383    }
384
385    void resetProperties() {
386        if (mCurrentAppType == UiccController.APP_FAM_3GPP) {
387            log("update icc_operator_numeric=" + "");
388            setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, mCardIndex, "");
389            setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, mCardIndex, "");
390            setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, mCardIndex, "");
391         }
392    }
393
394    private void HandleDetectedState() {
395    // CAF_MSIM SAND
396//        setExternalState(State.DETECTED, false);
397    }
398
399    private void updateExternalState() {
400        if (mUiccCard == null || mUiccCard.getCardState() == CardState.CARDSTATE_ABSENT) {
401            if (mRadioOn) {
402                setExternalState(State.ABSENT);
403            } else {
404                setExternalState(State.NOT_READY);
405            }
406            return;
407        }
408
409        if (mUiccCard.getCardState() == CardState.CARDSTATE_ERROR) {
410            setExternalState(State.CARD_IO_ERROR);
411            return;
412        }
413
414        if (mUiccApplication == null) {
415            setExternalState(State.NOT_READY);
416            return;
417        }
418
419        switch (mUiccApplication.getState()) {
420            case APPSTATE_UNKNOWN:
421                setExternalState(State.UNKNOWN);
422                break;
423            case APPSTATE_DETECTED:
424                HandleDetectedState();
425                break;
426            case APPSTATE_PIN:
427                setExternalState(State.PIN_REQUIRED);
428                break;
429            case APPSTATE_PUK:
430                setExternalState(State.PUK_REQUIRED);
431                break;
432            case APPSTATE_SUBSCRIPTION_PERSO:
433                if (mUiccApplication.getPersoSubState() ==
434                        PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
435                    setExternalState(State.NETWORK_LOCKED);
436                } else {
437                    setExternalState(State.UNKNOWN);
438                }
439                break;
440            case APPSTATE_READY:
441                setExternalState(State.READY);
442                break;
443        }
444    }
445
446    private void registerUiccCardEvents() {
447        if (mUiccCard != null) {
448            mUiccCard.registerForAbsent(this, EVENT_ICC_ABSENT, null);
449        }
450        if (mUiccApplication != null) {
451            mUiccApplication.registerForReady(this, EVENT_APP_READY, null);
452            mUiccApplication.registerForLocked(this, EVENT_ICC_LOCKED, null);
453            mUiccApplication.registerForNetworkLocked(this, EVENT_NETWORK_LOCKED, null);
454        }
455        if (mIccRecords != null) {
456            mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null);
457            mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
458            mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
459        }
460    }
461
462    private void unregisterUiccCardEvents() {
463        if (mUiccCard != null) mUiccCard.unregisterForAbsent(this);
464        if (mUiccApplication != null) mUiccApplication.unregisterForReady(this);
465        if (mUiccApplication != null) mUiccApplication.unregisterForLocked(this);
466        if (mUiccApplication != null) mUiccApplication.unregisterForNetworkLocked(this);
467        if (mIccRecords != null) mIccRecords.unregisterForImsiReady(this);
468        if (mIccRecords != null) mIccRecords.unregisterForRecordsLoaded(this);
469        if (mIccRecords != null) mIccRecords.unregisterForRecordsEvents(this);
470    }
471
472    private void updateStateProperty() {
473        setSystemProperty(PROPERTY_SIM_STATE, mCardIndex,getState().toString());
474    }
475
476    private void broadcastIccStateChangedIntent(String value, String reason) {
477        synchronized (mLock) {
478            if (mCardIndex == null) {
479                loge("broadcastIccStateChangedIntent: Card Index is not set; Return!!");
480                return;
481            }
482
483            if (mQuietMode) {
484                log("QuietMode: NOT Broadcasting intent ACTION_SIM_STATE_CHANGED " +  value
485                        + " reason " + reason);
486                return;
487            }
488
489            Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
490            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
491            intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
492            intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
493            intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
494            SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mCardIndex);
495            log("Broadcasting intent ACTION_SIM_STATE_CHANGED " +  value
496                + " reason " + reason + " for mCardIndex : " + mCardIndex);
497            ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
498                    UserHandle.USER_ALL);
499        }
500    }
501
502    private void setExternalState(State newState, boolean override) {
503        synchronized (mLock) {
504            if (mCardIndex == null) {
505                loge("setExternalState: Card Index is not set; Return!!");
506                return;
507            }
508
509            if (!override && newState == mExternalState) {
510                return;
511            }
512            mExternalState = newState;
513            setSystemProperty(PROPERTY_SIM_STATE, mCardIndex, getState().toString());
514            broadcastIccStateChangedIntent(getIccStateIntentString(mExternalState),
515                    getIccStateReason(mExternalState));
516            // TODO: Need to notify registrants for other states as well.
517            if ( State.ABSENT == mExternalState) {
518                mAbsentRegistrants.notifyRegistrants();
519            }
520        }
521    }
522
523    private void processLockedState() {
524        synchronized (mLock) {
525            if (mUiccApplication == null) {
526                //Don't need to do anything if non-existent application is locked
527                return;
528            }
529            PinState pin1State = mUiccApplication.getPin1State();
530            if (pin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
531                setExternalState(State.PERM_DISABLED);
532                return;
533            }
534
535            AppState appState = mUiccApplication.getState();
536            switch (appState) {
537                case APPSTATE_PIN:
538                    mPinLockedRegistrants.notifyRegistrants();
539                    setExternalState(State.PIN_REQUIRED);
540                    break;
541                case APPSTATE_PUK:
542                    setExternalState(State.PUK_REQUIRED);
543                    break;
544                case APPSTATE_DETECTED:
545                case APPSTATE_READY:
546                case APPSTATE_SUBSCRIPTION_PERSO:
547                case APPSTATE_UNKNOWN:
548                    // Neither required
549                    break;
550            }
551        }
552    }
553
554    private void setExternalState(State newState) {
555        setExternalState(newState, false);
556    }
557
558    public boolean getIccRecordsLoaded() {
559        synchronized (mLock) {
560            if (mIccRecords != null) {
561                return mIccRecords.getRecordsLoaded();
562            }
563            return false;
564        }
565    }
566
567    private String getIccStateIntentString(State state) {
568        switch (state) {
569            case ABSENT: return IccCardConstants.INTENT_VALUE_ICC_ABSENT;
570            case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
571            case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
572            case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
573            case READY: return IccCardConstants.INTENT_VALUE_ICC_READY;
574            case NOT_READY: return IccCardConstants.INTENT_VALUE_ICC_NOT_READY;
575            case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
576            case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR;
577            default: return IccCardConstants.INTENT_VALUE_ICC_UNKNOWN;
578        }
579    }
580
581    /**
582     * Locked state have a reason (PIN, PUK, NETWORK, PERM_DISABLED, CARD_IO_ERROR)
583     * @return reason
584     */
585    private String getIccStateReason(State state) {
586        switch (state) {
587            case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN;
588            case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK;
589            case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_LOCKED_NETWORK;
590            case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED;
591            case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR;
592            default: return null;
593       }
594    }
595
596    /* IccCard interface implementation */
597    @Override
598    public State getState() {
599        synchronized (mLock) {
600            return mExternalState;
601        }
602    }
603
604    @Override
605    public IccRecords getIccRecords() {
606        synchronized (mLock) {
607            return mIccRecords;
608        }
609    }
610
611    @Override
612    public IccFileHandler getIccFileHandler() {
613        synchronized (mLock) {
614            if (mUiccApplication != null) {
615                return mUiccApplication.getIccFileHandler();
616            }
617            return null;
618        }
619    }
620
621    /**
622     * Notifies handler of any transition into State.ABSENT
623     */
624    @Override
625    public void registerForAbsent(Handler h, int what, Object obj) {
626        synchronized (mLock) {
627            Registrant r = new Registrant (h, what, obj);
628
629            mAbsentRegistrants.add(r);
630
631            if (getState() == State.ABSENT) {
632                r.notifyRegistrant();
633            }
634        }
635    }
636
637    @Override
638    public void unregisterForAbsent(Handler h) {
639        synchronized (mLock) {
640            mAbsentRegistrants.remove(h);
641        }
642    }
643
644    /**
645     * Notifies handler of any transition into State.NETWORK_LOCKED
646     */
647    @Override
648    public void registerForNetworkLocked(Handler h, int what, Object obj) {
649        synchronized (mLock) {
650            Registrant r = new Registrant (h, what, obj);
651
652            mNetworkLockedRegistrants.add(r);
653
654            if (getState() == State.NETWORK_LOCKED) {
655                r.notifyRegistrant();
656            }
657        }
658    }
659
660    @Override
661    public void unregisterForNetworkLocked(Handler h) {
662        synchronized (mLock) {
663            mNetworkLockedRegistrants.remove(h);
664        }
665    }
666
667    /**
668     * Notifies handler of any transition into State.isPinLocked()
669     */
670    @Override
671    public void registerForLocked(Handler h, int what, Object obj) {
672        synchronized (mLock) {
673            Registrant r = new Registrant (h, what, obj);
674
675            mPinLockedRegistrants.add(r);
676
677            if (getState().isPinLocked()) {
678                r.notifyRegistrant();
679            }
680        }
681    }
682
683    @Override
684    public void unregisterForLocked(Handler h) {
685        synchronized (mLock) {
686            mPinLockedRegistrants.remove(h);
687        }
688    }
689
690    @Override
691    public void supplyPin(String pin, Message onComplete) {
692        synchronized (mLock) {
693            if (mUiccApplication != null) {
694                mUiccApplication.supplyPin(pin, onComplete);
695            } else if (onComplete != null) {
696                Exception e = new RuntimeException("ICC card is absent.");
697                AsyncResult.forMessage(onComplete).exception = e;
698                onComplete.sendToTarget();
699                return;
700            }
701        }
702    }
703
704    @Override
705    public void supplyPuk(String puk, String newPin, Message onComplete) {
706        synchronized (mLock) {
707            if (mUiccApplication != null) {
708                mUiccApplication.supplyPuk(puk, newPin, onComplete);
709            } else if (onComplete != null) {
710                Exception e = new RuntimeException("ICC card is absent.");
711                AsyncResult.forMessage(onComplete).exception = e;
712                onComplete.sendToTarget();
713                return;
714            }
715        }
716    }
717
718    @Override
719    public void supplyPin2(String pin2, Message onComplete) {
720        synchronized (mLock) {
721            if (mUiccApplication != null) {
722                mUiccApplication.supplyPin2(pin2, onComplete);
723            } else if (onComplete != null) {
724                Exception e = new RuntimeException("ICC card is absent.");
725                AsyncResult.forMessage(onComplete).exception = e;
726                onComplete.sendToTarget();
727                return;
728            }
729        }
730    }
731
732    @Override
733    public void supplyPuk2(String puk2, String newPin2, Message onComplete) {
734        synchronized (mLock) {
735            if (mUiccApplication != null) {
736                mUiccApplication.supplyPuk2(puk2, newPin2, onComplete);
737            } else if (onComplete != null) {
738                Exception e = new RuntimeException("ICC card is absent.");
739                AsyncResult.forMessage(onComplete).exception = e;
740                onComplete.sendToTarget();
741                return;
742            }
743        }
744    }
745
746    @Override
747    public void supplyNetworkDepersonalization(String pin, Message onComplete) {
748        synchronized (mLock) {
749            if (mUiccApplication != null) {
750                mUiccApplication.supplyNetworkDepersonalization(pin, onComplete);
751            } else if (onComplete != null) {
752                Exception e = new RuntimeException("CommandsInterface is not set.");
753                AsyncResult.forMessage(onComplete).exception = e;
754                onComplete.sendToTarget();
755                return;
756            }
757        }
758    }
759
760    @Override
761    public boolean getIccLockEnabled() {
762        synchronized (mLock) {
763            /* defaults to false, if ICC is absent/deactivated */
764            Boolean retValue = mUiccApplication != null ?
765                    mUiccApplication.getIccLockEnabled() : false;
766            return retValue;
767        }
768    }
769
770    @Override
771    public boolean getIccFdnEnabled() {
772        synchronized (mLock) {
773            Boolean retValue = mUiccApplication != null ?
774                    mUiccApplication.getIccFdnEnabled() : false;
775            return retValue;
776        }
777    }
778
779    public boolean getIccFdnAvailable() {
780        boolean retValue = mUiccApplication != null ? mUiccApplication.getIccFdnAvailable() : false;
781        return retValue;
782    }
783
784    public boolean getIccPin2Blocked() {
785        /* defaults to disabled */
786        Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccPin2Blocked() : false;
787        return retValue;
788    }
789
790    public boolean getIccPuk2Blocked() {
791        /* defaults to disabled */
792        Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccPuk2Blocked() : false;
793        return retValue;
794    }
795
796    @Override
797    public void setIccLockEnabled(boolean enabled, String password, Message onComplete) {
798        synchronized (mLock) {
799            if (mUiccApplication != null) {
800                mUiccApplication.setIccLockEnabled(enabled, password, onComplete);
801            } else if (onComplete != null) {
802                Exception e = new RuntimeException("ICC card is absent.");
803                AsyncResult.forMessage(onComplete).exception = e;
804                onComplete.sendToTarget();
805                return;
806            }
807        }
808    }
809
810    @Override
811    public void setIccFdnEnabled(boolean enabled, String password, Message onComplete) {
812        synchronized (mLock) {
813            if (mUiccApplication != null) {
814                mUiccApplication.setIccFdnEnabled(enabled, password, onComplete);
815            } else if (onComplete != null) {
816                Exception e = new RuntimeException("ICC card is absent.");
817                AsyncResult.forMessage(onComplete).exception = e;
818                onComplete.sendToTarget();
819                return;
820            }
821        }
822    }
823
824    @Override
825    public void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete) {
826        synchronized (mLock) {
827            if (mUiccApplication != null) {
828                mUiccApplication.changeIccLockPassword(oldPassword, newPassword, onComplete);
829            } else if (onComplete != null) {
830                Exception e = new RuntimeException("ICC card is absent.");
831                AsyncResult.forMessage(onComplete).exception = e;
832                onComplete.sendToTarget();
833                return;
834            }
835        }
836    }
837
838    @Override
839    public void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete) {
840        synchronized (mLock) {
841            if (mUiccApplication != null) {
842                mUiccApplication.changeIccFdnPassword(oldPassword, newPassword, onComplete);
843            } else if (onComplete != null) {
844                Exception e = new RuntimeException("ICC card is absent.");
845                AsyncResult.forMessage(onComplete).exception = e;
846                onComplete.sendToTarget();
847                return;
848            }
849        }
850    }
851
852    @Override
853    public String getServiceProviderName() {
854        synchronized (mLock) {
855            if (mIccRecords != null) {
856                return mIccRecords.getServiceProviderName();
857            }
858            return null;
859        }
860    }
861
862    @Override
863    public boolean isApplicationOnIcc(IccCardApplicationStatus.AppType type) {
864        synchronized (mLock) {
865            Boolean retValue = mUiccCard != null ? mUiccCard.isApplicationOnIcc(type) : false;
866            return retValue;
867        }
868    }
869
870    @Override
871    public boolean hasIccCard() {
872        synchronized (mLock) {
873            if (mUiccCard != null && mUiccCard.getCardState() != CardState.CARDSTATE_ABSENT) {
874                return true;
875            }
876            return false;
877        }
878    }
879
880    private void setSystemProperty(String property, int slotId, String value) {
881        long[] subId = SubscriptionController.getInstance().getSubId(slotId);
882        TelephonyManager.setTelephonyProperty(property, subId[0], value);
883    }
884
885    private void log(String s) {
886        Rlog.d(LOG_TAG, s);
887    }
888
889    private void loge(String msg) {
890        Rlog.e(LOG_TAG, msg);
891    }
892
893    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
894        pw.println("IccCardProxy: " + this);
895        pw.println(" mContext=" + mContext);
896        pw.println(" mCi=" + mCi);
897        pw.println(" mAbsentRegistrants: size=" + mAbsentRegistrants.size());
898        for (int i = 0; i < mAbsentRegistrants.size(); i++) {
899            pw.println("  mAbsentRegistrants[" + i + "]="
900                    + ((Registrant)mAbsentRegistrants.get(i)).getHandler());
901        }
902        pw.println(" mPinLockedRegistrants: size=" + mPinLockedRegistrants.size());
903        for (int i = 0; i < mPinLockedRegistrants.size(); i++) {
904            pw.println("  mPinLockedRegistrants[" + i + "]="
905                    + ((Registrant)mPinLockedRegistrants.get(i)).getHandler());
906        }
907        pw.println(" mNetworkLockedRegistrants: size=" + mNetworkLockedRegistrants.size());
908        for (int i = 0; i < mNetworkLockedRegistrants.size(); i++) {
909            pw.println("  mNetworkLockedRegistrants[" + i + "]="
910                    + ((Registrant)mNetworkLockedRegistrants.get(i)).getHandler());
911        }
912        pw.println(" mCurrentAppType=" + mCurrentAppType);
913        pw.println(" mUiccController=" + mUiccController);
914        pw.println(" mUiccCard=" + mUiccCard);
915        pw.println(" mUiccApplication=" + mUiccApplication);
916        pw.println(" mIccRecords=" + mIccRecords);
917        pw.println(" mCdmaSSM=" + mCdmaSSM);
918        pw.println(" mRadioOn=" + mRadioOn);
919        pw.println(" mQuietMode=" + mQuietMode);
920        pw.println(" mInitialized=" + mInitialized);
921        pw.println(" mExternalState=" + mExternalState);
922
923        pw.flush();
924    }
925}
926