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 
     26 import com.android.internal.telephony.CommandsInterface;
     27 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
     28 
     29 import java.io.FileDescriptor;
     30 import java.io.PrintWriter;
     31 import java.util.concurrent.atomic.AtomicBoolean;
     32 
     33 /**
     34  * {@hide}
     35  */
     36 public abstract class IccRecords extends Handler implements IccConstants {
     37     protected static final boolean DBG = true;
     38 
     39     // ***** Instance Variables
     40     protected AtomicBoolean mDestroyed = new AtomicBoolean(false);
     41     protected Context mContext;
     42     protected CommandsInterface mCi;
     43     protected IccFileHandler mFh;
     44     protected UiccCardApplication mParentApp;
     45 
     46     protected RegistrantList mRecordsLoadedRegistrants = new RegistrantList();
     47     protected RegistrantList mImsiReadyRegistrants = new RegistrantList();
     48     protected RegistrantList mRecordsEventsRegistrants = new RegistrantList();
     49     protected RegistrantList mNewSmsRegistrants = new RegistrantList();
     50     protected RegistrantList mNetworkSelectionModeAutomaticRegistrants = new RegistrantList();
     51 
     52     protected int mRecordsToLoad;  // number of pending load requests
     53 
     54     protected AdnRecordCache mAdnCache;
     55 
     56     // ***** Cached SIM State; cleared on channel close
     57 
     58     protected boolean mRecordsRequested = false; // true if we've made requests for the sim records
     59 
     60     protected String mIccId;
     61     protected String mMsisdn = null;  // My mobile number
     62     protected String mMsisdnTag = null;
     63     protected String mVoiceMailNum = null;
     64     protected String mVoiceMailTag = null;
     65     protected String mNewVoiceMailNum = null;
     66     protected String mNewVoiceMailTag = null;
     67     protected boolean mIsVoiceMailFixed = false;
     68     protected int mCountVoiceMessages = 0;
     69     protected String mImsi;
     70 
     71     protected int mMncLength = UNINITIALIZED;
     72     protected int mMailboxIndex = 0; // 0 is no mailbox dailing number associated
     73 
     74     protected String mSpn;
     75 
     76     protected String mGid1;
     77 
     78     // ***** Constants
     79 
     80     // Markers for mncLength
     81     protected static final int UNINITIALIZED = -1;
     82     protected static final int UNKNOWN = 0;
     83 
     84     // Bitmasks for SPN display rules.
     85     public static final int SPN_RULE_SHOW_SPN  = 0x01;
     86     public static final int SPN_RULE_SHOW_PLMN = 0x02;
     87 
     88     // ***** Event Constants
     89     protected static final int EVENT_SET_MSISDN_DONE = 30;
     90     public static final int EVENT_MWI = 0; // Message Waiting indication
     91     public static final int EVENT_CFI = 1; // Call Forwarding indication
     92     public static final int EVENT_SPN = 2; // Service Provider Name
     93 
     94     public static final int EVENT_GET_ICC_RECORD_DONE = 100;
     95     protected static final int EVENT_APP_READY = 1;
     96 
     97     @Override
     98     public String toString() {
     99         return "mDestroyed=" + mDestroyed
    100                 + " mContext=" + mContext
    101                 + " mCi=" + mCi
    102                 + " mFh=" + mFh
    103                 + " mParentApp=" + mParentApp
    104                 + " recordsLoadedRegistrants=" + mRecordsLoadedRegistrants
    105                 + " mImsiReadyRegistrants=" + mImsiReadyRegistrants
    106                 + " mRecordsEventsRegistrants=" + mRecordsEventsRegistrants
    107                 + " mNewSmsRegistrants=" + mNewSmsRegistrants
    108                 + " mNetworkSelectionModeAutomaticRegistrants="
    109                         + mNetworkSelectionModeAutomaticRegistrants
    110                 + " recordsToLoad=" + mRecordsToLoad
    111                 + " adnCache=" + mAdnCache
    112                 + " recordsRequested=" + mRecordsRequested
    113                 + " iccid=" + mIccId
    114                 + " msisdn=" + mMsisdn
    115                 + " msisdnTag=" + mMsisdnTag
    116                 + " voiceMailNum=" + mVoiceMailNum
    117                 + " voiceMailTag=" + mVoiceMailTag
    118                 + " newVoiceMailNum=" + mNewVoiceMailNum
    119                 + " newVoiceMailTag=" + mNewVoiceMailTag
    120                 + " isVoiceMailFixed=" + mIsVoiceMailFixed
    121                 + " countVoiceMessages=" + mCountVoiceMessages
    122                 + " mImsi=" + mImsi
    123                 + " mncLength=" + mMncLength
    124                 + " mailboxIndex=" + mMailboxIndex
    125                 + " spn=" + mSpn;
    126 
    127     }
    128 
    129     /**
    130      * Generic ICC record loaded callback. Subclasses can call EF load methods on
    131      * {@link IccFileHandler} passing a Message for onLoaded with the what field set to
    132      * {@link #EVENT_GET_ICC_RECORD_DONE} and the obj field set to an instance
    133      * of this interface. The {@link #handleMessage} method in this class will print a
    134      * log message using {@link #getEfName()} and decrement {@link #mRecordsToLoad}.
    135      *
    136      * If the record load was successful, {@link #onRecordLoaded} will be called with the result.
    137      * Otherwise, an error log message will be output by {@link #handleMessage} and
    138      * {@link #onRecordLoaded} will not be called.
    139      */
    140     public interface IccRecordLoaded {
    141         String getEfName();
    142         void onRecordLoaded(AsyncResult ar);
    143     }
    144 
    145     // ***** Constructor
    146     public IccRecords(UiccCardApplication app, Context c, CommandsInterface ci) {
    147         mContext = c;
    148         mCi = ci;
    149         mFh = app.getIccFileHandler();
    150         mParentApp = app;
    151     }
    152 
    153     /**
    154      * Call when the IccRecords object is no longer going to be used.
    155      */
    156     public void dispose() {
    157         mDestroyed.set(true);
    158         mParentApp = null;
    159         mFh = null;
    160         mCi = null;
    161         mContext = null;
    162     }
    163 
    164     public abstract void onReady();
    165 
    166     //***** Public Methods
    167     public AdnRecordCache getAdnCache() {
    168         return mAdnCache;
    169     }
    170 
    171     public String getIccId() {
    172         return mIccId;
    173     }
    174 
    175     public void registerForRecordsLoaded(Handler h, int what, Object obj) {
    176         if (mDestroyed.get()) {
    177             return;
    178         }
    179 
    180         Registrant r = new Registrant(h, what, obj);
    181         mRecordsLoadedRegistrants.add(r);
    182 
    183         if (mRecordsToLoad == 0 && mRecordsRequested == true) {
    184             r.notifyRegistrant(new AsyncResult(null, null, null));
    185         }
    186     }
    187     public void unregisterForRecordsLoaded(Handler h) {
    188         mRecordsLoadedRegistrants.remove(h);
    189     }
    190 
    191     public void registerForImsiReady(Handler h, int what, Object obj) {
    192         if (mDestroyed.get()) {
    193             return;
    194         }
    195 
    196         Registrant r = new Registrant(h, what, obj);
    197         mImsiReadyRegistrants.add(r);
    198 
    199         if (mImsi != null) {
    200             r.notifyRegistrant(new AsyncResult(null, null, null));
    201         }
    202     }
    203     public void unregisterForImsiReady(Handler h) {
    204         mImsiReadyRegistrants.remove(h);
    205     }
    206 
    207     public void registerForRecordsEvents(Handler h, int what, Object obj) {
    208         Registrant r = new Registrant (h, what, obj);
    209         mRecordsEventsRegistrants.add(r);
    210     }
    211     public void unregisterForRecordsEvents(Handler h) {
    212         mRecordsEventsRegistrants.remove(h);
    213     }
    214 
    215     public void registerForNewSms(Handler h, int what, Object obj) {
    216         Registrant r = new Registrant (h, what, obj);
    217         mNewSmsRegistrants.add(r);
    218     }
    219     public void unregisterForNewSms(Handler h) {
    220         mNewSmsRegistrants.remove(h);
    221     }
    222 
    223     public void registerForNetworkSelectionModeAutomatic(
    224             Handler h, int what, Object obj) {
    225         Registrant r = new Registrant (h, what, obj);
    226         mNetworkSelectionModeAutomaticRegistrants.add(r);
    227     }
    228     public void unregisterForNetworkSelectionModeAutomatic(Handler h) {
    229         mNetworkSelectionModeAutomaticRegistrants.remove(h);
    230     }
    231 
    232     /**
    233      * Get the International Mobile Subscriber ID (IMSI) on a SIM
    234      * for GSM, UMTS and like networks. Default is null if IMSI is
    235      * not supported or unavailable.
    236      *
    237      * @return null if SIM is not yet ready or unavailable
    238      */
    239     public String getIMSI() {
    240         return null;
    241     }
    242 
    243     /**
    244      * Imsi could be set by ServiceStateTrackers in case of cdma
    245      * @param imsi
    246      */
    247     public void setImsi(String imsi) {
    248         mImsi = imsi;
    249         mImsiReadyRegistrants.notifyRegistrants();
    250     }
    251 
    252     public String getMsisdnNumber() {
    253         return mMsisdn;
    254     }
    255 
    256     /**
    257      * Get the Group Identifier Level 1 (GID1) on a SIM for GSM.
    258      * @return null if SIM is not yet ready
    259      */
    260     public String getGid1() {
    261         return null;
    262     }
    263 
    264     /**
    265      * Set subscriber number to SIM record
    266      *
    267      * The subscriber number is stored in EF_MSISDN (TS 51.011)
    268      *
    269      * When the operation is complete, onComplete will be sent to its handler
    270      *
    271      * @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters)
    272      * @param number dailing nubmer (up to 20 digits)
    273      *        if the number starts with '+', then set to international TOA
    274      * @param onComplete
    275      *        onComplete.obj will be an AsyncResult
    276      *        ((AsyncResult)onComplete.obj).exception == null on success
    277      *        ((AsyncResult)onComplete.obj).exception != null on fail
    278      */
    279     public void setMsisdnNumber(String alphaTag, String number,
    280             Message onComplete) {
    281 
    282         mMsisdn = number;
    283         mMsisdnTag = alphaTag;
    284 
    285         if (DBG) log("Set MSISDN: " + mMsisdnTag +" " + mMsisdn);
    286 
    287 
    288         AdnRecord adn = new AdnRecord(mMsisdnTag, mMsisdn);
    289 
    290         new AdnRecordLoader(mFh).updateEF(adn, EF_MSISDN, EF_EXT1, 1, null,
    291                 obtainMessage(EVENT_SET_MSISDN_DONE, onComplete));
    292     }
    293 
    294     public String getMsisdnAlphaTag() {
    295         return mMsisdnTag;
    296     }
    297 
    298     public String getVoiceMailNumber() {
    299         return mVoiceMailNum;
    300     }
    301 
    302     /**
    303      * Return Service Provider Name stored in SIM (EF_SPN=0x6F46) or in RUIM (EF_RUIM_SPN=0x6F41)
    304      * @return null if SIM is not yet ready or no RUIM entry
    305      */
    306     public String getServiceProviderName() {
    307         return mSpn;
    308     }
    309 
    310     /**
    311      * Set voice mail number to SIM record
    312      *
    313      * The voice mail number can be stored either in EF_MBDN (TS 51.011) or
    314      * EF_MAILBOX_CPHS (CPHS 4.2)
    315      *
    316      * If EF_MBDN is available, store the voice mail number to EF_MBDN
    317      *
    318      * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS
    319      *
    320      * So the voice mail number will be stored in both EFs if both are available
    321      *
    322      * Return error only if both EF_MBDN and EF_MAILBOX_CPHS fail.
    323      *
    324      * When the operation is complete, onComplete will be sent to its handler
    325      *
    326      * @param alphaTag alpha-tagging of the dailing nubmer (upto 10 characters)
    327      * @param voiceNumber dailing nubmer (upto 20 digits)
    328      *        if the number is start with '+', then set to international TOA
    329      * @param onComplete
    330      *        onComplete.obj will be an AsyncResult
    331      *        ((AsyncResult)onComplete.obj).exception == null on success
    332      *        ((AsyncResult)onComplete.obj).exception != null on fail
    333      */
    334     public abstract void setVoiceMailNumber(String alphaTag, String voiceNumber,
    335             Message onComplete);
    336 
    337     public String getVoiceMailAlphaTag() {
    338         return mVoiceMailTag;
    339     }
    340 
    341     /**
    342      * Sets the SIM voice message waiting indicator records
    343      * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
    344      * @param countWaiting The number of messages waiting, if known. Use
    345      *                     -1 to indicate that an unknown number of
    346      *                      messages are waiting
    347      */
    348     public abstract void setVoiceMessageWaiting(int line, int countWaiting);
    349 
    350     /** @return  true if there are messages waiting, false otherwise. */
    351     public boolean getVoiceMessageWaiting() {
    352         return mCountVoiceMessages != 0;
    353     }
    354 
    355     /**
    356      * Returns number of voice messages waiting, if available
    357      * If not available (eg, on an older CPHS SIM) -1 is returned if
    358      * getVoiceMessageWaiting() is true
    359      */
    360     public int getVoiceMessageCount() {
    361         return mCountVoiceMessages;
    362     }
    363 
    364     /**
    365      * Called by STK Service when REFRESH is received.
    366      * @param fileChanged indicates whether any files changed
    367      * @param fileList if non-null, a list of EF files that changed
    368      */
    369     public abstract void onRefresh(boolean fileChanged, int[] fileList);
    370 
    371     /**
    372      * Called by subclasses (SimRecords and RuimRecords) whenever
    373      * IccRefreshResponse.REFRESH_RESULT_INIT event received
    374      */
    375     protected void onIccRefreshInit() {
    376         mAdnCache.reset();
    377         if (mParentApp.getState() == AppState.APPSTATE_READY) {
    378             // This will cause files to be reread
    379             sendMessage(obtainMessage(EVENT_APP_READY));
    380         }
    381     }
    382 
    383     public boolean getRecordsLoaded() {
    384         if (mRecordsToLoad == 0 && mRecordsRequested == true) {
    385             return true;
    386         } else {
    387             return false;
    388         }
    389     }
    390 
    391     //***** Overridden from Handler
    392     @Override
    393     public void handleMessage(Message msg) {
    394         switch (msg.what) {
    395             case EVENT_GET_ICC_RECORD_DONE:
    396                 try {
    397                     AsyncResult ar = (AsyncResult) msg.obj;
    398                     IccRecordLoaded recordLoaded = (IccRecordLoaded) ar.userObj;
    399                     if (DBG) log(recordLoaded.getEfName() + " LOADED");
    400 
    401                     if (ar.exception != null) {
    402                         loge("Record Load Exception: " + ar.exception);
    403                     } else {
    404                         recordLoaded.onRecordLoaded(ar);
    405                     }
    406                 }catch (RuntimeException exc) {
    407                     // I don't want these exceptions to be fatal
    408                     loge("Exception parsing SIM record: " + exc);
    409                 } finally {
    410                     // Count up record load responses even if they are fails
    411                     onRecordLoaded();
    412                 }
    413                 break;
    414 
    415             default:
    416                 super.handleMessage(msg);
    417         }
    418     }
    419 
    420     protected abstract void onRecordLoaded();
    421 
    422     protected abstract void onAllRecordsLoaded();
    423 
    424     /**
    425      * Returns the SpnDisplayRule based on settings on the SIM and the
    426      * specified plmn (currently-registered PLMN).  See TS 22.101 Annex A
    427      * and TS 51.011 10.3.11 for details.
    428      *
    429      * If the SPN is not found on the SIM, the rule is always PLMN_ONLY.
    430      * Generally used for GSM/UMTS and the like SIMs.
    431      */
    432     public abstract int getDisplayRule(String plmn);
    433 
    434     /**
    435      * Return true if "Restriction of menu options for manual PLMN selection"
    436      * bit is set or EF_CSP data is unavailable, return false otherwise.
    437      * Generally used for GSM/UMTS and the like SIMs.
    438      */
    439     public boolean isCspPlmnEnabled() {
    440         return false;
    441     }
    442 
    443     /**
    444      * Returns the 5 or 6 digit MCC/MNC of the operator that
    445      * provided the SIM card. Returns null of SIM is not yet ready
    446      * or is not valid for the type of IccCard. Generally used for
    447      * GSM/UMTS and the like SIMS
    448      */
    449     public String getOperatorNumeric() {
    450         return null;
    451     }
    452 
    453     /**
    454      * Get the current Voice call forwarding flag for GSM/UMTS and the like SIMs
    455      *
    456      * @return true if enabled
    457      */
    458     public boolean getVoiceCallForwardingFlag() {
    459         return false;
    460     }
    461 
    462     /**
    463      * Set the voice call forwarding flag for GSM/UMTS and the like SIMs
    464      *
    465      * @param line to enable/disable
    466      * @param enable
    467      */
    468     public void setVoiceCallForwardingFlag(int line, boolean enable) {
    469     }
    470 
    471     /**
    472      * Indicates wether SIM is in provisioned state or not.
    473      * Overridden only if SIM can be dynamically provisioned via OTA.
    474      *
    475      * @return true if provisioned
    476      */
    477     public boolean isProvisioned () {
    478         return true;
    479     }
    480 
    481     /**
    482      * Write string to log file
    483      *
    484      * @param s is the string to write
    485      */
    486     protected abstract void log(String s);
    487 
    488     /**
    489      * Write error string to log file.
    490      *
    491      * @param s is the string to write
    492      */
    493     protected abstract void loge(String s);
    494 
    495     /**
    496      * Return an interface to retrieve the ISIM records for IMS, if available.
    497      * @return the interface to retrieve the ISIM records, or null if not supported
    498      */
    499     public IsimRecords getIsimRecords() {
    500         return null;
    501     }
    502 
    503     public UsimServiceTable getUsimServiceTable() {
    504         return null;
    505     }
    506 
    507     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    508         pw.println("IccRecords: " + this);
    509         pw.println(" mDestroyed=" + mDestroyed);
    510         pw.println(" mCi=" + mCi);
    511         pw.println(" mFh=" + mFh);
    512         pw.println(" mParentApp=" + mParentApp);
    513         pw.println(" recordsLoadedRegistrants: size=" + mRecordsLoadedRegistrants.size());
    514         for (int i = 0; i < mRecordsLoadedRegistrants.size(); i++) {
    515             pw.println("  recordsLoadedRegistrants[" + i + "]="
    516                     + ((Registrant)mRecordsLoadedRegistrants.get(i)).getHandler());
    517         }
    518         pw.println(" mImsiReadyRegistrants: size=" + mImsiReadyRegistrants.size());
    519         for (int i = 0; i < mImsiReadyRegistrants.size(); i++) {
    520             pw.println("  mImsiReadyRegistrants[" + i + "]="
    521                     + ((Registrant)mImsiReadyRegistrants.get(i)).getHandler());
    522         }
    523         pw.println(" mRecordsEventsRegistrants: size=" + mRecordsEventsRegistrants.size());
    524         for (int i = 0; i < mRecordsEventsRegistrants.size(); i++) {
    525             pw.println("  mRecordsEventsRegistrants[" + i + "]="
    526                     + ((Registrant)mRecordsEventsRegistrants.get(i)).getHandler());
    527         }
    528         pw.println(" mNewSmsRegistrants: size=" + mNewSmsRegistrants.size());
    529         for (int i = 0; i < mNewSmsRegistrants.size(); i++) {
    530             pw.println("  mNewSmsRegistrants[" + i + "]="
    531                     + ((Registrant)mNewSmsRegistrants.get(i)).getHandler());
    532         }
    533         pw.println(" mNetworkSelectionModeAutomaticRegistrants: size="
    534                 + mNetworkSelectionModeAutomaticRegistrants.size());
    535         for (int i = 0; i < mNetworkSelectionModeAutomaticRegistrants.size(); i++) {
    536             pw.println("  mNetworkSelectionModeAutomaticRegistrants[" + i + "]="
    537                     + ((Registrant)mNetworkSelectionModeAutomaticRegistrants.get(i)).getHandler());
    538         }
    539         pw.println(" mRecordsRequested=" + mRecordsRequested);
    540         pw.println(" mRecordsToLoad=" + mRecordsToLoad);
    541         pw.println(" mRdnCache=" + mAdnCache);
    542         pw.println(" iccid=" + mIccId);
    543         pw.println(" mMsisdn=" + mMsisdn);
    544         pw.println(" mMsisdnTag=" + mMsisdnTag);
    545         pw.println(" mVoiceMailNum=" + mVoiceMailNum);
    546         pw.println(" mVoiceMailTag=" + mVoiceMailTag);
    547         pw.println(" mNewVoiceMailNum=" + mNewVoiceMailNum);
    548         pw.println(" mNewVoiceMailTag=" + mNewVoiceMailTag);
    549         pw.println(" mIsVoiceMailFixed=" + mIsVoiceMailFixed);
    550         pw.println(" mCountVoiceMessages=" + mCountVoiceMessages);
    551         pw.println(" mImsi=" + mImsi);
    552         pw.println(" mMncLength=" + mMncLength);
    553         pw.println(" mMailboxIndex=" + mMailboxIndex);
    554         pw.println(" mSpn=" + mSpn);
    555         pw.flush();
    556     }
    557 }
    558