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