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