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 static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
     20 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
     21 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
     22 import android.content.Context;
     23 import android.os.AsyncResult;
     24 import android.os.Message;
     25 import android.os.SystemProperties;
     26 import android.telephony.PhoneNumberUtils;
     27 import android.telephony.SmsMessage;
     28 import android.text.TextUtils;
     29 import android.telephony.Rlog;
     30 
     31 import com.android.internal.telephony.CommandsInterface;
     32 import com.android.internal.telephony.MccTable;
     33 import com.android.internal.telephony.SmsConstants;
     34 import com.android.internal.telephony.gsm.SimTlv;
     35 
     36 import java.io.FileDescriptor;
     37 import java.io.PrintWriter;
     38 import java.util.ArrayList;
     39 import java.util.Arrays;
     40 
     41 /**
     42  * {@hide}
     43  */
     44 public class SIMRecords extends IccRecords {
     45     protected static final String LOG_TAG = "SIMRecords";
     46 
     47     private static final boolean CRASH_RIL = false;
     48 
     49     // ***** Instance Variables
     50 
     51     VoiceMailConstants mVmConfig;
     52 
     53 
     54     SpnOverride mSpnOverride;
     55 
     56     // ***** Cached SIM State; cleared on channel close
     57 
     58     private boolean mCallForwardingEnabled;
     59 
     60 
     61     /**
     62      * States only used by getSpnFsm FSM
     63      */
     64     private GetSpnFsmState mSpnState;
     65 
     66     /** CPHS service information (See CPHS 4.2 B.3.1.1)
     67      *  It will be set in onSimReady if reading GET_CPHS_INFO successfully
     68      *  mCphsInfo[0] is CPHS Phase
     69      *  mCphsInfo[1] and mCphsInfo[2] is CPHS Service Table
     70      */
     71     private byte[] mCphsInfo = null;
     72     boolean mCspPlmnEnabled = true;
     73 
     74     byte[] mEfMWIS = null;
     75     byte[] mEfCPHS_MWI =null;
     76     byte[] mEfCff = null;
     77     byte[] mEfCfis = null;
     78 
     79 
     80     int mSpnDisplayCondition;
     81     // Numeric network codes listed in TS 51.011 EF[SPDI]
     82     ArrayList<String> mSpdiNetworks = null;
     83 
     84     String mPnnHomeName = null;
     85 
     86     UsimServiceTable mUsimServiceTable;
     87 
     88     @Override
     89     public String toString() {
     90         return "SimRecords: " + super.toString()
     91                 + " mVmConfig" + mVmConfig
     92                 + " mSpnOverride=" + "mSpnOverride"
     93                 + " callForwardingEnabled=" + mCallForwardingEnabled
     94                 + " spnState=" + mSpnState
     95                 + " mCphsInfo=" + mCphsInfo
     96                 + " mCspPlmnEnabled=" + mCspPlmnEnabled
     97                 + " efMWIS=" + mEfMWIS
     98                 + " efCPHS_MWI=" + mEfCPHS_MWI
     99                 + " mEfCff=" + mEfCff
    100                 + " mEfCfis=" + mEfCfis
    101                 + " getOperatorNumeric=" + getOperatorNumeric();
    102     }
    103 
    104     // ***** Constants
    105 
    106     // From TS 51.011 EF[SPDI] section
    107     static final int TAG_SPDI = 0xA3;
    108     static final int TAG_SPDI_PLMN_LIST = 0x80;
    109 
    110     // Full Name IEI from TS 24.008
    111     static final int TAG_FULL_NETWORK_NAME = 0x43;
    112 
    113     // Short Name IEI from TS 24.008
    114     static final int TAG_SHORT_NETWORK_NAME = 0x45;
    115 
    116     // active CFF from CPHS 4.2 B.4.5
    117     static final int CFF_UNCONDITIONAL_ACTIVE = 0x0a;
    118     static final int CFF_UNCONDITIONAL_DEACTIVE = 0x05;
    119     static final int CFF_LINE1_MASK = 0x0f;
    120     static final int CFF_LINE1_RESET = 0xf0;
    121 
    122     // CPHS Service Table (See CPHS 4.2 B.3.1)
    123     private static final int CPHS_SST_MBN_MASK = 0x30;
    124     private static final int CPHS_SST_MBN_ENABLED = 0x30;
    125 
    126     // EF_CFIS related constants
    127     // Spec reference TS 51.011 section 10.3.46.
    128     private static final int CFIS_BCD_NUMBER_LENGTH_OFFSET = 2;
    129     private static final int CFIS_TON_NPI_OFFSET = 3;
    130     private static final int CFIS_ADN_CAPABILITY_ID_OFFSET = 14;
    131     private static final int CFIS_ADN_EXTENSION_ID_OFFSET = 15;
    132 
    133     // ***** Event Constants
    134     private static final int EVENT_GET_IMSI_DONE = 3;
    135     private static final int EVENT_GET_ICCID_DONE = 4;
    136     private static final int EVENT_GET_MBI_DONE = 5;
    137     private static final int EVENT_GET_MBDN_DONE = 6;
    138     private static final int EVENT_GET_MWIS_DONE = 7;
    139     private static final int EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE = 8;
    140     protected static final int EVENT_GET_AD_DONE = 9; // Admin data on SIM
    141     protected static final int EVENT_GET_MSISDN_DONE = 10;
    142     private static final int EVENT_GET_CPHS_MAILBOX_DONE = 11;
    143     private static final int EVENT_GET_SPN_DONE = 12;
    144     private static final int EVENT_GET_SPDI_DONE = 13;
    145     private static final int EVENT_UPDATE_DONE = 14;
    146     private static final int EVENT_GET_PNN_DONE = 15;
    147     protected static final int EVENT_GET_SST_DONE = 17;
    148     private static final int EVENT_GET_ALL_SMS_DONE = 18;
    149     private static final int EVENT_MARK_SMS_READ_DONE = 19;
    150     private static final int EVENT_SET_MBDN_DONE = 20;
    151     private static final int EVENT_SMS_ON_SIM = 21;
    152     private static final int EVENT_GET_SMS_DONE = 22;
    153     private static final int EVENT_GET_CFF_DONE = 24;
    154     private static final int EVENT_SET_CPHS_MAILBOX_DONE = 25;
    155     private static final int EVENT_GET_INFO_CPHS_DONE = 26;
    156     // private static final int EVENT_SET_MSISDN_DONE = 30; Defined in IccRecords as 30
    157     private static final int EVENT_SIM_REFRESH = 31;
    158     private static final int EVENT_GET_CFIS_DONE = 32;
    159     private static final int EVENT_GET_CSP_CPHS_DONE = 33;
    160     private static final int EVENT_GET_GID1_DONE = 34;
    161 
    162     // Lookup table for carriers known to produce SIMs which incorrectly indicate MNC length.
    163 
    164     private static final String[] MCCMNC_CODES_HAVING_3DIGITS_MNC = {
    165         "302370", "302720", "310260",
    166         "405025", "405026", "405027", "405028", "405029", "405030", "405031", "405032",
    167         "405033", "405034", "405035", "405036", "405037", "405038", "405039", "405040",
    168         "405041", "405042", "405043", "405044", "405045", "405046", "405047", "405750",
    169         "405751", "405752", "405753", "405754", "405755", "405756", "405799", "405800",
    170         "405801", "405802", "405803", "405804", "405805", "405806", "405807", "405808",
    171         "405809", "405810", "405811", "405812", "405813", "405814", "405815", "405816",
    172         "405817", "405818", "405819", "405820", "405821", "405822", "405823", "405824",
    173         "405825", "405826", "405827", "405828", "405829", "405830", "405831", "405832",
    174         "405833", "405834", "405835", "405836", "405837", "405838", "405839", "405840",
    175         "405841", "405842", "405843", "405844", "405845", "405846", "405847", "405848",
    176         "405849", "405850", "405851", "405852", "405853", "405875", "405876", "405877",
    177         "405878", "405879", "405880", "405881", "405882", "405883", "405884", "405885",
    178         "405886", "405908", "405909", "405910", "405911", "405912", "405913", "405914",
    179         "405915", "405916", "405917", "405918", "405919", "405920", "405921", "405922",
    180         "405923", "405924", "405925", "405926", "405927", "405928", "405929", "405930",
    181         "405931", "405932", "502142", "502143", "502145", "502146", "502147", "502148"
    182     };
    183 
    184     // ***** Constructor
    185 
    186     public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) {
    187         super(app, c, ci);
    188 
    189         mAdnCache = new AdnRecordCache(mFh);
    190 
    191         mVmConfig = new VoiceMailConstants();
    192         mSpnOverride = new SpnOverride();
    193 
    194         mRecordsRequested = false;  // No load request is made till SIM ready
    195 
    196         // recordsToLoad is set to 0 because no requests are made yet
    197         mRecordsToLoad = 0;
    198 
    199         mCi.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null);
    200         mCi.registerForIccRefresh(this, EVENT_SIM_REFRESH, null);
    201 
    202         // Start off by setting empty state
    203         resetRecords();
    204         mParentApp.registerForReady(this, EVENT_APP_READY, null);
    205         if (DBG) log("SIMRecords X ctor this=" + this);
    206     }
    207 
    208     @Override
    209     public void dispose() {
    210         if (DBG) log("Disposing SIMRecords this=" + this);
    211         //Unregister for all events
    212         mCi.unregisterForIccRefresh(this);
    213         mCi.unSetOnSmsOnSim(this);
    214         mParentApp.unregisterForReady(this);
    215         resetRecords();
    216         super.dispose();
    217     }
    218 
    219     @Override
    220     protected void finalize() {
    221         if(DBG) log("finalized");
    222     }
    223 
    224     protected void resetRecords() {
    225         mImsi = null;
    226         mMsisdn = null;
    227         mVoiceMailNum = null;
    228         mCountVoiceMessages = 0;
    229         mMncLength = UNINITIALIZED;
    230         mIccId = null;
    231         // -1 means no EF_SPN found; treat accordingly.
    232         mSpnDisplayCondition = -1;
    233         mEfMWIS = null;
    234         mEfCPHS_MWI = null;
    235         mSpdiNetworks = null;
    236         mPnnHomeName = null;
    237         mGid1 = null;
    238 
    239         mAdnCache.reset();
    240 
    241         log("SIMRecords: onRadioOffOrNotAvailable set 'gsm.sim.operator.numeric' to operator=null");
    242         SystemProperties.set(PROPERTY_ICC_OPERATOR_NUMERIC, null);
    243         SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, null);
    244         SystemProperties.set(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, null);
    245 
    246         // recordsRequested is set to false indicating that the SIM
    247         // read requests made so far are not valid. This is set to
    248         // true only when fresh set of read requests are made.
    249         mRecordsRequested = false;
    250     }
    251 
    252 
    253     //***** Public Methods
    254 
    255     /**
    256      * {@inheritDoc}
    257      */
    258     @Override
    259     public String getIMSI() {
    260         return mImsi;
    261     }
    262 
    263     @Override
    264     public String getMsisdnNumber() {
    265         return mMsisdn;
    266     }
    267 
    268     @Override
    269     public String getGid1() {
    270         return mGid1;
    271     }
    272 
    273     @Override
    274     public UsimServiceTable getUsimServiceTable() {
    275         return mUsimServiceTable;
    276     }
    277 
    278     /**
    279      * Set subscriber number to SIM record
    280      *
    281      * The subscriber number is stored in EF_MSISDN (TS 51.011)
    282      *
    283      * When the operation is complete, onComplete will be sent to its handler
    284      *
    285      * @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters)
    286      * @param number dailing nubmer (up to 20 digits)
    287      *        if the number starts with '+', then set to international TOA
    288      * @param onComplete
    289      *        onComplete.obj will be an AsyncResult
    290      *        ((AsyncResult)onComplete.obj).exception == null on success
    291      *        ((AsyncResult)onComplete.obj).exception != null on fail
    292      */
    293     @Override
    294     public void setMsisdnNumber(String alphaTag, String number,
    295             Message onComplete) {
    296 
    297         mMsisdn = number;
    298         mMsisdnTag = alphaTag;
    299 
    300         if(DBG) log("Set MSISDN: " + mMsisdnTag + " " + /*mMsisdn*/ "xxxxxxx");
    301 
    302 
    303         AdnRecord adn = new AdnRecord(mMsisdnTag, mMsisdn);
    304 
    305         new AdnRecordLoader(mFh).updateEF(adn, EF_MSISDN, EF_EXT1, 1, null,
    306                 obtainMessage(EVENT_SET_MSISDN_DONE, onComplete));
    307     }
    308 
    309     @Override
    310     public String getMsisdnAlphaTag() {
    311         return mMsisdnTag;
    312     }
    313 
    314     @Override
    315     public String getVoiceMailNumber() {
    316         return mVoiceMailNum;
    317     }
    318 
    319     /**
    320      * Set voice mail number to SIM record
    321      *
    322      * The voice mail number can be stored either in EF_MBDN (TS 51.011) or
    323      * EF_MAILBOX_CPHS (CPHS 4.2)
    324      *
    325      * If EF_MBDN is available, store the voice mail number to EF_MBDN
    326      *
    327      * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS
    328      *
    329      * So the voice mail number will be stored in both EFs if both are available
    330      *
    331      * Return error only if both EF_MBDN and EF_MAILBOX_CPHS fail.
    332      *
    333      * When the operation is complete, onComplete will be sent to its handler
    334      *
    335      * @param alphaTag alpha-tagging of the dailing nubmer (upto 10 characters)
    336      * @param voiceNumber dailing nubmer (upto 20 digits)
    337      *        if the number is start with '+', then set to international TOA
    338      * @param onComplete
    339      *        onComplete.obj will be an AsyncResult
    340      *        ((AsyncResult)onComplete.obj).exception == null on success
    341      *        ((AsyncResult)onComplete.obj).exception != null on fail
    342      */
    343     @Override
    344     public void setVoiceMailNumber(String alphaTag, String voiceNumber,
    345             Message onComplete) {
    346         if (mIsVoiceMailFixed) {
    347             AsyncResult.forMessage((onComplete)).exception =
    348                     new IccVmFixedException("Voicemail number is fixed by operator");
    349             onComplete.sendToTarget();
    350             return;
    351         }
    352 
    353         mNewVoiceMailNum = voiceNumber;
    354         mNewVoiceMailTag = alphaTag;
    355 
    356         AdnRecord adn = new AdnRecord(mNewVoiceMailTag, mNewVoiceMailNum);
    357 
    358         if (mMailboxIndex != 0 && mMailboxIndex != 0xff) {
    359 
    360             new AdnRecordLoader(mFh).updateEF(adn, EF_MBDN, EF_EXT6,
    361                     mMailboxIndex, null,
    362                     obtainMessage(EVENT_SET_MBDN_DONE, onComplete));
    363 
    364         } else if (isCphsMailboxEnabled()) {
    365 
    366             new AdnRecordLoader(mFh).updateEF(adn, EF_MAILBOX_CPHS,
    367                     EF_EXT1, 1, null,
    368                     obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE, onComplete));
    369 
    370         } else {
    371             AsyncResult.forMessage((onComplete)).exception =
    372                     new IccVmNotSupportedException("Update SIM voice mailbox error");
    373             onComplete.sendToTarget();
    374         }
    375     }
    376 
    377     @Override
    378     public String getVoiceMailAlphaTag()
    379     {
    380         return mVoiceMailTag;
    381     }
    382 
    383     /**
    384      * Sets the SIM voice message waiting indicator records
    385      * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
    386      * @param countWaiting The number of messages waiting, if known. Use
    387      *                     -1 to indicate that an unknown number of
    388      *                      messages are waiting
    389      */
    390     @Override
    391     public void
    392     setVoiceMessageWaiting(int line, int countWaiting) {
    393         if (line != 1) {
    394             // only profile 1 is supported
    395             return;
    396         }
    397 
    398         // range check
    399         if (countWaiting < 0) {
    400             countWaiting = -1;
    401         } else if (countWaiting > 0xff) {
    402             // TS 23.040 9.2.3.24.2
    403             // "The value 255 shall be taken to mean 255 or greater"
    404             countWaiting = 0xff;
    405         }
    406 
    407         mCountVoiceMessages = countWaiting;
    408 
    409         mRecordsEventsRegistrants.notifyResult(EVENT_MWI);
    410 
    411         try {
    412             if (mEfMWIS != null) {
    413                 // TS 51.011 10.3.45
    414 
    415                 // lsb of byte 0 is 'voicemail' status
    416                 mEfMWIS[0] = (byte)((mEfMWIS[0] & 0xfe)
    417                                     | (mCountVoiceMessages == 0 ? 0 : 1));
    418 
    419                 // byte 1 is the number of voice messages waiting
    420                 if (countWaiting < 0) {
    421                     // The spec does not define what this should be
    422                     // if we don't know the count
    423                     mEfMWIS[1] = 0;
    424                 } else {
    425                     mEfMWIS[1] = (byte) countWaiting;
    426                 }
    427 
    428                 mFh.updateEFLinearFixed(
    429                     EF_MWIS, 1, mEfMWIS, null,
    430                     obtainMessage (EVENT_UPDATE_DONE, EF_MWIS));
    431             }
    432 
    433             if (mEfCPHS_MWI != null) {
    434                     // Refer CPHS4_2.WW6 B4.2.3
    435                 mEfCPHS_MWI[0] = (byte)((mEfCPHS_MWI[0] & 0xf0)
    436                             | (mCountVoiceMessages == 0 ? 0x5 : 0xa));
    437 
    438                 mFh.updateEFTransparent(
    439                     EF_VOICE_MAIL_INDICATOR_CPHS, mEfCPHS_MWI,
    440                     obtainMessage (EVENT_UPDATE_DONE, EF_VOICE_MAIL_INDICATOR_CPHS));
    441             }
    442         } catch (ArrayIndexOutOfBoundsException ex) {
    443             logw("Error saving voice mail state to SIM. Probably malformed SIM record", ex);
    444         }
    445     }
    446 
    447     // Validate data is !null and the MSP (Multiple Subscriber Profile)
    448     // byte is between 1 and 4. See ETSI TS 131 102 v11.3.0 section 4.2.64.
    449     private boolean validEfCfis(byte[] data) {
    450         return ((data != null) && (data[0] >= 1) && (data[0] <= 4));
    451     }
    452 
    453     /**
    454      * {@inheritDoc}
    455      */
    456     @Override
    457     public boolean getVoiceCallForwardingFlag() {
    458         return mCallForwardingEnabled;
    459     }
    460 
    461     /**
    462      * {@inheritDoc}
    463      */
    464     @Override
    465     public void setVoiceCallForwardingFlag(int line, boolean enable, String dialNumber) {
    466 
    467         if (line != 1) return; // only line 1 is supported
    468 
    469         mCallForwardingEnabled = enable;
    470 
    471         mRecordsEventsRegistrants.notifyResult(EVENT_CFI);
    472 
    473         try {
    474             if (validEfCfis(mEfCfis)) {
    475                 // lsb is of byte 1 is voice status
    476                 if (enable) {
    477                     mEfCfis[1] |= 1;
    478                 } else {
    479                     mEfCfis[1] &= 0xfe;
    480                 }
    481 
    482                 log("setVoiceCallForwardingFlag: enable=" + enable
    483                         + " mEfCfis=" + IccUtils.bytesToHexString(mEfCfis));
    484 
    485                 // Update dialNumber if not empty and CFU is enabled.
    486                 // Spec reference for EF_CFIS contents, TS 51.011 section 10.3.46.
    487                 if (enable && !TextUtils.isEmpty(dialNumber)) {
    488                     log("EF_CFIS: updating cf number, " + dialNumber);
    489                     byte[] bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(dialNumber);
    490 
    491                     System.arraycopy(bcdNumber, 0, mEfCfis, CFIS_TON_NPI_OFFSET, bcdNumber.length);
    492 
    493                     mEfCfis[CFIS_BCD_NUMBER_LENGTH_OFFSET] = (byte) (bcdNumber.length);
    494                     mEfCfis[CFIS_ADN_CAPABILITY_ID_OFFSET] = (byte) 0xFF;
    495                     mEfCfis[CFIS_ADN_EXTENSION_ID_OFFSET] = (byte) 0xFF;
    496                 }
    497 
    498                 mFh.updateEFLinearFixed(
    499                         EF_CFIS, 1, mEfCfis, null,
    500                         obtainMessage (EVENT_UPDATE_DONE, EF_CFIS));
    501             } else {
    502                 log("setVoiceCallForwardingFlag: ignoring enable=" + enable
    503                         + " invalid mEfCfis=" + IccUtils.bytesToHexString(mEfCfis));
    504             }
    505 
    506             if (mEfCff != null) {
    507                 if (enable) {
    508                     mEfCff[0] = (byte) ((mEfCff[0] & CFF_LINE1_RESET)
    509                             | CFF_UNCONDITIONAL_ACTIVE);
    510                 } else {
    511                     mEfCff[0] = (byte) ((mEfCff[0] & CFF_LINE1_RESET)
    512                             | CFF_UNCONDITIONAL_DEACTIVE);
    513                 }
    514 
    515                 mFh.updateEFTransparent(
    516                         EF_CFF_CPHS, mEfCff,
    517                         obtainMessage (EVENT_UPDATE_DONE, EF_CFF_CPHS));
    518             }
    519         } catch (ArrayIndexOutOfBoundsException ex) {
    520             logw("Error saving call forwarding flag to SIM. "
    521                             + "Probably malformed SIM record", ex);
    522 
    523         }
    524     }
    525 
    526     /**
    527      * Called by STK Service when REFRESH is received.
    528      * @param fileChanged indicates whether any files changed
    529      * @param fileList if non-null, a list of EF files that changed
    530      */
    531     @Override
    532     public void onRefresh(boolean fileChanged, int[] fileList) {
    533         if (fileChanged) {
    534             // A future optimization would be to inspect fileList and
    535             // only reload those files that we care about.  For now,
    536             // just re-fetch all SIM records that we cache.
    537             fetchSimRecords();
    538         }
    539     }
    540 
    541     /**
    542      * {@inheritDoc}
    543      */
    544     @Override
    545     public String getOperatorNumeric() {
    546         if (mImsi == null) {
    547             log("getOperatorNumeric: IMSI == null");
    548             return null;
    549         }
    550         if (mMncLength == UNINITIALIZED || mMncLength == UNKNOWN) {
    551             log("getSIMOperatorNumeric: bad mncLength");
    552             return null;
    553         }
    554 
    555         // Length = length of MCC + length of MNC
    556         // length of mcc = 3 (TS 23.003 Section 2.2)
    557         return mImsi.substring(0, 3 + mMncLength);
    558     }
    559 
    560     // ***** Overridden from Handler
    561     @Override
    562     public void handleMessage(Message msg) {
    563         AsyncResult ar;
    564         AdnRecord adn;
    565 
    566         byte data[];
    567 
    568         boolean isRecordLoadResponse = false;
    569 
    570         if (mDestroyed.get()) {
    571             loge("Received message " + msg + "[" + msg.what + "] " +
    572                     " while being destroyed. Ignoring.");
    573             return;
    574         }
    575 
    576         try { switch (msg.what) {
    577             case EVENT_APP_READY:
    578                 onReady();
    579                 break;
    580 
    581             /* IO events */
    582             case EVENT_GET_IMSI_DONE:
    583                 isRecordLoadResponse = true;
    584 
    585                 ar = (AsyncResult)msg.obj;
    586 
    587                 if (ar.exception != null) {
    588                     loge("Exception querying IMSI, Exception:" + ar.exception);
    589                     break;
    590                 }
    591 
    592                 mImsi = (String) ar.result;
    593 
    594                 // IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more
    595                 // than 15 (and usually 15).
    596                 if (mImsi != null && (mImsi.length() < 6 || mImsi.length() > 15)) {
    597                     loge("invalid IMSI " + mImsi);
    598                     mImsi = null;
    599                 }
    600 
    601                 log("IMSI: " + /* imsi.substring(0, 6) +*/ "xxxxxxx");
    602 
    603                 if (((mMncLength == UNKNOWN) || (mMncLength == 2)) &&
    604                         ((mImsi != null) && (mImsi.length() >= 6))) {
    605                     String mccmncCode = mImsi.substring(0, 6);
    606                     for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) {
    607                         if (mccmnc.equals(mccmncCode)) {
    608                             mMncLength = 3;
    609                             break;
    610                         }
    611                     }
    612                 }
    613 
    614                 if (mMncLength == UNKNOWN) {
    615                     // the SIM has told us all it knows, but it didn't know the mnc length.
    616                     // guess using the mcc
    617                     try {
    618                         int mcc = Integer.parseInt(mImsi.substring(0,3));
    619                         mMncLength = MccTable.smallestDigitsMccForMnc(mcc);
    620                     } catch (NumberFormatException e) {
    621                         mMncLength = UNKNOWN;
    622                         loge("Corrupt IMSI!");
    623                     }
    624                 }
    625 
    626                 if (mMncLength != UNKNOWN && mMncLength != UNINITIALIZED) {
    627                     // finally have both the imsi and the mncLength and can parse the imsi properly
    628                     MccTable.updateMccMncConfiguration(mContext, mImsi.substring(0, 3 + mMncLength));
    629                 }
    630                 mImsiReadyRegistrants.notifyRegistrants();
    631             break;
    632 
    633             case EVENT_GET_MBI_DONE:
    634                 boolean isValidMbdn;
    635                 isRecordLoadResponse = true;
    636 
    637                 ar = (AsyncResult)msg.obj;
    638                 data = (byte[]) ar.result;
    639 
    640                 isValidMbdn = false;
    641                 if (ar.exception == null) {
    642                     // Refer TS 51.011 Section 10.3.44 for content details
    643                     log("EF_MBI: " + IccUtils.bytesToHexString(data));
    644 
    645                     // Voice mail record number stored first
    646                     mMailboxIndex = data[0] & 0xff;
    647 
    648                     // check if dailing numbe id valid
    649                     if (mMailboxIndex != 0 && mMailboxIndex != 0xff) {
    650                         log("Got valid mailbox number for MBDN");
    651                         isValidMbdn = true;
    652                     }
    653                 }
    654 
    655                 // one more record to load
    656                 mRecordsToLoad += 1;
    657 
    658                 if (isValidMbdn) {
    659                     // Note: MBDN was not included in NUM_OF_SIM_RECORDS_LOADED
    660                     new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6,
    661                             mMailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
    662                 } else {
    663                     // If this EF not present, try mailbox as in CPHS standard
    664                     // CPHS (CPHS4_2.WW6) is a european standard.
    665                     new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS,
    666                             EF_EXT1, 1,
    667                             obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
    668                 }
    669 
    670                 break;
    671             case EVENT_GET_CPHS_MAILBOX_DONE:
    672             case EVENT_GET_MBDN_DONE:
    673                 //Resetting the voice mail number and voice mail tag to null
    674                 //as these should be updated from the data read from EF_MBDN.
    675                 //If they are not reset, incase of invalid data/exception these
    676                 //variables are retaining their previous values and are
    677                 //causing invalid voice mailbox info display to user.
    678                 mVoiceMailNum = null;
    679                 mVoiceMailTag = null;
    680                 isRecordLoadResponse = true;
    681 
    682                 ar = (AsyncResult)msg.obj;
    683 
    684                 if (ar.exception != null) {
    685 
    686                     log("Invalid or missing EF"
    687                         + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? "[MAILBOX]" : "[MBDN]"));
    688 
    689                     // Bug #645770 fall back to CPHS
    690                     // FIXME should use SST to decide
    691 
    692                     if (msg.what == EVENT_GET_MBDN_DONE) {
    693                         //load CPHS on fail...
    694                         // FIXME right now, only load line1's CPHS voice mail entry
    695 
    696                         mRecordsToLoad += 1;
    697                         new AdnRecordLoader(mFh).loadFromEF(
    698                                 EF_MAILBOX_CPHS, EF_EXT1, 1,
    699                                 obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
    700                     }
    701                     break;
    702                 }
    703 
    704                 adn = (AdnRecord)ar.result;
    705 
    706                 log("VM: " + adn +
    707                         ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? " EF[MAILBOX]" : " EF[MBDN]"));
    708 
    709                 if (adn.isEmpty() && msg.what == EVENT_GET_MBDN_DONE) {
    710                     // Bug #645770 fall back to CPHS
    711                     // FIXME should use SST to decide
    712                     // FIXME right now, only load line1's CPHS voice mail entry
    713                     mRecordsToLoad += 1;
    714                     new AdnRecordLoader(mFh).loadFromEF(
    715                             EF_MAILBOX_CPHS, EF_EXT1, 1,
    716                             obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
    717 
    718                     break;
    719                 }
    720 
    721                 mVoiceMailNum = adn.getNumber();
    722                 mVoiceMailTag = adn.getAlphaTag();
    723             break;
    724 
    725             case EVENT_GET_MSISDN_DONE:
    726                 isRecordLoadResponse = true;
    727 
    728                 ar = (AsyncResult)msg.obj;
    729 
    730                 if (ar.exception != null) {
    731                     log("Invalid or missing EF[MSISDN]");
    732                     break;
    733                 }
    734 
    735                 adn = (AdnRecord)ar.result;
    736 
    737                 mMsisdn = adn.getNumber();
    738                 mMsisdnTag = adn.getAlphaTag();
    739 
    740                 log("MSISDN: " + /*mMsisdn*/ "xxxxxxx");
    741             break;
    742 
    743             case EVENT_SET_MSISDN_DONE:
    744                 isRecordLoadResponse = false;
    745                 ar = (AsyncResult)msg.obj;
    746 
    747                 if (ar.userObj != null) {
    748                     AsyncResult.forMessage(((Message) ar.userObj)).exception
    749                             = ar.exception;
    750                     ((Message) ar.userObj).sendToTarget();
    751                 }
    752                 break;
    753 
    754             case EVENT_GET_MWIS_DONE:
    755                 isRecordLoadResponse = true;
    756 
    757                 ar = (AsyncResult)msg.obj;
    758                 data = (byte[])ar.result;
    759 
    760                 if (ar.exception != null) {
    761                     break;
    762                 }
    763 
    764                 log("EF_MWIS: " + IccUtils.bytesToHexString(data));
    765 
    766                 mEfMWIS = data;
    767 
    768                 if ((data[0] & 0xff) == 0xff) {
    769                     log("Uninitialized record MWIS");
    770                     break;
    771                 }
    772 
    773                 // Refer TS 51.011 Section 10.3.45 for the content description
    774                 boolean voiceMailWaiting = ((data[0] & 0x01) != 0);
    775                 mCountVoiceMessages = data[1] & 0xff;
    776 
    777                 if (voiceMailWaiting && mCountVoiceMessages == 0) {
    778                     // Unknown count = -1
    779                     mCountVoiceMessages = -1;
    780                 }
    781 
    782                 mRecordsEventsRegistrants.notifyResult(EVENT_MWI);
    783             break;
    784 
    785             case EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE:
    786                 isRecordLoadResponse = true;
    787 
    788                 ar = (AsyncResult)msg.obj;
    789                 data = (byte[])ar.result;
    790 
    791                 if (ar.exception != null) {
    792                     break;
    793                 }
    794 
    795                 mEfCPHS_MWI = data;
    796 
    797                 // Use this data if the EF[MWIS] exists and
    798                 // has been loaded
    799 
    800                 if (mEfMWIS == null) {
    801                     int indicator = data[0] & 0xf;
    802 
    803                     // Refer CPHS4_2.WW6 B4.2.3
    804                     if (indicator == 0xA) {
    805                         // Unknown count = -1
    806                         mCountVoiceMessages = -1;
    807                     } else if (indicator == 0x5) {
    808                         mCountVoiceMessages = 0;
    809                     }
    810 
    811                     mRecordsEventsRegistrants.notifyResult(EVENT_MWI);
    812                 }
    813             break;
    814 
    815             case EVENT_GET_ICCID_DONE:
    816                 isRecordLoadResponse = true;
    817 
    818                 ar = (AsyncResult)msg.obj;
    819                 data = (byte[])ar.result;
    820 
    821                 if (ar.exception != null) {
    822                     break;
    823                 }
    824 
    825                 mIccId = IccUtils.bcdToString(data, 0, data.length);
    826 
    827                 log("iccid: " + mIccId);
    828 
    829             break;
    830 
    831 
    832             case EVENT_GET_AD_DONE:
    833                 try {
    834                     isRecordLoadResponse = true;
    835 
    836                     ar = (AsyncResult)msg.obj;
    837                     data = (byte[])ar.result;
    838 
    839                     if (ar.exception != null) {
    840                         break;
    841                     }
    842 
    843                     log("EF_AD: " + IccUtils.bytesToHexString(data));
    844 
    845                     if (data.length < 3) {
    846                         log("Corrupt AD data on SIM");
    847                         break;
    848                     }
    849 
    850                     if (data.length == 3) {
    851                         log("MNC length not present in EF_AD");
    852                         break;
    853                     }
    854 
    855                     mMncLength = data[3] & 0xf;
    856 
    857                     if (mMncLength == 0xf) {
    858                         mMncLength = UNKNOWN;
    859                     }
    860                 } finally {
    861                     if (((mMncLength == UNINITIALIZED) || (mMncLength == UNKNOWN) ||
    862                             (mMncLength == 2)) && ((mImsi != null) && (mImsi.length() >= 6))) {
    863                         String mccmncCode = mImsi.substring(0, 6);
    864                         for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) {
    865                             if (mccmnc.equals(mccmncCode)) {
    866                                 mMncLength = 3;
    867                                 break;
    868                             }
    869                         }
    870                     }
    871 
    872                     if (mMncLength == UNKNOWN || mMncLength == UNINITIALIZED) {
    873                         if (mImsi != null) {
    874                             try {
    875                                 int mcc = Integer.parseInt(mImsi.substring(0,3));
    876 
    877                                 mMncLength = MccTable.smallestDigitsMccForMnc(mcc);
    878                             } catch (NumberFormatException e) {
    879                                 mMncLength = UNKNOWN;
    880                                 loge("Corrupt IMSI!");
    881                             }
    882                         } else {
    883                             // Indicate we got this info, but it didn't contain the length.
    884                             mMncLength = UNKNOWN;
    885 
    886                             log("MNC length not present in EF_AD");
    887                         }
    888                     }
    889                     if (mImsi != null && mMncLength != UNKNOWN) {
    890                         // finally have both imsi and the length of the mnc and can parse
    891                         // the imsi properly
    892                         MccTable.updateMccMncConfiguration(mContext,
    893                                 mImsi.substring(0, 3 + mMncLength));
    894                     }
    895                 }
    896             break;
    897 
    898             case EVENT_GET_SPN_DONE:
    899                 isRecordLoadResponse = true;
    900                 ar = (AsyncResult) msg.obj;
    901                 getSpnFsm(false, ar);
    902             break;
    903 
    904             case EVENT_GET_CFF_DONE:
    905                 isRecordLoadResponse = true;
    906 
    907                 ar = (AsyncResult) msg.obj;
    908                 data = (byte[]) ar.result;
    909 
    910                 if (ar.exception != null) {
    911                     break;
    912                 }
    913 
    914                 log("EF_CFF_CPHS: " + IccUtils.bytesToHexString(data));
    915                 mEfCff = data;
    916 
    917                 // if EF_CFIS is valid, prefer it to EF_CFF_CPHS
    918                 if (!validEfCfis(mEfCfis)) {
    919                     mCallForwardingEnabled =
    920                         ((data[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE);
    921 
    922                     mRecordsEventsRegistrants.notifyResult(EVENT_CFI);
    923                 } else {
    924                     log("EVENT_GET_CFF_DONE: EF_CFIS is valid, ignoring EF_CFF_CPHS");
    925                 }
    926                 break;
    927 
    928             case EVENT_GET_SPDI_DONE:
    929                 isRecordLoadResponse = true;
    930 
    931                 ar = (AsyncResult)msg.obj;
    932                 data = (byte[])ar.result;
    933 
    934                 if (ar.exception != null) {
    935                     break;
    936                 }
    937 
    938                 parseEfSpdi(data);
    939             break;
    940 
    941             case EVENT_UPDATE_DONE:
    942                 ar = (AsyncResult)msg.obj;
    943                 if (ar.exception != null) {
    944                     logw("update failed. ", ar.exception);
    945                 }
    946             break;
    947 
    948             case EVENT_GET_PNN_DONE:
    949                 isRecordLoadResponse = true;
    950 
    951                 ar = (AsyncResult)msg.obj;
    952                 data = (byte[])ar.result;
    953 
    954                 if (ar.exception != null) {
    955                     break;
    956                 }
    957 
    958                 SimTlv tlv = new SimTlv(data, 0, data.length);
    959 
    960                 for ( ; tlv.isValidObject() ; tlv.nextObject()) {
    961                     if (tlv.getTag() == TAG_FULL_NETWORK_NAME) {
    962                         mPnnHomeName
    963                             = IccUtils.networkNameToString(
    964                                 tlv.getData(), 0, tlv.getData().length);
    965                         break;
    966                     }
    967                 }
    968             break;
    969 
    970             case EVENT_GET_ALL_SMS_DONE:
    971                 isRecordLoadResponse = true;
    972 
    973                 ar = (AsyncResult)msg.obj;
    974                 if (ar.exception != null)
    975                     break;
    976 
    977                 handleSmses((ArrayList<byte []>) ar.result);
    978                 break;
    979 
    980             case EVENT_MARK_SMS_READ_DONE:
    981                 Rlog.i("ENF", "marked read: sms " + msg.arg1);
    982                 break;
    983 
    984 
    985             case EVENT_SMS_ON_SIM:
    986                 isRecordLoadResponse = false;
    987 
    988                 ar = (AsyncResult)msg.obj;
    989 
    990                 int[] index = (int[])ar.result;
    991 
    992                 if (ar.exception != null || index.length != 1) {
    993                     loge("Error on SMS_ON_SIM with exp "
    994                             + ar.exception + " length " + index.length);
    995                 } else {
    996                     log("READ EF_SMS RECORD index=" + index[0]);
    997                     mFh.loadEFLinearFixed(EF_SMS,index[0],
    998                             obtainMessage(EVENT_GET_SMS_DONE));
    999                 }
   1000                 break;
   1001 
   1002             case EVENT_GET_SMS_DONE:
   1003                 isRecordLoadResponse = false;
   1004                 ar = (AsyncResult)msg.obj;
   1005                 if (ar.exception == null) {
   1006                     handleSms((byte[])ar.result);
   1007                 } else {
   1008                     loge("Error on GET_SMS with exp " + ar.exception);
   1009                 }
   1010                 break;
   1011             case EVENT_GET_SST_DONE:
   1012                 isRecordLoadResponse = true;
   1013 
   1014                 ar = (AsyncResult)msg.obj;
   1015                 data = (byte[])ar.result;
   1016 
   1017                 if (ar.exception != null) {
   1018                     break;
   1019                 }
   1020 
   1021                 mUsimServiceTable = new UsimServiceTable(data);
   1022                 if (DBG) log("SST: " + mUsimServiceTable);
   1023                 break;
   1024 
   1025             case EVENT_GET_INFO_CPHS_DONE:
   1026                 isRecordLoadResponse = true;
   1027 
   1028                 ar = (AsyncResult)msg.obj;
   1029 
   1030                 if (ar.exception != null) {
   1031                     break;
   1032                 }
   1033 
   1034                 mCphsInfo = (byte[])ar.result;
   1035 
   1036                 if (DBG) log("iCPHS: " + IccUtils.bytesToHexString(mCphsInfo));
   1037             break;
   1038 
   1039             case EVENT_SET_MBDN_DONE:
   1040                 isRecordLoadResponse = false;
   1041                 ar = (AsyncResult)msg.obj;
   1042 
   1043                 if (ar.exception == null) {
   1044                     mVoiceMailNum = mNewVoiceMailNum;
   1045                     mVoiceMailTag = mNewVoiceMailTag;
   1046                 }
   1047 
   1048                 if (isCphsMailboxEnabled()) {
   1049                     adn = new AdnRecord(mVoiceMailTag, mVoiceMailNum);
   1050                     Message onCphsCompleted = (Message) ar.userObj;
   1051 
   1052                     /* write to cphs mailbox whenever it is available but
   1053                     * we only need notify caller once if both updating are
   1054                     * successful.
   1055                     *
   1056                     * so if set_mbdn successful, notify caller here and set
   1057                     * onCphsCompleted to null
   1058                     */
   1059                     if (ar.exception == null && ar.userObj != null) {
   1060                         AsyncResult.forMessage(((Message) ar.userObj)).exception
   1061                                 = null;
   1062                         ((Message) ar.userObj).sendToTarget();
   1063 
   1064                         if (DBG) log("Callback with MBDN successful.");
   1065 
   1066                         onCphsCompleted = null;
   1067                     }
   1068 
   1069                     new AdnRecordLoader(mFh).
   1070                             updateEF(adn, EF_MAILBOX_CPHS, EF_EXT1, 1, null,
   1071                             obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE,
   1072                                     onCphsCompleted));
   1073                 } else {
   1074                     if (ar.userObj != null) {
   1075                         AsyncResult.forMessage(((Message) ar.userObj)).exception
   1076                                 = ar.exception;
   1077                         ((Message) ar.userObj).sendToTarget();
   1078                     }
   1079                 }
   1080                 break;
   1081             case EVENT_SET_CPHS_MAILBOX_DONE:
   1082                 isRecordLoadResponse = false;
   1083                 ar = (AsyncResult)msg.obj;
   1084                 if(ar.exception == null) {
   1085                     mVoiceMailNum = mNewVoiceMailNum;
   1086                     mVoiceMailTag = mNewVoiceMailTag;
   1087                 } else {
   1088                     if (DBG) log("Set CPHS MailBox with exception: "
   1089                             + ar.exception);
   1090                 }
   1091                 if (ar.userObj != null) {
   1092                     if (DBG) log("Callback with CPHS MB successful.");
   1093                     AsyncResult.forMessage(((Message) ar.userObj)).exception
   1094                             = ar.exception;
   1095                     ((Message) ar.userObj).sendToTarget();
   1096                 }
   1097                 break;
   1098             case EVENT_SIM_REFRESH:
   1099                 isRecordLoadResponse = false;
   1100                 ar = (AsyncResult)msg.obj;
   1101                 if (DBG) log("Sim REFRESH with exception: " + ar.exception);
   1102                 if (ar.exception == null) {
   1103                     handleSimRefresh((IccRefreshResponse)ar.result);
   1104                 }
   1105                 break;
   1106             case EVENT_GET_CFIS_DONE:
   1107                 isRecordLoadResponse = true;
   1108 
   1109                 ar = (AsyncResult)msg.obj;
   1110                 data = (byte[])ar.result;
   1111 
   1112                 if (ar.exception != null) {
   1113                     break;
   1114                 }
   1115 
   1116                 log("EF_CFIS: " + IccUtils.bytesToHexString(data));
   1117 
   1118                 if (validEfCfis(data)) {
   1119                     mEfCfis = data;
   1120 
   1121                     // Refer TS 51.011 Section 10.3.46 for the content description
   1122                     mCallForwardingEnabled = ((data[1] & 0x01) != 0);
   1123                     log("EF_CFIS: callForwardingEnabled=" + mCallForwardingEnabled);
   1124 
   1125                     mRecordsEventsRegistrants.notifyResult(EVENT_CFI);
   1126                 } else {
   1127                     log("EF_CFIS: invalid data=" + IccUtils.bytesToHexString(data));
   1128                 }
   1129                 break;
   1130 
   1131             case EVENT_GET_CSP_CPHS_DONE:
   1132                 isRecordLoadResponse = true;
   1133 
   1134                 ar = (AsyncResult)msg.obj;
   1135 
   1136                 if (ar.exception != null) {
   1137                     loge("Exception in fetching EF_CSP data " + ar.exception);
   1138                     break;
   1139                 }
   1140 
   1141                 data = (byte[])ar.result;
   1142 
   1143                 log("EF_CSP: " + IccUtils.bytesToHexString(data));
   1144                 handleEfCspData(data);
   1145                 break;
   1146 
   1147             case EVENT_GET_GID1_DONE:
   1148                 isRecordLoadResponse = true;
   1149 
   1150                 ar = (AsyncResult)msg.obj;
   1151                 data =(byte[])ar.result;
   1152 
   1153                 if (ar.exception != null) {
   1154                     loge("Exception in get GID1 " + ar.exception);
   1155                     mGid1 = null;
   1156                     break;
   1157                 }
   1158                 mGid1 = IccUtils.bytesToHexString(data);
   1159                 log("GID1: " + mGid1);
   1160 
   1161                 break;
   1162 
   1163             default:
   1164                 super.handleMessage(msg);   // IccRecords handles generic record load responses
   1165 
   1166         }}catch (RuntimeException exc) {
   1167             // I don't want these exceptions to be fatal
   1168             logw("Exception parsing SIM record", exc);
   1169         } finally {
   1170             // Count up record load responses even if they are fails
   1171             if (isRecordLoadResponse) {
   1172                 onRecordLoaded();
   1173             }
   1174         }
   1175     }
   1176 
   1177     private void handleFileUpdate(int efid) {
   1178         switch(efid) {
   1179             case EF_MBDN:
   1180                 mRecordsToLoad++;
   1181                 new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6,
   1182                         mMailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
   1183                 break;
   1184             case EF_MAILBOX_CPHS:
   1185                 mRecordsToLoad++;
   1186                 new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1,
   1187                         1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
   1188                 break;
   1189             case EF_CSP_CPHS:
   1190                 mRecordsToLoad++;
   1191                 log("[CSP] SIM Refresh for EF_CSP_CPHS");
   1192                 mFh.loadEFTransparent(EF_CSP_CPHS,
   1193                         obtainMessage(EVENT_GET_CSP_CPHS_DONE));
   1194                 break;
   1195             default:
   1196                 // For now, fetch all records if this is not a
   1197                 // voicemail number.
   1198                 // TODO: Handle other cases, instead of fetching all.
   1199                 mAdnCache.reset();
   1200                 fetchSimRecords();
   1201                 break;
   1202         }
   1203     }
   1204 
   1205     private void handleSimRefresh(IccRefreshResponse refreshResponse){
   1206         if (refreshResponse == null) {
   1207             if (DBG) log("handleSimRefresh received without input");
   1208             return;
   1209         }
   1210 
   1211         if (refreshResponse.aid != null &&
   1212                 !refreshResponse.aid.equals(mParentApp.getAid())) {
   1213             // This is for different app. Ignore.
   1214             return;
   1215         }
   1216 
   1217         switch (refreshResponse.refreshResult) {
   1218             case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE:
   1219                 if (DBG) log("handleSimRefresh with SIM_FILE_UPDATED");
   1220                 handleFileUpdate(refreshResponse.efId);
   1221                 break;
   1222             case IccRefreshResponse.REFRESH_RESULT_INIT:
   1223                 if (DBG) log("handleSimRefresh with SIM_REFRESH_INIT");
   1224                 // need to reload all files (that we care about)
   1225                 onIccRefreshInit();
   1226                 break;
   1227             case IccRefreshResponse.REFRESH_RESULT_RESET:
   1228                 if (DBG) log("handleSimRefresh with SIM_REFRESH_RESET");
   1229                 mCi.setRadioPower(false, null);
   1230                 /* Note: no need to call setRadioPower(true).  Assuming the desired
   1231                 * radio power state is still ON (as tracked by ServiceStateTracker),
   1232                 * ServiceStateTracker will call setRadioPower when it receives the
   1233                 * RADIO_STATE_CHANGED notification for the power off.  And if the
   1234                 * desired power state has changed in the interim, we don't want to
   1235                 * override it with an unconditional power on.
   1236                 */
   1237                 break;
   1238             default:
   1239                 // unknown refresh operation
   1240                 if (DBG) log("handleSimRefresh with unknown operation");
   1241                 break;
   1242         }
   1243     }
   1244 
   1245     /**
   1246      * Dispatch 3GPP format message to registrant ({@code GSMPhone} or {@code CDMALTEPhone})
   1247      * to pass to the 3GPP SMS dispatcher for delivery.
   1248      */
   1249     private int dispatchGsmMessage(SmsMessage message) {
   1250         mNewSmsRegistrants.notifyResult(message);
   1251         return 0;
   1252     }
   1253 
   1254     private void handleSms(byte[] ba) {
   1255         if (ba[0] != 0)
   1256             Rlog.d("ENF", "status : " + ba[0]);
   1257 
   1258         // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
   1259         // 3 == "received by MS from network; message to be read"
   1260         if (ba[0] == 3) {
   1261             int n = ba.length;
   1262 
   1263             // Note: Data may include trailing FF's.  That's OK; message
   1264             // should still parse correctly.
   1265             byte[] pdu = new byte[n - 1];
   1266             System.arraycopy(ba, 1, pdu, 0, n - 1);
   1267             SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP);
   1268 
   1269             dispatchGsmMessage(message);
   1270         }
   1271     }
   1272 
   1273 
   1274     private void handleSmses(ArrayList<byte[]> messages) {
   1275         int count = messages.size();
   1276 
   1277         for (int i = 0; i < count; i++) {
   1278             byte[] ba = messages.get(i);
   1279 
   1280             if (ba[0] != 0)
   1281                 Rlog.i("ENF", "status " + i + ": " + ba[0]);
   1282 
   1283             // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
   1284             // 3 == "received by MS from network; message to be read"
   1285 
   1286             if (ba[0] == 3) {
   1287                 int n = ba.length;
   1288 
   1289                 // Note: Data may include trailing FF's.  That's OK; message
   1290                 // should still parse correctly.
   1291                 byte[] pdu = new byte[n - 1];
   1292                 System.arraycopy(ba, 1, pdu, 0, n - 1);
   1293                 SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP);
   1294 
   1295                 dispatchGsmMessage(message);
   1296 
   1297                 // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
   1298                 // 1 == "received by MS from network; message read"
   1299 
   1300                 ba[0] = 1;
   1301 
   1302                 if (false) { // FIXME: writing seems to crash RdoServD
   1303                     mFh.updateEFLinearFixed(EF_SMS,
   1304                             i, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, i));
   1305                 }
   1306             }
   1307         }
   1308     }
   1309 
   1310     @Override
   1311     protected void onRecordLoaded() {
   1312         // One record loaded successfully or failed, In either case
   1313         // we need to update the recordsToLoad count
   1314         mRecordsToLoad -= 1;
   1315         if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested);
   1316 
   1317         if (mRecordsToLoad == 0 && mRecordsRequested == true) {
   1318             onAllRecordsLoaded();
   1319         } else if (mRecordsToLoad < 0) {
   1320             loge("recordsToLoad <0, programmer error suspected");
   1321             mRecordsToLoad = 0;
   1322         }
   1323     }
   1324 
   1325     @Override
   1326     protected void onAllRecordsLoaded() {
   1327         if (DBG) log("record load complete");
   1328 
   1329         // Some fields require more than one SIM record to set
   1330 
   1331         String operator = getOperatorNumeric();
   1332         if (!TextUtils.isEmpty(operator)) {
   1333             log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" +
   1334                     operator + "'");
   1335             SystemProperties.set(PROPERTY_ICC_OPERATOR_NUMERIC, operator);
   1336         } else {
   1337             log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping");
   1338         }
   1339 
   1340         if (!TextUtils.isEmpty(mImsi)) {
   1341             log("onAllRecordsLoaded set mcc imsi=" + mImsi);
   1342             SystemProperties.set(PROPERTY_ICC_OPERATOR_ISO_COUNTRY,
   1343                     MccTable.countryCodeForMcc(Integer.parseInt(mImsi.substring(0,3))));
   1344         } else {
   1345             log("onAllRecordsLoaded empty imsi skipping setting mcc");
   1346         }
   1347 
   1348         setVoiceMailByCountry(operator);
   1349         setSpnFromConfig(operator);
   1350 
   1351         mRecordsLoadedRegistrants.notifyRegistrants(
   1352             new AsyncResult(null, null, null));
   1353     }
   1354 
   1355     //***** Private methods
   1356 
   1357     private void setSpnFromConfig(String carrier) {
   1358         if (mSpnOverride.containsCarrier(carrier)) {
   1359             mSpn = mSpnOverride.getSpn(carrier);
   1360         }
   1361     }
   1362 
   1363 
   1364     private void setVoiceMailByCountry (String spn) {
   1365         if (mVmConfig.containsCarrier(spn)) {
   1366             mIsVoiceMailFixed = true;
   1367             mVoiceMailNum = mVmConfig.getVoiceMailNumber(spn);
   1368             mVoiceMailTag = mVmConfig.getVoiceMailTag(spn);
   1369         }
   1370     }
   1371 
   1372     @Override
   1373     public void onReady() {
   1374         fetchSimRecords();
   1375     }
   1376 
   1377     protected void fetchSimRecords() {
   1378         mRecordsRequested = true;
   1379 
   1380         if (DBG) log("fetchSimRecords " + mRecordsToLoad);
   1381 
   1382         mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
   1383         mRecordsToLoad++;
   1384 
   1385         mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
   1386         mRecordsToLoad++;
   1387 
   1388         // FIXME should examine EF[MSISDN]'s capability configuration
   1389         // to determine which is the voice/data/fax line
   1390         new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, EF_EXT1, 1,
   1391                     obtainMessage(EVENT_GET_MSISDN_DONE));
   1392         mRecordsToLoad++;
   1393 
   1394         // Record number is subscriber profile
   1395         mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));
   1396         mRecordsToLoad++;
   1397 
   1398         mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
   1399         mRecordsToLoad++;
   1400 
   1401         // Record number is subscriber profile
   1402         mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE));
   1403         mRecordsToLoad++;
   1404 
   1405 
   1406         // Also load CPHS-style voice mail indicator, which stores
   1407         // the same info as EF[MWIS]. If both exist, both are updated
   1408         // but the EF[MWIS] data is preferred
   1409         // Please note this must be loaded after EF[MWIS]
   1410         mFh.loadEFTransparent(
   1411                 EF_VOICE_MAIL_INDICATOR_CPHS,
   1412                 obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE));
   1413         mRecordsToLoad++;
   1414 
   1415         // Same goes for Call Forward Status indicator: fetch both
   1416         // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred.
   1417         mFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE));
   1418         mRecordsToLoad++;
   1419         mFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE));
   1420         mRecordsToLoad++;
   1421 
   1422 
   1423         getSpnFsm(true, null);
   1424 
   1425         mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));
   1426         mRecordsToLoad++;
   1427 
   1428         mFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE));
   1429         mRecordsToLoad++;
   1430 
   1431         mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));
   1432         mRecordsToLoad++;
   1433 
   1434         mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));
   1435         mRecordsToLoad++;
   1436 
   1437         mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE));
   1438         mRecordsToLoad++;
   1439 
   1440         mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE));
   1441         mRecordsToLoad++;
   1442 
   1443         // XXX should seek instead of examining them all
   1444         if (false) { // XXX
   1445             mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));
   1446             mRecordsToLoad++;
   1447         }
   1448 
   1449         if (CRASH_RIL) {
   1450             String sms = "0107912160130310f20404d0110041007030208054832b0120"
   1451                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
   1452                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
   1453                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
   1454                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
   1455                          + "ffffffffffffffffffffffffffffff";
   1456             byte[] ba = IccUtils.hexStringToBytes(sms);
   1457 
   1458             mFh.updateEFLinearFixed(EF_SMS, 1, ba, null,
   1459                             obtainMessage(EVENT_MARK_SMS_READ_DONE, 1));
   1460         }
   1461         if (DBG) log("fetchSimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested);
   1462     }
   1463 
   1464     /**
   1465      * Returns the SpnDisplayRule based on settings on the SIM and the
   1466      * specified plmn (currently-registered PLMN).  See TS 22.101 Annex A
   1467      * and TS 51.011 10.3.11 for details.
   1468      *
   1469      * If the SPN is not found on the SIM or is empty, the rule is
   1470      * always PLMN_ONLY.
   1471      */
   1472     @Override
   1473     public int getDisplayRule(String plmn) {
   1474         int rule;
   1475         if (TextUtils.isEmpty(mSpn) || mSpnDisplayCondition == -1) {
   1476             // No EF_SPN content was found on the SIM, or not yet loaded.  Just show ONS.
   1477             rule = SPN_RULE_SHOW_PLMN;
   1478         } else if (isOnMatchingPlmn(plmn)) {
   1479             rule = SPN_RULE_SHOW_SPN;
   1480             if ((mSpnDisplayCondition & 0x01) == 0x01) {
   1481                 // ONS required when registered to HPLMN or PLMN in EF_SPDI
   1482                 rule |= SPN_RULE_SHOW_PLMN;
   1483             }
   1484         } else {
   1485             rule = SPN_RULE_SHOW_PLMN;
   1486             if ((mSpnDisplayCondition & 0x02) == 0x00) {
   1487                 // SPN required if not registered to HPLMN or PLMN in EF_SPDI
   1488                 rule |= SPN_RULE_SHOW_SPN;
   1489             }
   1490         }
   1491         return rule;
   1492     }
   1493 
   1494     /**
   1495      * Checks if plmn is HPLMN or on the spdiNetworks list.
   1496      */
   1497     private boolean isOnMatchingPlmn(String plmn) {
   1498         if (plmn == null) return false;
   1499 
   1500         if (plmn.equals(getOperatorNumeric())) {
   1501             return true;
   1502         }
   1503 
   1504         if (mSpdiNetworks != null) {
   1505             for (String spdiNet : mSpdiNetworks) {
   1506                 if (plmn.equals(spdiNet)) {
   1507                     return true;
   1508                 }
   1509             }
   1510         }
   1511         return false;
   1512     }
   1513 
   1514     /**
   1515      * States of Get SPN Finite State Machine which only used by getSpnFsm()
   1516      */
   1517     private enum GetSpnFsmState {
   1518         IDLE,               // No initialized
   1519         INIT,               // Start FSM
   1520         READ_SPN_3GPP,      // Load EF_SPN firstly
   1521         READ_SPN_CPHS,      // Load EF_SPN_CPHS secondly
   1522         READ_SPN_SHORT_CPHS // Load EF_SPN_SHORT_CPHS last
   1523     }
   1524 
   1525     /**
   1526      * Finite State Machine to load Service Provider Name , which can be stored
   1527      * in either EF_SPN (3GPP), EF_SPN_CPHS, or EF_SPN_SHORT_CPHS (CPHS4.2)
   1528      *
   1529      * After starting, FSM will search SPN EFs in order and stop after finding
   1530      * the first valid SPN
   1531      *
   1532      * If the FSM gets restart while waiting for one of
   1533      * SPN EFs results (i.e. a SIM refresh occurs after issuing
   1534      * read EF_CPHS_SPN), it will re-initialize only after
   1535      * receiving and discarding the unfinished SPN EF result.
   1536      *
   1537      * @param start set true only for initialize loading
   1538      * @param ar the AsyncResult from loadEFTransparent
   1539      *        ar.exception holds exception in error
   1540      *        ar.result is byte[] for data in success
   1541      */
   1542     private void getSpnFsm(boolean start, AsyncResult ar) {
   1543         byte[] data;
   1544 
   1545         if (start) {
   1546             // Check previous state to see if there is outstanding
   1547             // SPN read
   1548             if(mSpnState == GetSpnFsmState.READ_SPN_3GPP ||
   1549                mSpnState == GetSpnFsmState.READ_SPN_CPHS ||
   1550                mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS ||
   1551                mSpnState == GetSpnFsmState.INIT) {
   1552                 // Set INIT then return so the INIT code
   1553                 // will run when the outstanding read done.
   1554                 mSpnState = GetSpnFsmState.INIT;
   1555                 return;
   1556             } else {
   1557                 mSpnState = GetSpnFsmState.INIT;
   1558             }
   1559         }
   1560 
   1561         switch(mSpnState){
   1562             case INIT:
   1563                 mSpn = null;
   1564 
   1565                 mFh.loadEFTransparent(EF_SPN,
   1566                         obtainMessage(EVENT_GET_SPN_DONE));
   1567                 mRecordsToLoad++;
   1568 
   1569                 mSpnState = GetSpnFsmState.READ_SPN_3GPP;
   1570                 break;
   1571             case READ_SPN_3GPP:
   1572                 if (ar != null && ar.exception == null) {
   1573                     data = (byte[]) ar.result;
   1574                     mSpnDisplayCondition = 0xff & data[0];
   1575                     mSpn = IccUtils.adnStringFieldToString(data, 1, data.length - 1);
   1576 
   1577                     if (DBG) log("Load EF_SPN: " + mSpn
   1578                             + " spnDisplayCondition: " + mSpnDisplayCondition);
   1579                     SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, mSpn);
   1580 
   1581                     mSpnState = GetSpnFsmState.IDLE;
   1582                 } else {
   1583                     mFh.loadEFTransparent( EF_SPN_CPHS,
   1584                             obtainMessage(EVENT_GET_SPN_DONE));
   1585                     mRecordsToLoad++;
   1586 
   1587                     mSpnState = GetSpnFsmState.READ_SPN_CPHS;
   1588 
   1589                     // See TS 51.011 10.3.11.  Basically, default to
   1590                     // show PLMN always, and SPN also if roaming.
   1591                     mSpnDisplayCondition = -1;
   1592                 }
   1593                 break;
   1594             case READ_SPN_CPHS:
   1595                 if (ar != null && ar.exception == null) {
   1596                     data = (byte[]) ar.result;
   1597                     mSpn = IccUtils.adnStringFieldToString(data, 0, data.length);
   1598 
   1599                     if (DBG) log("Load EF_SPN_CPHS: " + mSpn);
   1600                     SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, mSpn);
   1601 
   1602                     mSpnState = GetSpnFsmState.IDLE;
   1603                 } else {
   1604                     mFh.loadEFTransparent(
   1605                             EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE));
   1606                     mRecordsToLoad++;
   1607 
   1608                     mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS;
   1609                 }
   1610                 break;
   1611             case READ_SPN_SHORT_CPHS:
   1612                 if (ar != null && ar.exception == null) {
   1613                     data = (byte[]) ar.result;
   1614                     mSpn = IccUtils.adnStringFieldToString(data, 0, data.length);
   1615 
   1616                     if (DBG) log("Load EF_SPN_SHORT_CPHS: " + mSpn);
   1617                     SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, mSpn);
   1618                 }else {
   1619                     if (DBG) log("No SPN loaded in either CHPS or 3GPP");
   1620                 }
   1621 
   1622                 mSpnState = GetSpnFsmState.IDLE;
   1623                 break;
   1624             default:
   1625                 mSpnState = GetSpnFsmState.IDLE;
   1626         }
   1627     }
   1628 
   1629     /**
   1630      * Parse TS 51.011 EF[SPDI] record
   1631      * This record contains the list of numeric network IDs that
   1632      * are treated specially when determining SPN display
   1633      */
   1634     private void
   1635     parseEfSpdi(byte[] data) {
   1636         SimTlv tlv = new SimTlv(data, 0, data.length);
   1637 
   1638         byte[] plmnEntries = null;
   1639 
   1640         for ( ; tlv.isValidObject() ; tlv.nextObject()) {
   1641             // Skip SPDI tag, if existant
   1642             if (tlv.getTag() == TAG_SPDI) {
   1643               tlv = new SimTlv(tlv.getData(), 0, tlv.getData().length);
   1644             }
   1645             // There should only be one TAG_SPDI_PLMN_LIST
   1646             if (tlv.getTag() == TAG_SPDI_PLMN_LIST) {
   1647                 plmnEntries = tlv.getData();
   1648                 break;
   1649             }
   1650         }
   1651 
   1652         if (plmnEntries == null) {
   1653             return;
   1654         }
   1655 
   1656         mSpdiNetworks = new ArrayList<String>(plmnEntries.length / 3);
   1657 
   1658         for (int i = 0 ; i + 2 < plmnEntries.length ; i += 3) {
   1659             String plmnCode;
   1660             plmnCode = IccUtils.bcdToString(plmnEntries, i, 3);
   1661 
   1662             // Valid operator codes are 5 or 6 digits
   1663             if (plmnCode.length() >= 5) {
   1664                 log("EF_SPDI network: " + plmnCode);
   1665                 mSpdiNetworks.add(plmnCode);
   1666             }
   1667         }
   1668     }
   1669 
   1670     /**
   1671      * check to see if Mailbox Number is allocated and activated in CPHS SST
   1672      */
   1673     private boolean isCphsMailboxEnabled() {
   1674         if (mCphsInfo == null)  return false;
   1675         return ((mCphsInfo[1] & CPHS_SST_MBN_MASK) == CPHS_SST_MBN_ENABLED );
   1676     }
   1677 
   1678     @Override
   1679     protected void log(String s) {
   1680         Rlog.d(LOG_TAG, "[SIMRecords] " + s);
   1681     }
   1682 
   1683     @Override
   1684     protected void loge(String s) {
   1685         Rlog.e(LOG_TAG, "[SIMRecords] " + s);
   1686     }
   1687 
   1688     protected void logw(String s, Throwable tr) {
   1689         Rlog.w(LOG_TAG, "[SIMRecords] " + s, tr);
   1690     }
   1691 
   1692     protected void logv(String s) {
   1693         Rlog.v(LOG_TAG, "[SIMRecords] " + s);
   1694     }
   1695 
   1696     /**
   1697      * Return true if "Restriction of menu options for manual PLMN selection"
   1698      * bit is set or EF_CSP data is unavailable, return false otherwise.
   1699      */
   1700     @Override
   1701     public boolean isCspPlmnEnabled() {
   1702         return mCspPlmnEnabled;
   1703     }
   1704 
   1705     /**
   1706      * Parse EF_CSP data and check if
   1707      * "Restriction of menu options for manual PLMN selection" is
   1708      * Enabled/Disabled
   1709      *
   1710      * @param data EF_CSP hex data.
   1711      */
   1712     private void handleEfCspData(byte[] data) {
   1713         // As per spec CPHS4_2.WW6, CPHS B.4.7.1, EF_CSP contains CPHS defined
   1714         // 18 bytes (i.e 9 service groups info) and additional data specific to
   1715         // operator. The valueAddedServicesGroup is not part of standard
   1716         // services. This is operator specific and can be programmed any where.
   1717         // Normally this is programmed as 10th service after the standard
   1718         // services.
   1719         int usedCspGroups = data.length / 2;
   1720         // This is the "Service Group Number" of "Value Added Services Group".
   1721         byte valueAddedServicesGroup = (byte)0xC0;
   1722 
   1723         mCspPlmnEnabled = true;
   1724         for (int i = 0; i < usedCspGroups; i++) {
   1725              if (data[2 * i] == valueAddedServicesGroup) {
   1726                  log("[CSP] found ValueAddedServicesGroup, value " + data[(2 * i) + 1]);
   1727                  if ((data[(2 * i) + 1] & 0x80) == 0x80) {
   1728                      // Bit 8 is for
   1729                      // "Restriction of menu options for manual PLMN selection".
   1730                      // Operator Selection menu should be enabled.
   1731                      mCspPlmnEnabled = true;
   1732                  } else {
   1733                      mCspPlmnEnabled = false;
   1734                      // Operator Selection menu should be disabled.
   1735                      // Operator Selection Mode should be set to Automatic.
   1736                      log("[CSP] Set Automatic Network Selection");
   1737                      mNetworkSelectionModeAutomaticRegistrants.notifyRegistrants();
   1738                  }
   1739                  return;
   1740              }
   1741         }
   1742 
   1743         log("[CSP] Value Added Service Group (0xC0), not found!");
   1744     }
   1745 
   1746     @Override
   1747     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1748         pw.println("SIMRecords: " + this);
   1749         pw.println(" extends:");
   1750         super.dump(fd, pw, args);
   1751         pw.println(" mVmConfig=" + mVmConfig);
   1752         pw.println(" mSpnOverride=" + mSpnOverride);
   1753         pw.println(" mCallForwardingEnabled=" + mCallForwardingEnabled);
   1754         pw.println(" mSpnState=" + mSpnState);
   1755         pw.println(" mCphsInfo=" + mCphsInfo);
   1756         pw.println(" mCspPlmnEnabled=" + mCspPlmnEnabled);
   1757         pw.println(" mEfMWIS[]=" + Arrays.toString(mEfMWIS));
   1758         pw.println(" mEfCPHS_MWI[]=" + Arrays.toString(mEfCPHS_MWI));
   1759         pw.println(" mEfCff[]=" + Arrays.toString(mEfCff));
   1760         pw.println(" mEfCfis[]=" + Arrays.toString(mEfCfis));
   1761         pw.println(" mSpnDisplayCondition=" + mSpnDisplayCondition);
   1762         pw.println(" mSpdiNetworks[]=" + mSpdiNetworks);
   1763         pw.println(" mPnnHomeName=" + mPnnHomeName);
   1764         pw.println(" mUsimServiceTable=" + mUsimServiceTable);
   1765         pw.println(" mGid1=" + mGid1);
   1766         pw.flush();
   1767     }
   1768 }
   1769