1/*
2 * Copyright (C) 2006, 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 android.content.Context;
20import android.os.AsyncResult;
21import android.os.Handler;
22import android.os.Message;
23import android.os.Registrant;
24import android.os.RegistrantList;
25import android.telephony.Rlog;
26
27import com.android.internal.telephony.CommandsInterface;
28import com.android.internal.telephony.PhoneConstants;
29import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
30import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
31import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState;
32import com.android.internal.telephony.uicc.IccCardStatus.PinState;
33import com.android.internal.telephony.SubscriptionController;
34
35import java.io.FileDescriptor;
36import java.io.PrintWriter;
37
38/**
39 * {@hide}
40 */
41public class UiccCardApplication {
42    private static final String LOG_TAG = "UiccCardApplication";
43    private static final boolean DBG = true;
44
45    private static final int EVENT_PIN1_PUK1_DONE = 1;
46    private static final int EVENT_CHANGE_PIN1_DONE = 2;
47    private static final int EVENT_CHANGE_PIN2_DONE = 3;
48    private static final int EVENT_QUERY_FACILITY_FDN_DONE = 4;
49    private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 5;
50    private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 6;
51    private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 7;
52    private static final int EVENT_PIN2_PUK2_DONE = 8;
53    private static final int EVENT_RADIO_UNAVAILABLE = 9;
54
55    /**
56     * These values are for authContext (parameter P2) per 3GPP TS 31.102 (Section 7.1.2)
57     */
58    public static final int AUTH_CONTEXT_EAP_SIM = PhoneConstants.AUTH_CONTEXT_EAP_SIM;
59    public static final int AUTH_CONTEXT_EAP_AKA = PhoneConstants.AUTH_CONTEXT_EAP_AKA;
60    public static final int AUTH_CONTEXT_UNDEFINED = PhoneConstants.AUTH_CONTEXT_UNDEFINED;
61
62    private final Object  mLock = new Object();
63    private UiccCard      mUiccCard; //parent
64    private AppState      mAppState;
65    private AppType       mAppType;
66    private int           mAuthContext;
67    private PersoSubState mPersoSubState;
68    private String        mAid;
69    private String        mAppLabel;
70    private boolean       mPin1Replaced;
71    private PinState      mPin1State;
72    private PinState      mPin2State;
73    private boolean       mIccFdnEnabled;
74    private boolean       mDesiredFdnEnabled;
75    private boolean       mIccLockEnabled;
76    private boolean       mDesiredPinLocked;
77    private boolean       mIccFdnAvailable = true; // Default is enabled.
78
79    private CommandsInterface mCi;
80    private Context mContext;
81    private IccRecords mIccRecords;
82    private IccFileHandler mIccFh;
83
84    private boolean mDestroyed;//set to true once this App is commanded to be disposed of.
85
86    private RegistrantList mReadyRegistrants = new RegistrantList();
87    private RegistrantList mPinLockedRegistrants = new RegistrantList();
88    private RegistrantList mNetworkLockedRegistrants = new RegistrantList();
89
90    public UiccCardApplication(UiccCard uiccCard,
91                        IccCardApplicationStatus as,
92                        Context c,
93                        CommandsInterface ci) {
94        if (DBG) log("Creating UiccApp: " + as);
95        mUiccCard = uiccCard;
96        mAppState = as.app_state;
97        mAppType = as.app_type;
98        mAuthContext = getAuthContext(mAppType);
99        mPersoSubState = as.perso_substate;
100        mAid = as.aid;
101        mAppLabel = as.app_label;
102        mPin1Replaced = (as.pin1_replaced != 0);
103        mPin1State = as.pin1;
104        mPin2State = as.pin2;
105
106        mContext = c;
107        mCi = ci;
108
109        mIccFh = createIccFileHandler(as.app_type);
110        mIccRecords = createIccRecords(as.app_type, mContext, mCi);
111        if (mAppState == AppState.APPSTATE_READY) {
112            queryFdn();
113            queryPin1State();
114        }
115        mCi.registerForNotAvailable(mHandler, EVENT_RADIO_UNAVAILABLE, null);
116    }
117
118    public void update (IccCardApplicationStatus as, Context c, CommandsInterface ci) {
119        synchronized (mLock) {
120            if (mDestroyed) {
121                loge("Application updated after destroyed! Fix me!");
122                return;
123            }
124
125            if (DBG) log(mAppType + " update. New " + as);
126            mContext = c;
127            mCi = ci;
128            AppType oldAppType = mAppType;
129            AppState oldAppState = mAppState;
130            PersoSubState oldPersoSubState = mPersoSubState;
131            mAppType = as.app_type;
132            mAuthContext = getAuthContext(mAppType);
133            mAppState = as.app_state;
134            mPersoSubState = as.perso_substate;
135            mAid = as.aid;
136            mAppLabel = as.app_label;
137            mPin1Replaced = (as.pin1_replaced != 0);
138            mPin1State = as.pin1;
139            mPin2State = as.pin2;
140
141            if (mAppType != oldAppType) {
142                if (mIccFh != null) { mIccFh.dispose();}
143                if (mIccRecords != null) { mIccRecords.dispose();}
144                mIccFh = createIccFileHandler(as.app_type);
145                mIccRecords = createIccRecords(as.app_type, c, ci);
146            }
147
148            if (mPersoSubState != oldPersoSubState &&
149                    mPersoSubState == PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
150                notifyNetworkLockedRegistrantsIfNeeded(null);
151            }
152
153            if (mAppState != oldAppState) {
154                if (DBG) log(oldAppType + " changed state: " + oldAppState + " -> " + mAppState);
155                // If the app state turns to APPSTATE_READY, then query FDN status,
156                //as it might have failed in earlier attempt.
157                if (mAppState == AppState.APPSTATE_READY) {
158                    queryFdn();
159                    queryPin1State();
160                }
161                notifyPinLockedRegistrantsIfNeeded(null);
162                notifyReadyRegistrantsIfNeeded(null);
163            }
164        }
165    }
166
167    void dispose() {
168        synchronized (mLock) {
169            if (DBG) log(mAppType + " being Disposed");
170            mDestroyed = true;
171            if (mIccRecords != null) { mIccRecords.dispose();}
172            if (mIccFh != null) { mIccFh.dispose();}
173            mIccRecords = null;
174            mIccFh = null;
175            mCi.unregisterForNotAvailable(mHandler);
176        }
177    }
178
179    private IccRecords createIccRecords(AppType type, Context c, CommandsInterface ci) {
180        if (type == AppType.APPTYPE_USIM || type == AppType.APPTYPE_SIM) {
181            return new SIMRecords(this, c, ci);
182        } else if (type == AppType.APPTYPE_RUIM || type == AppType.APPTYPE_CSIM){
183            return new RuimRecords(this, c, ci);
184        } else if (type == AppType.APPTYPE_ISIM) {
185            return new IsimUiccRecords(this, c, ci);
186        } else {
187            // Unknown app type (maybe detection is still in progress)
188            return null;
189        }
190    }
191
192    private IccFileHandler createIccFileHandler(AppType type) {
193        switch (type) {
194            case APPTYPE_SIM:
195                return new SIMFileHandler(this, mAid, mCi);
196            case APPTYPE_RUIM:
197                return new RuimFileHandler(this, mAid, mCi);
198            case APPTYPE_USIM:
199                return new UsimFileHandler(this, mAid, mCi);
200            case APPTYPE_CSIM:
201                return new CsimFileHandler(this, mAid, mCi);
202            case APPTYPE_ISIM:
203                return new IsimFileHandler(this, mAid, mCi);
204            default:
205                return null;
206        }
207    }
208
209    /** Assumes mLock is held. */
210    public void queryFdn() {
211        //This shouldn't change run-time. So needs to be called only once.
212        int serviceClassX;
213
214        serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
215                        CommandsInterface.SERVICE_CLASS_DATA +
216                        CommandsInterface.SERVICE_CLASS_FAX;
217        mCi.queryFacilityLockForApp (
218                CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX,
219                mAid, mHandler.obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE));
220    }
221    /**
222     * Interpret EVENT_QUERY_FACILITY_LOCK_DONE
223     * @param ar is asyncResult of Query_Facility_Locked
224     */
225    private void onQueryFdnEnabled(AsyncResult ar) {
226        synchronized (mLock) {
227            if (ar.exception != null) {
228                if (DBG) log("Error in querying facility lock:" + ar.exception);
229                return;
230            }
231
232            int[] result = (int[])ar.result;
233            if(result.length != 0) {
234                //0 - Available & Disabled, 1-Available & Enabled, 2-Unavailable.
235                if (result[0] == 2) {
236                    mIccFdnEnabled = false;
237                    mIccFdnAvailable = false;
238                } else {
239                    mIccFdnEnabled = (result[0] == 1) ? true : false;
240                    mIccFdnAvailable = true;
241                }
242                log("Query facility FDN : FDN service available: "+ mIccFdnAvailable
243                        +" enabled: "  + mIccFdnEnabled);
244            } else {
245                loge("Bogus facility lock response");
246            }
247        }
248    }
249
250    private void onChangeFdnDone(AsyncResult ar) {
251        synchronized (mLock) {
252            int attemptsRemaining = -1;
253
254            if (ar.exception == null) {
255                mIccFdnEnabled = mDesiredFdnEnabled;
256                if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
257                        "mIccFdnEnabled=" + mIccFdnEnabled);
258            } else {
259                attemptsRemaining = parsePinPukErrorResult(ar);
260                loge("Error change facility fdn with exception " + ar.exception);
261            }
262            Message response = (Message)ar.userObj;
263            response.arg1 = attemptsRemaining;
264            AsyncResult.forMessage(response).exception = ar.exception;
265            response.sendToTarget();
266        }
267    }
268
269    /** REMOVE when mIccLockEnabled is not needed, assumes mLock is held */
270    private void queryPin1State() {
271        int serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
272                CommandsInterface.SERVICE_CLASS_DATA +
273                CommandsInterface.SERVICE_CLASS_FAX;
274        mCi.queryFacilityLockForApp (
275            CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
276            mAid, mHandler.obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
277    }
278
279    /** REMOVE when mIccLockEnabled is not needed*/
280    private void onQueryFacilityLock(AsyncResult ar) {
281        synchronized (mLock) {
282            if(ar.exception != null) {
283                if (DBG) log("Error in querying facility lock:" + ar.exception);
284                return;
285            }
286
287            int[] ints = (int[])ar.result;
288            if(ints.length != 0) {
289                if (DBG) log("Query facility lock : "  + ints[0]);
290
291                mIccLockEnabled = (ints[0] != 0);
292
293                if (mIccLockEnabled) {
294                    mPinLockedRegistrants.notifyRegistrants();
295                }
296
297                // Sanity check: we expect mPin1State to match mIccLockEnabled.
298                // When mPin1State is DISABLED mIccLockEanbled should be false.
299                // When mPin1State is ENABLED mIccLockEnabled should be true.
300                //
301                // Here we validate these assumptions to assist in identifying which ril/radio's
302                // have not correctly implemented GET_SIM_STATUS
303                switch (mPin1State) {
304                    case PINSTATE_DISABLED:
305                        if (mIccLockEnabled) {
306                            loge("QUERY_FACILITY_LOCK:enabled GET_SIM_STATUS.Pin1:disabled."
307                                    + " Fixme");
308                        }
309                        break;
310                    case PINSTATE_ENABLED_NOT_VERIFIED:
311                    case PINSTATE_ENABLED_VERIFIED:
312                    case PINSTATE_ENABLED_BLOCKED:
313                    case PINSTATE_ENABLED_PERM_BLOCKED:
314                        if (!mIccLockEnabled) {
315                            loge("QUERY_FACILITY_LOCK:disabled GET_SIM_STATUS.Pin1:enabled."
316                                    + " Fixme");
317                        }
318                    case PINSTATE_UNKNOWN:
319                    default:
320                        if (DBG) log("Ignoring: pin1state=" + mPin1State);
321                        break;
322                }
323            } else {
324                loge("Bogus facility lock response");
325            }
326        }
327    }
328
329    /** REMOVE when mIccLockEnabled is not needed */
330    private void onChangeFacilityLock(AsyncResult ar) {
331        synchronized (mLock) {
332            int attemptsRemaining = -1;
333
334            if (ar.exception == null) {
335                mIccLockEnabled = mDesiredPinLocked;
336                if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: mIccLockEnabled= "
337                        + mIccLockEnabled);
338            } else {
339                attemptsRemaining = parsePinPukErrorResult(ar);
340                loge("Error change facility lock with exception " + ar.exception);
341            }
342            Message response = (Message)ar.userObj;
343            AsyncResult.forMessage(response).exception = ar.exception;
344            response.arg1 = attemptsRemaining;
345            response.sendToTarget();
346        }
347    }
348
349    /**
350     * Parse the error response to obtain number of attempts remaining
351     */
352    private int parsePinPukErrorResult(AsyncResult ar) {
353        int[] result = (int[]) ar.result;
354        if (result == null) {
355            return -1;
356        } else {
357            int length = result.length;
358            int attemptsRemaining = -1;
359            if (length > 0) {
360                attemptsRemaining = result[0];
361            }
362            log("parsePinPukErrorResult: attemptsRemaining=" + attemptsRemaining);
363            return attemptsRemaining;
364        }
365    }
366
367    private Handler mHandler = new Handler() {
368        @Override
369        public void handleMessage(Message msg){
370            AsyncResult ar;
371
372            if (mDestroyed) {
373                loge("Received message " + msg + "[" + msg.what
374                        + "] while being destroyed. Ignoring.");
375                return;
376            }
377
378            switch (msg.what) {
379                case EVENT_PIN1_PUK1_DONE:
380                case EVENT_PIN2_PUK2_DONE:
381                case EVENT_CHANGE_PIN1_DONE:
382                case EVENT_CHANGE_PIN2_DONE:
383                    // a PIN/PUK/PIN2/PUK2 complete
384                    // request has completed. ar.userObj is the response Message
385                    int attemptsRemaining = -1;
386                    ar = (AsyncResult)msg.obj;
387                    if ((ar.exception != null) && (ar.result != null)) {
388                        attemptsRemaining = parsePinPukErrorResult(ar);
389                    }
390                    Message response = (Message)ar.userObj;
391                    AsyncResult.forMessage(response).exception = ar.exception;
392                    response.arg1 = attemptsRemaining;
393                    response.sendToTarget();
394                    break;
395                case EVENT_QUERY_FACILITY_FDN_DONE:
396                    ar = (AsyncResult)msg.obj;
397                    onQueryFdnEnabled(ar);
398                    break;
399                case EVENT_CHANGE_FACILITY_FDN_DONE:
400                    ar = (AsyncResult)msg.obj;
401                    onChangeFdnDone(ar);
402                    break;
403                case EVENT_QUERY_FACILITY_LOCK_DONE:
404                    ar = (AsyncResult)msg.obj;
405                    onQueryFacilityLock(ar);
406                    break;
407                case EVENT_CHANGE_FACILITY_LOCK_DONE:
408                    ar = (AsyncResult)msg.obj;
409                    onChangeFacilityLock(ar);
410                    break;
411                case EVENT_RADIO_UNAVAILABLE:
412                    if (DBG) log("handleMessage (EVENT_RADIO_UNAVAILABLE)");
413                    mAppState = AppState.APPSTATE_UNKNOWN;
414                    break;
415                default:
416                    loge("Unknown Event " + msg.what);
417            }
418        }
419    };
420
421    public void registerForReady(Handler h, int what, Object obj) {
422        synchronized (mLock) {
423            Registrant r = new Registrant (h, what, obj);
424            mReadyRegistrants.add(r);
425            notifyReadyRegistrantsIfNeeded(r);
426        }
427    }
428
429    public void unregisterForReady(Handler h) {
430        synchronized (mLock) {
431            mReadyRegistrants.remove(h);
432        }
433    }
434
435    /**
436     * Notifies handler of any transition into State.isPinLocked()
437     */
438    public void registerForLocked(Handler h, int what, Object obj) {
439        synchronized (mLock) {
440            Registrant r = new Registrant (h, what, obj);
441            mPinLockedRegistrants.add(r);
442            notifyPinLockedRegistrantsIfNeeded(r);
443        }
444    }
445
446    public void unregisterForLocked(Handler h) {
447        synchronized (mLock) {
448            mPinLockedRegistrants.remove(h);
449        }
450    }
451
452    /**
453     * Notifies handler of any transition into State.NETWORK_LOCKED
454     */
455    public void registerForNetworkLocked(Handler h, int what, Object obj) {
456        synchronized (mLock) {
457            Registrant r = new Registrant (h, what, obj);
458            mNetworkLockedRegistrants.add(r);
459            notifyNetworkLockedRegistrantsIfNeeded(r);
460        }
461    }
462
463    public void unregisterForNetworkLocked(Handler h) {
464        synchronized (mLock) {
465            mNetworkLockedRegistrants.remove(h);
466        }
467    }
468
469    /**
470     * Notifies specified registrant, assume mLock is held.
471     *
472     * @param r Registrant to be notified. If null - all registrants will be notified
473     */
474    private void notifyReadyRegistrantsIfNeeded(Registrant r) {
475        if (mDestroyed) {
476            return;
477        }
478        if (mAppState == AppState.APPSTATE_READY) {
479            if (mPin1State == PinState.PINSTATE_ENABLED_NOT_VERIFIED ||
480                    mPin1State == PinState.PINSTATE_ENABLED_BLOCKED ||
481                    mPin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
482                loge("Sanity check failed! APPSTATE is ready while PIN1 is not verified!!!");
483                // Don't notify if application is in insane state
484                return;
485            }
486            if (r == null) {
487                if (DBG) log("Notifying registrants: READY");
488                mReadyRegistrants.notifyRegistrants();
489            } else {
490                if (DBG) log("Notifying 1 registrant: READY");
491                r.notifyRegistrant(new AsyncResult(null, null, null));
492            }
493        }
494    }
495
496    /**
497     * Notifies specified registrant, assume mLock is held.
498     *
499     * @param r Registrant to be notified. If null - all registrants will be notified
500     */
501    private void notifyPinLockedRegistrantsIfNeeded(Registrant r) {
502        if (mDestroyed) {
503            return;
504        }
505
506        if (mAppState == AppState.APPSTATE_PIN ||
507                mAppState == AppState.APPSTATE_PUK) {
508            if (mPin1State == PinState.PINSTATE_ENABLED_VERIFIED ||
509                    mPin1State == PinState.PINSTATE_DISABLED) {
510                loge("Sanity check failed! APPSTATE is locked while PIN1 is not!!!");
511                //Don't notify if application is in insane state
512                return;
513            }
514            if (r == null) {
515                if (DBG) log("Notifying registrants: LOCKED");
516                mPinLockedRegistrants.notifyRegistrants();
517            } else {
518                if (DBG) log("Notifying 1 registrant: LOCKED");
519                r.notifyRegistrant(new AsyncResult(null, null, null));
520            }
521        }
522    }
523
524    /**
525     * Notifies specified registrant, assume mLock is held.
526     *
527     * @param r Registrant to be notified. If null - all registrants will be notified
528     */
529    private void notifyNetworkLockedRegistrantsIfNeeded(Registrant r) {
530        if (mDestroyed) {
531            return;
532        }
533
534        if (mAppState == AppState.APPSTATE_SUBSCRIPTION_PERSO &&
535                mPersoSubState == PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
536            if (r == null) {
537                if (DBG) log("Notifying registrants: NETWORK_LOCKED");
538                mNetworkLockedRegistrants.notifyRegistrants();
539            } else {
540                if (DBG) log("Notifying 1 registrant: NETWORK_LOCED");
541                r.notifyRegistrant(new AsyncResult(null, null, null));
542            }
543        }
544    }
545
546    public AppState getState() {
547        synchronized (mLock) {
548            return mAppState;
549        }
550    }
551
552    public AppType getType() {
553        synchronized (mLock) {
554            return mAppType;
555        }
556    }
557
558    public int getAuthContext() {
559        synchronized (mLock) {
560            return mAuthContext;
561        }
562    }
563
564    /**
565     * Returns the authContext based on the type of UiccCard.
566     *
567     * @param appType the app type
568     * @return authContext corresponding to the type or AUTH_CONTEXT_UNDEFINED if appType not
569     * supported
570     */
571    private static int getAuthContext(AppType appType) {
572        int authContext;
573
574        switch (appType) {
575            case APPTYPE_SIM:
576                authContext = AUTH_CONTEXT_EAP_SIM;
577                break;
578
579            case APPTYPE_USIM:
580                authContext = AUTH_CONTEXT_EAP_AKA;
581                break;
582
583            default:
584                authContext = AUTH_CONTEXT_UNDEFINED;
585                break;
586        }
587
588        return authContext;
589    }
590
591    public PersoSubState getPersoSubState() {
592        synchronized (mLock) {
593            return mPersoSubState;
594        }
595    }
596
597    public String getAid() {
598        synchronized (mLock) {
599            return mAid;
600        }
601    }
602
603    public String getAppLabel() {
604        return mAppLabel;
605    }
606
607    public PinState getPin1State() {
608        synchronized (mLock) {
609            if (mPin1Replaced) {
610                return mUiccCard.getUniversalPinState();
611            }
612            return mPin1State;
613        }
614    }
615
616    public IccFileHandler getIccFileHandler() {
617        synchronized (mLock) {
618            return mIccFh;
619        }
620    }
621
622    public IccRecords getIccRecords() {
623        synchronized (mLock) {
624            return mIccRecords;
625        }
626    }
627
628    /**
629     * Supply the ICC PIN to the ICC
630     *
631     * When the operation is complete, onComplete will be sent to its
632     * Handler.
633     *
634     * onComplete.obj will be an AsyncResult
635     * onComplete.arg1 = remaining attempts before puk locked or -1 if unknown
636     *
637     * ((AsyncResult)onComplete.obj).exception == null on success
638     * ((AsyncResult)onComplete.obj).exception != null on fail
639     *
640     * If the supplied PIN is incorrect:
641     * ((AsyncResult)onComplete.obj).exception != null
642     * && ((AsyncResult)onComplete.obj).exception
643     *       instanceof com.android.internal.telephony.gsm.CommandException)
644     * && ((CommandException)(((AsyncResult)onComplete.obj).exception))
645     *          .getCommandError() == CommandException.Error.PASSWORD_INCORRECT
646     */
647    public void supplyPin (String pin, Message onComplete) {
648        synchronized (mLock) {
649            mCi.supplyIccPinForApp(pin, mAid, mHandler.obtainMessage(EVENT_PIN1_PUK1_DONE,
650                    onComplete));
651        }
652    }
653
654    /**
655     * Supply the ICC PUK to the ICC
656     *
657     * When the operation is complete, onComplete will be sent to its
658     * Handler.
659     *
660     * onComplete.obj will be an AsyncResult
661     * onComplete.arg1 = remaining attempts before Icc will be permanently unusable
662     * or -1 if unknown
663     *
664     * ((AsyncResult)onComplete.obj).exception == null on success
665     * ((AsyncResult)onComplete.obj).exception != null on fail
666     *
667     * If the supplied PIN is incorrect:
668     * ((AsyncResult)onComplete.obj).exception != null
669     * && ((AsyncResult)onComplete.obj).exception
670     *       instanceof com.android.internal.telephony.gsm.CommandException)
671     * && ((CommandException)(((AsyncResult)onComplete.obj).exception))
672     *          .getCommandError() == CommandException.Error.PASSWORD_INCORRECT
673     *
674     *
675     */
676    public void supplyPuk (String puk, String newPin, Message onComplete) {
677        synchronized (mLock) {
678        mCi.supplyIccPukForApp(puk, newPin, mAid,
679                mHandler.obtainMessage(EVENT_PIN1_PUK1_DONE, onComplete));
680        }
681    }
682
683    public void supplyPin2 (String pin2, Message onComplete) {
684        synchronized (mLock) {
685            mCi.supplyIccPin2ForApp(pin2, mAid,
686                    mHandler.obtainMessage(EVENT_PIN2_PUK2_DONE, onComplete));
687        }
688    }
689
690    public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
691        synchronized (mLock) {
692            mCi.supplyIccPuk2ForApp(puk2, newPin2, mAid,
693                    mHandler.obtainMessage(EVENT_PIN2_PUK2_DONE, onComplete));
694        }
695    }
696
697    public void supplyNetworkDepersonalization (String pin, Message onComplete) {
698        synchronized (mLock) {
699            if (DBG) log("supplyNetworkDepersonalization");
700            mCi.supplyNetworkDepersonalization(pin, onComplete);
701        }
702    }
703
704    /**
705     * Check whether ICC pin lock is enabled
706     * This is a sync call which returns the cached pin enabled state
707     *
708     * @return true for ICC locked enabled
709     *         false for ICC locked disabled
710     */
711    public boolean getIccLockEnabled() {
712        return mIccLockEnabled;
713        /* STOPSHIP: Remove line above and all code associated with setting
714           mIccLockEanbled once all RIL correctly sends the pin1 state.
715        // Use getPin1State to take into account pin1Replaced flag
716        PinState pinState = getPin1State();
717        return pinState == PinState.PINSTATE_ENABLED_NOT_VERIFIED ||
718               pinState == PinState.PINSTATE_ENABLED_VERIFIED ||
719               pinState == PinState.PINSTATE_ENABLED_BLOCKED ||
720               pinState == PinState.PINSTATE_ENABLED_PERM_BLOCKED;*/
721     }
722
723    /**
724     * Check whether ICC fdn (fixed dialing number) is enabled
725     * This is a sync call which returns the cached pin enabled state
726     *
727     * @return true for ICC fdn enabled
728     *         false for ICC fdn disabled
729     */
730    public boolean getIccFdnEnabled() {
731        synchronized (mLock) {
732            return mIccFdnEnabled;
733        }
734    }
735
736    /**
737     * Check whether fdn (fixed dialing number) service is available.
738     * @return true if ICC fdn service available
739     *         false if ICC fdn service not available
740     */
741    public boolean getIccFdnAvailable() {
742        return mIccFdnAvailable;
743    }
744
745    /**
746     * Set the ICC pin lock enabled or disabled
747     * When the operation is complete, onComplete will be sent to its handler
748     *
749     * @param enabled "true" for locked "false" for unlocked.
750     * @param password needed to change the ICC pin state, aka. Pin1
751     * @param onComplete
752     *        onComplete.obj will be an AsyncResult
753     *        ((AsyncResult)onComplete.obj).exception == null on success
754     *        ((AsyncResult)onComplete.obj).exception != null on fail
755     */
756    public void setIccLockEnabled (boolean enabled,
757            String password, Message onComplete) {
758        synchronized (mLock) {
759            int serviceClassX;
760            serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
761                    CommandsInterface.SERVICE_CLASS_DATA +
762                    CommandsInterface.SERVICE_CLASS_FAX;
763
764            mDesiredPinLocked = enabled;
765
766            mCi.setFacilityLockForApp(CommandsInterface.CB_FACILITY_BA_SIM,
767                    enabled, password, serviceClassX, mAid,
768                    mHandler.obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete));
769        }
770    }
771
772    /**
773     * Set the ICC fdn enabled or disabled
774     * When the operation is complete, onComplete will be sent to its handler
775     *
776     * @param enabled "true" for locked "false" for unlocked.
777     * @param password needed to change the ICC fdn enable, aka Pin2
778     * @param onComplete
779     *        onComplete.obj will be an AsyncResult
780     *        ((AsyncResult)onComplete.obj).exception == null on success
781     *        ((AsyncResult)onComplete.obj).exception != null on fail
782     */
783    public void setIccFdnEnabled (boolean enabled,
784            String password, Message onComplete) {
785        synchronized (mLock) {
786            int serviceClassX;
787            serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
788                    CommandsInterface.SERVICE_CLASS_DATA +
789                    CommandsInterface.SERVICE_CLASS_FAX +
790                    CommandsInterface.SERVICE_CLASS_SMS;
791
792            mDesiredFdnEnabled = enabled;
793
794            mCi.setFacilityLockForApp(CommandsInterface.CB_FACILITY_BA_FD,
795                    enabled, password, serviceClassX, mAid,
796                    mHandler.obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete));
797        }
798    }
799
800    /**
801     * Change the ICC password used in ICC pin lock
802     * When the operation is complete, onComplete will be sent to its handler
803     *
804     * @param oldPassword is the old password
805     * @param newPassword is the new password
806     * @param onComplete
807     *        onComplete.obj will be an AsyncResult
808     *        onComplete.arg1 = attempts remaining or -1 if unknown
809     *        ((AsyncResult)onComplete.obj).exception == null on success
810     *        ((AsyncResult)onComplete.obj).exception != null on fail
811     */
812    public void changeIccLockPassword(String oldPassword, String newPassword,
813            Message onComplete) {
814        synchronized (mLock) {
815            if (DBG) log("changeIccLockPassword");
816            mCi.changeIccPinForApp(oldPassword, newPassword, mAid,
817                    mHandler.obtainMessage(EVENT_CHANGE_PIN1_DONE, onComplete));
818        }
819    }
820
821    /**
822     * Change the ICC password used in ICC fdn enable
823     * When the operation is complete, onComplete will be sent to its handler
824     *
825     * @param oldPassword is the old password
826     * @param newPassword is the new password
827     * @param onComplete
828     *        onComplete.obj will be an AsyncResult
829     *        ((AsyncResult)onComplete.obj).exception == null on success
830     *        ((AsyncResult)onComplete.obj).exception != null on fail
831     */
832    public void changeIccFdnPassword(String oldPassword, String newPassword,
833            Message onComplete) {
834        synchronized (mLock) {
835            if (DBG) log("changeIccFdnPassword");
836            mCi.changeIccPin2ForApp(oldPassword, newPassword, mAid,
837                    mHandler.obtainMessage(EVENT_CHANGE_PIN2_DONE, onComplete));
838        }
839    }
840
841    /**
842     * @return true if ICC card is PIN2 blocked
843     */
844    public boolean getIccPin2Blocked() {
845        synchronized (mLock) {
846            return mPin2State == PinState.PINSTATE_ENABLED_BLOCKED;
847        }
848    }
849
850    /**
851     * @return true if ICC card is PUK2 blocked
852     */
853    public boolean getIccPuk2Blocked() {
854        synchronized (mLock) {
855            return mPin2State == PinState.PINSTATE_ENABLED_PERM_BLOCKED;
856        }
857    }
858
859    public int getPhoneId() {
860        return mUiccCard.getPhoneId();
861    }
862
863    protected UiccCard getUiccCard() {
864        return mUiccCard;
865    }
866
867    private void log(String msg) {
868        Rlog.d(LOG_TAG, msg);
869    }
870
871    private void loge(String msg) {
872        Rlog.e(LOG_TAG, msg);
873    }
874
875    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
876        pw.println("UiccCardApplication: " + this);
877        pw.println(" mUiccCard=" + mUiccCard);
878        pw.println(" mAppState=" + mAppState);
879        pw.println(" mAppType=" + mAppType);
880        pw.println(" mPersoSubState=" + mPersoSubState);
881        pw.println(" mAid=" + mAid);
882        pw.println(" mAppLabel=" + mAppLabel);
883        pw.println(" mPin1Replaced=" + mPin1Replaced);
884        pw.println(" mPin1State=" + mPin1State);
885        pw.println(" mPin2State=" + mPin2State);
886        pw.println(" mIccFdnEnabled=" + mIccFdnEnabled);
887        pw.println(" mDesiredFdnEnabled=" + mDesiredFdnEnabled);
888        pw.println(" mIccLockEnabled=" + mIccLockEnabled);
889        pw.println(" mDesiredPinLocked=" + mDesiredPinLocked);
890        pw.println(" mCi=" + mCi);
891        pw.println(" mIccRecords=" + mIccRecords);
892        pw.println(" mIccFh=" + mIccFh);
893        pw.println(" mDestroyed=" + mDestroyed);
894        pw.println(" mReadyRegistrants: size=" + mReadyRegistrants.size());
895        for (int i = 0; i < mReadyRegistrants.size(); i++) {
896            pw.println("  mReadyRegistrants[" + i + "]="
897                    + ((Registrant)mReadyRegistrants.get(i)).getHandler());
898        }
899        pw.println(" mPinLockedRegistrants: size=" + mPinLockedRegistrants.size());
900        for (int i = 0; i < mPinLockedRegistrants.size(); i++) {
901            pw.println("  mPinLockedRegistrants[" + i + "]="
902                    + ((Registrant)mPinLockedRegistrants.get(i)).getHandler());
903        }
904        pw.println(" mNetworkLockedRegistrants: size=" + mNetworkLockedRegistrants.size());
905        for (int i = 0; i < mNetworkLockedRegistrants.size(); i++) {
906            pw.println("  mNetworkLockedRegistrants[" + i + "]="
907                    + ((Registrant)mNetworkLockedRegistrants.get(i)).getHandler());
908        }
909        pw.flush();
910    }
911}
912