IccCardProxy.java revision 062a2a3838c8d8adf16f4d9fbde8d52450da0336
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    private Integer mPhoneId = null;
101
102    private final Object mLock = new Object();
103    private Context mContext;
104    private CommandsInterface mCi;
105
106    private RegistrantList mAbsentRegistrants = new RegistrantList();
107    private RegistrantList mPinLockedRegistrants = new RegistrantList();
108    private RegistrantList mNetworkLockedRegistrants = new RegistrantList();
109
110    private int mCurrentAppType = UiccController.APP_FAM_3GPP; //default to 3gpp?
111    private UiccController mUiccController = null;
112    private UiccCard mUiccCard = null;
113    private UiccCardApplication mUiccApplication = null;
114    private IccRecords mIccRecords = null;
115    private CdmaSubscriptionSourceManager mCdmaSSM = null;
116    private boolean mRadioOn = false;
117    private boolean mQuietMode = false; // when set to true IccCardProxy will not broadcast
118                                        // ACTION_SIM_STATE_CHANGED intents
119    private boolean mInitialized = false;
120    private State mExternalState = State.UNKNOWN;
121
122    public static final String ACTION_INTERNAL_SIM_STATE_CHANGED = "android.intent.action.internal_sim_state_changed";
123
124    public IccCardProxy(Context context, CommandsInterface ci, int phoneId) {
125        if (DBG) log("ctor: ci=" + ci + " phoneId=" + phoneId);
126        mContext = context;
127        mCi = ci;
128        mPhoneId = phoneId;
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
136        resetProperties();
137        setExternalState(State.NOT_READY, false);
138    }
139
140    public void dispose() {
141        synchronized (mLock) {
142            log("Disposing");
143            //Cleanup icc references
144            mUiccController.unregisterForIccChanged(this);
145            mUiccController = null;
146            mCi.unregisterForOn(this);
147            mCi.unregisterForOffOrNotAvailable(this);
148            mCdmaSSM.dispose(this);
149        }
150    }
151
152    /*
153     * The card application that the external world sees will be based on the
154     * voice radio technology only!
155     */
156    public void setVoiceRadioTech(int radioTech) {
157        synchronized (mLock) {
158            if (DBG) {
159                log("Setting radio tech " + ServiceState.rilRadioTechnologyToString(radioTech));
160            }
161            if (ServiceState.isGsm(radioTech)) {
162                mCurrentAppType = UiccController.APP_FAM_3GPP;
163            } else {
164                mCurrentAppType = UiccController.APP_FAM_3GPP2;
165            }
166            updateQuietMode();
167        }
168    }
169
170    /**
171     * In case of 3gpp2 we need to find out if subscription used is coming from
172     * NV in which case we shouldn't broadcast any sim states changes.
173     */
174    private void updateQuietMode() {
175        synchronized (mLock) {
176            boolean oldQuietMode = mQuietMode;
177            boolean newQuietMode;
178            int cdmaSource = Phone.CDMA_SUBSCRIPTION_UNKNOWN;
179            boolean isLteOnCdmaMode = TelephonyManager.getLteOnCdmaModeStatic()
180                    == PhoneConstants.LTE_ON_CDMA_TRUE;
181            if (mCurrentAppType == UiccController.APP_FAM_3GPP) {
182                newQuietMode = false;
183                if (DBG) log("updateQuietMode: 3GPP subscription -> newQuietMode=" + newQuietMode);
184            } else {
185                if (isLteOnCdmaMode) {
186                    log("updateQuietMode: is cdma/lte device, force IccCardProxy into 3gpp mode");
187                    mCurrentAppType = UiccController.APP_FAM_3GPP;
188                }
189                cdmaSource = mCdmaSSM != null ?
190                        mCdmaSSM.getCdmaSubscriptionSource() : Phone.CDMA_SUBSCRIPTION_UNKNOWN;
191
192                newQuietMode = (cdmaSource == Phone.CDMA_SUBSCRIPTION_NV)
193                        && (mCurrentAppType == UiccController.APP_FAM_3GPP2)
194                        && !isLteOnCdmaMode;
195                if (DBG) {
196                    log("updateQuietMode: cdmaSource=" + cdmaSource
197                            + " mCurrentAppType=" + mCurrentAppType
198                            + " isLteOnCdmaMode=" + isLteOnCdmaMode
199                            + " newQuietMode=" + newQuietMode);
200                }
201            }
202
203            if (mQuietMode == false && newQuietMode == true) {
204                // Last thing to do before switching to quiet mode is
205                // broadcast ICC_READY
206                log("Switching to QuietMode.");
207                setExternalState(State.READY);
208                mQuietMode = newQuietMode;
209            } else if (mQuietMode == true && newQuietMode == false) {
210                if (DBG) {
211                    log("updateQuietMode: Switching out from QuietMode."
212                            + " Force broadcast of current state=" + mExternalState);
213                }
214                mQuietMode = newQuietMode;
215                setExternalState(mExternalState, true);
216            } else {
217                if (DBG) log("updateQuietMode: no changes don't setExternalState");
218            }
219            if (DBG) {
220                log("updateQuietMode: QuietMode is " + mQuietMode + " (app_type="
221                    + mCurrentAppType + " isLteOnCdmaMode=" + isLteOnCdmaMode
222                    + " cdmaSource=" + cdmaSource + ")");
223            }
224            mInitialized = true;
225            sendMessage(obtainMessage(EVENT_ICC_CHANGED));
226        }
227    }
228
229    @Override
230    public void handleMessage(Message msg) {
231        switch (msg.what) {
232            case EVENT_RADIO_OFF_OR_UNAVAILABLE:
233                mRadioOn = false;
234                if (CommandsInterface.RadioState.RADIO_UNAVAILABLE == mCi.getRadioState()) {
235                    setExternalState(State.NOT_READY);
236                }
237                break;
238            case EVENT_RADIO_ON:
239                mRadioOn = true;
240                if (!mInitialized) {
241                    updateQuietMode();
242                }
243                break;
244            case EVENT_ICC_CHANGED:
245                if (mInitialized) {
246                    updateIccAvailability();
247                }
248                break;
249            case EVENT_ICC_ABSENT:
250                mAbsentRegistrants.notifyRegistrants();
251                setExternalState(State.ABSENT);
252                break;
253            case EVENT_ICC_LOCKED:
254                processLockedState();
255                break;
256            case EVENT_APP_READY:
257                setExternalState(State.READY);
258                break;
259            case EVENT_RECORDS_LOADED:
260                // Update the MCC/MNC.
261                if (mIccRecords != null) {
262                    String operator = mIccRecords.getOperatorNumeric();
263                    log("operator=" + operator + " mPhoneId=" + mPhoneId);
264
265                    if (operator != null) {
266                        log("update icc_operator_numeric=" + operator);
267                        setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, operator);
268                        String countryCode = operator.substring(0,3);
269                        if (countryCode != null) {
270                            setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY,
271                                    MccTable.countryCodeForMcc(Integer.parseInt(countryCode)));
272                        } else {
273                            loge("EVENT_RECORDS_LOADED Country code is null");
274                        }
275                    } else {
276                        loge("EVENT_RECORDS_LOADED Operator name is null");
277                    }
278                }
279                if (mUiccCard != null && !mUiccCard.areCarrierPriviligeRulesLoaded()) {
280                    mUiccCard.registerForCarrierPrivilegeRulesLoaded(
281                        this, EVENT_CARRIER_PRIVILIGES_LOADED, null);
282                } else {
283                    onRecordsLoaded();
284                }
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                    AsyncResult ar = (AsyncResult)msg.obj;
309                    int eventCode = (Integer) ar.result;
310                    if (eventCode == SIMRecords.EVENT_SPN) {
311                        setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA,
312                                mIccRecords.getServiceProviderName());
313                    }
314                }
315                break;
316
317            case EVENT_CARRIER_PRIVILIGES_LOADED:
318                log("EVENT_CARRIER_PRIVILEGES_LOADED");
319                if (mUiccCard != null) {
320                    mUiccCard.unregisterForCarrierPrivilegeRulesLoaded(this);
321                }
322                onRecordsLoaded();
323                break;
324
325            default:
326                loge("Unhandled message with number: " + msg.what);
327                break;
328        }
329    }
330
331    private void onSubscriptionActivated() {
332        updateIccAvailability();
333        updateStateProperty();
334    }
335
336    private void onSubscriptionDeactivated() {
337        resetProperties();
338        updateIccAvailability();
339        updateStateProperty();
340    }
341
342    private void onRecordsLoaded() {
343        broadcastInternalIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
344    }
345
346    private void updateIccAvailability() {
347        synchronized (mLock) {
348            UiccCard newCard = mUiccController.getUiccCard(mPhoneId);
349            CardState state = CardState.CARDSTATE_ABSENT;
350            UiccCardApplication newApp = null;
351            IccRecords newRecords = null;
352            if (newCard != null) {
353                state = newCard.getCardState();
354                newApp = newCard.getApplication(mCurrentAppType);
355                if (newApp != null) {
356                    newRecords = newApp.getIccRecords();
357                }
358            }
359
360            if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) {
361                if (DBG) log("Icc changed. Reregestering.");
362                unregisterUiccCardEvents();
363                mUiccCard = newCard;
364                mUiccApplication = newApp;
365                mIccRecords = newRecords;
366                registerUiccCardEvents();
367            }
368
369            updateExternalState();
370        }
371    }
372
373    void resetProperties() {
374        if (mCurrentAppType == UiccController.APP_FAM_3GPP) {
375            log("update icc_operator_numeric=" + "");
376            setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, "");
377            setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, "");
378            setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, "");
379         }
380    }
381
382    private void HandleDetectedState() {
383    // CAF_MSIM SAND
384//        setExternalState(State.DETECTED, false);
385    }
386
387    private void updateExternalState() {
388        if (mUiccCard == null || mUiccCard.getCardState() == CardState.CARDSTATE_ABSENT) {
389            if (mRadioOn) {
390                setExternalState(State.ABSENT);
391            } else {
392                setExternalState(State.NOT_READY);
393            }
394            return;
395        }
396
397        if (mUiccCard.getCardState() == CardState.CARDSTATE_ERROR) {
398            setExternalState(State.CARD_IO_ERROR);
399            return;
400        }
401
402        if (mUiccApplication == null) {
403            setExternalState(State.NOT_READY);
404            return;
405        }
406
407        switch (mUiccApplication.getState()) {
408            case APPSTATE_UNKNOWN:
409                setExternalState(State.UNKNOWN);
410                break;
411            case APPSTATE_DETECTED:
412                HandleDetectedState();
413                break;
414            case APPSTATE_PIN:
415                setExternalState(State.PIN_REQUIRED);
416                break;
417            case APPSTATE_PUK:
418                setExternalState(State.PUK_REQUIRED);
419                break;
420            case APPSTATE_SUBSCRIPTION_PERSO:
421                if (mUiccApplication.getPersoSubState() ==
422                        PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
423                    setExternalState(State.NETWORK_LOCKED);
424                } else {
425                    setExternalState(State.UNKNOWN);
426                }
427                break;
428            case APPSTATE_READY:
429                setExternalState(State.READY);
430                break;
431        }
432    }
433
434    private void registerUiccCardEvents() {
435        if (mUiccCard != null) {
436            mUiccCard.registerForAbsent(this, EVENT_ICC_ABSENT, null);
437        }
438        if (mUiccApplication != null) {
439            mUiccApplication.registerForReady(this, EVENT_APP_READY, null);
440            mUiccApplication.registerForLocked(this, EVENT_ICC_LOCKED, null);
441            mUiccApplication.registerForNetworkLocked(this, EVENT_NETWORK_LOCKED, null);
442        }
443        if (mIccRecords != null) {
444            mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null);
445            mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
446            mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
447        }
448    }
449
450    private void unregisterUiccCardEvents() {
451        if (mUiccCard != null) mUiccCard.unregisterForAbsent(this);
452        if (mUiccApplication != null) mUiccApplication.unregisterForReady(this);
453        if (mUiccApplication != null) mUiccApplication.unregisterForLocked(this);
454        if (mUiccApplication != null) mUiccApplication.unregisterForNetworkLocked(this);
455        if (mIccRecords != null) mIccRecords.unregisterForImsiReady(this);
456        if (mIccRecords != null) mIccRecords.unregisterForRecordsLoaded(this);
457        if (mIccRecords != null) mIccRecords.unregisterForRecordsEvents(this);
458    }
459
460    private void updateStateProperty() {
461        setSystemProperty(PROPERTY_SIM_STATE, getState().toString());
462    }
463
464    private void broadcastIccStateChangedIntent(String value, String reason) {
465        synchronized (mLock) {
466            if (mPhoneId == null || !SubscriptionManager.isValidSlotId(mPhoneId)) {
467                loge("broadcastIccStateChangedIntent: mPhoneId=" + mPhoneId
468                        + " is invalid; Return!!");
469                return;
470            }
471
472            if (mQuietMode) {
473                log("broadcastIccStateChangedIntent: QuietMode"
474                        + " NOT Broadcasting intent ACTION_SIM_STATE_CHANGED "
475                        + " value=" +  value + " reason=" + reason);
476                return;
477            }
478
479            Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
480            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
481            intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
482            intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
483            intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
484            SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhoneId);
485            log("broadcastIccStateChangedIntent intent ACTION_SIM_STATE_CHANGED value=" + value
486                + " reason=" + reason + " for mPhoneId=" + mPhoneId);
487            ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
488                    UserHandle.USER_ALL);
489        }
490    }
491
492    private void broadcastInternalIccStateChangedIntent(String value, String reason) {
493        synchronized (mLock) {
494            if (mPhoneId == null) {
495                loge("broadcastInternalIccStateChangedIntent: Card Index is not set; Return!!");
496                return;
497            }
498
499            Intent intent = new Intent(ACTION_INTERNAL_SIM_STATE_CHANGED);
500            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
501            intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
502            intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
503            intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
504            intent.putExtra(PhoneConstants.PHONE_KEY, mPhoneId);  // SubId may not be valid.
505            log("Sending intent ACTION_INTERNAL_SIM_STATE_CHANGED" + " for mPhoneId : " + mPhoneId);
506            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
507        }
508    }
509
510    private void setExternalState(State newState, boolean override) {
511        synchronized (mLock) {
512            if (mPhoneId == null || !SubscriptionManager.isValidSlotId(mPhoneId)) {
513                loge("setExternalState: mPhoneId=" + mPhoneId + " is invalid; Return!!");
514                return;
515            }
516
517            if (!override && newState == mExternalState) {
518                loge("setExternalState: !override and newstate unchanged from " + newState);
519                return;
520            }
521            mExternalState = newState;
522            loge("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState);
523            setSystemProperty(PROPERTY_SIM_STATE, getState().toString());
524
525            // For locked states, we should be sending internal broadcast.
526            if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(getIccStateIntentString(mExternalState))) {
527                broadcastInternalIccStateChangedIntent(getIccStateIntentString(mExternalState),
528                        getIccStateReason(mExternalState));
529            } else {
530                broadcastIccStateChangedIntent(getIccStateIntentString(mExternalState),
531                        getIccStateReason(mExternalState));
532            }
533            // TODO: Need to notify registrants for other states as well.
534            if ( State.ABSENT == mExternalState) {
535                mAbsentRegistrants.notifyRegistrants();
536            }
537        }
538    }
539
540    private void processLockedState() {
541        synchronized (mLock) {
542            if (mUiccApplication == null) {
543                //Don't need to do anything if non-existent application is locked
544                return;
545            }
546            PinState pin1State = mUiccApplication.getPin1State();
547            if (pin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
548                setExternalState(State.PERM_DISABLED);
549                return;
550            }
551
552            AppState appState = mUiccApplication.getState();
553            switch (appState) {
554                case APPSTATE_PIN:
555                    mPinLockedRegistrants.notifyRegistrants();
556                    setExternalState(State.PIN_REQUIRED);
557                    break;
558                case APPSTATE_PUK:
559                    setExternalState(State.PUK_REQUIRED);
560                    break;
561                case APPSTATE_DETECTED:
562                case APPSTATE_READY:
563                case APPSTATE_SUBSCRIPTION_PERSO:
564                case APPSTATE_UNKNOWN:
565                    // Neither required
566                    break;
567            }
568        }
569    }
570
571    private void setExternalState(State newState) {
572        setExternalState(newState, false);
573    }
574
575    public boolean getIccRecordsLoaded() {
576        synchronized (mLock) {
577            if (mIccRecords != null) {
578                return mIccRecords.getRecordsLoaded();
579            }
580            return false;
581        }
582    }
583
584    private String getIccStateIntentString(State state) {
585        switch (state) {
586            case ABSENT: return IccCardConstants.INTENT_VALUE_ICC_ABSENT;
587            case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
588            case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
589            case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
590            case READY: return IccCardConstants.INTENT_VALUE_ICC_READY;
591            case NOT_READY: return IccCardConstants.INTENT_VALUE_ICC_NOT_READY;
592            case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
593            case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR;
594            default: return IccCardConstants.INTENT_VALUE_ICC_UNKNOWN;
595        }
596    }
597
598    /**
599     * Locked state have a reason (PIN, PUK, NETWORK, PERM_DISABLED, CARD_IO_ERROR)
600     * @return reason
601     */
602    private String getIccStateReason(State state) {
603        switch (state) {
604            case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN;
605            case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK;
606            case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_LOCKED_NETWORK;
607            case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED;
608            case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR;
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