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,
    629                             mImsi.substring(0, 3 + mMncLength), false);
    630                 }
    631                 mImsiReadyRegistrants.notifyRegistrants();
    632             break;
    633 
    634             case EVENT_GET_MBI_DONE:
    635                 boolean isValidMbdn;
    636                 isRecordLoadResponse = true;
    637 
    638                 ar = (AsyncResult)msg.obj;
    639                 data = (byte[]) ar.result;
    640 
    641                 isValidMbdn = false;
    642                 if (ar.exception == null) {
    643                     // Refer TS 51.011 Section 10.3.44 for content details
    644                     log("EF_MBI: " + IccUtils.bytesToHexString(data));
    645 
    646                     // Voice mail record number stored first
    647                     mMailboxIndex = data[0] & 0xff;
    648 
    649                     // check if dailing numbe id valid
    650                     if (mMailboxIndex != 0 && mMailboxIndex != 0xff) {
    651                         log("Got valid mailbox number for MBDN");
    652                         isValidMbdn = true;
    653                     }
    654                 }
    655 
    656                 // one more record to load
    657                 mRecordsToLoad += 1;
    658 
    659                 if (isValidMbdn) {
    660                     // Note: MBDN was not included in NUM_OF_SIM_RECORDS_LOADED
    661                     new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6,
    662                             mMailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
    663                 } else {
    664                     // If this EF not present, try mailbox as in CPHS standard
    665                     // CPHS (CPHS4_2.WW6) is a european standard.
    666                     new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS,
    667                             EF_EXT1, 1,
    668                             obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
    669                 }
    670 
    671                 break;
    672             case EVENT_GET_CPHS_MAILBOX_DONE:
    673             case EVENT_GET_MBDN_DONE:
    674                 //Resetting the voice mail number and voice mail tag to null
    675                 //as these should be updated from the data read from EF_MBDN.
    676                 //If they are not reset, incase of invalid data/exception these
    677                 //variables are retaining their previous values and are
    678                 //causing invalid voice mailbox info display to user.
    679                 mVoiceMailNum = null;
    680                 mVoiceMailTag = null;
    681                 isRecordLoadResponse = true;
    682 
    683                 ar = (AsyncResult)msg.obj;
    684 
    685                 if (ar.exception != null) {
    686 
    687                     log("Invalid or missing EF"
    688                         + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? "[MAILBOX]" : "[MBDN]"));
    689 
    690                     // Bug #645770 fall back to CPHS
    691                     // FIXME should use SST to decide
    692 
    693                     if (msg.what == EVENT_GET_MBDN_DONE) {
    694                         //load CPHS on fail...
    695                         // FIXME right now, only load line1's CPHS voice mail entry
    696 
    697                         mRecordsToLoad += 1;
    698                         new AdnRecordLoader(mFh).loadFromEF(
    699                                 EF_MAILBOX_CPHS, EF_EXT1, 1,
    700                                 obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
    701                     }
    702                     break;
    703                 }
    704 
    705                 adn = (AdnRecord)ar.result;
    706 
    707                 log("VM: " + adn +
    708                         ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? " EF[MAILBOX]" : " EF[MBDN]"));
    709 
    710                 if (adn.isEmpty() && msg.what == EVENT_GET_MBDN_DONE) {
    711                     // Bug #645770 fall back to CPHS
    712                     // FIXME should use SST to decide
    713                     // FIXME right now, only load line1's CPHS voice mail entry
    714                     mRecordsToLoad += 1;
    715                     new AdnRecordLoader(mFh).loadFromEF(
    716                             EF_MAILBOX_CPHS, EF_EXT1, 1,
    717                             obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
    718 
    719                     break;
    720                 }
    721 
    722                 mVoiceMailNum = adn.getNumber();
    723                 mVoiceMailTag = adn.getAlphaTag();
    724             break;
    725 
    726             case EVENT_GET_MSISDN_DONE:
    727                 isRecordLoadResponse = true;
    728 
    729                 ar = (AsyncResult)msg.obj;
    730 
    731                 if (ar.exception != null) {
    732                     log("Invalid or missing EF[MSISDN]");
    733                     break;
    734                 }
    735 
    736                 adn = (AdnRecord)ar.result;
    737 
    738                 mMsisdn = adn.getNumber();
    739                 mMsisdnTag = adn.getAlphaTag();
    740 
    741                 log("MSISDN: " + /*mMsisdn*/ "xxxxxxx");
    742             break;
    743 
    744             case EVENT_SET_MSISDN_DONE:
    745                 isRecordLoadResponse = false;
    746                 ar = (AsyncResult)msg.obj;
    747 
    748                 if (ar.userObj != null) {
    749                     AsyncResult.forMessage(((Message) ar.userObj)).exception
    750                             = ar.exception;
    751                     ((Message) ar.userObj).sendToTarget();
    752                 }
    753                 break;
    754 
    755             case EVENT_GET_MWIS_DONE:
    756                 isRecordLoadResponse = true;
    757 
    758                 ar = (AsyncResult)msg.obj;
    759                 data = (byte[])ar.result;
    760 
    761                 if (ar.exception != null) {
    762                     break;
    763                 }
    764 
    765                 log("EF_MWIS: " + IccUtils.bytesToHexString(data));
    766 
    767                 mEfMWIS = data;
    768 
    769                 if ((data[0] & 0xff) == 0xff) {
    770                     log("Uninitialized record MWIS");
    771                     break;
    772                 }
    773 
    774                 // Refer TS 51.011 Section 10.3.45 for the content description
    775                 boolean voiceMailWaiting = ((data[0] & 0x01) != 0);
    776                 mCountVoiceMessages = data[1] & 0xff;
    777 
    778                 if (voiceMailWaiting && mCountVoiceMessages == 0) {
    779                     // Unknown count = -1
    780                     mCountVoiceMessages = -1;
    781                 }
    782 
    783                 mRecordsEventsRegistrants.notifyResult(EVENT_MWI);
    784             break;
    785 
    786             case EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE:
    787                 isRecordLoadResponse = true;
    788 
    789                 ar = (AsyncResult)msg.obj;
    790                 data = (byte[])ar.result;
    791 
    792                 if (ar.exception != null) {
    793                     break;
    794                 }
    795 
    796                 mEfCPHS_MWI = data;
    797 
    798                 // Use this data if the EF[MWIS] exists and
    799                 // has been loaded
    800 
    801                 if (mEfMWIS == null) {
    802                     int indicator = data[0] & 0xf;
    803 
    804                     // Refer CPHS4_2.WW6 B4.2.3
    805                     if (indicator == 0xA) {
    806                         // Unknown count = -1
    807                         mCountVoiceMessages = -1;
    808                     } else if (indicator == 0x5) {
    809                         mCountVoiceMessages = 0;
    810                     }
    811 
    812                     mRecordsEventsRegistrants.notifyResult(EVENT_MWI);
    813                 }
    814             break;
    815 
    816             case EVENT_GET_ICCID_DONE:
    817                 isRecordLoadResponse = true;
    818 
    819                 ar = (AsyncResult)msg.obj;
    820                 data = (byte[])ar.result;
    821 
    822                 if (ar.exception != null) {
    823                     break;
    824                 }
    825 
    826                 mIccId = IccUtils.bcdToString(data, 0, data.length);
    827 
    828                 log("iccid: " + mIccId);
    829 
    830             break;
    831 
    832 
    833             case EVENT_GET_AD_DONE:
    834                 try {
    835                     isRecordLoadResponse = true;
    836 
    837                     ar = (AsyncResult)msg.obj;
    838                     data = (byte[])ar.result;
    839 
    840                     if (ar.exception != null) {
    841                         break;
    842                     }
    843 
    844                     log("EF_AD: " + IccUtils.bytesToHexString(data));
    845 
    846                     if (data.length < 3) {
    847                         log("Corrupt AD data on SIM");
    848                         break;
    849                     }
    850 
    851                     if (data.length == 3) {
    852                         log("MNC length not present in EF_AD");
    853                         break;
    854                     }
    855 
    856                     mMncLength = data[3] & 0xf;
    857 
    858                     if (mMncLength == 0xf) {
    859                         mMncLength = UNKNOWN;
    860                     }
    861                 } finally {
    862                     if (((mMncLength == UNINITIALIZED) || (mMncLength == UNKNOWN) ||
    863                             (mMncLength == 2)) && ((mImsi != null) && (mImsi.length() >= 6))) {
    864                         String mccmncCode = mImsi.substring(0, 6);
    865                         for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) {
    866                             if (mccmnc.equals(mccmncCode)) {
    867                                 mMncLength = 3;
    868                                 break;
    869                             }
    870                         }
    871                     }
    872 
    873                     if (mMncLength == UNKNOWN || mMncLength == UNINITIALIZED) {
    874                         if (mImsi != null) {
    875                             try {
    876                                 int mcc = Integer.parseInt(mImsi.substring(0,3));
    877 
    878                                 mMncLength = MccTable.smallestDigitsMccForMnc(mcc);
    879                             } catch (NumberFormatException e) {
    880                                 mMncLength = UNKNOWN;
    881                                 loge("Corrupt IMSI!");
    882                             }
    883                         } else {
    884                             // Indicate we got this info, but it didn't contain the length.
    885                             mMncLength = UNKNOWN;
    886 
    887                             log("MNC length not present in EF_AD");
    888                         }
    889                     }
    890                     if (mImsi != null && mMncLength != UNKNOWN) {
    891                         // finally have both imsi and the length of the mnc and can parse
    892                         // the imsi properly
    893                         MccTable.updateMccMncConfiguration(mContext,
    894                                 mImsi.substring(0, 3 + mMncLength), false);
    895                     }
    896                 }
    897             break;
    898 
    899             case EVENT_GET_SPN_DONE:
    900                 isRecordLoadResponse = true;
    901                 ar = (AsyncResult) msg.obj;
    902                 getSpnFsm(false, ar);
    903             break;
    904 
    905             case EVENT_GET_CFF_DONE:
    906                 isRecordLoadResponse = true;
    907 
    908                 ar = (AsyncResult) msg.obj;
    909                 data = (byte[]) ar.result;
    910 
    911                 if (ar.exception != null) {
    912                     break;
    913                 }
    914 
    915                 log("EF_CFF_CPHS: " + IccUtils.bytesToHexString(data));
    916                 mEfCff = data;
    917 
    918                 // if EF_CFIS is valid, prefer it to EF_CFF_CPHS
    919                 if (!validEfCfis(mEfCfis)) {
    920                     mCallForwardingEnabled =
    921                         ((data[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE);
    922 
    923                     mRecordsEventsRegistrants.notifyResult(EVENT_CFI);
    924                 } else {
    925                     log("EVENT_GET_CFF_DONE: EF_CFIS is valid, ignoring EF_CFF_CPHS");
    926                 }
    927                 break;
    928 
    929             case EVENT_GET_SPDI_DONE:
    930                 isRecordLoadResponse = true;
    931 
    932                 ar = (AsyncResult)msg.obj;
    933                 data = (byte[])ar.result;
    934 
    935                 if (ar.exception != null) {
    936                     break;
    937                 }
    938 
    939                 parseEfSpdi(data);
    940             break;
    941 
    942             case EVENT_UPDATE_DONE:
    943                 ar = (AsyncResult)msg.obj;
    944                 if (ar.exception != null) {
    945                     logw("update failed. ", ar.exception);
    946                 }
    947             break;
    948 
    949             case EVENT_GET_PNN_DONE:
    950                 isRecordLoadResponse = true;
    951 
    952                 ar = (AsyncResult)msg.obj;
    953                 data = (byte[])ar.result;
    954 
    955                 if (ar.exception != null) {
    956                     break;
    957                 }
    958 
    959                 SimTlv tlv = new SimTlv(data, 0, data.length);
    960 
    961                 for ( ; tlv.isValidObject() ; tlv.nextObject()) {
    962                     if (tlv.getTag() == TAG_FULL_NETWORK_NAME) {
    963                         mPnnHomeName
    964                             = IccUtils.networkNameToString(
    965                                 tlv.getData(), 0, tlv.getData().length);
    966                         break;
    967                     }
    968                 }
    969             break;
    970 
    971             case EVENT_GET_ALL_SMS_DONE:
    972                 isRecordLoadResponse = true;
    973 
    974                 ar = (AsyncResult)msg.obj;
    975                 if (ar.exception != null)
    976                     break;
    977 
    978                 handleSmses((ArrayList<byte []>) ar.result);
    979                 break;
    980 
    981             case EVENT_MARK_SMS_READ_DONE:
    982                 Rlog.i("ENF", "marked read: sms " + msg.arg1);
    983                 break;
    984 
    985 
    986             case EVENT_SMS_ON_SIM:
    987                 isRecordLoadResponse = false;
    988 
    989                 ar = (AsyncResult)msg.obj;
    990 
    991                 int[] index = (int[])ar.result;
    992 
    993                 if (ar.exception != null || index.length != 1) {
    994                     loge("Error on SMS_ON_SIM with exp "
    995                             + ar.exception + " length " + index.length);
    996                 } else {
    997                     log("READ EF_SMS RECORD index=" + index[0]);
    998                     mFh.loadEFLinearFixed(EF_SMS,index[0],
    999                             obtainMessage(EVENT_GET_SMS_DONE));
   1000                 }
   1001                 break;
   1002 
   1003             case EVENT_GET_SMS_DONE:
   1004                 isRecordLoadResponse = false;
   1005                 ar = (AsyncResult)msg.obj;
   1006                 if (ar.exception == null) {
   1007                     handleSms((byte[])ar.result);
   1008                 } else {
   1009                     loge("Error on GET_SMS with exp " + ar.exception);
   1010                 }
   1011                 break;
   1012             case EVENT_GET_SST_DONE:
   1013                 isRecordLoadResponse = true;
   1014 
   1015                 ar = (AsyncResult)msg.obj;
   1016                 data = (byte[])ar.result;
   1017 
   1018                 if (ar.exception != null) {
   1019                     break;
   1020                 }
   1021 
   1022                 mUsimServiceTable = new UsimServiceTable(data);
   1023                 if (DBG) log("SST: " + mUsimServiceTable);
   1024                 break;
   1025 
   1026             case EVENT_GET_INFO_CPHS_DONE:
   1027                 isRecordLoadResponse = true;
   1028 
   1029                 ar = (AsyncResult)msg.obj;
   1030 
   1031                 if (ar.exception != null) {
   1032                     break;
   1033                 }
   1034 
   1035                 mCphsInfo = (byte[])ar.result;
   1036 
   1037                 if (DBG) log("iCPHS: " + IccUtils.bytesToHexString(mCphsInfo));
   1038             break;
   1039 
   1040             case EVENT_SET_MBDN_DONE:
   1041                 isRecordLoadResponse = false;
   1042                 ar = (AsyncResult)msg.obj;
   1043 
   1044                 if (ar.exception == null) {
   1045                     mVoiceMailNum = mNewVoiceMailNum;
   1046                     mVoiceMailTag = mNewVoiceMailTag;
   1047                 }
   1048 
   1049                 if (isCphsMailboxEnabled()) {
   1050                     adn = new AdnRecord(mVoiceMailTag, mVoiceMailNum);
   1051                     Message onCphsCompleted = (Message) ar.userObj;
   1052 
   1053                     /* write to cphs mailbox whenever it is available but
   1054                     * we only need notify caller once if both updating are
   1055                     * successful.
   1056                     *
   1057                     * so if set_mbdn successful, notify caller here and set
   1058                     * onCphsCompleted to null
   1059                     */
   1060                     if (ar.exception == null && ar.userObj != null) {
   1061                         AsyncResult.forMessage(((Message) ar.userObj)).exception
   1062                                 = null;
   1063                         ((Message) ar.userObj).sendToTarget();
   1064 
   1065                         if (DBG) log("Callback with MBDN successful.");
   1066 
   1067                         onCphsCompleted = null;
   1068                     }
   1069 
   1070                     new AdnRecordLoader(mFh).
   1071                             updateEF(adn, EF_MAILBOX_CPHS, EF_EXT1, 1, null,
   1072                             obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE,
   1073                                     onCphsCompleted));
   1074                 } else {
   1075                     if (ar.userObj != null) {
   1076                         AsyncResult.forMessage(((Message) ar.userObj)).exception
   1077                                 = ar.exception;
   1078                         ((Message) ar.userObj).sendToTarget();
   1079                     }
   1080                 }
   1081                 break;
   1082             case EVENT_SET_CPHS_MAILBOX_DONE:
   1083                 isRecordLoadResponse = false;
   1084                 ar = (AsyncResult)msg.obj;
   1085                 if(ar.exception == null) {
   1086                     mVoiceMailNum = mNewVoiceMailNum;
   1087                     mVoiceMailTag = mNewVoiceMailTag;
   1088                 } else {
   1089                     if (DBG) log("Set CPHS MailBox with exception: "
   1090                             + ar.exception);
   1091                 }
   1092                 if (ar.userObj != null) {
   1093                     if (DBG) log("Callback with CPHS MB successful.");
   1094                     AsyncResult.forMessage(((Message) ar.userObj)).exception
   1095                             = ar.exception;
   1096                     ((Message) ar.userObj).sendToTarget();
   1097                 }
   1098                 break;
   1099             case EVENT_SIM_REFRESH:
   1100                 isRecordLoadResponse = false;
   1101                 ar = (AsyncResult)msg.obj;
   1102                 if (DBG) log("Sim REFRESH with exception: " + ar.exception);
   1103                 if (ar.exception == null) {
   1104                     handleSimRefresh((IccRefreshResponse)ar.result);
   1105                 }
   1106                 break;
   1107             case EVENT_GET_CFIS_DONE:
   1108                 isRecordLoadResponse = true;
   1109 
   1110                 ar = (AsyncResult)msg.obj;
   1111                 data = (byte[])ar.result;
   1112 
   1113                 if (ar.exception != null) {
   1114                     break;
   1115                 }
   1116 
   1117                 log("EF_CFIS: " + IccUtils.bytesToHexString(data));
   1118 
   1119                 if (validEfCfis(data)) {
   1120                     mEfCfis = data;
   1121 
   1122                     // Refer TS 51.011 Section 10.3.46 for the content description
   1123                     mCallForwardingEnabled = ((data[1] & 0x01) != 0);
   1124                     log("EF_CFIS: callForwardingEnabled=" + mCallForwardingEnabled);
   1125 
   1126                     mRecordsEventsRegistrants.notifyResult(EVENT_CFI);
   1127                 } else {
   1128                     log("EF_CFIS: invalid data=" + IccUtils.bytesToHexString(data));
   1129                 }
   1130                 break;
   1131 
   1132             case EVENT_GET_CSP_CPHS_DONE:
   1133                 isRecordLoadResponse = true;
   1134 
   1135                 ar = (AsyncResult)msg.obj;
   1136 
   1137                 if (ar.exception != null) {
   1138                     loge("Exception in fetching EF_CSP data " + ar.exception);
   1139                     break;
   1140                 }
   1141 
   1142                 data = (byte[])ar.result;
   1143 
   1144                 log("EF_CSP: " + IccUtils.bytesToHexString(data));
   1145                 handleEfCspData(data);
   1146                 break;
   1147 
   1148             case EVENT_GET_GID1_DONE:
   1149                 isRecordLoadResponse = true;
   1150 
   1151                 ar = (AsyncResult)msg.obj;
   1152                 data =(byte[])ar.result;
   1153 
   1154                 if (ar.exception != null) {
   1155                     loge("Exception in get GID1 " + ar.exception);
   1156                     mGid1 = null;
   1157                     break;
   1158                 }
   1159                 mGid1 = IccUtils.bytesToHexString(data);
   1160                 log("GID1: " + mGid1);
   1161 
   1162                 break;
   1163 
   1164             default:
   1165                 super.handleMessage(msg);   // IccRecords handles generic record load responses
   1166 
   1167         }}catch (RuntimeException exc) {
   1168             // I don't want these exceptions to be fatal
   1169             logw("Exception parsing SIM record", exc);
   1170         } finally {
   1171             // Count up record load responses even if they are fails
   1172             if (isRecordLoadResponse) {
   1173                 onRecordLoaded();
   1174             }
   1175         }
   1176     }
   1177 
   1178     private void handleFileUpdate(int efid) {
   1179         switch(efid) {
   1180             case EF_MBDN:
   1181                 mRecordsToLoad++;
   1182                 new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6,
   1183                         mMailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
   1184                 break;
   1185             case EF_MAILBOX_CPHS:
   1186                 mRecordsToLoad++;
   1187                 new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1,
   1188                         1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
   1189                 break;
   1190             case EF_CSP_CPHS:
   1191                 mRecordsToLoad++;
   1192                 log("[CSP] SIM Refresh for EF_CSP_CPHS");
   1193                 mFh.loadEFTransparent(EF_CSP_CPHS,
   1194                         obtainMessage(EVENT_GET_CSP_CPHS_DONE));
   1195                 break;
   1196             default:
   1197                 // For now, fetch all records if this is not a
   1198                 // voicemail number.
   1199                 // TODO: Handle other cases, instead of fetching all.
   1200                 mAdnCache.reset();
   1201                 fetchSimRecords();
   1202                 break;
   1203         }
   1204     }
   1205 
   1206     private void handleSimRefresh(IccRefreshResponse refreshResponse){
   1207         if (refreshResponse == null) {
   1208             if (DBG) log("handleSimRefresh received without input");
   1209             return;
   1210         }
   1211 
   1212         if (refreshResponse.aid != null &&
   1213                 !refreshResponse.aid.equals(mParentApp.getAid())) {
   1214             // This is for different app. Ignore.
   1215             return;
   1216         }
   1217 
   1218         switch (refreshResponse.refreshResult) {
   1219             case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE:
   1220                 if (DBG) log("handleSimRefresh with SIM_FILE_UPDATED");
   1221                 handleFileUpdate(refreshResponse.efId);
   1222                 break;
   1223             case IccRefreshResponse.REFRESH_RESULT_INIT:
   1224                 if (DBG) log("handleSimRefresh with SIM_REFRESH_INIT");
   1225                 // need to reload all files (that we care about)
   1226                 onIccRefreshInit();
   1227                 break;
   1228             case IccRefreshResponse.REFRESH_RESULT_RESET:
   1229                 if (DBG) log("handleSimRefresh with SIM_REFRESH_RESET");
   1230                 mCi.setRadioPower(false, null);
   1231                 /* Note: no need to call setRadioPower(true).  Assuming the desired
   1232                 * radio power state is still ON (as tracked by ServiceStateTracker),
   1233                 * ServiceStateTracker will call setRadioPower when it receives the
   1234                 * RADIO_STATE_CHANGED notification for the power off.  And if the
   1235                 * desired power state has changed in the interim, we don't want to
   1236                 * override it with an unconditional power on.
   1237                 */
   1238                 mAdnCache.reset();
   1239                 break;
   1240             default:
   1241                 // unknown refresh operation
   1242                 if (DBG) log("handleSimRefresh with unknown operation");
   1243                 break;
   1244         }
   1245     }
   1246 
   1247     /**
   1248      * Dispatch 3GPP format message to registrant ({@code GSMPhone} or {@code CDMALTEPhone})
   1249      * to pass to the 3GPP SMS dispatcher for delivery.
   1250      */
   1251     private int dispatchGsmMessage(SmsMessage message) {
   1252         mNewSmsRegistrants.notifyResult(message);
   1253         return 0;
   1254     }
   1255 
   1256     private void handleSms(byte[] ba) {
   1257         if (ba[0] != 0)
   1258             Rlog.d("ENF", "status : " + ba[0]);
   1259 
   1260         // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
   1261         // 3 == "received by MS from network; message to be read"
   1262         if (ba[0] == 3) {
   1263             int n = ba.length;
   1264 
   1265             // Note: Data may include trailing FF's.  That's OK; message
   1266             // should still parse correctly.
   1267             byte[] pdu = new byte[n - 1];
   1268             System.arraycopy(ba, 1, pdu, 0, n - 1);
   1269             SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP);
   1270 
   1271             dispatchGsmMessage(message);
   1272         }
   1273     }
   1274 
   1275 
   1276     private void handleSmses(ArrayList<byte[]> messages) {
   1277         int count = messages.size();
   1278 
   1279         for (int i = 0; i < count; i++) {
   1280             byte[] ba = messages.get(i);
   1281 
   1282             if (ba[0] != 0)
   1283                 Rlog.i("ENF", "status " + i + ": " + ba[0]);
   1284 
   1285             // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
   1286             // 3 == "received by MS from network; message to be read"
   1287 
   1288             if (ba[0] == 3) {
   1289                 int n = ba.length;
   1290 
   1291                 // Note: Data may include trailing FF's.  That's OK; message
   1292                 // should still parse correctly.
   1293                 byte[] pdu = new byte[n - 1];
   1294                 System.arraycopy(ba, 1, pdu, 0, n - 1);
   1295                 SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP);
   1296 
   1297                 dispatchGsmMessage(message);
   1298 
   1299                 // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
   1300                 // 1 == "received by MS from network; message read"
   1301 
   1302                 ba[0] = 1;
   1303 
   1304                 if (false) { // FIXME: writing seems to crash RdoServD
   1305                     mFh.updateEFLinearFixed(EF_SMS,
   1306                             i, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, i));
   1307                 }
   1308             }
   1309         }
   1310     }
   1311 
   1312     @Override
   1313     protected void onRecordLoaded() {
   1314         // One record loaded successfully or failed, In either case
   1315         // we need to update the recordsToLoad count
   1316         mRecordsToLoad -= 1;
   1317         if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested);
   1318 
   1319         if (mRecordsToLoad == 0 && mRecordsRequested == true) {
   1320             onAllRecordsLoaded();
   1321         } else if (mRecordsToLoad < 0) {
   1322             loge("recordsToLoad <0, programmer error suspected");
   1323             mRecordsToLoad = 0;
   1324         }
   1325     }
   1326 
   1327     @Override
   1328     protected void onAllRecordsLoaded() {
   1329         if (DBG) log("record load complete");
   1330 
   1331         // Some fields require more than one SIM record to set
   1332 
   1333         String operator = getOperatorNumeric();
   1334         if (!TextUtils.isEmpty(operator)) {
   1335             log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" +
   1336                     operator + "'");
   1337             SystemProperties.set(PROPERTY_ICC_OPERATOR_NUMERIC, operator);
   1338         } else {
   1339             log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping");
   1340         }
   1341 
   1342         if (!TextUtils.isEmpty(mImsi)) {
   1343             log("onAllRecordsLoaded set mcc imsi=" + mImsi);
   1344             SystemProperties.set(PROPERTY_ICC_OPERATOR_ISO_COUNTRY,
   1345                     MccTable.countryCodeForMcc(Integer.parseInt(mImsi.substring(0,3))));
   1346         } else {
   1347             log("onAllRecordsLoaded empty imsi skipping setting mcc");
   1348         }
   1349 
   1350         setVoiceMailByCountry(operator);
   1351         setSpnFromConfig(operator);
   1352 
   1353         mRecordsLoadedRegistrants.notifyRegistrants(
   1354             new AsyncResult(null, null, null));
   1355     }
   1356 
   1357     //***** Private methods
   1358 
   1359     private void setSpnFromConfig(String carrier) {
   1360         if (mSpnOverride.containsCarrier(carrier)) {
   1361             mSpn = mSpnOverride.getSpn(carrier);
   1362         }
   1363     }
   1364 
   1365 
   1366     private void setVoiceMailByCountry (String spn) {
   1367         if (mVmConfig.containsCarrier(spn)) {
   1368             mIsVoiceMailFixed = true;
   1369             mVoiceMailNum = mVmConfig.getVoiceMailNumber(spn);
   1370             mVoiceMailTag = mVmConfig.getVoiceMailTag(spn);
   1371         }
   1372     }
   1373 
   1374     @Override
   1375     public void onReady() {
   1376         fetchSimRecords();
   1377     }
   1378 
   1379     protected void fetchSimRecords() {
   1380         mRecordsRequested = true;
   1381 
   1382         if (DBG) log("fetchSimRecords " + mRecordsToLoad);
   1383 
   1384         mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
   1385         mRecordsToLoad++;
   1386 
   1387         mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
   1388         mRecordsToLoad++;
   1389 
   1390         // FIXME should examine EF[MSISDN]'s capability configuration
   1391         // to determine which is the voice/data/fax line
   1392         new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, EF_EXT1, 1,
   1393                     obtainMessage(EVENT_GET_MSISDN_DONE));
   1394         mRecordsToLoad++;
   1395 
   1396         // Record number is subscriber profile
   1397         mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));
   1398         mRecordsToLoad++;
   1399 
   1400         mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
   1401         mRecordsToLoad++;
   1402 
   1403         // Record number is subscriber profile
   1404         mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE));
   1405         mRecordsToLoad++;
   1406 
   1407 
   1408         // Also load CPHS-style voice mail indicator, which stores
   1409         // the same info as EF[MWIS]. If both exist, both are updated
   1410         // but the EF[MWIS] data is preferred
   1411         // Please note this must be loaded after EF[MWIS]
   1412         mFh.loadEFTransparent(
   1413                 EF_VOICE_MAIL_INDICATOR_CPHS,
   1414                 obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE));
   1415         mRecordsToLoad++;
   1416 
   1417         // Same goes for Call Forward Status indicator: fetch both
   1418         // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred.
   1419         mFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE));
   1420         mRecordsToLoad++;
   1421         mFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE));
   1422         mRecordsToLoad++;
   1423 
   1424 
   1425         getSpnFsm(true, null);
   1426 
   1427         mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));
   1428         mRecordsToLoad++;
   1429 
   1430         mFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE));
   1431         mRecordsToLoad++;
   1432 
   1433         mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));
   1434         mRecordsToLoad++;
   1435 
   1436         mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));
   1437         mRecordsToLoad++;
   1438 
   1439         mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE));
   1440         mRecordsToLoad++;
   1441 
   1442         mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE));
   1443         mRecordsToLoad++;
   1444 
   1445         // XXX should seek instead of examining them all
   1446         if (false) { // XXX
   1447             mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));
   1448             mRecordsToLoad++;
   1449         }
   1450 
   1451         if (CRASH_RIL) {
   1452             String sms = "0107912160130310f20404d0110041007030208054832b0120"
   1453                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
   1454                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
   1455                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
   1456                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
   1457                          + "ffffffffffffffffffffffffffffff";
   1458             byte[] ba = IccUtils.hexStringToBytes(sms);
   1459 
   1460             mFh.updateEFLinearFixed(EF_SMS, 1, ba, null,
   1461                             obtainMessage(EVENT_MARK_SMS_READ_DONE, 1));
   1462         }
   1463         if (DBG) log("fetchSimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested);
   1464     }
   1465 
   1466     /**
   1467      * Returns the SpnDisplayRule based on settings on the SIM and the
   1468      * specified plmn (currently-registered PLMN).  See TS 22.101 Annex A
   1469      * and TS 51.011 10.3.11 for details.
   1470      *
   1471      * If the SPN is not found on the SIM or is empty, the rule is
   1472      * always PLMN_ONLY.
   1473      */
   1474     @Override
   1475     public int getDisplayRule(String plmn) {
   1476         int rule;
   1477         if (TextUtils.isEmpty(mSpn) || mSpnDisplayCondition == -1) {
   1478             // No EF_SPN content was found on the SIM, or not yet loaded.  Just show ONS.
   1479             rule = SPN_RULE_SHOW_PLMN;
   1480         } else if (isOnMatchingPlmn(plmn)) {
   1481             rule = SPN_RULE_SHOW_SPN;
   1482             if ((mSpnDisplayCondition & 0x01) == 0x01) {
   1483                 // ONS required when registered to HPLMN or PLMN in EF_SPDI
   1484                 rule |= SPN_RULE_SHOW_PLMN;
   1485             }
   1486         } else {
   1487             rule = SPN_RULE_SHOW_PLMN;
   1488             if ((mSpnDisplayCondition & 0x02) == 0x00) {
   1489                 // SPN required if not registered to HPLMN or PLMN in EF_SPDI
   1490                 rule |= SPN_RULE_SHOW_SPN;
   1491             }
   1492         }
   1493         return rule;
   1494     }
   1495 
   1496     /**
   1497      * Checks if plmn is HPLMN or on the spdiNetworks list.
   1498      */
   1499     private boolean isOnMatchingPlmn(String plmn) {
   1500         if (plmn == null) return false;
   1501 
   1502         if (plmn.equals(getOperatorNumeric())) {
   1503             return true;
   1504         }
   1505 
   1506         if (mSpdiNetworks != null) {
   1507             for (String spdiNet : mSpdiNetworks) {
   1508                 if (plmn.equals(spdiNet)) {
   1509                     return true;
   1510                 }
   1511             }
   1512         }
   1513         return false;
   1514     }
   1515 
   1516     /**
   1517      * States of Get SPN Finite State Machine which only used by getSpnFsm()
   1518      */
   1519     private enum GetSpnFsmState {
   1520         IDLE,               // No initialized
   1521         INIT,               // Start FSM
   1522         READ_SPN_3GPP,      // Load EF_SPN firstly
   1523         READ_SPN_CPHS,      // Load EF_SPN_CPHS secondly
   1524         READ_SPN_SHORT_CPHS // Load EF_SPN_SHORT_CPHS last
   1525     }
   1526 
   1527     /**
   1528      * Finite State Machine to load Service Provider Name , which can be stored
   1529      * in either EF_SPN (3GPP), EF_SPN_CPHS, or EF_SPN_SHORT_CPHS (CPHS4.2)
   1530      *
   1531      * After starting, FSM will search SPN EFs in order and stop after finding
   1532      * the first valid SPN
   1533      *
   1534      * If the FSM gets restart while waiting for one of
   1535      * SPN EFs results (i.e. a SIM refresh occurs after issuing
   1536      * read EF_CPHS_SPN), it will re-initialize only after
   1537      * receiving and discarding the unfinished SPN EF result.
   1538      *
   1539      * @param start set true only for initialize loading
   1540      * @param ar the AsyncResult from loadEFTransparent
   1541      *        ar.exception holds exception in error
   1542      *        ar.result is byte[] for data in success
   1543      */
   1544     private void getSpnFsm(boolean start, AsyncResult ar) {
   1545         byte[] data;
   1546 
   1547         if (start) {
   1548             // Check previous state to see if there is outstanding
   1549             // SPN read
   1550             if(mSpnState == GetSpnFsmState.READ_SPN_3GPP ||
   1551                mSpnState == GetSpnFsmState.READ_SPN_CPHS ||
   1552                mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS ||
   1553                mSpnState == GetSpnFsmState.INIT) {
   1554                 // Set INIT then return so the INIT code
   1555                 // will run when the outstanding read done.
   1556                 mSpnState = GetSpnFsmState.INIT;
   1557                 return;
   1558             } else {
   1559                 mSpnState = GetSpnFsmState.INIT;
   1560             }
   1561         }
   1562 
   1563         switch(mSpnState){
   1564             case INIT:
   1565                 mSpn = null;
   1566 
   1567                 mFh.loadEFTransparent(EF_SPN,
   1568                         obtainMessage(EVENT_GET_SPN_DONE));
   1569                 mRecordsToLoad++;
   1570 
   1571                 mSpnState = GetSpnFsmState.READ_SPN_3GPP;
   1572                 break;
   1573             case READ_SPN_3GPP:
   1574                 if (ar != null && ar.exception == null) {
   1575                     data = (byte[]) ar.result;
   1576                     mSpnDisplayCondition = 0xff & data[0];
   1577                     mSpn = IccUtils.adnStringFieldToString(data, 1, data.length - 1);
   1578 
   1579                     if (DBG) log("Load EF_SPN: " + mSpn
   1580                             + " spnDisplayCondition: " + mSpnDisplayCondition);
   1581                     SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, mSpn);
   1582 
   1583                     mSpnState = GetSpnFsmState.IDLE;
   1584                 } else {
   1585                     mFh.loadEFTransparent( EF_SPN_CPHS,
   1586                             obtainMessage(EVENT_GET_SPN_DONE));
   1587                     mRecordsToLoad++;
   1588 
   1589                     mSpnState = GetSpnFsmState.READ_SPN_CPHS;
   1590 
   1591                     // See TS 51.011 10.3.11.  Basically, default to
   1592                     // show PLMN always, and SPN also if roaming.
   1593                     mSpnDisplayCondition = -1;
   1594                 }
   1595                 break;
   1596             case READ_SPN_CPHS:
   1597                 if (ar != null && ar.exception == null) {
   1598                     data = (byte[]) ar.result;
   1599                     mSpn = IccUtils.adnStringFieldToString(data, 0, data.length);
   1600 
   1601                     if (DBG) log("Load EF_SPN_CPHS: " + mSpn);
   1602                     SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, mSpn);
   1603 
   1604                     mSpnState = GetSpnFsmState.IDLE;
   1605                 } else {
   1606                     mFh.loadEFTransparent(
   1607                             EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE));
   1608                     mRecordsToLoad++;
   1609 
   1610                     mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS;
   1611                 }
   1612                 break;
   1613             case READ_SPN_SHORT_CPHS:
   1614                 if (ar != null && ar.exception == null) {
   1615                     data = (byte[]) ar.result;
   1616                     mSpn = IccUtils.adnStringFieldToString(data, 0, data.length);
   1617 
   1618                     if (DBG) log("Load EF_SPN_SHORT_CPHS: " + mSpn);
   1619                     SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, mSpn);
   1620                 }else {
   1621                     if (DBG) log("No SPN loaded in either CHPS or 3GPP");
   1622                 }
   1623 
   1624                 mSpnState = GetSpnFsmState.IDLE;
   1625                 break;
   1626             default:
   1627                 mSpnState = GetSpnFsmState.IDLE;
   1628         }
   1629     }
   1630 
   1631     /**
   1632      * Parse TS 51.011 EF[SPDI] record
   1633      * This record contains the list of numeric network IDs that
   1634      * are treated specially when determining SPN display
   1635      */
   1636     private void
   1637     parseEfSpdi(byte[] data) {
   1638         SimTlv tlv = new SimTlv(data, 0, data.length);
   1639 
   1640         byte[] plmnEntries = null;
   1641 
   1642         for ( ; tlv.isValidObject() ; tlv.nextObject()) {
   1643             // Skip SPDI tag, if existant
   1644             if (tlv.getTag() == TAG_SPDI) {
   1645               tlv = new SimTlv(tlv.getData(), 0, tlv.getData().length);
   1646             }
   1647             // There should only be one TAG_SPDI_PLMN_LIST
   1648             if (tlv.getTag() == TAG_SPDI_PLMN_LIST) {
   1649                 plmnEntries = tlv.getData();
   1650                 break;
   1651             }
   1652         }
   1653 
   1654         if (plmnEntries == null) {
   1655             return;
   1656         }
   1657 
   1658         mSpdiNetworks = new ArrayList<String>(plmnEntries.length / 3);
   1659 
   1660         for (int i = 0 ; i + 2 < plmnEntries.length ; i += 3) {
   1661             String plmnCode;
   1662             plmnCode = IccUtils.bcdToString(plmnEntries, i, 3);
   1663 
   1664             // Valid operator codes are 5 or 6 digits
   1665             if (plmnCode.length() >= 5) {
   1666                 log("EF_SPDI network: " + plmnCode);
   1667                 mSpdiNetworks.add(plmnCode);
   1668             }
   1669         }
   1670     }
   1671 
   1672     /**
   1673      * check to see if Mailbox Number is allocated and activated in CPHS SST
   1674      */
   1675     private boolean isCphsMailboxEnabled() {
   1676         if (mCphsInfo == null)  return false;
   1677         return ((mCphsInfo[1] & CPHS_SST_MBN_MASK) == CPHS_SST_MBN_ENABLED );
   1678     }
   1679 
   1680     @Override
   1681     protected void log(String s) {
   1682         Rlog.d(LOG_TAG, "[SIMRecords] " + s);
   1683     }
   1684 
   1685     @Override
   1686     protected void loge(String s) {
   1687         Rlog.e(LOG_TAG, "[SIMRecords] " + s);
   1688     }
   1689 
   1690     protected void logw(String s, Throwable tr) {
   1691         Rlog.w(LOG_TAG, "[SIMRecords] " + s, tr);
   1692     }
   1693 
   1694     protected void logv(String s) {
   1695         Rlog.v(LOG_TAG, "[SIMRecords] " + s);
   1696     }
   1697 
   1698     /**
   1699      * Return true if "Restriction of menu options for manual PLMN selection"
   1700      * bit is set or EF_CSP data is unavailable, return false otherwise.
   1701      */
   1702     @Override
   1703     public boolean isCspPlmnEnabled() {
   1704         return mCspPlmnEnabled;
   1705     }
   1706 
   1707     /**
   1708      * Parse EF_CSP data and check if
   1709      * "Restriction of menu options for manual PLMN selection" is
   1710      * Enabled/Disabled
   1711      *
   1712      * @param data EF_CSP hex data.
   1713      */
   1714     private void handleEfCspData(byte[] data) {
   1715         // As per spec CPHS4_2.WW6, CPHS B.4.7.1, EF_CSP contains CPHS defined
   1716         // 18 bytes (i.e 9 service groups info) and additional data specific to
   1717         // operator. The valueAddedServicesGroup is not part of standard
   1718         // services. This is operator specific and can be programmed any where.
   1719         // Normally this is programmed as 10th service after the standard
   1720         // services.
   1721         int usedCspGroups = data.length / 2;
   1722         // This is the "Service Group Number" of "Value Added Services Group".
   1723         byte valueAddedServicesGroup = (byte)0xC0;
   1724 
   1725         mCspPlmnEnabled = true;
   1726         for (int i = 0; i < usedCspGroups; i++) {
   1727              if (data[2 * i] == valueAddedServicesGroup) {
   1728                  log("[CSP] found ValueAddedServicesGroup, value " + data[(2 * i) + 1]);
   1729                  if ((data[(2 * i) + 1] & 0x80) == 0x80) {
   1730                      // Bit 8 is for
   1731                      // "Restriction of menu options for manual PLMN selection".
   1732                      // Operator Selection menu should be enabled.
   1733                      mCspPlmnEnabled = true;
   1734                  } else {
   1735                      mCspPlmnEnabled = false;
   1736                      // Operator Selection menu should be disabled.
   1737                      // Operator Selection Mode should be set to Automatic.
   1738                      log("[CSP] Set Automatic Network Selection");
   1739                      mNetworkSelectionModeAutomaticRegistrants.notifyRegistrants();
   1740                  }
   1741                  return;
   1742              }
   1743         }
   1744 
   1745         log("[CSP] Value Added Service Group (0xC0), not found!");
   1746     }
   1747 
   1748     @Override
   1749     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1750         pw.println("SIMRecords: " + this);
   1751         pw.println(" extends:");
   1752         super.dump(fd, pw, args);
   1753         pw.println(" mVmConfig=" + mVmConfig);
   1754         pw.println(" mSpnOverride=" + mSpnOverride);
   1755         pw.println(" mCallForwardingEnabled=" + mCallForwardingEnabled);
   1756         pw.println(" mSpnState=" + mSpnState);
   1757         pw.println(" mCphsInfo=" + mCphsInfo);
   1758         pw.println(" mCspPlmnEnabled=" + mCspPlmnEnabled);
   1759         pw.println(" mEfMWIS[]=" + Arrays.toString(mEfMWIS));
   1760         pw.println(" mEfCPHS_MWI[]=" + Arrays.toString(mEfCPHS_MWI));
   1761         pw.println(" mEfCff[]=" + Arrays.toString(mEfCff));
   1762         pw.println(" mEfCfis[]=" + Arrays.toString(mEfCfis));
   1763         pw.println(" mSpnDisplayCondition=" + mSpnDisplayCondition);
   1764         pw.println(" mSpdiNetworks[]=" + mSpdiNetworks);
   1765         pw.println(" mPnnHomeName=" + mPnnHomeName);
   1766         pw.println(" mUsimServiceTable=" + mUsimServiceTable);
   1767         pw.println(" mGid1=" + mGid1);
   1768         pw.flush();
   1769     }
   1770 }
   1771