1 /*
2  * Copyright (C) 2006 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 import android.telephony.SubscriptionInfo;
27 import android.telephony.TelephonyManager;
28 
29 import com.android.internal.telephony.CommandsInterface;
30 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
31 
32 import java.io.FileDescriptor;
33 import java.io.PrintWriter;
34 import java.io.UnsupportedEncodingException;
35 import java.util.Arrays;
36 import java.util.HashMap;
37 import java.util.concurrent.atomic.AtomicBoolean;
38 import java.util.concurrent.atomic.AtomicInteger;
39 
40 /**
41  * {@hide}
42  */
43 public abstract class IccRecords extends Handler implements IccConstants {
44     protected static final boolean DBG = true;
45     protected static final boolean VDBG = false; // STOPSHIP if true
46 
47     // ***** Instance Variables
48     protected AtomicBoolean mDestroyed = new AtomicBoolean(false);
49     protected Context mContext;
50     protected CommandsInterface mCi;
51     protected IccFileHandler mFh;
52     protected UiccCardApplication mParentApp;
53     protected TelephonyManager mTelephonyManager;
54 
55     protected RegistrantList mRecordsLoadedRegistrants = new RegistrantList();
56     protected RegistrantList mImsiReadyRegistrants = new RegistrantList();
57     protected RegistrantList mRecordsEventsRegistrants = new RegistrantList();
58     protected RegistrantList mNewSmsRegistrants = new RegistrantList();
59     protected RegistrantList mNetworkSelectionModeAutomaticRegistrants = new RegistrantList();
60 
61     protected int mRecordsToLoad;  // number of pending load requests
62 
63     protected AdnRecordCache mAdnCache;
64 
65     // ***** Cached SIM State; cleared on channel close
66 
67     protected boolean mRecordsRequested = false; // true if we've made requests for the sim records
68 
69     protected String mIccId;  // Includes only decimals (no hex)
70     protected String mFullIccId;  // Includes hex characters in ICCID
71     protected String mMsisdn = null;  // My mobile number
72     protected String mMsisdnTag = null;
73     protected String mNewMsisdn = null;
74     protected String mNewMsisdnTag = null;
75     protected String mVoiceMailNum = null;
76     protected String mVoiceMailTag = null;
77     protected String mNewVoiceMailNum = null;
78     protected String mNewVoiceMailTag = null;
79     protected boolean mIsVoiceMailFixed = false;
80     protected String mImsi;
81     private IccIoResult auth_rsp;
82 
83     protected int mMncLength = UNINITIALIZED;
84     protected int mMailboxIndex = 0; // 0 is no mailbox dailing number associated
85 
86     private String mSpn;
87 
88     protected String mGid1;
89     protected String mGid2;
90     protected String mPrefLang;
91 
92     protected PlmnActRecord[] mHplmnActRecords;
93     protected PlmnActRecord[] mOplmnActRecords;
94     protected PlmnActRecord[] mPlmnActRecords;
95 
96     protected String[] mEhplmns;
97     protected String[] mFplmns;
98 
99     private final Object mLock = new Object();
100 
101     //Arbitrary offset for the Handler
102     protected static final int HANDLER_ACTION_BASE = 0x12E500;
103     protected static final int HANDLER_ACTION_NONE = HANDLER_ACTION_BASE + 0;
104     protected static final int HANDLER_ACTION_SEND_RESPONSE = HANDLER_ACTION_BASE + 1;
105     protected static AtomicInteger sNextRequestId = new AtomicInteger(1);
106     protected final HashMap<Integer, Message> mPendingResponses = new HashMap<>();
107 
108     // ***** Constants
109 
110     // Markers for mncLength
111     protected static final int UNINITIALIZED = -1;
112     protected static final int UNKNOWN = 0;
113 
114     // Bitmasks for SPN display rules.
115     public static final int SPN_RULE_SHOW_SPN  = 0x01;
116     public static final int SPN_RULE_SHOW_PLMN = 0x02;
117 
118     // ***** Event Constants
119     public static final int EVENT_MWI = 0; // Message Waiting indication
120     public static final int EVENT_CFI = 1; // Call Forwarding indication
121     public static final int EVENT_SPN = 2; // Service Provider Name
122 
123     public static final int EVENT_GET_ICC_RECORD_DONE = 100;
124     protected static final int EVENT_APP_READY = 1;
125     private static final int EVENT_AKA_AUTHENTICATE_DONE          = 90;
126 
127     public static final int CALL_FORWARDING_STATUS_DISABLED = 0;
128     public static final int CALL_FORWARDING_STATUS_ENABLED = 1;
129     public static final int CALL_FORWARDING_STATUS_UNKNOWN = -1;
130 
131     public static final int DEFAULT_VOICE_MESSAGE_COUNT = -2;
132     public static final int UNKNOWN_VOICE_MESSAGE_COUNT = -1;
133 
134     @Override
toString()135     public String toString() {
136         String iccIdToPrint = SubscriptionInfo.givePrintableIccid(mFullIccId);
137         return "mDestroyed=" + mDestroyed
138                 + " mContext=" + mContext
139                 + " mCi=" + mCi
140                 + " mFh=" + mFh
141                 + " mParentApp=" + mParentApp
142                 + " recordsLoadedRegistrants=" + mRecordsLoadedRegistrants
143                 + " mImsiReadyRegistrants=" + mImsiReadyRegistrants
144                 + " mRecordsEventsRegistrants=" + mRecordsEventsRegistrants
145                 + " mNewSmsRegistrants=" + mNewSmsRegistrants
146                 + " mNetworkSelectionModeAutomaticRegistrants="
147                         + mNetworkSelectionModeAutomaticRegistrants
148                 + " recordsToLoad=" + mRecordsToLoad
149                 + " adnCache=" + mAdnCache
150                 + " recordsRequested=" + mRecordsRequested
151                 + " iccid=" + iccIdToPrint
152                 + " msisdnTag=" + mMsisdnTag
153                 + " voiceMailNum=" + Rlog.pii(VDBG, mVoiceMailNum)
154                 + " voiceMailTag=" + mVoiceMailTag
155                 + " voiceMailNum=" + Rlog.pii(VDBG, mNewVoiceMailNum)
156                 + " newVoiceMailTag=" + mNewVoiceMailTag
157                 + " isVoiceMailFixed=" + mIsVoiceMailFixed
158                 + " mImsi=" + ((mImsi != null) ?
159                 mImsi.substring(0, 6) + Rlog.pii(VDBG, mImsi.substring(6)) : "null")
160                 + " mncLength=" + mMncLength
161                 + " mailboxIndex=" + mMailboxIndex
162                 + " spn=" + mSpn;
163 
164     }
165 
166     /**
167      * Generic ICC record loaded callback. Subclasses can call EF load methods on
168      * {@link IccFileHandler} passing a Message for onLoaded with the what field set to
169      * {@link #EVENT_GET_ICC_RECORD_DONE} and the obj field set to an instance
170      * of this interface. The {@link #handleMessage} method in this class will print a
171      * log message using {@link #getEfName()} and decrement {@link #mRecordsToLoad}.
172      *
173      * If the record load was successful, {@link #onRecordLoaded} will be called with the result.
174      * Otherwise, an error log message will be output by {@link #handleMessage} and
175      * {@link #onRecordLoaded} will not be called.
176      */
177     public interface IccRecordLoaded {
getEfName()178         String getEfName();
onRecordLoaded(AsyncResult ar)179         void onRecordLoaded(AsyncResult ar);
180     }
181 
182     // ***** Constructor
IccRecords(UiccCardApplication app, Context c, CommandsInterface ci)183     public IccRecords(UiccCardApplication app, Context c, CommandsInterface ci) {
184         mContext = c;
185         mCi = ci;
186         mFh = app.getIccFileHandler();
187         mParentApp = app;
188         mTelephonyManager = (TelephonyManager) mContext.getSystemService(
189                 Context.TELEPHONY_SERVICE);
190     }
191 
192     /**
193      * Call when the IccRecords object is no longer going to be used.
194      */
dispose()195     public void dispose() {
196         mDestroyed.set(true);
197 
198         // It is possible that there is another thread waiting for the response
199         // to requestIccSimAuthentication() in getIccSimChallengeResponse().
200         auth_rsp = null;
201         synchronized (mLock) {
202             mLock.notifyAll();
203         }
204 
205         mParentApp = null;
206         mFh = null;
207         mCi = null;
208         mContext = null;
209     }
210 
onReady()211     public abstract void onReady();
212 
213     //***** Public Methods
getAdnCache()214     public AdnRecordCache getAdnCache() {
215         return mAdnCache;
216     }
217 
218     /**
219      * Adds a message to the pending requests list by generating a unique
220      * (integer) hash key and returning it. The message should never be null.
221      */
storePendingResponseMessage(Message msg)222     public int storePendingResponseMessage(Message msg) {
223         int key = sNextRequestId.getAndIncrement();
224         synchronized (mPendingResponses) {
225             mPendingResponses.put(key, msg);
226         }
227         return key;
228     }
229 
230     /**
231      * Returns the pending request, if any or null
232      */
retrievePendingResponseMessage(Integer key)233     public Message retrievePendingResponseMessage(Integer key) {
234         Message m;
235         synchronized (mPendingResponses) {
236             return mPendingResponses.remove(key);
237         }
238     }
239 
240     /**
241      * Returns the ICC ID stripped at the first hex character. Some SIMs have ICC IDs
242      * containing hex digits; {@link #getFullIccId()} should be used to get the full ID including
243      * hex digits.
244      * @return ICC ID without hex digits
245      */
getIccId()246     public String getIccId() {
247         return mIccId;
248     }
249 
250     /**
251      * Returns the full ICC ID including hex digits.
252      * @return full ICC ID including hex digits
253      */
getFullIccId()254     public String getFullIccId() {
255         return mFullIccId;
256     }
257 
registerForRecordsLoaded(Handler h, int what, Object obj)258     public void registerForRecordsLoaded(Handler h, int what, Object obj) {
259         if (mDestroyed.get()) {
260             return;
261         }
262 
263         Registrant r = new Registrant(h, what, obj);
264         mRecordsLoadedRegistrants.add(r);
265 
266         if (mRecordsToLoad == 0 && mRecordsRequested == true) {
267             r.notifyRegistrant(new AsyncResult(null, null, null));
268         }
269     }
unregisterForRecordsLoaded(Handler h)270     public void unregisterForRecordsLoaded(Handler h) {
271         mRecordsLoadedRegistrants.remove(h);
272     }
273 
registerForImsiReady(Handler h, int what, Object obj)274     public void registerForImsiReady(Handler h, int what, Object obj) {
275         if (mDestroyed.get()) {
276             return;
277         }
278 
279         Registrant r = new Registrant(h, what, obj);
280         mImsiReadyRegistrants.add(r);
281 
282         if (mImsi != null) {
283             r.notifyRegistrant(new AsyncResult(null, null, null));
284         }
285     }
unregisterForImsiReady(Handler h)286     public void unregisterForImsiReady(Handler h) {
287         mImsiReadyRegistrants.remove(h);
288     }
289 
registerForRecordsEvents(Handler h, int what, Object obj)290     public void registerForRecordsEvents(Handler h, int what, Object obj) {
291         Registrant r = new Registrant (h, what, obj);
292         mRecordsEventsRegistrants.add(r);
293 
294         /* Notify registrant of all the possible events. This is to make sure registrant is
295         notified even if event occurred in the past. */
296         r.notifyResult(EVENT_MWI);
297         r.notifyResult(EVENT_CFI);
298     }
unregisterForRecordsEvents(Handler h)299     public void unregisterForRecordsEvents(Handler h) {
300         mRecordsEventsRegistrants.remove(h);
301     }
302 
registerForNewSms(Handler h, int what, Object obj)303     public void registerForNewSms(Handler h, int what, Object obj) {
304         Registrant r = new Registrant (h, what, obj);
305         mNewSmsRegistrants.add(r);
306     }
unregisterForNewSms(Handler h)307     public void unregisterForNewSms(Handler h) {
308         mNewSmsRegistrants.remove(h);
309     }
310 
registerForNetworkSelectionModeAutomatic( Handler h, int what, Object obj)311     public void registerForNetworkSelectionModeAutomatic(
312             Handler h, int what, Object obj) {
313         Registrant r = new Registrant (h, what, obj);
314         mNetworkSelectionModeAutomaticRegistrants.add(r);
315     }
unregisterForNetworkSelectionModeAutomatic(Handler h)316     public void unregisterForNetworkSelectionModeAutomatic(Handler h) {
317         mNetworkSelectionModeAutomaticRegistrants.remove(h);
318     }
319 
320     /**
321      * Get the International Mobile Subscriber ID (IMSI) on a SIM
322      * for GSM, UMTS and like networks. Default is null if IMSI is
323      * not supported or unavailable.
324      *
325      * @return null if SIM is not yet ready or unavailable
326      */
getIMSI()327     public String getIMSI() {
328         return null;
329     }
330 
331     /**
332      * Imsi could be set by ServiceStateTrackers in case of cdma
333      * @param imsi
334      */
setImsi(String imsi)335     public void setImsi(String imsi) {
336         mImsi = imsi;
337         mImsiReadyRegistrants.notifyRegistrants();
338     }
339 
340     /**
341      * Get the Network Access ID (NAI) on a CSIM for CDMA like networks. Default is null if IMSI is
342      * not supported or unavailable.
343      *
344      * @return null if NAI is not yet ready or unavailable
345      */
getNAI()346     public String getNAI() {
347         return null;
348     }
349 
getMsisdnNumber()350     public String getMsisdnNumber() {
351         return mMsisdn;
352     }
353 
354     /**
355      * Get the Group Identifier Level 1 (GID1) on a SIM for GSM.
356      * @return null if SIM is not yet ready
357      */
getGid1()358     public String getGid1() {
359         return null;
360     }
361 
362     /**
363      * Get the Group Identifier Level 2 (GID2) on a SIM.
364      * @return null if SIM is not yet ready
365      */
getGid2()366     public String getGid2() {
367         return null;
368     }
369 
setMsisdnNumber(String alphaTag, String number, Message onComplete)370     public void setMsisdnNumber(String alphaTag, String number,
371             Message onComplete) {
372         loge("setMsisdn() should not be invoked on base IccRecords");
373         // synthesize a "File Not Found" exception and return it
374         AsyncResult.forMessage(onComplete).exception =
375             (new IccIoResult(0x6A, 0x82, (byte[]) null)).getException();
376         onComplete.sendToTarget();
377     }
378 
getMsisdnAlphaTag()379     public String getMsisdnAlphaTag() {
380         return mMsisdnTag;
381     }
382 
getVoiceMailNumber()383     public String getVoiceMailNumber() {
384         return mVoiceMailNum;
385     }
386 
387     /**
388      * Return Service Provider Name stored in SIM (EF_SPN=0x6F46) or in RUIM (EF_RUIM_SPN=0x6F41).
389      *
390      * @return null if SIM is not yet ready or no RUIM entry
391      */
getServiceProviderName()392     public String getServiceProviderName() {
393         String providerName = mSpn;
394 
395         // Check for null pointers, mParentApp can be null after dispose,
396         // which did occur after removing a SIM.
397         UiccCardApplication parentApp = mParentApp;
398         if (parentApp != null) {
399             UiccCard card = parentApp.getUiccCard();
400             if (card != null) {
401                 String brandOverride = card.getOperatorBrandOverride();
402                 if (brandOverride != null) {
403                     log("getServiceProviderName: override, providerName=" + providerName);
404                     providerName = brandOverride;
405                 } else {
406                     log("getServiceProviderName: no brandOverride, providerName=" + providerName);
407                 }
408             } else {
409                 log("getServiceProviderName: card is null, providerName=" + providerName);
410             }
411         } else {
412             log("getServiceProviderName: mParentApp is null, providerName=" + providerName);
413         }
414         return providerName;
415     }
416 
setServiceProviderName(String spn)417     protected void setServiceProviderName(String spn) {
418         mSpn = spn;
419     }
420 
421     /**
422      * Set voice mail number to SIM record
423      *
424      * The voice mail number can be stored either in EF_MBDN (TS 51.011) or
425      * EF_MAILBOX_CPHS (CPHS 4.2)
426      *
427      * If EF_MBDN is available, store the voice mail number to EF_MBDN
428      *
429      * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS
430      *
431      * So the voice mail number will be stored in both EFs if both are available
432      *
433      * Return error only if both EF_MBDN and EF_MAILBOX_CPHS fail.
434      *
435      * When the operation is complete, onComplete will be sent to its handler
436      *
437      * @param alphaTag alpha-tagging of the dailing nubmer (upto 10 characters)
438      * @param voiceNumber dailing nubmer (upto 20 digits)
439      *        if the number is start with '+', then set to international TOA
440      * @param onComplete
441      *        onComplete.obj will be an AsyncResult
442      *        ((AsyncResult)onComplete.obj).exception == null on success
443      *        ((AsyncResult)onComplete.obj).exception != null on fail
444      */
setVoiceMailNumber(String alphaTag, String voiceNumber, Message onComplete)445     public abstract void setVoiceMailNumber(String alphaTag, String voiceNumber,
446             Message onComplete);
447 
getVoiceMailAlphaTag()448     public String getVoiceMailAlphaTag() {
449         return mVoiceMailTag;
450     }
451 
452     /**
453      * Sets the SIM voice message waiting indicator records
454      * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
455      * @param countWaiting The number of messages waiting, if known. Use
456      *                     -1 to indicate that an unknown number of
457      *                      messages are waiting
458      */
setVoiceMessageWaiting(int line, int countWaiting)459     public abstract void setVoiceMessageWaiting(int line, int countWaiting);
460 
461     /**
462      * Called by GsmCdmaPhone to update VoiceMail count
463      */
getVoiceMessageCount()464     public abstract int getVoiceMessageCount();
465 
466     /**
467      * Called by STK Service when REFRESH is received.
468      * @param fileChanged indicates whether any files changed
469      * @param fileList if non-null, a list of EF files that changed
470      */
onRefresh(boolean fileChanged, int[] fileList)471     public abstract void onRefresh(boolean fileChanged, int[] fileList);
472 
473     /**
474      * Called by subclasses (SimRecords and RuimRecords) whenever
475      * IccRefreshResponse.REFRESH_RESULT_INIT event received
476      */
onIccRefreshInit()477     protected void onIccRefreshInit() {
478         mAdnCache.reset();
479         UiccCardApplication parentApp = mParentApp;
480         if ((parentApp != null) &&
481                 (parentApp.getState() == AppState.APPSTATE_READY)) {
482             // This will cause files to be reread
483             sendMessage(obtainMessage(EVENT_APP_READY));
484         }
485     }
486 
getRecordsLoaded()487     public boolean getRecordsLoaded() {
488         if (mRecordsToLoad == 0 && mRecordsRequested == true) {
489             return true;
490         } else {
491             return false;
492         }
493     }
494 
495     //***** Overridden from Handler
496     @Override
handleMessage(Message msg)497     public void handleMessage(Message msg) {
498         AsyncResult ar;
499 
500         switch (msg.what) {
501             case EVENT_GET_ICC_RECORD_DONE:
502                 try {
503                     ar = (AsyncResult) msg.obj;
504                     IccRecordLoaded recordLoaded = (IccRecordLoaded) ar.userObj;
505                     if (DBG) log(recordLoaded.getEfName() + " LOADED");
506 
507                     if (ar.exception != null) {
508                         loge("Record Load Exception: " + ar.exception);
509                     } else {
510                         recordLoaded.onRecordLoaded(ar);
511                     }
512                 }catch (RuntimeException exc) {
513                     // I don't want these exceptions to be fatal
514                     loge("Exception parsing SIM record: " + exc);
515                 } finally {
516                     // Count up record load responses even if they are fails
517                     onRecordLoaded();
518                 }
519                 break;
520 
521             case EVENT_AKA_AUTHENTICATE_DONE:
522                 ar = (AsyncResult)msg.obj;
523                 auth_rsp = null;
524                 if (DBG) log("EVENT_AKA_AUTHENTICATE_DONE");
525                 if (ar.exception != null) {
526                     loge("Exception ICC SIM AKA: " + ar.exception);
527                 } else {
528                     try {
529                         auth_rsp = (IccIoResult)ar.result;
530                         if (DBG) log("ICC SIM AKA: auth_rsp = " + auth_rsp);
531                     } catch (Exception e) {
532                         loge("Failed to parse ICC SIM AKA contents: " + e);
533                     }
534                 }
535                 synchronized (mLock) {
536                     mLock.notifyAll();
537                 }
538 
539                 break;
540 
541             default:
542                 super.handleMessage(msg);
543         }
544     }
545 
546     /**
547      * Returns the SIM language derived from the EF-LI and EF-PL sim records.
548      */
getSimLanguage()549     public String getSimLanguage() {
550         return mPrefLang;
551     }
552 
setSimLanguage(byte[] efLi, byte[] efPl)553     protected void setSimLanguage(byte[] efLi, byte[] efPl) {
554         String[] locales = mContext.getAssets().getLocales();
555         try {
556             mPrefLang = findBestLanguage(efLi, locales);
557         } catch (UnsupportedEncodingException uee) {
558             log("Unable to parse EF-LI: " + Arrays.toString(efLi));
559         }
560 
561         if (mPrefLang == null) {
562             try {
563                 mPrefLang = findBestLanguage(efPl, locales);
564             } catch (UnsupportedEncodingException uee) {
565                 log("Unable to parse EF-PL: " + Arrays.toString(efLi));
566             }
567         }
568     }
569 
findBestLanguage(byte[] languages, String[] locales)570     protected static String findBestLanguage(byte[] languages, String[] locales)
571             throws UnsupportedEncodingException {
572         if ((languages == null) || (locales == null)) return null;
573 
574         // Each 2-bytes consists of one language
575         for (int i = 0; (i + 1) < languages.length; i += 2) {
576             String lang = new String(languages, i, 2, "ISO-8859-1");
577             for (int j = 0; j < locales.length; j++) {
578                 if (locales[j] != null && locales[j].length() >= 2 &&
579                         locales[j].substring(0, 2).equalsIgnoreCase(lang)) {
580                     return lang;
581                 }
582             }
583         }
584 
585         // no match found. return null
586         return null;
587     }
588 
onRecordLoaded()589     protected abstract void onRecordLoaded();
590 
onAllRecordsLoaded()591     protected abstract void onAllRecordsLoaded();
592 
593     /**
594      * Returns the SpnDisplayRule based on settings on the SIM and the
595      * specified plmn (currently-registered PLMN).  See TS 22.101 Annex A
596      * and TS 51.011 10.3.11 for details.
597      *
598      * If the SPN is not found on the SIM, the rule is always PLMN_ONLY.
599      * Generally used for GSM/UMTS and the like SIMs.
600      */
getDisplayRule(String plmn)601     public abstract int getDisplayRule(String plmn);
602 
603     /**
604      * Return true if "Restriction of menu options for manual PLMN selection"
605      * bit is set or EF_CSP data is unavailable, return false otherwise.
606      * Generally used for GSM/UMTS and the like SIMs.
607      */
isCspPlmnEnabled()608     public boolean isCspPlmnEnabled() {
609         return false;
610     }
611 
612     /**
613      * Returns the 5 or 6 digit MCC/MNC of the operator that
614      * provided the SIM card. Returns null of SIM is not yet ready
615      * or is not valid for the type of IccCard. Generally used for
616      * GSM/UMTS and the like SIMS
617      */
getOperatorNumeric()618     public String getOperatorNumeric() {
619         return null;
620     }
621 
622     /**
623      * Get the current Voice call forwarding flag for GSM/UMTS and the like SIMs
624      *
625      * @return CALL_FORWARDING_STATUS_XXX (DISABLED/ENABLED/UNKNOWN)
626      */
getVoiceCallForwardingFlag()627     public int getVoiceCallForwardingFlag() {
628         return CALL_FORWARDING_STATUS_UNKNOWN;
629     }
630 
631     /**
632      * Set the voice call forwarding flag for GSM/UMTS and the like SIMs
633      *
634      * @param line to enable/disable
635      * @param enable
636      * @param number to which CFU is enabled
637      */
setVoiceCallForwardingFlag(int line, boolean enable, String number)638     public void setVoiceCallForwardingFlag(int line, boolean enable, String number) {
639     }
640 
641     /**
642      * Indicates wether SIM is in provisioned state or not.
643      * Overridden only if SIM can be dynamically provisioned via OTA.
644      *
645      * @return true if provisioned
646      */
isProvisioned()647     public boolean isProvisioned () {
648         return true;
649     }
650 
651     /**
652      * Write string to log file
653      *
654      * @param s is the string to write
655      */
log(String s)656     protected abstract void log(String s);
657 
658     /**
659      * Write error string to log file.
660      *
661      * @param s is the string to write
662      */
loge(String s)663     protected abstract void loge(String s);
664 
665     /**
666      * Return an interface to retrieve the ISIM records for IMS, if available.
667      * @return the interface to retrieve the ISIM records, or null if not supported
668      */
getIsimRecords()669     public IsimRecords getIsimRecords() {
670         return null;
671     }
672 
getUsimServiceTable()673     public UsimServiceTable getUsimServiceTable() {
674         return null;
675     }
676 
setSystemProperty(String key, String val)677     protected void setSystemProperty(String key, String val) {
678         TelephonyManager.getDefault().setTelephonyProperty(mParentApp.getPhoneId(), key, val);
679 
680         log("[key, value]=" + key + ", " +  val);
681     }
682 
683     /**
684      * Returns the response of the SIM application on the UICC to authentication
685      * challenge/response algorithm. The data string and challenge response are
686      * Base64 encoded Strings.
687      * Can support EAP-SIM, EAP-AKA with results encoded per 3GPP TS 31.102.
688      *
689      * @param authContext parameter P2 that specifies the authentication context per 3GPP TS 31.102 (Section 7.1.2)
690      * @param data authentication challenge data
691      * @return challenge response
692      */
getIccSimChallengeResponse(int authContext, String data)693     public String getIccSimChallengeResponse(int authContext, String data) {
694         if (DBG) log("getIccSimChallengeResponse:");
695 
696         try {
697             synchronized(mLock) {
698                 CommandsInterface ci = mCi;
699                 UiccCardApplication parentApp = mParentApp;
700                 if (ci != null && parentApp != null) {
701                     ci.requestIccSimAuthentication(authContext, data,
702                             parentApp.getAid(),
703                             obtainMessage(EVENT_AKA_AUTHENTICATE_DONE));
704                     try {
705                         mLock.wait();
706                     } catch (InterruptedException e) {
707                         loge("getIccSimChallengeResponse: Fail, interrupted"
708                                 + " while trying to request Icc Sim Auth");
709                         return null;
710                     }
711                 } else {
712                     loge( "getIccSimChallengeResponse: "
713                             + "Fail, ci or parentApp is null");
714                     return null;
715                 }
716             }
717         } catch(Exception e) {
718             loge( "getIccSimChallengeResponse: "
719                     + "Fail while trying to request Icc Sim Auth");
720             return null;
721         }
722 
723         if (auth_rsp == null) {
724             loge("getIccSimChallengeResponse: No authentication response");
725             return null;
726         }
727 
728         if (DBG) log("getIccSimChallengeResponse: return auth_rsp");
729 
730         return android.util.Base64.encodeToString(auth_rsp.payload, android.util.Base64.NO_WRAP);
731     }
732 
dump(FileDescriptor fd, PrintWriter pw, String[] args)733     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
734         pw.println("IccRecords: " + this);
735         pw.println(" mDestroyed=" + mDestroyed);
736         pw.println(" mCi=" + mCi);
737         pw.println(" mFh=" + mFh);
738         pw.println(" mParentApp=" + mParentApp);
739         pw.println(" recordsLoadedRegistrants: size=" + mRecordsLoadedRegistrants.size());
740         for (int i = 0; i < mRecordsLoadedRegistrants.size(); i++) {
741             pw.println("  recordsLoadedRegistrants[" + i + "]="
742                     + ((Registrant)mRecordsLoadedRegistrants.get(i)).getHandler());
743         }
744         pw.println(" mImsiReadyRegistrants: size=" + mImsiReadyRegistrants.size());
745         for (int i = 0; i < mImsiReadyRegistrants.size(); i++) {
746             pw.println("  mImsiReadyRegistrants[" + i + "]="
747                     + ((Registrant)mImsiReadyRegistrants.get(i)).getHandler());
748         }
749         pw.println(" mRecordsEventsRegistrants: size=" + mRecordsEventsRegistrants.size());
750         for (int i = 0; i < mRecordsEventsRegistrants.size(); i++) {
751             pw.println("  mRecordsEventsRegistrants[" + i + "]="
752                     + ((Registrant)mRecordsEventsRegistrants.get(i)).getHandler());
753         }
754         pw.println(" mNewSmsRegistrants: size=" + mNewSmsRegistrants.size());
755         for (int i = 0; i < mNewSmsRegistrants.size(); i++) {
756             pw.println("  mNewSmsRegistrants[" + i + "]="
757                     + ((Registrant)mNewSmsRegistrants.get(i)).getHandler());
758         }
759         pw.println(" mNetworkSelectionModeAutomaticRegistrants: size="
760                 + mNetworkSelectionModeAutomaticRegistrants.size());
761         for (int i = 0; i < mNetworkSelectionModeAutomaticRegistrants.size(); i++) {
762             pw.println("  mNetworkSelectionModeAutomaticRegistrants[" + i + "]="
763                     + ((Registrant)mNetworkSelectionModeAutomaticRegistrants.get(i)).getHandler());
764         }
765         pw.println(" mRecordsRequested=" + mRecordsRequested);
766         pw.println(" mRecordsToLoad=" + mRecordsToLoad);
767         pw.println(" mRdnCache=" + mAdnCache);
768 
769         String iccIdToPrint = SubscriptionInfo.givePrintableIccid(mFullIccId);
770         pw.println(" iccid=" + iccIdToPrint);
771         pw.println(" mMsisdn=" + Rlog.pii(VDBG, mMsisdn));
772         pw.println(" mMsisdnTag=" + mMsisdnTag);
773         pw.println(" mVoiceMailNum=" + Rlog.pii(VDBG, mVoiceMailNum));
774         pw.println(" mVoiceMailTag=" + mVoiceMailTag);
775         pw.println(" mNewVoiceMailNum=" + Rlog.pii(VDBG, mNewVoiceMailNum));
776         pw.println(" mNewVoiceMailTag=" + mNewVoiceMailTag);
777         pw.println(" mIsVoiceMailFixed=" + mIsVoiceMailFixed);
778         pw.println(" mImsi=" + ((mImsi != null) ?
779                 mImsi.substring(0, 6) + Rlog.pii(VDBG, mImsi.substring(6)) : "null"));
780         pw.println(" mMncLength=" + mMncLength);
781         pw.println(" mMailboxIndex=" + mMailboxIndex);
782         pw.println(" mSpn=" + mSpn);
783         pw.flush();
784     }
785 }
786