IccCardProxy.java revision d720945f2be5ea5fe0faf67e67d9ea0e184eba67
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.TelephonyManager;
33
34import com.android.internal.telephony.CommandsInterface;
35import com.android.internal.telephony.IccCard;
36import com.android.internal.telephony.IccCardConstants;
37import com.android.internal.telephony.PhoneConstants;
38import com.android.internal.telephony.TelephonyIntents;
39import com.android.internal.telephony.IccCardConstants.State;
40import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
41import com.android.internal.telephony.Phone;
42import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
43import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
44import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState;
45import com.android.internal.telephony.uicc.IccCardStatus.CardState;
46import com.android.internal.telephony.uicc.IccCardStatus.PinState;
47import com.android.internal.telephony.uicc.UiccController;
48
49import static com.android.internal.telephony.TelephonyProperties.PROPERTY_SIM_STATE;
50
51/**
52 * @Deprecated use {@link UiccController}.getUiccCard instead.
53 *
54 * The Phone App assumes that there is only one icc card, and one icc application
55 * available at a time. Moreover, it assumes such object (represented with IccCard)
56 * is available all the time (whether {@link RILConstants.RIL_REQUEST_GET_SIM_STATUS} returned
57 * or not, whether card has desired application or not, whether there really is a card in the
58 * slot or not).
59 *
60 * UiccController, however, can handle multiple instances of icc objects (multiple
61 * {@link UiccCardApplication}, multiple {@link IccFileHandler}, multiple {@link IccRecords})
62 * created and destroyed dynamically during phone operation.
63 *
64 * This class implements the IccCard interface that is always available (right after default
65 * phone object is constructed) to expose the current (based on voice radio technology)
66 * application on the uicc card, so that external apps won't break.
67 */
68
69public class IccCardProxy extends Handler implements IccCard {
70    private static final boolean DBG = true;
71    private static final String LOG_TAG = "RIL_IccCardProxy";
72
73    private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 1;
74    private static final int EVENT_RADIO_ON = 2;
75    private static final int EVENT_ICC_CHANGED = 3;
76    private static final int EVENT_ICC_ABSENT = 4;
77    private static final int EVENT_ICC_LOCKED = 5;
78    private static final int EVENT_APP_READY = 6;
79    private static final int EVENT_RECORDS_LOADED = 7;
80    private static final int EVENT_IMSI_READY = 8;
81    private static final int EVENT_NETWORK_LOCKED = 9;
82    private static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 11;
83
84    private final Object mLock = new Object();
85    private Context mContext;
86    private CommandsInterface mCi;
87
88    private RegistrantList mAbsentRegistrants = new RegistrantList();
89    private RegistrantList mPinLockedRegistrants = new RegistrantList();
90    private RegistrantList mNetworkLockedRegistrants = new RegistrantList();
91
92    private int mCurrentAppType = UiccController.APP_FAM_3GPP; //default to 3gpp?
93    private UiccController mUiccController = null;
94    private UiccCard mUiccCard = null;
95    private UiccCardApplication mUiccApplication = null;
96    private IccRecords mIccRecords = null;
97    private CdmaSubscriptionSourceManager mCdmaSSM = null;
98    private boolean mRadioOn = false;
99    private boolean mQuietMode = false; // when set to true IccCardProxy will not broadcast
100                                        // ACTION_SIM_STATE_CHANGED intents
101    private boolean mInitialized = false;
102    private State mExternalState = State.UNKNOWN;
103
104    public IccCardProxy(Context context, CommandsInterface ci) {
105        log("Creating");
106        this.mContext = context;
107        this.mCi = ci;
108        mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(context,
109                ci, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
110        mUiccController = UiccController.getInstance();
111        mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
112        ci.registerForOn(this,EVENT_RADIO_ON, null);
113        ci.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_UNAVAILABLE, null);
114        setExternalState(State.NOT_READY);
115    }
116
117    public void dispose() {
118        synchronized (mLock) {
119            log("Disposing");
120            //Cleanup icc references
121            mUiccController.unregisterForIccChanged(this);
122            mUiccController = null;
123            mCi.unregisterForOn(this);
124            mCi.unregisterForOffOrNotAvailable(this);
125            mCdmaSSM.dispose(this);
126        }
127    }
128
129    /*
130     * The card application that the external world sees will be based on the
131     * voice radio technology only!
132     */
133    public void setVoiceRadioTech(int radioTech) {
134        synchronized (mLock) {
135            if (DBG) {
136                log("Setting radio tech " + ServiceState.rilRadioTechnologyToString(radioTech));
137            }
138            if (ServiceState.isGsm(radioTech)) {
139                mCurrentAppType = UiccController.APP_FAM_3GPP;
140            } else {
141                mCurrentAppType = UiccController.APP_FAM_3GPP2;
142            }
143            updateQuietMode();
144        }
145    }
146
147    /**
148     * In case of 3gpp2 we need to find out if subscription used is coming from
149     * NV in which case we shouldn't broadcast any sim states changes.
150     */
151    private void updateQuietMode() {
152        synchronized (mLock) {
153            boolean oldQuietMode = mQuietMode;
154            boolean newQuietMode;
155            int cdmaSource = Phone.CDMA_SUBSCRIPTION_UNKNOWN;
156            boolean isLteOnCdmaMode = TelephonyManager.getLteOnCdmaModeStatic()
157                    == PhoneConstants.LTE_ON_CDMA_TRUE;
158            if (mCurrentAppType == UiccController.APP_FAM_3GPP) {
159                newQuietMode = false;
160                if (DBG) log("updateQuietMode: 3GPP subscription -> newQuietMode=" + newQuietMode);
161            } else {
162                if (isLteOnCdmaMode) {
163                    log("updateQuietMode: is cdma/lte device, force IccCardProxy into 3gpp mode");
164                    mCurrentAppType = UiccController.APP_FAM_3GPP;
165                }
166                cdmaSource = mCdmaSSM != null ?
167                        mCdmaSSM.getCdmaSubscriptionSource() : Phone.CDMA_SUBSCRIPTION_UNKNOWN;
168
169                newQuietMode = (cdmaSource == Phone.CDMA_SUBSCRIPTION_NV)
170                        && (mCurrentAppType == UiccController.APP_FAM_3GPP2)
171                        && !isLteOnCdmaMode;
172            }
173
174            if (mQuietMode == false && newQuietMode == true) {
175                // Last thing to do before switching to quiet mode is
176                // broadcast ICC_READY
177                log("Switching to QuietMode.");
178                setExternalState(State.READY);
179                mQuietMode = newQuietMode;
180            } else if (mQuietMode == true && newQuietMode == false) {
181                if (DBG) {
182                    log("updateQuietMode: Switching out from QuietMode."
183                            + " Force broadcast of current state=" + mExternalState);
184                }
185                mQuietMode = newQuietMode;
186                setExternalState(mExternalState, true);
187            }
188            if (DBG) {
189                log("updateQuietMode: QuietMode is " + mQuietMode + " (app_type="
190                    + mCurrentAppType + " isLteOnCdmaMode=" + isLteOnCdmaMode
191                    + " cdmaSource=" + cdmaSource + ")");
192            }
193            mInitialized = true;
194            sendMessage(obtainMessage(EVENT_ICC_CHANGED));
195        }
196    }
197
198    public void handleMessage(Message msg) {
199        switch (msg.what) {
200            case EVENT_RADIO_OFF_OR_UNAVAILABLE:
201                mRadioOn = false;
202                break;
203            case EVENT_RADIO_ON:
204                mRadioOn = true;
205                if (!mInitialized) {
206                    updateQuietMode();
207                }
208                break;
209            case EVENT_ICC_CHANGED:
210                if (mInitialized) {
211                    updateIccAvailability();
212                }
213                break;
214            case EVENT_ICC_ABSENT:
215                mAbsentRegistrants.notifyRegistrants();
216                setExternalState(State.ABSENT);
217                break;
218            case EVENT_ICC_LOCKED:
219                processLockedState();
220                break;
221            case EVENT_APP_READY:
222                setExternalState(State.READY);
223                break;
224            case EVENT_RECORDS_LOADED:
225                broadcastIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
226                break;
227            case EVENT_IMSI_READY:
228                broadcastIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_IMSI, null);
229                break;
230            case EVENT_NETWORK_LOCKED:
231                mNetworkLockedRegistrants.notifyRegistrants();
232                setExternalState(State.NETWORK_LOCKED);
233                break;
234            case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
235                updateQuietMode();
236                break;
237            default:
238                loge("Unhandled message with number: " + msg.what);
239                break;
240        }
241    }
242
243    private void updateIccAvailability() {
244        synchronized (mLock) {
245            UiccCard newCard = mUiccController.getUiccCard();
246            CardState state = CardState.CARDSTATE_ABSENT;
247            UiccCardApplication newApp = null;
248            IccRecords newRecords = null;
249            if (newCard != null) {
250                state = newCard.getCardState();
251                newApp = newCard.getApplication(mCurrentAppType);
252                if (newApp != null) {
253                    newRecords = newApp.getIccRecords();
254                }
255            }
256
257            if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) {
258                if (DBG) log("Icc changed. Reregestering.");
259                unregisterUiccCardEvents();
260                mUiccCard = newCard;
261                mUiccApplication = newApp;
262                mIccRecords = newRecords;
263                registerUiccCardEvents();
264            }
265
266            updateExternalState();
267        }
268    }
269
270    private void updateExternalState() {
271        if (mUiccCard == null || mUiccCard.getCardState() == CardState.CARDSTATE_ABSENT) {
272            if (mRadioOn) {
273                setExternalState(State.ABSENT);
274            } else {
275                setExternalState(State.NOT_READY);
276            }
277            return;
278        }
279
280        if (mUiccCard.getCardState() == CardState.CARDSTATE_ERROR ||
281                mUiccApplication == null) {
282            setExternalState(State.UNKNOWN);
283            return;
284        }
285
286        switch (mUiccApplication.getState()) {
287            case APPSTATE_UNKNOWN:
288            case APPSTATE_DETECTED:
289                setExternalState(State.UNKNOWN);
290                break;
291            case APPSTATE_PIN:
292                setExternalState(State.PIN_REQUIRED);
293                break;
294            case APPSTATE_PUK:
295                setExternalState(State.PUK_REQUIRED);
296                break;
297            case APPSTATE_SUBSCRIPTION_PERSO:
298                if (mUiccApplication.getPersoSubState() == PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
299                    setExternalState(State.NETWORK_LOCKED);
300                } else {
301                    setExternalState(State.UNKNOWN);
302                }
303                break;
304            case APPSTATE_READY:
305                setExternalState(State.READY);
306                break;
307        }
308    }
309
310    private void registerUiccCardEvents() {
311        if (mUiccCard != null) mUiccCard.registerForAbsent(this, EVENT_ICC_ABSENT, null);
312        if (mUiccApplication != null) {
313            mUiccApplication.registerForReady(this, EVENT_APP_READY, null);
314            mUiccApplication.registerForLocked(this, EVENT_ICC_LOCKED, null);
315            mUiccApplication.registerForNetworkLocked(this, EVENT_NETWORK_LOCKED, null);
316        }
317        if (mIccRecords != null) {
318            mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null);
319            mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
320        }
321    }
322
323    private void unregisterUiccCardEvents() {
324        if (mUiccCard != null) mUiccCard.unregisterForAbsent(this);
325        if (mUiccApplication != null) mUiccApplication.unregisterForReady(this);
326        if (mUiccApplication != null) mUiccApplication.unregisterForLocked(this);
327        if (mUiccApplication != null) mUiccApplication.unregisterForNetworkLocked(this);
328        if (mIccRecords != null) mIccRecords.unregisterForImsiReady(this);
329        if (mIccRecords != null) mIccRecords.unregisterForRecordsLoaded(this);
330    }
331
332    private void broadcastIccStateChangedIntent(String value, String reason) {
333        synchronized (mLock) {
334            if (mQuietMode) {
335                log("QuietMode: NOT Broadcasting intent ACTION_SIM_STATE_CHANGED " +  value
336                        + " reason " + reason);
337                return;
338            }
339
340            Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
341            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
342            intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
343            intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
344            intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
345
346            if (DBG) log("Broadcasting intent ACTION_SIM_STATE_CHANGED " +  value
347                    + " reason " + reason);
348            ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
349                    UserHandle.USER_ALL);
350        }
351    }
352
353    private void processLockedState() {
354        synchronized (mLock) {
355            if (mUiccApplication == null) {
356                //Don't need to do anything if non-existent application is locked
357                return;
358            }
359            PinState pin1State = mUiccApplication.getPin1State();
360            if (pin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
361                setExternalState(State.PERM_DISABLED);
362                return;
363            }
364
365            AppState appState = mUiccApplication.getState();
366            switch (appState) {
367                case APPSTATE_PIN:
368                    mPinLockedRegistrants.notifyRegistrants();
369                    setExternalState(State.PIN_REQUIRED);
370                    break;
371                case APPSTATE_PUK:
372                    setExternalState(State.PUK_REQUIRED);
373                    break;
374            }
375        }
376    }
377
378    private void setExternalState(State newState, boolean override) {
379        synchronized (mLock) {
380            if (!override && newState == mExternalState) {
381                return;
382            }
383            mExternalState = newState;
384            SystemProperties.set(PROPERTY_SIM_STATE, mExternalState.toString());
385            broadcastIccStateChangedIntent(getIccStateIntentString(mExternalState),
386                    getIccStateReason(mExternalState));
387        }
388    }
389
390    private void setExternalState(State newState) {
391        setExternalState(newState, false);
392    }
393
394    public boolean getIccRecordsLoaded() {
395        synchronized (mLock) {
396            if (mIccRecords != null) {
397                return mIccRecords.getRecordsLoaded();
398            }
399            return false;
400        }
401    }
402
403    private String getIccStateIntentString(State state) {
404        switch (state) {
405            case ABSENT: return IccCardConstants.INTENT_VALUE_ICC_ABSENT;
406            case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
407            case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
408            case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
409            case READY: return IccCardConstants.INTENT_VALUE_ICC_READY;
410            case NOT_READY: return IccCardConstants.INTENT_VALUE_ICC_NOT_READY;
411            case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
412            default: return IccCardConstants.INTENT_VALUE_ICC_UNKNOWN;
413        }
414    }
415
416    /**
417     * Locked state have a reason (PIN, PUK, NETWORK, PERM_DISABLED)
418     * @return reason
419     */
420    private String getIccStateReason(State state) {
421        switch (state) {
422            case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN;
423            case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK;
424            case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_LOCKED_NETWORK;
425            case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED;
426            default: return null;
427       }
428    }
429
430    /* IccCard interface implementation */
431    @Override
432    public State getState() {
433        synchronized (mLock) {
434            return mExternalState;
435        }
436    }
437
438    @Override
439    public IccRecords getIccRecords() {
440        synchronized (mLock) {
441            return mIccRecords;
442        }
443    }
444
445    @Override
446    public IccFileHandler getIccFileHandler() {
447        synchronized (mLock) {
448            if (mUiccApplication != null) {
449                return mUiccApplication.getIccFileHandler();
450            }
451            return null;
452        }
453    }
454
455    /**
456     * Notifies handler of any transition into State.ABSENT
457     */
458    @Override
459    public void registerForAbsent(Handler h, int what, Object obj) {
460        synchronized (mLock) {
461            Registrant r = new Registrant (h, what, obj);
462
463            mAbsentRegistrants.add(r);
464
465            if (getState() == State.ABSENT) {
466                r.notifyRegistrant();
467            }
468        }
469    }
470
471    @Override
472    public void unregisterForAbsent(Handler h) {
473        synchronized (mLock) {
474            mAbsentRegistrants.remove(h);
475        }
476    }
477
478    /**
479     * Notifies handler of any transition into State.NETWORK_LOCKED
480     */
481    @Override
482    public void registerForNetworkLocked(Handler h, int what, Object obj) {
483        synchronized (mLock) {
484            Registrant r = new Registrant (h, what, obj);
485
486            mNetworkLockedRegistrants.add(r);
487
488            if (getState() == State.NETWORK_LOCKED) {
489                r.notifyRegistrant();
490            }
491        }
492    }
493
494    @Override
495    public void unregisterForNetworkLocked(Handler h) {
496        synchronized (mLock) {
497            mNetworkLockedRegistrants.remove(h);
498        }
499    }
500
501    /**
502     * Notifies handler of any transition into State.isPinLocked()
503     */
504    @Override
505    public void registerForLocked(Handler h, int what, Object obj) {
506        synchronized (mLock) {
507            Registrant r = new Registrant (h, what, obj);
508
509            mPinLockedRegistrants.add(r);
510
511            if (getState().isPinLocked()) {
512                r.notifyRegistrant();
513            }
514        }
515    }
516
517    @Override
518    public void unregisterForLocked(Handler h) {
519        synchronized (mLock) {
520            mPinLockedRegistrants.remove(h);
521        }
522    }
523
524    @Override
525    public void supplyPin(String pin, Message onComplete) {
526        synchronized (mLock) {
527            if (mUiccApplication != null) {
528                mUiccApplication.supplyPin(pin, onComplete);
529            } else if (onComplete != null) {
530                Exception e = new RuntimeException("ICC card is absent.");
531                AsyncResult.forMessage(onComplete).exception = e;
532                onComplete.sendToTarget();
533                return;
534            }
535        }
536    }
537
538    @Override
539    public void supplyPuk(String puk, String newPin, Message onComplete) {
540        synchronized (mLock) {
541            if (mUiccApplication != null) {
542                mUiccApplication.supplyPuk(puk, newPin, onComplete);
543            } else if (onComplete != null) {
544                Exception e = new RuntimeException("ICC card is absent.");
545                AsyncResult.forMessage(onComplete).exception = e;
546                onComplete.sendToTarget();
547                return;
548            }
549        }
550    }
551
552    @Override
553    public void supplyPin2(String pin2, Message onComplete) {
554        synchronized (mLock) {
555            if (mUiccApplication != null) {
556                mUiccApplication.supplyPin2(pin2, onComplete);
557            } else if (onComplete != null) {
558                Exception e = new RuntimeException("ICC card is absent.");
559                AsyncResult.forMessage(onComplete).exception = e;
560                onComplete.sendToTarget();
561                return;
562            }
563        }
564    }
565
566    @Override
567    public void supplyPuk2(String puk2, String newPin2, Message onComplete) {
568        synchronized (mLock) {
569            if (mUiccApplication != null) {
570                mUiccApplication.supplyPuk2(puk2, newPin2, onComplete);
571            } else if (onComplete != null) {
572                Exception e = new RuntimeException("ICC card is absent.");
573                AsyncResult.forMessage(onComplete).exception = e;
574                onComplete.sendToTarget();
575                return;
576            }
577        }
578    }
579
580    @Override
581    public void supplyNetworkDepersonalization(String pin, Message onComplete) {
582        synchronized (mLock) {
583            if (mUiccApplication != null) {
584                mUiccApplication.supplyNetworkDepersonalization(pin, onComplete);
585            } else if (onComplete != null) {
586                Exception e = new RuntimeException("CommandsInterface is not set.");
587                AsyncResult.forMessage(onComplete).exception = e;
588                onComplete.sendToTarget();
589                return;
590            }
591        }
592    }
593
594    @Override
595    public boolean getIccLockEnabled() {
596        synchronized (mLock) {
597            /* defaults to true, if ICC is absent */
598            Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccLockEnabled() : true;
599            return retValue;
600        }
601    }
602
603    @Override
604    public boolean getIccFdnEnabled() {
605        synchronized (mLock) {
606            Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccFdnEnabled() : false;
607            return retValue;
608        }
609    }
610
611    @Override
612    public void setIccLockEnabled(boolean enabled, String password, Message onComplete) {
613        synchronized (mLock) {
614            if (mUiccApplication != null) {
615                mUiccApplication.setIccLockEnabled(enabled, password, onComplete);
616            } else if (onComplete != null) {
617                Exception e = new RuntimeException("ICC card is absent.");
618                AsyncResult.forMessage(onComplete).exception = e;
619                onComplete.sendToTarget();
620                return;
621            }
622        }
623    }
624
625    @Override
626    public void setIccFdnEnabled(boolean enabled, String password, Message onComplete) {
627        synchronized (mLock) {
628            if (mUiccApplication != null) {
629                mUiccApplication.setIccFdnEnabled(enabled, password, onComplete);
630            } else if (onComplete != null) {
631                Exception e = new RuntimeException("ICC card is absent.");
632                AsyncResult.forMessage(onComplete).exception = e;
633                onComplete.sendToTarget();
634                return;
635            }
636        }
637    }
638
639    @Override
640    public void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete) {
641        synchronized (mLock) {
642            if (mUiccApplication != null) {
643                mUiccApplication.changeIccLockPassword(oldPassword, newPassword, onComplete);
644            } else if (onComplete != null) {
645                Exception e = new RuntimeException("ICC card is absent.");
646                AsyncResult.forMessage(onComplete).exception = e;
647                onComplete.sendToTarget();
648                return;
649            }
650        }
651    }
652
653    @Override
654    public void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete) {
655        synchronized (mLock) {
656            if (mUiccApplication != null) {
657                mUiccApplication.changeIccFdnPassword(oldPassword, newPassword, onComplete);
658            } else if (onComplete != null) {
659                Exception e = new RuntimeException("ICC card is absent.");
660                AsyncResult.forMessage(onComplete).exception = e;
661                onComplete.sendToTarget();
662                return;
663            }
664        }
665    }
666
667    @Override
668    public String getServiceProviderName() {
669        synchronized (mLock) {
670            if (mIccRecords != null) {
671                return mIccRecords.getServiceProviderName();
672            }
673            return null;
674        }
675    }
676
677    @Override
678    public boolean isApplicationOnIcc(IccCardApplicationStatus.AppType type) {
679        synchronized (mLock) {
680            Boolean retValue = mUiccCard != null ? mUiccCard.isApplicationOnIcc(type) : false;
681            return retValue;
682        }
683    }
684
685    @Override
686    public boolean hasIccCard() {
687        synchronized (mLock) {
688            if (mUiccCard != null && mUiccCard.getCardState() != CardState.CARDSTATE_ABSENT) {
689                return true;
690            }
691            return false;
692        }
693    }
694
695    private void log(String s) {
696        Rlog.d(LOG_TAG, s);
697    }
698
699    private void loge(String msg) {
700        Rlog.e(LOG_TAG, msg);
701    }
702}
703