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 
17 package com.android.internal.telephony.uicc;
18 
19 import android.content.Context;
20 import android.os.AsyncResult;
21 import android.os.Handler;
22 import android.os.Message;
23 import android.os.Registrant;
24 import android.os.RegistrantList;
25 import android.telephony.Rlog;
26 
27 import com.android.internal.telephony.CommandsInterface;
28 import com.android.internal.telephony.PhoneConstants;
29 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
30 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
31 import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState;
32 import com.android.internal.telephony.uicc.IccCardStatus.PinState;
33 import com.android.internal.telephony.SubscriptionController;
34 
35 import java.io.FileDescriptor;
36 import java.io.PrintWriter;
37 
38 /**
39  * {@hide}
40  */
41 public 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 = 128;
59     public static final int AUTH_CONTEXT_EAP_AKA = 129;
60     public static final int AUTH_CONTEXT_UNDEFINED = -1;
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 
UiccCardApplication(UiccCard uiccCard, IccCardApplicationStatus as, Context c, CommandsInterface ci)90     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 
update(IccCardApplicationStatus as, Context c, CommandsInterface ci)118     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 
dispose()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 
createIccRecords(AppType type, Context c, CommandsInterface ci)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 
createIccFileHandler(AppType type)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. */
queryFdn()210     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      */
onQueryFdnEnabled(AsyncResult ar)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 
onChangeFdnDone(AsyncResult ar)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 */
queryPin1State()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*/
onQueryFacilityLock(AsyncResult ar)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 */
onChangeFacilityLock(AsyncResult ar)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      */
parsePinPukErrorResult(AsyncResult ar)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 
registerForReady(Handler h, int what, Object obj)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 
unregisterForReady(Handler h)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      */
registerForLocked(Handler h, int what, Object obj)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 
unregisterForLocked(Handler h)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      */
registerForNetworkLocked(Handler h, int what, Object obj)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 
unregisterForNetworkLocked(Handler h)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      */
notifyReadyRegistrantsIfNeeded(Registrant r)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      */
notifyPinLockedRegistrantsIfNeeded(Registrant r)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      */
notifyNetworkLockedRegistrantsIfNeeded(Registrant r)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 
getState()546     public AppState getState() {
547         synchronized (mLock) {
548             return mAppState;
549         }
550     }
551 
getType()552     public AppType getType() {
553         synchronized (mLock) {
554             return mAppType;
555         }
556     }
557 
getAuthContext()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      */
getAuthContext(AppType appType)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 
getPersoSubState()591     public PersoSubState getPersoSubState() {
592         synchronized (mLock) {
593             return mPersoSubState;
594         }
595     }
596 
getAid()597     public String getAid() {
598         synchronized (mLock) {
599             return mAid;
600         }
601     }
602 
getAppLabel()603     public String getAppLabel() {
604         return mAppLabel;
605     }
606 
getPin1State()607     public PinState getPin1State() {
608         synchronized (mLock) {
609             if (mPin1Replaced) {
610                 return mUiccCard.getUniversalPinState();
611             }
612             return mPin1State;
613         }
614     }
615 
getIccFileHandler()616     public IccFileHandler getIccFileHandler() {
617         synchronized (mLock) {
618             return mIccFh;
619         }
620     }
621 
getIccRecords()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      */
supplyPin(String pin, Message onComplete)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      */
supplyPuk(String puk, String newPin, Message onComplete)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 
supplyPin2(String pin2, Message onComplete)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 
supplyPuk2(String puk2, String newPin2, Message onComplete)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 
supplyNetworkDepersonalization(String pin, Message onComplete)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      */
getIccLockEnabled()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      */
getIccFdnEnabled()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      */
getIccFdnAvailable()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      */
setIccLockEnabled(boolean enabled, String password, Message onComplete)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      */
setIccFdnEnabled(boolean enabled, String password, Message onComplete)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      */
changeIccLockPassword(String oldPassword, String newPassword, Message onComplete)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      */
changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete)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      */
getIccPin2Blocked()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      */
getIccPuk2Blocked()853     public boolean getIccPuk2Blocked() {
854         synchronized (mLock) {
855             return mPin2State == PinState.PINSTATE_ENABLED_PERM_BLOCKED;
856         }
857     }
858 
getPhoneId()859     public int getPhoneId() {
860         return mUiccCard.getPhoneId();
861     }
862 
getUiccCard()863     protected UiccCard getUiccCard() {
864         return mUiccCard;
865     }
866 
log(String msg)867     private void log(String msg) {
868         Rlog.d(LOG_TAG, msg);
869     }
870 
loge(String msg)871     private void loge(String msg) {
872         Rlog.e(LOG_TAG, msg);
873     }
874 
dump(FileDescriptor fd, PrintWriter pw, String[] args)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