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