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;
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.util.Log;
26
27import com.android.internal.telephony.IccCardApplicationStatus.AppState;
28import com.android.internal.telephony.IccCardApplicationStatus.AppType;
29import com.android.internal.telephony.IccCardApplicationStatus.PersoSubState;
30import com.android.internal.telephony.IccCardStatus.PinState;
31import com.android.internal.telephony.cdma.RuimFileHandler;
32import com.android.internal.telephony.cdma.RuimRecords;
33import com.android.internal.telephony.gsm.SIMFileHandler;
34import com.android.internal.telephony.gsm.SIMRecords;
35import com.android.internal.telephony.ims.IsimFileHandler;
36import com.android.internal.telephony.ims.IsimUiccRecords;
37
38/**
39 * {@hide}
40 */
41public class UiccCardApplication {
42    private static final String LOG_TAG = "RIL_UiccCardApplication";
43    private static final boolean DBG = true;
44
45    private static final int EVENT_QUERY_FACILITY_FDN_DONE = 1;
46    private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 2;
47    private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 3;
48    private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 4;
49
50    private final Object  mLock = new Object();
51    private UiccCard      mUiccCard; //parent
52    private AppState      mAppState;
53    private AppType       mAppType;
54    private PersoSubState mPersoSubState;
55    private String        mAid;
56    private String        mAppLabel;
57    private boolean       mPin1Replaced;
58    private PinState      mPin1State;
59    private PinState      mPin2State;
60    private boolean       mIccFdnEnabled;
61    private boolean       mDesiredFdnEnabled;
62    private boolean       mIccLockEnabled;
63    private boolean       mDesiredPinLocked;
64
65    private CommandsInterface mCi;
66    private Context mContext;
67    private IccRecords mIccRecords;
68    private IccFileHandler mIccFh;
69
70    private boolean mDestroyed;//set to true once this App is commanded to be disposed of.
71
72    private RegistrantList mReadyRegistrants = new RegistrantList();
73    private RegistrantList mPinLockedRegistrants = new RegistrantList();
74    private RegistrantList mNetworkLockedRegistrants = new RegistrantList();
75
76    UiccCardApplication(UiccCard uiccCard,
77                        IccCardApplicationStatus as,
78                        Context c,
79                        CommandsInterface ci) {
80        if (DBG) log("Creating UiccApp: " + as);
81        mUiccCard = uiccCard;
82        mAppState = as.app_state;
83        mAppType = as.app_type;
84        mPersoSubState = as.perso_substate;
85        mAid = as.aid;
86        mAppLabel = as.app_label;
87        mPin1Replaced = (as.pin1_replaced != 0);
88        mPin1State = as.pin1;
89        mPin2State = as.pin2;
90
91        mContext = c;
92        mCi = ci;
93
94        mIccFh = createIccFileHandler(as.app_type);
95        mIccRecords = createIccRecords(as.app_type, mContext, mCi);
96        if (mAppState == AppState.APPSTATE_READY) {
97            queryFdn();
98            queryPin1State();
99        }
100    }
101
102    void update (IccCardApplicationStatus as, Context c, CommandsInterface ci) {
103        synchronized (mLock) {
104            if (mDestroyed) {
105                loge("Application updated after destroyed! Fix me!");
106                return;
107            }
108
109            if (DBG) log(mAppType + " update. New " + as);
110            mContext = c;
111            mCi = ci;
112            AppType oldAppType = mAppType;
113            AppState oldAppState = mAppState;
114            PersoSubState oldPersoSubState = mPersoSubState;
115            mAppType = as.app_type;
116            mAppState = as.app_state;
117            mPersoSubState = as.perso_substate;
118            mAid = as.aid;
119            mAppLabel = as.app_label;
120            mPin1Replaced = (as.pin1_replaced != 0);
121            mPin1State = as.pin1;
122            mPin2State = as.pin2;
123
124            if (mAppType != oldAppType) {
125                if (mIccFh != null) { mIccFh.dispose();}
126                if (mIccRecords != null) { mIccRecords.dispose();}
127                mIccFh = createIccFileHandler(as.app_type);
128                mIccRecords = createIccRecords(as.app_type, c, ci);
129            }
130
131            if (mPersoSubState != oldPersoSubState &&
132                    mPersoSubState == PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
133                notifyNetworkLockedRegistrantsIfNeeded(null);
134            }
135
136            if (mAppState != oldAppState) {
137                if (DBG) log(oldAppType + " changed state: " + oldAppState + " -> " + mAppState);
138                // If the app state turns to APPSTATE_READY, then query FDN status,
139                //as it might have failed in earlier attempt.
140                if (mAppState == AppState.APPSTATE_READY) {
141                    queryFdn();
142                    queryPin1State();
143                }
144                notifyPinLockedRegistrantsIfNeeded(null);
145                notifyReadyRegistrantsIfNeeded(null);
146            }
147        }
148    }
149
150    void dispose() {
151        synchronized (mLock) {
152            if (DBG) log(mAppType + " being Disposed");
153            mDestroyed = true;
154            if (mIccRecords != null) { mIccRecords.dispose();}
155            if (mIccFh != null) { mIccFh.dispose();}
156            mIccRecords = null;
157            mIccFh = null;
158        }
159    }
160
161    private IccRecords createIccRecords(AppType type, Context c, CommandsInterface ci) {
162        if (type == AppType.APPTYPE_USIM || type == AppType.APPTYPE_SIM) {
163            return new SIMRecords(this, c, ci);
164        } else if (type == AppType.APPTYPE_RUIM || type == AppType.APPTYPE_CSIM){
165            return new RuimRecords(this, c, ci);
166        } else if (type == AppType.APPTYPE_ISIM) {
167            return new IsimUiccRecords(this, c, ci);
168        } else {
169            // Unknown app type (maybe detection is still in progress)
170            return null;
171        }
172    }
173
174    private IccFileHandler createIccFileHandler(AppType type) {
175        switch (type) {
176            case APPTYPE_SIM:
177                return new SIMFileHandler(this, mAid, mCi);
178            case APPTYPE_RUIM:
179                return new RuimFileHandler(this, mAid, mCi);
180            case APPTYPE_USIM:
181                return new UsimFileHandler(this, mAid, mCi);
182            case APPTYPE_CSIM:
183                return new CsimFileHandler(this, mAid, mCi);
184            case APPTYPE_ISIM:
185                return new IsimFileHandler(this, mAid, mCi);
186            default:
187                return null;
188        }
189    }
190
191    /** Assumes mLock is held. */
192    private void queryFdn() {
193        //This shouldn't change run-time. So needs to be called only once.
194        int serviceClassX;
195
196        serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
197                        CommandsInterface.SERVICE_CLASS_DATA +
198                        CommandsInterface.SERVICE_CLASS_FAX;
199        mCi.queryFacilityLockForApp (
200                CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX,
201                mAid, mHandler.obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE));
202    }
203    /**
204     * Interpret EVENT_QUERY_FACILITY_LOCK_DONE
205     * @param ar is asyncResult of Query_Facility_Locked
206     */
207    private void onQueryFdnEnabled(AsyncResult ar) {
208        synchronized (mLock) {
209            if (ar.exception != null) {
210                if (DBG) log("Error in querying facility lock:" + ar.exception);
211                return;
212            }
213
214            int[] ints = (int[])ar.result;
215            if(ints.length != 0) {
216                mIccFdnEnabled = (0!=ints[0]);
217                if (DBG) log("Query facility lock : "  + mIccFdnEnabled);
218            } else {
219                loge("Bogus facility lock response");
220            }
221        }
222    }
223
224    private void onChangeFdnDone(AsyncResult ar) {
225        synchronized (mLock) {
226            if (ar.exception == null) {
227                mIccFdnEnabled = mDesiredFdnEnabled;
228                if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
229                        "mIccFdnEnabled=" + mIccFdnEnabled);
230            } else {
231                loge("Error change facility fdn with exception " + ar.exception);
232            }
233            Message response = (Message)ar.userObj;
234            AsyncResult.forMessage(response).exception = ar.exception;
235            response.sendToTarget();
236        }
237    }
238
239    /** REMOVE when mIccLockEnabled is not needed, assumes mLock is held */
240    private void queryPin1State() {
241        int serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
242                CommandsInterface.SERVICE_CLASS_DATA +
243                CommandsInterface.SERVICE_CLASS_FAX;
244        mCi.queryFacilityLockForApp (
245            CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
246            mAid, mHandler.obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
247    }
248
249    /** REMOVE when mIccLockEnabled is not needed*/
250    private void onQueryFacilityLock(AsyncResult ar) {
251        synchronized (mLock) {
252            if(ar.exception != null) {
253                if (DBG) log("Error in querying facility lock:" + ar.exception);
254                return;
255            }
256
257            int[] ints = (int[])ar.result;
258            if(ints.length != 0) {
259                if (DBG) log("Query facility lock : "  + ints[0]);
260
261                mIccLockEnabled = (ints[0] != 0);
262
263                if (mIccLockEnabled) {
264                    mPinLockedRegistrants.notifyRegistrants();
265                }
266
267                // Sanity check: we expect mPin1State to match mIccLockEnabled.
268                // When mPin1State is DISABLED mIccLockEanbled should be false.
269                // When mPin1State is ENABLED mIccLockEnabled should be true.
270                //
271                // Here we validate these assumptions to assist in identifying which ril/radio's
272                // have not correctly implemented GET_SIM_STATUS
273                switch (mPin1State) {
274                    case PINSTATE_DISABLED:
275                        if (mIccLockEnabled) {
276                            loge("QUERY_FACILITY_LOCK:enabled GET_SIM_STATUS.Pin1:disabled."
277                                    + " Fixme");
278                        }
279                        break;
280                    case PINSTATE_ENABLED_NOT_VERIFIED:
281                    case PINSTATE_ENABLED_VERIFIED:
282                    case PINSTATE_ENABLED_BLOCKED:
283                    case PINSTATE_ENABLED_PERM_BLOCKED:
284                        if (!mIccLockEnabled) {
285                            loge("QUERY_FACILITY_LOCK:disabled GET_SIM_STATUS.Pin1:enabled."
286                                    + " Fixme");
287                        }
288                }
289            } else {
290                loge("Bogus facility lock response");
291            }
292        }
293    }
294
295    /** REMOVE when mIccLockEnabled is not needed */
296    private void onChangeFacilityLock(AsyncResult ar) {
297        synchronized (mLock) {
298            if (ar.exception == null) {
299                mIccLockEnabled = mDesiredPinLocked;
300                if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: mIccLockEnabled= "
301                        + mIccLockEnabled);
302            } else {
303                loge("Error change facility lock with exception " + ar.exception);
304            }
305            AsyncResult.forMessage(((Message)ar.userObj)).exception = ar.exception;
306            ((Message)ar.userObj).sendToTarget();
307        }
308    }
309
310    private Handler mHandler = new Handler() {
311        @Override
312        public void handleMessage(Message msg){
313            AsyncResult ar;
314
315            if (mDestroyed) {
316                loge("Received message " + msg + "[" + msg.what
317                        + "] while being destroyed. Ignoring.");
318                return;
319            }
320
321            switch (msg.what) {
322                case EVENT_QUERY_FACILITY_FDN_DONE:
323                    ar = (AsyncResult)msg.obj;
324                    onQueryFdnEnabled(ar);
325                    break;
326                case EVENT_CHANGE_FACILITY_FDN_DONE:
327                    ar = (AsyncResult)msg.obj;
328                    onChangeFdnDone(ar);
329                    break;
330                case EVENT_QUERY_FACILITY_LOCK_DONE:
331                    ar = (AsyncResult)msg.obj;
332                    onQueryFacilityLock(ar);
333                    break;
334                case EVENT_CHANGE_FACILITY_LOCK_DONE:
335                    ar = (AsyncResult)msg.obj;
336                    onChangeFacilityLock(ar);
337                    break;
338                default:
339                    loge("Unknown Event " + msg.what);
340            }
341        }
342    };
343
344    public void registerForReady(Handler h, int what, Object obj) {
345        synchronized (mLock) {
346            Registrant r = new Registrant (h, what, obj);
347            mReadyRegistrants.add(r);
348            notifyReadyRegistrantsIfNeeded(r);
349        }
350    }
351
352    public void unregisterForReady(Handler h) {
353        synchronized (mLock) {
354            mReadyRegistrants.remove(h);
355        }
356    }
357
358    /**
359     * Notifies handler of any transition into State.isPinLocked()
360     */
361    public void registerForLocked(Handler h, int what, Object obj) {
362        synchronized (mLock) {
363            Registrant r = new Registrant (h, what, obj);
364            mPinLockedRegistrants.add(r);
365            notifyPinLockedRegistrantsIfNeeded(r);
366        }
367    }
368
369    public void unregisterForLocked(Handler h) {
370        synchronized (mLock) {
371            mPinLockedRegistrants.remove(h);
372        }
373    }
374
375    /**
376     * Notifies handler of any transition into State.NETWORK_LOCKED
377     */
378    public void registerForNetworkLocked(Handler h, int what, Object obj) {
379        synchronized (mLock) {
380            Registrant r = new Registrant (h, what, obj);
381            mNetworkLockedRegistrants.add(r);
382            notifyNetworkLockedRegistrantsIfNeeded(r);
383        }
384    }
385
386    public void unregisterForNetworkLocked(Handler h) {
387        synchronized (mLock) {
388            mNetworkLockedRegistrants.remove(h);
389        }
390    }
391
392    /**
393     * Notifies specified registrant, assume mLock is held.
394     *
395     * @param r Registrant to be notified. If null - all registrants will be notified
396     */
397    private void notifyReadyRegistrantsIfNeeded(Registrant r) {
398        if (mDestroyed) {
399            return;
400        }
401        if (mAppState == AppState.APPSTATE_READY) {
402            if (mPin1State == PinState.PINSTATE_ENABLED_NOT_VERIFIED ||
403                    mPin1State == PinState.PINSTATE_ENABLED_BLOCKED ||
404                    mPin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
405                loge("Sanity check failed! APPSTATE is ready while PIN1 is not verified!!!");
406                // Don't notify if application is in insane state
407                return;
408            }
409            if (r == null) {
410                if (DBG) log("Notifying registrants: READY");
411                mReadyRegistrants.notifyRegistrants();
412            } else {
413                if (DBG) log("Notifying 1 registrant: READY");
414                r.notifyRegistrant(new AsyncResult(null, null, null));
415            }
416        }
417    }
418
419    /**
420     * Notifies specified registrant, assume mLock is held.
421     *
422     * @param r Registrant to be notified. If null - all registrants will be notified
423     */
424    private void notifyPinLockedRegistrantsIfNeeded(Registrant r) {
425        if (mDestroyed) {
426            return;
427        }
428
429        if (mAppState == AppState.APPSTATE_PIN ||
430                mAppState == AppState.APPSTATE_PUK) {
431            if (mPin1State == PinState.PINSTATE_ENABLED_VERIFIED ||
432                    mPin1State == PinState.PINSTATE_DISABLED) {
433                loge("Sanity check failed! APPSTATE is locked while PIN1 is not!!!");
434                //Don't notify if application is in insane state
435                return;
436            }
437            if (r == null) {
438                if (DBG) log("Notifying registrants: LOCKED");
439                mPinLockedRegistrants.notifyRegistrants();
440            } else {
441                if (DBG) log("Notifying 1 registrant: LOCKED");
442                r.notifyRegistrant(new AsyncResult(null, null, null));
443            }
444        }
445    }
446
447    /**
448     * Notifies specified registrant, assume mLock is held.
449     *
450     * @param r Registrant to be notified. If null - all registrants will be notified
451     */
452    private void notifyNetworkLockedRegistrantsIfNeeded(Registrant r) {
453        if (mDestroyed) {
454            return;
455        }
456
457        if (mAppState == AppState.APPSTATE_SUBSCRIPTION_PERSO &&
458                mPersoSubState == PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
459            if (r == null) {
460                if (DBG) log("Notifying registrants: NETWORK_LOCKED");
461                mNetworkLockedRegistrants.notifyRegistrants();
462            } else {
463                if (DBG) log("Notifying 1 registrant: NETWORK_LOCED");
464                r.notifyRegistrant(new AsyncResult(null, null, null));
465            }
466        }
467    }
468
469    public AppState getState() {
470        synchronized (mLock) {
471            return mAppState;
472        }
473    }
474
475    public AppType getType() {
476        synchronized (mLock) {
477            return mAppType;
478        }
479    }
480
481    public PersoSubState getPersoSubState() {
482        synchronized (mLock) {
483            return mPersoSubState;
484        }
485    }
486
487    public String getAid() {
488        synchronized (mLock) {
489            return mAid;
490        }
491    }
492
493    public PinState getPin1State() {
494        synchronized (mLock) {
495            if (mPin1Replaced) {
496                return mUiccCard.getUniversalPinState();
497            }
498            return mPin1State;
499        }
500    }
501
502    public IccFileHandler getIccFileHandler() {
503        synchronized (mLock) {
504            return mIccFh;
505        }
506    }
507
508    public IccRecords getIccRecords() {
509        synchronized (mLock) {
510            return mIccRecords;
511        }
512    }
513
514    /**
515     * Supply the ICC PIN to the ICC
516     *
517     * When the operation is complete, onComplete will be sent to its
518     * Handler.
519     *
520     * onComplete.obj will be an AsyncResult
521     *
522     * ((AsyncResult)onComplete.obj).exception == null on success
523     * ((AsyncResult)onComplete.obj).exception != null on fail
524     *
525     * If the supplied PIN is incorrect:
526     * ((AsyncResult)onComplete.obj).exception != null
527     * && ((AsyncResult)onComplete.obj).exception
528     *       instanceof com.android.internal.telephony.gsm.CommandException)
529     * && ((CommandException)(((AsyncResult)onComplete.obj).exception))
530     *          .getCommandError() == CommandException.Error.PASSWORD_INCORRECT
531     *
532     *
533     */
534    public void supplyPin (String pin, Message onComplete) {
535        synchronized (mLock) {
536            mCi.supplyIccPin(pin, onComplete);
537        }
538    }
539
540    public void supplyPuk (String puk, String newPin, Message onComplete) {
541        synchronized (mLock) {
542            mCi.supplyIccPuk(puk, newPin, onComplete);
543        }
544    }
545
546    public void supplyPin2 (String pin2, Message onComplete) {
547        synchronized (mLock) {
548            mCi.supplyIccPin2(pin2, onComplete);
549        }
550    }
551
552    public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
553        synchronized (mLock) {
554            mCi.supplyIccPuk2(puk2, newPin2, onComplete);
555        }
556    }
557
558    public void supplyNetworkDepersonalization (String pin, Message onComplete) {
559        synchronized (mLock) {
560            if (DBG) log("supplyNetworkDepersonalization");
561            mCi.supplyNetworkDepersonalization(pin, onComplete);
562        }
563    }
564
565    /**
566     * Check whether ICC pin lock is enabled
567     * This is a sync call which returns the cached pin enabled state
568     *
569     * @return true for ICC locked enabled
570     *         false for ICC locked disabled
571     */
572    public boolean getIccLockEnabled() {
573        return mIccLockEnabled;
574        /* STOPSHIP: Remove line above and all code associated with setting
575           mIccLockEanbled once all RIL correctly sends the pin1 state.
576        // Use getPin1State to take into account pin1Replaced flag
577        PinState pinState = getPin1State();
578        return pinState == PinState.PINSTATE_ENABLED_NOT_VERIFIED ||
579               pinState == PinState.PINSTATE_ENABLED_VERIFIED ||
580               pinState == PinState.PINSTATE_ENABLED_BLOCKED ||
581               pinState == PinState.PINSTATE_ENABLED_PERM_BLOCKED;*/
582     }
583
584    /**
585     * Check whether ICC fdn (fixed dialing number) is enabled
586     * This is a sync call which returns the cached pin enabled state
587     *
588     * @return true for ICC fdn enabled
589     *         false for ICC fdn disabled
590     */
591    public boolean getIccFdnEnabled() {
592        synchronized (mLock) {
593            return mIccFdnEnabled;
594        }
595    }
596
597    /**
598     * Set the ICC pin lock enabled or disabled
599     * When the operation is complete, onComplete will be sent to its handler
600     *
601     * @param enabled "true" for locked "false" for unlocked.
602     * @param password needed to change the ICC pin state, aka. Pin1
603     * @param onComplete
604     *        onComplete.obj will be an AsyncResult
605     *        ((AsyncResult)onComplete.obj).exception == null on success
606     *        ((AsyncResult)onComplete.obj).exception != null on fail
607     */
608    public void setIccLockEnabled (boolean enabled,
609            String password, Message onComplete) {
610        synchronized (mLock) {
611            int serviceClassX;
612            serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
613                    CommandsInterface.SERVICE_CLASS_DATA +
614                    CommandsInterface.SERVICE_CLASS_FAX;
615
616            mDesiredPinLocked = enabled;
617
618            mCi.setFacilityLockForApp(CommandsInterface.CB_FACILITY_BA_SIM,
619                    enabled, password, serviceClassX, mAid,
620                    mHandler.obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete));
621        }
622    }
623
624    /**
625     * Set the ICC fdn enabled or disabled
626     * When the operation is complete, onComplete will be sent to its handler
627     *
628     * @param enabled "true" for locked "false" for unlocked.
629     * @param password needed to change the ICC fdn enable, aka Pin2
630     * @param onComplete
631     *        onComplete.obj will be an AsyncResult
632     *        ((AsyncResult)onComplete.obj).exception == null on success
633     *        ((AsyncResult)onComplete.obj).exception != null on fail
634     */
635    public void setIccFdnEnabled (boolean enabled,
636            String password, Message onComplete) {
637        synchronized (mLock) {
638            int serviceClassX;
639            serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
640                    CommandsInterface.SERVICE_CLASS_DATA +
641                    CommandsInterface.SERVICE_CLASS_FAX +
642                    CommandsInterface.SERVICE_CLASS_SMS;
643
644            mDesiredFdnEnabled = enabled;
645
646            mCi.setFacilityLockForApp(CommandsInterface.CB_FACILITY_BA_FD,
647                    enabled, password, serviceClassX, mAid,
648                    mHandler.obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete));
649        }
650    }
651
652    /**
653     * Change the ICC password used in ICC pin lock
654     * When the operation is complete, onComplete will be sent to its handler
655     *
656     * @param oldPassword is the old password
657     * @param newPassword is the new password
658     * @param onComplete
659     *        onComplete.obj will be an AsyncResult
660     *        ((AsyncResult)onComplete.obj).exception == null on success
661     *        ((AsyncResult)onComplete.obj).exception != null on fail
662     */
663    public void changeIccLockPassword(String oldPassword, String newPassword,
664            Message onComplete) {
665        synchronized (mLock) {
666            if (DBG) log("changeIccLockPassword");
667            mCi.changeIccPinForApp(oldPassword, newPassword, mAid,
668                    onComplete);
669        }
670    }
671
672    /**
673     * Change the ICC password used in ICC fdn enable
674     * When the operation is complete, onComplete will be sent to its handler
675     *
676     * @param oldPassword is the old password
677     * @param newPassword is the new password
678     * @param onComplete
679     *        onComplete.obj will be an AsyncResult
680     *        ((AsyncResult)onComplete.obj).exception == null on success
681     *        ((AsyncResult)onComplete.obj).exception != null on fail
682     */
683    public void changeIccFdnPassword(String oldPassword, String newPassword,
684            Message onComplete) {
685        synchronized (mLock) {
686            if (DBG) log("changeIccFdnPassword");
687            mCi.changeIccPin2ForApp(oldPassword, newPassword, mAid,
688                    onComplete);
689        }
690    }
691
692    private void log(String msg) {
693        Log.d(LOG_TAG, msg);
694    }
695
696    private void loge(String msg) {
697        Log.e(LOG_TAG, msg);
698    }
699}
700