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