Home | History | Annotate | Download | only in uicc
      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
    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 {
    199         String getEfName();
    200         void onRecordLoaded(AsyncResult ar);
    201     }
    202 
    203     // ***** Constructor
    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
    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      */
    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 
    249     public abstract void onReady();
    250 
    251     //***** Public Methods
    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      */
    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      */
    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      */
    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      */
    296     public String getFullIccId() {
    297         return mFullIccId;
    298     }
    299 
    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 
    313     public void unregisterForRecordsLoaded(Handler h) {
    314         mRecordsLoadedRegistrants.remove(h);
    315     }
    316 
    317     public void unregisterForRecordsOverride(Handler h) {
    318         mRecordsOverrideRegistrants.remove(h);
    319     }
    320 
    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      */
    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      */
    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      */
    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      */
    376     public void unregisterForNetworkLockedRecordsLoaded(Handler h) {
    377         mNetworkLockedRecordsLoadedRegistrants.remove(h);
    378     }
    379 
    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     }
    392     public void unregisterForImsiReady(Handler h) {
    393         mImsiReadyRegistrants.remove(h);
    394     }
    395 
    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     }
    408     public void unregisterForSpnUpdate(Handler h) {
    409         mSpnUpdatedRegistrants.remove(h);
    410     }
    411 
    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     }
    421     public void unregisterForRecordsEvents(Handler h) {
    422         mRecordsEventsRegistrants.remove(h);
    423     }
    424 
    425     public void registerForNewSms(Handler h, int what, Object obj) {
    426         Registrant r = new Registrant (h, what, obj);
    427         mNewSmsRegistrants.add(r);
    428     }
    429     public void unregisterForNewSms(Handler h) {
    430         mNewSmsRegistrants.remove(h);
    431     }
    432 
    433     public void registerForNetworkSelectionModeAutomatic(
    434             Handler h, int what, Object obj) {
    435         Registrant r = new Registrant (h, what, obj);
    436         mNetworkSelectionModeAutomaticRegistrants.add(r);
    437     }
    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      */
    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      */
    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      */
    472     public String getNAI() {
    473         return null;
    474     }
    475 
    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      */
    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      */
    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      */
    508     public String getPnnHomeName() {
    509         if (mCarrierTestOverride.isInTestMode()
    510                 && mCarrierTestOverride.getFakePnnHomeName() != null) {
    511             return mCarrierTestOverride.getFakePnnHomeName();
    512         } else {
    513             return mPnnHomeName;
    514         }
    515     }
    516 
    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 
    526     public String getMsisdnAlphaTag() {
    527         return mMsisdnTag;
    528     }
    529 
    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      */
    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 
    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      */
    598     public abstract void setVoiceMailNumber(String alphaTag, String voiceNumber,
    599             Message onComplete);
    600 
    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      */
    612     public abstract void setVoiceMessageWaiting(int line, int countWaiting);
    613 
    614     /**
    615      * Called by GsmCdmaPhone to update VoiceMail count
    616      */
    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      */
    624     public abstract void onRefresh(boolean fileChanged, int[] fileList);
    625 
    626     public boolean getRecordsLoaded() {
    627         return mRecordsToLoad == 0 && mRecordsRequested;
    628     }
    629 
    630     protected boolean getLockedRecordsLoaded() {
    631         return mRecordsToLoad == 0
    632                 && mLockedRecordsReqReason == LOCKED_RECORDS_REQ_REASON_LOCKED;
    633     }
    634 
    635     protected boolean getNetworkLockedRecordsLoaded() {
    636         return mRecordsToLoad == 0
    637                 && mLockedRecordsReqReason == LOCKED_RECORDS_REQ_REASON_NETWORK_LOCKED;
    638     }
    639 
    640     //***** Overridden from Handler
    641     @Override
    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      */
    704     public String getSimLanguage() {
    705         return mPrefLang;
    706     }
    707 
    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 
    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 
    744     protected abstract void handleFileUpdate(int efid);
    745 
    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 
    770     protected abstract void onRecordLoaded();
    771 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    865     public IsimRecords getIsimRecords() {
    866         return null;
    867     }
    868 
    869     public UsimServiceTable getUsimServiceTable() {
    870         return null;
    871     }
    872 
    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      */
    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 
    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