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