UiccCardApplication.java revision 309d5afed9da8bb06de355561287dbb6b4274031
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;
33
34import java.io.FileDescriptor;
35import java.io.PrintWriter;
36
37/**
38 * {@hide}
39 */
40public class UiccCardApplication {
41    private static final String LOG_TAG = "UiccCardApplication";
42    private static final boolean DBG = true;
43
44    private static final int EVENT_PIN1_PUK1_DONE = 1;
45    private static final int EVENT_CHANGE_PIN1_DONE = 2;
46    private static final int EVENT_CHANGE_PIN2_DONE = 3;
47    private static final int EVENT_QUERY_FACILITY_FDN_DONE = 4;
48    private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 5;
49    private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 6;
50    private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 7;
51    private static final int EVENT_PIN2_PUK2_DONE = 8;
52    private static final int EVENT_RADIO_UNAVAILABLE = 9;
53
54    /**
55     * These values are for authContext (parameter P2) per 3GPP TS 31.102 (Section 7.1.2)
56     */
57    public static final int AUTH_CONTEXT_EAP_SIM = PhoneConstants.AUTH_CONTEXT_EAP_SIM;
58    public static final int AUTH_CONTEXT_EAP_AKA = PhoneConstants.AUTH_CONTEXT_EAP_AKA;
59    public static final int AUTH_CONTEXT_UNDEFINED = PhoneConstants.AUTH_CONTEXT_UNDEFINED;
60
61    private final Object  mLock = new Object();
62    private UiccProfile   mUiccProfile; //parent
63    private AppState      mAppState;
64    private AppType       mAppType;
65    private int           mAuthContext;
66    private PersoSubState mPersoSubState;
67    private String        mAid;
68    private String        mAppLabel;
69    private boolean       mPin1Replaced;
70    private PinState      mPin1State;
71    private PinState      mPin2State;
72    private boolean       mIccFdnEnabled;
73    private boolean       mDesiredFdnEnabled;
74    private boolean       mIccLockEnabled;
75    private boolean       mDesiredPinLocked;
76
77    // App state will be ignored while deciding whether the card is ready or not.
78    private boolean       mIgnoreApp;
79    private boolean       mIccFdnAvailable = true; // Default is enabled.
80
81    private CommandsInterface mCi;
82    private Context mContext;
83    private IccRecords mIccRecords;
84    private IccFileHandler mIccFh;
85
86    private boolean mDestroyed;//set to true once this App is commanded to be disposed of.
87
88    private RegistrantList mReadyRegistrants = new RegistrantList();
89    private RegistrantList mPinLockedRegistrants = new RegistrantList();
90    private RegistrantList mNetworkLockedRegistrants = new RegistrantList();
91
92    public UiccCardApplication(UiccProfile uiccProfile,
93                        IccCardApplicationStatus as,
94                        Context c,
95                        CommandsInterface ci) {
96        if (DBG) log("Creating UiccApp: " + as);
97        mUiccProfile = uiccProfile;
98        mAppState = as.app_state;
99        mAppType = as.app_type;
100        mAuthContext = getAuthContext(mAppType);
101        mPersoSubState = as.perso_substate;
102        mAid = as.aid;
103        mAppLabel = as.app_label;
104        mPin1Replaced = (as.pin1_replaced != 0);
105        mPin1State = as.pin1;
106        mPin2State = as.pin2;
107        mIgnoreApp = false;
108
109        mContext = c;
110        mCi = ci;
111
112        mIccFh = createIccFileHandler(as.app_type);
113        mIccRecords = createIccRecords(as.app_type, mContext, mCi);
114        if (mAppState == AppState.APPSTATE_READY) {
115            queryFdn();
116            queryPin1State();
117        }
118        mCi.registerForNotAvailable(mHandler, EVENT_RADIO_UNAVAILABLE, null);
119    }
120
121    public void update (IccCardApplicationStatus as, Context c, CommandsInterface ci) {
122        synchronized (mLock) {
123            if (mDestroyed) {
124                loge("Application updated after destroyed! Fix me!");
125                return;
126            }
127
128            if (DBG) log(mAppType + " update. New " + as);
129            mContext = c;
130            mCi = ci;
131            AppType oldAppType = mAppType;
132            AppState oldAppState = mAppState;
133            PersoSubState oldPersoSubState = mPersoSubState;
134            mAppType = as.app_type;
135            mAuthContext = getAuthContext(mAppType);
136            mAppState = as.app_state;
137            mPersoSubState = as.perso_substate;
138            mAid = as.aid;
139            mAppLabel = as.app_label;
140            mPin1Replaced = (as.pin1_replaced != 0);
141            mPin1State = as.pin1;
142            mPin2State = as.pin2;
143
144            if (mAppType != oldAppType) {
145                if (mIccFh != null) { mIccFh.dispose();}
146                if (mIccRecords != null) { mIccRecords.dispose();}
147                mIccFh = createIccFileHandler(as.app_type);
148                mIccRecords = createIccRecords(as.app_type, c, ci);
149            }
150
151            if (mPersoSubState != oldPersoSubState &&
152                    mPersoSubState == PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
153                notifyNetworkLockedRegistrantsIfNeeded(null);
154            }
155
156            if (mAppState != oldAppState) {
157                if (DBG) log(oldAppType + " changed state: " + oldAppState + " -> " + mAppState);
158                // If the app state turns to APPSTATE_READY, then query FDN status,
159                //as it might have failed in earlier attempt.
160                if (mAppState == AppState.APPSTATE_READY) {
161                    queryFdn();
162                    queryPin1State();
163                }
164                notifyPinLockedRegistrantsIfNeeded(null);
165                notifyReadyRegistrantsIfNeeded(null);
166            }
167        }
168    }
169
170    void dispose() {
171        synchronized (mLock) {
172            if (DBG) log(mAppType + " being Disposed");
173            mDestroyed = true;
174            if (mIccRecords != null) { mIccRecords.dispose();}
175            if (mIccFh != null) { mIccFh.dispose();}
176            mIccRecords = null;
177            mIccFh = null;
178            mCi.unregisterForNotAvailable(mHandler);
179        }
180    }
181
182    private IccRecords createIccRecords(AppType type, Context c, CommandsInterface ci) {
183        if (type == AppType.APPTYPE_USIM || type == AppType.APPTYPE_SIM) {
184            return new SIMRecords(this, c, ci);
185        } else if (type == AppType.APPTYPE_RUIM || type == AppType.APPTYPE_CSIM){
186            return new RuimRecords(this, c, ci);
187        } else if (type == AppType.APPTYPE_ISIM) {
188            return new IsimUiccRecords(this, c, ci);
189        } else {
190            // Unknown app type (maybe detection is still in progress)
191            return null;
192        }
193    }
194
195    private IccFileHandler createIccFileHandler(AppType type) {
196        switch (type) {
197            case APPTYPE_SIM:
198                return new SIMFileHandler(this, mAid, mCi);
199            case APPTYPE_RUIM:
200                return new RuimFileHandler(this, mAid, mCi);
201            case APPTYPE_USIM:
202                return new UsimFileHandler(this, mAid, mCi);
203            case APPTYPE_CSIM:
204                return new CsimFileHandler(this, mAid, mCi);
205            case APPTYPE_ISIM:
206                return new IsimFileHandler(this, mAid, mCi);
207            default:
208                return null;
209        }
210    }
211
212    /** Assumes mLock is held. */
213    public void queryFdn() {
214        //This shouldn't change run-time. So needs to be called only once.
215        int serviceClassX;
216
217        serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
218                        CommandsInterface.SERVICE_CLASS_DATA +
219                        CommandsInterface.SERVICE_CLASS_FAX;
220        mCi.queryFacilityLockForApp (
221                CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX,
222                mAid, mHandler.obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE));
223    }
224    /**
225     * Interpret EVENT_QUERY_FACILITY_LOCK_DONE
226     * @param ar is asyncResult of Query_Facility_Locked
227     */
228    private void onQueryFdnEnabled(AsyncResult ar) {
229        synchronized (mLock) {
230            if (ar.exception != null) {
231                if (DBG) log("Error in querying facility lock:" + ar.exception);
232                return;
233            }
234
235            int[] result = (int[])ar.result;
236            if(result.length != 0) {
237                //0 - Available & Disabled, 1-Available & Enabled, 2-Unavailable.
238                if (result[0] == 2) {
239                    mIccFdnEnabled = false;
240                    mIccFdnAvailable = false;
241                } else {
242                    mIccFdnEnabled = (result[0] == 1) ? true : false;
243                    mIccFdnAvailable = true;
244                }
245                log("Query facility FDN : FDN service available: "+ mIccFdnAvailable
246                        +" enabled: "  + mIccFdnEnabled);
247            } else {
248                loge("Bogus facility lock response");
249            }
250        }
251    }
252
253    private void onChangeFdnDone(AsyncResult ar) {
254        synchronized (mLock) {
255            int attemptsRemaining = -1;
256
257            if (ar.exception == null) {
258                mIccFdnEnabled = mDesiredFdnEnabled;
259                if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
260                        "mIccFdnEnabled=" + mIccFdnEnabled);
261            } else {
262                attemptsRemaining = parsePinPukErrorResult(ar);
263                loge("Error change facility fdn with exception " + ar.exception);
264            }
265            Message response = (Message)ar.userObj;
266            response.arg1 = attemptsRemaining;
267            AsyncResult.forMessage(response).exception = ar.exception;
268            response.sendToTarget();
269        }
270    }
271
272    /** REMOVE when mIccLockEnabled is not needed, assumes mLock is held */
273    private void queryPin1State() {
274        int serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
275                CommandsInterface.SERVICE_CLASS_DATA +
276                CommandsInterface.SERVICE_CLASS_FAX;
277        mCi.queryFacilityLockForApp (
278            CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
279            mAid, mHandler.obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
280    }
281
282    /** REMOVE when mIccLockEnabled is not needed*/
283    private void onQueryFacilityLock(AsyncResult ar) {
284        synchronized (mLock) {
285            if(ar.exception != null) {
286                if (DBG) log("Error in querying facility lock:" + ar.exception);
287                return;
288            }
289
290            int[] ints = (int[])ar.result;
291            if(ints.length != 0) {
292                if (DBG) log("Query facility lock : "  + ints[0]);
293
294                mIccLockEnabled = (ints[0] != 0);
295
296                if (mIccLockEnabled) {
297                    mPinLockedRegistrants.notifyRegistrants();
298                }
299
300                // Sanity check: we expect mPin1State to match mIccLockEnabled.
301                // When mPin1State is DISABLED mIccLockEanbled should be false.
302                // When mPin1State is ENABLED mIccLockEnabled should be true.
303                //
304                // Here we validate these assumptions to assist in identifying which ril/radio's
305                // have not correctly implemented GET_SIM_STATUS
306                switch (mPin1State) {
307                    case PINSTATE_DISABLED:
308                        if (mIccLockEnabled) {
309                            loge("QUERY_FACILITY_LOCK:enabled GET_SIM_STATUS.Pin1:disabled."
310                                    + " Fixme");
311                        }
312                        break;
313                    case PINSTATE_ENABLED_NOT_VERIFIED:
314                    case PINSTATE_ENABLED_VERIFIED:
315                    case PINSTATE_ENABLED_BLOCKED:
316                    case PINSTATE_ENABLED_PERM_BLOCKED:
317                        if (!mIccLockEnabled) {
318                            loge("QUERY_FACILITY_LOCK:disabled GET_SIM_STATUS.Pin1:enabled."
319                                    + " Fixme");
320                        }
321                    case PINSTATE_UNKNOWN:
322                    default:
323                        if (DBG) log("Ignoring: pin1state=" + mPin1State);
324                        break;
325                }
326            } else {
327                loge("Bogus facility lock response");
328            }
329        }
330    }
331
332    /** REMOVE when mIccLockEnabled is not needed */
333    private void onChangeFacilityLock(AsyncResult ar) {
334        synchronized (mLock) {
335            int attemptsRemaining = -1;
336
337            if (ar.exception == null) {
338                mIccLockEnabled = mDesiredPinLocked;
339                if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: mIccLockEnabled= "
340                        + mIccLockEnabled);
341            } else {
342                attemptsRemaining = parsePinPukErrorResult(ar);
343                loge("Error change facility lock with exception " + ar.exception);
344            }
345            Message response = (Message)ar.userObj;
346            AsyncResult.forMessage(response).exception = ar.exception;
347            response.arg1 = attemptsRemaining;
348            response.sendToTarget();
349        }
350    }
351
352    /**
353     * Parse the error response to obtain number of attempts remaining
354     */
355    private int parsePinPukErrorResult(AsyncResult ar) {
356        int[] result = (int[]) ar.result;
357        if (result == null) {
358            return -1;
359        } else {
360            int length = result.length;
361            int attemptsRemaining = -1;
362            if (length > 0) {
363                attemptsRemaining = result[0];
364            }
365            log("parsePinPukErrorResult: attemptsRemaining=" + attemptsRemaining);
366            return attemptsRemaining;
367        }
368    }
369
370    private Handler mHandler = new Handler() {
371        @Override
372        public void handleMessage(Message msg){
373            AsyncResult ar;
374
375            if (mDestroyed) {
376                loge("Received message " + msg + "[" + msg.what
377                        + "] while being destroyed. Ignoring.");
378                return;
379            }
380
381            switch (msg.what) {
382                case EVENT_PIN1_PUK1_DONE:
383                case EVENT_PIN2_PUK2_DONE:
384                case EVENT_CHANGE_PIN1_DONE:
385                case EVENT_CHANGE_PIN2_DONE:
386                    // a PIN/PUK/PIN2/PUK2 complete
387                    // request has completed. ar.userObj is the response Message
388                    ar = (AsyncResult)msg.obj;
389                    int attemptsRemaining = parsePinPukErrorResult(ar);
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    protected 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    protected 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    protected 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    protected 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 mUiccProfile.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 the UiccCardApplication is ready.
843     */
844    public boolean isReady() {
845        synchronized (mLock) {
846            if (mAppState != AppState.APPSTATE_READY) {
847                return false;
848            } else if (mPin1State == PinState.PINSTATE_ENABLED_NOT_VERIFIED
849                    || mPin1State == PinState.PINSTATE_ENABLED_BLOCKED
850                    || mPin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
851                loge("Sanity check failed! APPSTATE is ready while PIN1 is not verified!!!");
852                return false;
853            } else {
854                return true;
855            }
856        }
857    }
858
859    /**
860     * @return true if ICC card is PIN2 blocked
861     */
862    public boolean getIccPin2Blocked() {
863        synchronized (mLock) {
864            return mPin2State == PinState.PINSTATE_ENABLED_BLOCKED;
865        }
866    }
867
868    /**
869     * @return true if ICC card is PUK2 blocked
870     */
871    public boolean getIccPuk2Blocked() {
872        synchronized (mLock) {
873            return mPin2State == PinState.PINSTATE_ENABLED_PERM_BLOCKED;
874        }
875    }
876
877    public int getPhoneId() {
878        return mUiccProfile.getPhoneId();
879    }
880
881    public boolean isAppIgnored() {
882        return mIgnoreApp;
883    }
884
885    public void setAppIgnoreState(boolean ignore) {
886        mIgnoreApp = ignore;
887    }
888
889    protected UiccProfile getUiccProfile() {
890        return mUiccProfile;
891    }
892
893    private void log(String msg) {
894        Rlog.d(LOG_TAG, msg);
895    }
896
897    private void loge(String msg) {
898        Rlog.e(LOG_TAG, msg);
899    }
900
901    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
902        pw.println("UiccCardApplication: " + this);
903        pw.println(" mUiccProfile=" + mUiccProfile);
904        pw.println(" mAppState=" + mAppState);
905        pw.println(" mAppType=" + mAppType);
906        pw.println(" mPersoSubState=" + mPersoSubState);
907        pw.println(" mAid=" + mAid);
908        pw.println(" mAppLabel=" + mAppLabel);
909        pw.println(" mPin1Replaced=" + mPin1Replaced);
910        pw.println(" mPin1State=" + mPin1State);
911        pw.println(" mPin2State=" + mPin2State);
912        pw.println(" mIccFdnEnabled=" + mIccFdnEnabled);
913        pw.println(" mDesiredFdnEnabled=" + mDesiredFdnEnabled);
914        pw.println(" mIccLockEnabled=" + mIccLockEnabled);
915        pw.println(" mDesiredPinLocked=" + mDesiredPinLocked);
916        pw.println(" mCi=" + mCi);
917        pw.println(" mIccRecords=" + mIccRecords);
918        pw.println(" mIccFh=" + mIccFh);
919        pw.println(" mDestroyed=" + mDestroyed);
920        pw.println(" mReadyRegistrants: size=" + mReadyRegistrants.size());
921        for (int i = 0; i < mReadyRegistrants.size(); i++) {
922            pw.println("  mReadyRegistrants[" + i + "]="
923                    + ((Registrant)mReadyRegistrants.get(i)).getHandler());
924        }
925        pw.println(" mPinLockedRegistrants: size=" + mPinLockedRegistrants.size());
926        for (int i = 0; i < mPinLockedRegistrants.size(); i++) {
927            pw.println("  mPinLockedRegistrants[" + i + "]="
928                    + ((Registrant)mPinLockedRegistrants.get(i)).getHandler());
929        }
930        pw.println(" mNetworkLockedRegistrants: size=" + mNetworkLockedRegistrants.size());
931        for (int i = 0; i < mNetworkLockedRegistrants.size(); i++) {
932            pw.println("  mNetworkLockedRegistrants[" + i + "]="
933                    + ((Registrant)mNetworkLockedRegistrants.get(i)).getHandler());
934        }
935        pw.flush();
936    }
937}
938