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 
34 import java.io.FileDescriptor;
35 import java.io.PrintWriter;
36 
37 /**
38  * {@hide}
39  */
40 public 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 
UiccCardApplication(UiccProfile uiccProfile, IccCardApplicationStatus as, Context c, CommandsInterface ci)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 
update(IccCardApplicationStatus as, Context c, CommandsInterface ci)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 
dispose()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 
createIccRecords(AppType type, Context c, CommandsInterface ci)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 
createIccFileHandler(AppType type)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. */
queryFdn()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      */
onQueryFdnEnabled(AsyncResult ar)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 
onChangeFdnDone(AsyncResult ar)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 */
queryPin1State()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*/
onQueryFacilityLock(AsyncResult ar)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 */
onChangeFacilityLock(AsyncResult ar)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      */
parsePinPukErrorResult(AsyncResult ar)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 
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     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 
unregisterForLocked(Handler h)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      */
registerForNetworkLocked(Handler h, int what, Object obj)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 
unregisterForNetworkLocked(Handler h)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      */
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 mUiccProfile.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 the UiccCardApplication is ready.
843      */
isReady()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      */
getIccPin2Blocked()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      */
getIccPuk2Blocked()871     public boolean getIccPuk2Blocked() {
872         synchronized (mLock) {
873             return mPin2State == PinState.PINSTATE_ENABLED_PERM_BLOCKED;
874         }
875     }
876 
getPhoneId()877     public int getPhoneId() {
878         return mUiccProfile.getPhoneId();
879     }
880 
isAppIgnored()881     public boolean isAppIgnored() {
882         return mIgnoreApp;
883     }
884 
setAppIgnoreState(boolean ignore)885     public void setAppIgnoreState(boolean ignore) {
886         mIgnoreApp = ignore;
887     }
888 
getUiccProfile()889     protected UiccProfile getUiccProfile() {
890         return mUiccProfile;
891     }
892 
log(String msg)893     private void log(String msg) {
894         Rlog.d(LOG_TAG, msg);
895     }
896 
loge(String msg)897     private void loge(String msg) {
898         Rlog.e(LOG_TAG, msg);
899     }
900 
dump(FileDescriptor fd, PrintWriter pw, String[] args)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