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