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