IccCardProxy.java revision 47b83a09b03fe159a0cc7f7a60f9120a9fb4fca7
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.SubscriptionController;
47import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
48import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState;
49import com.android.internal.telephony.uicc.IccCardStatus.CardState;
50import com.android.internal.telephony.uicc.IccCardStatus.PinState;
51import com.android.internal.telephony.uicc.UiccController;
52
53import java.io.FileDescriptor;
54import java.io.PrintWriter;
55
56import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
57import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
58import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
59import static com.android.internal.telephony.TelephonyProperties.PROPERTY_SIM_STATE;
60
61
62/**
63 * @Deprecated use {@link UiccController}.getUiccCard instead.
64 *
65 * The Phone App assumes that there is only one icc card, and one icc application
66 * available at a time. Moreover, it assumes such object (represented with IccCard)
67 * is available all the time (whether {@link RILConstants#RIL_REQUEST_GET_SIM_STATUS} returned
68 * or not, whether card has desired application or not, whether there really is a card in the
69 * slot or not).
70 *
71 * UiccController, however, can handle multiple instances of icc objects (multiple
72 * {@link UiccCardApplication}, multiple {@link IccFileHandler}, multiple {@link IccRecords})
73 * created and destroyed dynamically during phone operation.
74 *
75 * This class implements the IccCard interface that is always available (right after default
76 * phone object is constructed) to expose the current (based on voice radio technology)
77 * application on the uicc card, so that external apps won't break.
78 */
79
80public class IccCardProxy extends Handler implements IccCard {
81    private static final boolean DBG = true;
82    private static final String LOG_TAG = "IccCardProxy";
83
84    private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 1;
85    private static final int EVENT_RADIO_ON = 2;
86    private static final int EVENT_ICC_CHANGED = 3;
87    private static final int EVENT_ICC_ABSENT = 4;
88    private static final int EVENT_ICC_LOCKED = 5;
89    private static final int EVENT_APP_READY = 6;
90    private static final int EVENT_RECORDS_LOADED = 7;
91    private static final int EVENT_IMSI_READY = 8;
92    private static final int EVENT_NETWORK_LOCKED = 9;
93    private static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 11;
94
95    private static final int EVENT_ICC_RECORD_EVENTS = 500;
96    private static final int EVENT_SUBSCRIPTION_ACTIVATED = 501;
97    private static final int EVENT_SUBSCRIPTION_DEACTIVATED = 502;
98    private static final int EVENT_CARRIER_PRIVILIGES_LOADED = 503;
99
100    // FIXME Rename mCardIndex to mSlotId.
101    private Integer mCardIndex = null;
102
103    private final Object mLock = new Object();
104    private Context mContext;
105    private CommandsInterface mCi;
106
107    private RegistrantList mAbsentRegistrants = new RegistrantList();
108    private RegistrantList mPinLockedRegistrants = new RegistrantList();
109    private RegistrantList mNetworkLockedRegistrants = new RegistrantList();
110
111    private int mCurrentAppType = UiccController.APP_FAM_3GPP; //default to 3gpp?
112    private UiccController mUiccController = null;
113    private UiccCard mUiccCard = null;
114    private UiccCardApplication mUiccApplication = null;
115    private IccRecords mIccRecords = null;
116    private CdmaSubscriptionSourceManager mCdmaSSM = null;
117    private boolean mRadioOn = false;
118    private boolean mQuietMode = false; // when set to true IccCardProxy will not broadcast
119                                        // ACTION_SIM_STATE_CHANGED intents
120    private boolean mInitialized = false;
121    private State mExternalState = State.UNKNOWN;
122
123    private int mRecordsToLoad;  // number of pending load requests
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                onRecordsLoaded();
285                break;
286            case EVENT_IMSI_READY:
287                broadcastIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_IMSI, null);
288                break;
289            case EVENT_NETWORK_LOCKED:
290                mNetworkLockedRegistrants.notifyRegistrants();
291                setExternalState(State.NETWORK_LOCKED);
292                break;
293            case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
294                updateQuietMode();
295                break;
296            case EVENT_SUBSCRIPTION_ACTIVATED:
297                log("EVENT_SUBSCRIPTION_ACTIVATED");
298                onSubscriptionActivated();
299                break;
300
301            case EVENT_SUBSCRIPTION_DEACTIVATED:
302                log("EVENT_SUBSCRIPTION_DEACTIVATED");
303                onSubscriptionDeactivated();
304                break;
305
306            case EVENT_ICC_RECORD_EVENTS:
307                if ((mCurrentAppType == UiccController.APP_FAM_3GPP) && (mIccRecords != null)) {
308                    int slotId = mCardIndex;
309                    AsyncResult ar = (AsyncResult)msg.obj;
310                    int eventCode = (Integer) ar.result;
311                    if (eventCode == SIMRecords.EVENT_SPN) {
312                        setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, slotId,
313                                mIccRecords.getServiceProviderName());
314                    }
315                }
316                break;
317
318            case EVENT_CARRIER_PRIVILIGES_LOADED:
319                log("EVENT_CARRIER_PRIVILEGES_LOADED");
320                onRecordsLoaded();
321                break;
322
323            default:
324                loge("Unhandled message with number: " + msg.what);
325                break;
326        }
327    }
328
329    private void onSubscriptionActivated() {
330        updateIccAvailability();
331        updateStateProperty();
332    }
333
334    private void onSubscriptionDeactivated() {
335        resetProperties();
336        updateIccAvailability();
337        updateStateProperty();
338    }
339
340    private void onRecordsLoaded() {
341        synchronized (mLock) {
342            --mRecordsToLoad;
343            if (mRecordsToLoad == 0) {
344                broadcastIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
345            }
346        }
347    }
348
349    private void updateIccAvailability() {
350        synchronized (mLock) {
351            UiccCard newCard = mUiccController.getUiccCard(mCardIndex);
352            CardState state = CardState.CARDSTATE_ABSENT;
353            UiccCardApplication newApp = null;
354            IccRecords newRecords = null;
355            if (newCard != null) {
356                state = newCard.getCardState();
357                newApp = newCard.getApplication(mCurrentAppType);
358                if (newApp != null) {
359                    newRecords = newApp.getIccRecords();
360                }
361            }
362
363            if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) {
364                if (DBG) log("Icc changed. Reregestering.");
365                mRecordsToLoad = 0;
366                unregisterUiccCardEvents();
367                mUiccCard = newCard;
368                mUiccApplication = newApp;
369                mIccRecords = newRecords;
370                registerUiccCardEvents();
371            }
372
373            updateExternalState();
374        }
375    }
376
377    void resetProperties() {
378        if (mCurrentAppType == UiccController.APP_FAM_3GPP) {
379            log("update icc_operator_numeric=" + "");
380            setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, mCardIndex, "");
381            setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, mCardIndex, "");
382            setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, mCardIndex, "");
383         }
384    }
385
386    private void HandleDetectedState() {
387    // CAF_MSIM SAND
388//        setExternalState(State.DETECTED, false);
389    }
390
391    private void updateExternalState() {
392        if (mUiccCard == null || mUiccCard.getCardState() == CardState.CARDSTATE_ABSENT) {
393            if (mRadioOn) {
394                setExternalState(State.ABSENT);
395            } else {
396                setExternalState(State.NOT_READY);
397            }
398            return;
399        }
400
401        if (mUiccCard.getCardState() == CardState.CARDSTATE_ERROR) {
402            setExternalState(State.CARD_IO_ERROR);
403            return;
404        }
405
406        if (mUiccApplication == null) {
407            setExternalState(State.NOT_READY);
408            return;
409        }
410
411        switch (mUiccApplication.getState()) {
412            case APPSTATE_UNKNOWN:
413                setExternalState(State.UNKNOWN);
414                break;
415            case APPSTATE_DETECTED:
416                HandleDetectedState();
417                break;
418            case APPSTATE_PIN:
419                setExternalState(State.PIN_REQUIRED);
420                break;
421            case APPSTATE_PUK:
422                setExternalState(State.PUK_REQUIRED);
423                break;
424            case APPSTATE_SUBSCRIPTION_PERSO:
425                if (mUiccApplication.getPersoSubState() ==
426                        PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
427                    setExternalState(State.NETWORK_LOCKED);
428                } else {
429                    setExternalState(State.UNKNOWN);
430                }
431                break;
432            case APPSTATE_READY:
433                setExternalState(State.READY);
434                break;
435        }
436    }
437
438    private void registerUiccCardEvents() {
439        mRecordsToLoad = (mUiccCard != null ? 1 : 0) +
440            (mIccRecords != null ? 1 : 0);
441
442        if (mUiccCard != null) {
443            mUiccCard.registerForAbsent(this, EVENT_ICC_ABSENT, null);
444            mUiccCard.registerForCarrierPrivilegeRulesLoaded(
445                    this, EVENT_CARRIER_PRIVILIGES_LOADED, 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 (mUiccCard != null) mUiccCard.unregisterForCarrierPrivilegeRulesLoaded(this);
462        if (mUiccApplication != null) mUiccApplication.unregisterForReady(this);
463        if (mUiccApplication != null) mUiccApplication.unregisterForLocked(this);
464        if (mUiccApplication != null) mUiccApplication.unregisterForNetworkLocked(this);
465        if (mIccRecords != null) mIccRecords.unregisterForImsiReady(this);
466        if (mIccRecords != null) mIccRecords.unregisterForRecordsLoaded(this);
467        if (mIccRecords != null) mIccRecords.unregisterForRecordsEvents(this);
468    }
469
470    private void updateStateProperty() {
471        setSystemProperty(PROPERTY_SIM_STATE, mCardIndex,getState().toString());
472    }
473
474    private void broadcastIccStateChangedIntent(String value, String reason) {
475        synchronized (mLock) {
476            if (mCardIndex == null) {
477                loge("broadcastIccStateChangedIntent: Card Index is not set; Return!!");
478                return;
479            }
480
481            if (mQuietMode) {
482                log("QuietMode: NOT Broadcasting intent ACTION_SIM_STATE_CHANGED " +  value
483                        + " reason " + reason);
484                return;
485            }
486
487            Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
488            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
489            intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
490            intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
491            intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
492            SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mCardIndex);
493            log("Broadcasting intent ACTION_SIM_STATE_CHANGED " +  value
494                + " reason " + reason + " for mCardIndex : " + mCardIndex);
495            ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
496                    UserHandle.USER_ALL);
497        }
498    }
499
500    private void setExternalState(State newState, boolean override) {
501        synchronized (mLock) {
502            if (mCardIndex == null) {
503                loge("setExternalState: Card Index is not set; Return!!");
504                return;
505            }
506
507            if (!override && newState == mExternalState) {
508                return;
509            }
510            mExternalState = newState;
511            setSystemProperty(PROPERTY_SIM_STATE, mCardIndex, getState().toString());
512            broadcastIccStateChangedIntent(getIccStateIntentString(mExternalState),
513                    getIccStateReason(mExternalState));
514            // TODO: Need to notify registrants for other states as well.
515            if ( State.ABSENT == mExternalState) {
516                mAbsentRegistrants.notifyRegistrants();
517            }
518        }
519    }
520
521    private void processLockedState() {
522        synchronized (mLock) {
523            if (mUiccApplication == null) {
524                //Don't need to do anything if non-existent application is locked
525                return;
526            }
527            PinState pin1State = mUiccApplication.getPin1State();
528            if (pin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
529                setExternalState(State.PERM_DISABLED);
530                return;
531            }
532
533            AppState appState = mUiccApplication.getState();
534            switch (appState) {
535                case APPSTATE_PIN:
536                    mPinLockedRegistrants.notifyRegistrants();
537                    setExternalState(State.PIN_REQUIRED);
538                    break;
539                case APPSTATE_PUK:
540                    setExternalState(State.PUK_REQUIRED);
541                    break;
542                case APPSTATE_DETECTED:
543                case APPSTATE_READY:
544                case APPSTATE_SUBSCRIPTION_PERSO:
545                case APPSTATE_UNKNOWN:
546                    // Neither required
547                    break;
548            }
549        }
550    }
551
552    private void setExternalState(State newState) {
553        setExternalState(newState, false);
554    }
555
556    public boolean getIccRecordsLoaded() {
557        synchronized (mLock) {
558            if (mIccRecords != null) {
559                return mIccRecords.getRecordsLoaded();
560            }
561            return false;
562        }
563    }
564
565    private String getIccStateIntentString(State state) {
566        switch (state) {
567            case ABSENT: return IccCardConstants.INTENT_VALUE_ICC_ABSENT;
568            case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
569            case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
570            case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
571            case READY: return IccCardConstants.INTENT_VALUE_ICC_READY;
572            case NOT_READY: return IccCardConstants.INTENT_VALUE_ICC_NOT_READY;
573            case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
574            case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR;
575            default: return IccCardConstants.INTENT_VALUE_ICC_UNKNOWN;
576        }
577    }
578
579    /**
580     * Locked state have a reason (PIN, PUK, NETWORK, PERM_DISABLED, CARD_IO_ERROR)
581     * @return reason
582     */
583    private String getIccStateReason(State state) {
584        switch (state) {
585            case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN;
586            case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK;
587            case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_LOCKED_NETWORK;
588            case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED;
589            case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR;
590            default: return null;
591       }
592    }
593
594    /* IccCard interface implementation */
595    @Override
596    public State getState() {
597        synchronized (mLock) {
598            return mExternalState;
599        }
600    }
601
602    @Override
603    public IccRecords getIccRecords() {
604        synchronized (mLock) {
605            return mIccRecords;
606        }
607    }
608
609    @Override
610    public IccFileHandler getIccFileHandler() {
611        synchronized (mLock) {
612            if (mUiccApplication != null) {
613                return mUiccApplication.getIccFileHandler();
614            }
615            return null;
616        }
617    }
618
619    /**
620     * Notifies handler of any transition into State.ABSENT
621     */
622    @Override
623    public void registerForAbsent(Handler h, int what, Object obj) {
624        synchronized (mLock) {
625            Registrant r = new Registrant (h, what, obj);
626
627            mAbsentRegistrants.add(r);
628
629            if (getState() == State.ABSENT) {
630                r.notifyRegistrant();
631            }
632        }
633    }
634
635    @Override
636    public void unregisterForAbsent(Handler h) {
637        synchronized (mLock) {
638            mAbsentRegistrants.remove(h);
639        }
640    }
641
642    /**
643     * Notifies handler of any transition into State.NETWORK_LOCKED
644     */
645    @Override
646    public void registerForNetworkLocked(Handler h, int what, Object obj) {
647        synchronized (mLock) {
648            Registrant r = new Registrant (h, what, obj);
649
650            mNetworkLockedRegistrants.add(r);
651
652            if (getState() == State.NETWORK_LOCKED) {
653                r.notifyRegistrant();
654            }
655        }
656    }
657
658    @Override
659    public void unregisterForNetworkLocked(Handler h) {
660        synchronized (mLock) {
661            mNetworkLockedRegistrants.remove(h);
662        }
663    }
664
665    /**
666     * Notifies handler of any transition into State.isPinLocked()
667     */
668    @Override
669    public void registerForLocked(Handler h, int what, Object obj) {
670        synchronized (mLock) {
671            Registrant r = new Registrant (h, what, obj);
672
673            mPinLockedRegistrants.add(r);
674
675            if (getState().isPinLocked()) {
676                r.notifyRegistrant();
677            }
678        }
679    }
680
681    @Override
682    public void unregisterForLocked(Handler h) {
683        synchronized (mLock) {
684            mPinLockedRegistrants.remove(h);
685        }
686    }
687
688    @Override
689    public void supplyPin(String pin, Message onComplete) {
690        synchronized (mLock) {
691            if (mUiccApplication != null) {
692                mUiccApplication.supplyPin(pin, onComplete);
693            } else if (onComplete != null) {
694                Exception e = new RuntimeException("ICC card is absent.");
695                AsyncResult.forMessage(onComplete).exception = e;
696                onComplete.sendToTarget();
697                return;
698            }
699        }
700    }
701
702    @Override
703    public void supplyPuk(String puk, String newPin, Message onComplete) {
704        synchronized (mLock) {
705            if (mUiccApplication != null) {
706                mUiccApplication.supplyPuk(puk, newPin, onComplete);
707            } else if (onComplete != null) {
708                Exception e = new RuntimeException("ICC card is absent.");
709                AsyncResult.forMessage(onComplete).exception = e;
710                onComplete.sendToTarget();
711                return;
712            }
713        }
714    }
715
716    @Override
717    public void supplyPin2(String pin2, Message onComplete) {
718        synchronized (mLock) {
719            if (mUiccApplication != null) {
720                mUiccApplication.supplyPin2(pin2, onComplete);
721            } else if (onComplete != null) {
722                Exception e = new RuntimeException("ICC card is absent.");
723                AsyncResult.forMessage(onComplete).exception = e;
724                onComplete.sendToTarget();
725                return;
726            }
727        }
728    }
729
730    @Override
731    public void supplyPuk2(String puk2, String newPin2, Message onComplete) {
732        synchronized (mLock) {
733            if (mUiccApplication != null) {
734                mUiccApplication.supplyPuk2(puk2, newPin2, onComplete);
735            } else if (onComplete != null) {
736                Exception e = new RuntimeException("ICC card is absent.");
737                AsyncResult.forMessage(onComplete).exception = e;
738                onComplete.sendToTarget();
739                return;
740            }
741        }
742    }
743
744    @Override
745    public void supplyNetworkDepersonalization(String pin, Message onComplete) {
746        synchronized (mLock) {
747            if (mUiccApplication != null) {
748                mUiccApplication.supplyNetworkDepersonalization(pin, onComplete);
749            } else if (onComplete != null) {
750                Exception e = new RuntimeException("CommandsInterface is not set.");
751                AsyncResult.forMessage(onComplete).exception = e;
752                onComplete.sendToTarget();
753                return;
754            }
755        }
756    }
757
758    @Override
759    public boolean getIccLockEnabled() {
760        synchronized (mLock) {
761            /* defaults to false, if ICC is absent/deactivated */
762            Boolean retValue = mUiccApplication != null ?
763                    mUiccApplication.getIccLockEnabled() : false;
764            return retValue;
765        }
766    }
767
768    @Override
769    public boolean getIccFdnEnabled() {
770        synchronized (mLock) {
771            Boolean retValue = mUiccApplication != null ?
772                    mUiccApplication.getIccFdnEnabled() : false;
773            return retValue;
774        }
775    }
776
777    public boolean getIccFdnAvailable() {
778        boolean retValue = mUiccApplication != null ? mUiccApplication.getIccFdnAvailable() : false;
779        return retValue;
780    }
781
782    public boolean getIccPin2Blocked() {
783        /* defaults to disabled */
784        Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccPin2Blocked() : false;
785        return retValue;
786    }
787
788    public boolean getIccPuk2Blocked() {
789        /* defaults to disabled */
790        Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccPuk2Blocked() : false;
791        return retValue;
792    }
793
794    @Override
795    public void setIccLockEnabled(boolean enabled, String password, Message onComplete) {
796        synchronized (mLock) {
797            if (mUiccApplication != null) {
798                mUiccApplication.setIccLockEnabled(enabled, password, onComplete);
799            } else if (onComplete != null) {
800                Exception e = new RuntimeException("ICC card is absent.");
801                AsyncResult.forMessage(onComplete).exception = e;
802                onComplete.sendToTarget();
803                return;
804            }
805        }
806    }
807
808    @Override
809    public void setIccFdnEnabled(boolean enabled, String password, Message onComplete) {
810        synchronized (mLock) {
811            if (mUiccApplication != null) {
812                mUiccApplication.setIccFdnEnabled(enabled, password, onComplete);
813            } else if (onComplete != null) {
814                Exception e = new RuntimeException("ICC card is absent.");
815                AsyncResult.forMessage(onComplete).exception = e;
816                onComplete.sendToTarget();
817                return;
818            }
819        }
820    }
821
822    @Override
823    public void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete) {
824        synchronized (mLock) {
825            if (mUiccApplication != null) {
826                mUiccApplication.changeIccLockPassword(oldPassword, newPassword, onComplete);
827            } else if (onComplete != null) {
828                Exception e = new RuntimeException("ICC card is absent.");
829                AsyncResult.forMessage(onComplete).exception = e;
830                onComplete.sendToTarget();
831                return;
832            }
833        }
834    }
835
836    @Override
837    public void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete) {
838        synchronized (mLock) {
839            if (mUiccApplication != null) {
840                mUiccApplication.changeIccFdnPassword(oldPassword, newPassword, onComplete);
841            } else if (onComplete != null) {
842                Exception e = new RuntimeException("ICC card is absent.");
843                AsyncResult.forMessage(onComplete).exception = e;
844                onComplete.sendToTarget();
845                return;
846            }
847        }
848    }
849
850    @Override
851    public String getServiceProviderName() {
852        synchronized (mLock) {
853            if (mIccRecords != null) {
854                return mIccRecords.getServiceProviderName();
855            }
856            return null;
857        }
858    }
859
860    @Override
861    public boolean isApplicationOnIcc(IccCardApplicationStatus.AppType type) {
862        synchronized (mLock) {
863            Boolean retValue = mUiccCard != null ? mUiccCard.isApplicationOnIcc(type) : false;
864            return retValue;
865        }
866    }
867
868    @Override
869    public boolean hasIccCard() {
870        synchronized (mLock) {
871            if (mUiccCard != null && mUiccCard.getCardState() != CardState.CARDSTATE_ABSENT) {
872                return true;
873            }
874            return false;
875        }
876    }
877
878    private void setSystemProperty(String property, int slotId, String value) {
879        // FIXME: Add SubscriptionController.getPhoneIdUsingSlotId
880        long[] subId = SubscriptionController.getInstance().getSubIdUsingSlotId(slotId);
881        if (subId != null && subId.length > 0) {
882            int phoneId = SubscriptionController.getInstance().getPhoneId(subId[0]);
883            TelephonyManager.setTelephonyProperty(phoneId, property, value);
884        } else {
885            loge("setSystemProperty: subId is null or subId.length == 0");
886        }
887    }
888
889    private void log(String s) {
890        Rlog.d(LOG_TAG, s);
891    }
892
893    private void loge(String msg) {
894        Rlog.e(LOG_TAG, msg);
895    }
896
897    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
898        pw.println("IccCardProxy: " + this);
899        pw.println(" mContext=" + mContext);
900        pw.println(" mCi=" + mCi);
901        pw.println(" mAbsentRegistrants: size=" + mAbsentRegistrants.size());
902        for (int i = 0; i < mAbsentRegistrants.size(); i++) {
903            pw.println("  mAbsentRegistrants[" + i + "]="
904                    + ((Registrant)mAbsentRegistrants.get(i)).getHandler());
905        }
906        pw.println(" mPinLockedRegistrants: size=" + mPinLockedRegistrants.size());
907        for (int i = 0; i < mPinLockedRegistrants.size(); i++) {
908            pw.println("  mPinLockedRegistrants[" + i + "]="
909                    + ((Registrant)mPinLockedRegistrants.get(i)).getHandler());
910        }
911        pw.println(" mNetworkLockedRegistrants: size=" + mNetworkLockedRegistrants.size());
912        for (int i = 0; i < mNetworkLockedRegistrants.size(); i++) {
913            pw.println("  mNetworkLockedRegistrants[" + i + "]="
914                    + ((Registrant)mNetworkLockedRegistrants.get(i)).getHandler());
915        }
916        pw.println(" mCurrentAppType=" + mCurrentAppType);
917        pw.println(" mUiccController=" + mUiccController);
918        pw.println(" mUiccCard=" + mUiccCard);
919        pw.println(" mUiccApplication=" + mUiccApplication);
920        pw.println(" mIccRecords=" + mIccRecords);
921        pw.println(" mCdmaSSM=" + mCdmaSSM);
922        pw.println(" mRadioOn=" + mRadioOn);
923        pw.println(" mQuietMode=" + mQuietMode);
924        pw.println(" mInitialized=" + mInitialized);
925        pw.println(" mExternalState=" + mExternalState);
926
927        pw.flush();
928    }
929}
930