Home | History | Annotate | Download | only in uicc
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.telephony.uicc;
     18 
     19 import android.content.Context;
     20 import android.content.res.Resources;
     21 import android.os.AsyncResult;
     22 import android.os.Message;
     23 import android.os.PersistableBundle;
     24 import android.telephony.CarrierConfigManager;
     25 import android.telephony.PhoneNumberUtils;
     26 import android.telephony.Rlog;
     27 import android.telephony.ServiceState;
     28 import android.telephony.SmsMessage;
     29 import android.telephony.SubscriptionInfo;
     30 import android.text.TextUtils;
     31 
     32 import com.android.internal.telephony.CommandsInterface;
     33 import com.android.internal.telephony.MccTable;
     34 import com.android.internal.telephony.SmsConstants;
     35 import com.android.internal.telephony.SubscriptionController;
     36 import com.android.internal.telephony.gsm.SimTlv;
     37 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
     38 
     39 import java.io.FileDescriptor;
     40 import java.io.PrintWriter;
     41 import java.util.ArrayList;
     42 import java.util.Arrays;
     43 
     44 /**
     45  * {@hide}
     46  */
     47 public class SIMRecords extends IccRecords {
     48     protected static final String LOG_TAG = "SIMRecords";
     49 
     50     private static final boolean CRASH_RIL = false;
     51 
     52     private static final boolean VDBG = false;
     53 
     54     // ***** Instance Variables
     55 
     56     VoiceMailConstants mVmConfig;
     57 
     58     // ***** Cached SIM State; cleared on channel close
     59 
     60     private int mCallForwardingStatus;
     61 
     62 
     63     /**
     64      * States only used by getSpnFsm FSM
     65      */
     66     private GetSpnFsmState mSpnState;
     67 
     68     /** CPHS service information (See CPHS 4.2 B.3.1.1)
     69      *  It will be set in onSimReady if reading GET_CPHS_INFO successfully
     70      *  mCphsInfo[0] is CPHS Phase
     71      *  mCphsInfo[1] and mCphsInfo[2] is CPHS Service Table
     72      */
     73     private byte[] mCphsInfo = null;
     74     boolean mCspPlmnEnabled = true;
     75 
     76     byte[] mEfMWIS = null;
     77     byte[] mEfCPHS_MWI =null;
     78     byte[] mEfCff = null;
     79     byte[] mEfCfis = null;
     80 
     81     byte[] mEfLi = null;
     82     byte[] mEfPl = null;
     83 
     84     int mSpnDisplayCondition;
     85     // Numeric network codes listed in TS 51.011 EF[SPDI]
     86     ArrayList<String> mSpdiNetworks = null;
     87 
     88     UsimServiceTable mUsimServiceTable;
     89 
     90     @Override
     91     public String toString() {
     92         return "SimRecords: " + super.toString()
     93                 + " mVmConfig" + mVmConfig
     94                 + " callForwardingEnabled=" + mCallForwardingStatus
     95                 + " spnState=" + mSpnState
     96                 + " mCphsInfo=" + mCphsInfo
     97                 + " mCspPlmnEnabled=" + mCspPlmnEnabled
     98                 + " efMWIS=" + mEfMWIS
     99                 + " efCPHS_MWI=" + mEfCPHS_MWI
    100                 + " mEfCff=" + mEfCff
    101                 + " mEfCfis=" + mEfCfis
    102                 + " getOperatorNumeric=" + getOperatorNumeric();
    103     }
    104 
    105     // ***** Constants
    106 
    107     // From TS 51.011 EF[SPDI] section
    108     static final int TAG_SPDI = 0xA3;
    109     static final int TAG_SPDI_PLMN_LIST = 0x80;
    110 
    111     // Full Name IEI from TS 24.008
    112     static final int TAG_FULL_NETWORK_NAME = 0x43;
    113 
    114     // Short Name IEI from TS 24.008
    115     static final int TAG_SHORT_NETWORK_NAME = 0x45;
    116 
    117     // active CFF from CPHS 4.2 B.4.5
    118     static final int CFF_UNCONDITIONAL_ACTIVE = 0x0a;
    119     static final int CFF_UNCONDITIONAL_DEACTIVE = 0x05;
    120     static final int CFF_LINE1_MASK = 0x0f;
    121     static final int CFF_LINE1_RESET = 0xf0;
    122 
    123     // CPHS Service Table (See CPHS 4.2 B.3.1)
    124     private static final int CPHS_SST_MBN_MASK = 0x30;
    125     private static final int CPHS_SST_MBN_ENABLED = 0x30;
    126 
    127     // EF_CFIS related constants
    128     // Spec reference TS 51.011 section 10.3.46.
    129     private static final int CFIS_BCD_NUMBER_LENGTH_OFFSET = 2;
    130     private static final int CFIS_TON_NPI_OFFSET = 3;
    131     private static final int CFIS_ADN_CAPABILITY_ID_OFFSET = 14;
    132     private static final int CFIS_ADN_EXTENSION_ID_OFFSET = 15;
    133 
    134     // ***** Event Constants
    135     private static final int SIM_RECORD_EVENT_BASE = 0x00;
    136     private static final int EVENT_GET_IMSI_DONE = 3 + SIM_RECORD_EVENT_BASE;
    137     private static final int EVENT_GET_ICCID_DONE = 4 + SIM_RECORD_EVENT_BASE;
    138     private static final int EVENT_GET_MBI_DONE = 5 + SIM_RECORD_EVENT_BASE;
    139     private static final int EVENT_GET_MBDN_DONE = 6 + SIM_RECORD_EVENT_BASE;
    140     private static final int EVENT_GET_MWIS_DONE = 7 + SIM_RECORD_EVENT_BASE;
    141     private static final int EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE = 8 + SIM_RECORD_EVENT_BASE;
    142     private static final int EVENT_GET_AD_DONE = 9 + SIM_RECORD_EVENT_BASE; // Admin data on SIM
    143     private static final int EVENT_GET_MSISDN_DONE = 10 + SIM_RECORD_EVENT_BASE;
    144     private static final int EVENT_GET_CPHS_MAILBOX_DONE = 11 + SIM_RECORD_EVENT_BASE;
    145     private static final int EVENT_GET_SPN_DONE = 12 + SIM_RECORD_EVENT_BASE;
    146     private static final int EVENT_GET_SPDI_DONE = 13 + SIM_RECORD_EVENT_BASE;
    147     private static final int EVENT_UPDATE_DONE = 14 + SIM_RECORD_EVENT_BASE;
    148     private static final int EVENT_GET_PNN_DONE = 15 + SIM_RECORD_EVENT_BASE;
    149     private static final int EVENT_GET_SST_DONE = 17 + SIM_RECORD_EVENT_BASE;
    150     private static final int EVENT_GET_ALL_SMS_DONE = 18 + SIM_RECORD_EVENT_BASE;
    151     private static final int EVENT_MARK_SMS_READ_DONE = 19 + SIM_RECORD_EVENT_BASE;
    152     private static final int EVENT_SET_MBDN_DONE = 20 + SIM_RECORD_EVENT_BASE;
    153     private static final int EVENT_SMS_ON_SIM = 21 + SIM_RECORD_EVENT_BASE;
    154     private static final int EVENT_GET_SMS_DONE = 22 + SIM_RECORD_EVENT_BASE;
    155     private static final int EVENT_GET_CFF_DONE = 24 + SIM_RECORD_EVENT_BASE;
    156     private static final int EVENT_SET_CPHS_MAILBOX_DONE = 25 + SIM_RECORD_EVENT_BASE;
    157     private static final int EVENT_GET_INFO_CPHS_DONE = 26 + SIM_RECORD_EVENT_BASE;
    158     private static final int EVENT_SET_MSISDN_DONE = 30 + SIM_RECORD_EVENT_BASE;
    159     private static final int EVENT_GET_CFIS_DONE = 32 + SIM_RECORD_EVENT_BASE;
    160     private static final int EVENT_GET_CSP_CPHS_DONE = 33 + SIM_RECORD_EVENT_BASE;
    161     private static final int EVENT_GET_GID1_DONE = 34 + SIM_RECORD_EVENT_BASE;
    162     private static final int EVENT_GET_GID2_DONE = 36 + SIM_RECORD_EVENT_BASE;
    163     private static final int EVENT_GET_PLMN_W_ACT_DONE = 37 + SIM_RECORD_EVENT_BASE;
    164     private static final int EVENT_GET_OPLMN_W_ACT_DONE = 38 + SIM_RECORD_EVENT_BASE;
    165     private static final int EVENT_GET_HPLMN_W_ACT_DONE = 39 + SIM_RECORD_EVENT_BASE;
    166     private static final int EVENT_GET_EHPLMN_DONE = 40 + SIM_RECORD_EVENT_BASE;
    167     private static final int EVENT_GET_FPLMN_DONE = 41 + SIM_RECORD_EVENT_BASE;
    168 
    169     // TODO: Possibly move these to IccRecords.java
    170     private static final int SYSTEM_EVENT_BASE = 0x100;
    171     private static final int EVENT_APP_LOCKED = 2 + SYSTEM_EVENT_BASE;
    172     private static final int EVENT_APP_NETWORK_LOCKED = 3 + SYSTEM_EVENT_BASE;
    173 
    174 
    175     // Lookup table for carriers known to produce SIMs which incorrectly indicate MNC length.
    176 
    177     private static final String[] MCCMNC_CODES_HAVING_3DIGITS_MNC = {
    178         "302370", "302720", "310260",
    179         "405025", "405026", "405027", "405028", "405029", "405030", "405031", "405032",
    180         "405033", "405034", "405035", "405036", "405037", "405038", "405039", "405040",
    181         "405041", "405042", "405043", "405044", "405045", "405046", "405047", "405750",
    182         "405751", "405752", "405753", "405754", "405755", "405756", "405799", "405800",
    183         "405801", "405802", "405803", "405804", "405805", "405806", "405807", "405808",
    184         "405809", "405810", "405811", "405812", "405813", "405814", "405815", "405816",
    185         "405817", "405818", "405819", "405820", "405821", "405822", "405823", "405824",
    186         "405825", "405826", "405827", "405828", "405829", "405830", "405831", "405832",
    187         "405833", "405834", "405835", "405836", "405837", "405838", "405839", "405840",
    188         "405841", "405842", "405843", "405844", "405845", "405846", "405847", "405848",
    189         "405849", "405850", "405851", "405852", "405853", "405854", "405855", "405856",
    190         "405857", "405858", "405859", "405860", "405861", "405862", "405863", "405864",
    191         "405865", "405866", "405867", "405868", "405869", "405870", "405871", "405872",
    192         "405873", "405874", "405875", "405876", "405877", "405878", "405879", "405880",
    193         "405881", "405882", "405883", "405884", "405885", "405886", "405908", "405909",
    194         "405910", "405911", "405912", "405913", "405914", "405915", "405916", "405917",
    195         "405918", "405919", "405920", "405921", "405922", "405923", "405924", "405925",
    196         "405926", "405927", "405928", "405929", "405930", "405931", "405932", "502142",
    197         "502143", "502145", "502146", "502147", "502148"
    198     };
    199 
    200     // ***** Constructor
    201 
    202     public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) {
    203         super(app, c, ci);
    204 
    205         mAdnCache = new AdnRecordCache(mFh);
    206 
    207         mVmConfig = new VoiceMailConstants();
    208 
    209         mRecordsRequested = false;  // No load request is made till SIM ready
    210         mLockedRecordsReqReason = LOCKED_RECORDS_REQ_REASON_NONE;
    211 
    212         // recordsToLoad is set to 0 because no requests are made yet
    213         mRecordsToLoad = 0;
    214 
    215         mCi.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null);
    216 
    217         // Start off by setting empty state
    218         resetRecords();
    219         mParentApp.registerForReady(this, EVENT_APP_READY, null);
    220         mParentApp.registerForLocked(this, EVENT_APP_LOCKED, null);
    221         mParentApp.registerForNetworkLocked(this, EVENT_APP_NETWORK_LOCKED, null);
    222         if (DBG) log("SIMRecords X ctor this=" + this);
    223     }
    224 
    225     @Override
    226     public void dispose() {
    227         if (DBG) log("Disposing SIMRecords this=" + this);
    228         //Unregister for all events
    229         mCi.unSetOnSmsOnSim(this);
    230         mParentApp.unregisterForReady(this);
    231         mParentApp.unregisterForLocked(this);
    232         mParentApp.unregisterForNetworkLocked(this);
    233         resetRecords();
    234         super.dispose();
    235     }
    236 
    237     @Override
    238     protected void finalize() {
    239         if (DBG) log("finalized");
    240     }
    241 
    242     protected void resetRecords() {
    243         mImsi = null;
    244         mMsisdn = null;
    245         mVoiceMailNum = null;
    246         mMncLength = UNINITIALIZED;
    247         log("setting0 mMncLength" + mMncLength);
    248         mIccId = null;
    249         mFullIccId = null;
    250         // -1 means no EF_SPN found; treat accordingly.
    251         mSpnDisplayCondition = -1;
    252         mEfMWIS = null;
    253         mEfCPHS_MWI = null;
    254         mSpdiNetworks = null;
    255         mPnnHomeName = null;
    256         mGid1 = null;
    257         mGid2 = null;
    258         mPlmnActRecords = null;
    259         mOplmnActRecords = null;
    260         mHplmnActRecords = null;
    261         mFplmns = null;
    262         mEhplmns = null;
    263 
    264         mAdnCache.reset();
    265 
    266         log("SIMRecords: onRadioOffOrNotAvailable set 'gsm.sim.operator.numeric' to operator=null");
    267         log("update icc_operator_numeric=" + null);
    268         mTelephonyManager.setSimOperatorNumericForPhone(mParentApp.getPhoneId(), "");
    269         mTelephonyManager.setSimOperatorNameForPhone(mParentApp.getPhoneId(), "");
    270         mTelephonyManager.setSimCountryIsoForPhone(mParentApp.getPhoneId(), "");
    271 
    272         // recordsRequested is set to false indicating that the SIM
    273         // read requests made so far are not valid. This is set to
    274         // true only when fresh set of read requests are made.
    275         mRecordsRequested = false;
    276         mLockedRecordsReqReason = LOCKED_RECORDS_REQ_REASON_NONE;
    277         mLoaded.set(false);
    278     }
    279 
    280     //***** Public Methods
    281 
    282     @Override
    283     public String getMsisdnNumber() {
    284         return mMsisdn;
    285     }
    286 
    287     @Override
    288     public UsimServiceTable getUsimServiceTable() {
    289         return mUsimServiceTable;
    290     }
    291 
    292     private int getExtFromEf(int ef) {
    293         int ext;
    294         switch (ef) {
    295             case EF_MSISDN:
    296                 /* For USIM apps use EXT5. (TS 31.102 Section 4.2.37) */
    297                 if (mParentApp.getType() == AppType.APPTYPE_USIM) {
    298                     ext = EF_EXT5;
    299                 } else {
    300                     ext = EF_EXT1;
    301                 }
    302                 break;
    303             default:
    304                 ext = EF_EXT1;
    305         }
    306         return ext;
    307     }
    308 
    309     /**
    310      * Set subscriber number to SIM record
    311      *
    312      * The subscriber number is stored in EF_MSISDN (TS 51.011)
    313      *
    314      * When the operation is complete, onComplete will be sent to its handler
    315      *
    316      * @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters)
    317      * @param number dialing number (up to 20 digits)
    318      *        if the number starts with '+', then set to international TOA
    319      * @param onComplete
    320      *        onComplete.obj will be an AsyncResult
    321      *        ((AsyncResult)onComplete.obj).exception == null on success
    322      *        ((AsyncResult)onComplete.obj).exception != null on fail
    323      */
    324     @Override
    325     public void setMsisdnNumber(String alphaTag, String number,
    326             Message onComplete) {
    327 
    328         // If the SIM card is locked by PIN, we will set EF_MSISDN fail.
    329         // In that case, msisdn and msisdnTag should not be update.
    330         mNewMsisdn = number;
    331         mNewMsisdnTag = alphaTag;
    332 
    333         if(DBG) log("Set MSISDN: " + mNewMsisdnTag + " " + /*mNewMsisdn*/
    334                 Rlog.pii(LOG_TAG, mNewMsisdn));
    335 
    336         AdnRecord adn = new AdnRecord(mNewMsisdnTag, mNewMsisdn);
    337 
    338         new AdnRecordLoader(mFh).updateEF(adn, EF_MSISDN, getExtFromEf(EF_MSISDN), 1, null,
    339                 obtainMessage(EVENT_SET_MSISDN_DONE, onComplete));
    340     }
    341 
    342     @Override
    343     public String getMsisdnAlphaTag() {
    344         return mMsisdnTag;
    345     }
    346 
    347     @Override
    348     public String getVoiceMailNumber() {
    349         return mVoiceMailNum;
    350     }
    351 
    352     /**
    353      * Set voice mail number to SIM record
    354      *
    355      * The voice mail number can be stored either in EF_MBDN (TS 51.011) or
    356      * EF_MAILBOX_CPHS (CPHS 4.2)
    357      *
    358      * If EF_MBDN is available, store the voice mail number to EF_MBDN
    359      *
    360      * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS
    361      *
    362      * So the voice mail number will be stored in both EFs if both are available
    363      *
    364      * Return error only if both EF_MBDN and EF_MAILBOX_CPHS fail.
    365      *
    366      * When the operation is complete, onComplete will be sent to its handler
    367      *
    368      * @param alphaTag alpha-tagging of the dailing nubmer (upto 10 characters)
    369      * @param voiceNumber dailing nubmer (upto 20 digits)
    370      *        if the number is start with '+', then set to international TOA
    371      * @param onComplete
    372      *        onComplete.obj will be an AsyncResult
    373      *        ((AsyncResult)onComplete.obj).exception == null on success
    374      *        ((AsyncResult)onComplete.obj).exception != null on fail
    375      */
    376     @Override
    377     public void setVoiceMailNumber(String alphaTag, String voiceNumber,
    378             Message onComplete) {
    379         if (mIsVoiceMailFixed) {
    380             AsyncResult.forMessage((onComplete)).exception =
    381                     new IccVmFixedException("Voicemail number is fixed by operator");
    382             onComplete.sendToTarget();
    383             return;
    384         }
    385 
    386         mNewVoiceMailNum = voiceNumber;
    387         mNewVoiceMailTag = alphaTag;
    388 
    389         AdnRecord adn = new AdnRecord(mNewVoiceMailTag, mNewVoiceMailNum);
    390 
    391         if (mMailboxIndex != 0 && mMailboxIndex != 0xff) {
    392 
    393             new AdnRecordLoader(mFh).updateEF(adn, EF_MBDN, EF_EXT6,
    394                     mMailboxIndex, null,
    395                     obtainMessage(EVENT_SET_MBDN_DONE, onComplete));
    396 
    397         } else if (isCphsMailboxEnabled()) {
    398 
    399             new AdnRecordLoader(mFh).updateEF(adn, EF_MAILBOX_CPHS,
    400                     EF_EXT1, 1, null,
    401                     obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE, onComplete));
    402 
    403         } else {
    404             AsyncResult.forMessage((onComplete)).exception =
    405                     new IccVmNotSupportedException("Update SIM voice mailbox error");
    406             onComplete.sendToTarget();
    407         }
    408     }
    409 
    410     @Override
    411     public String getVoiceMailAlphaTag()
    412     {
    413         return mVoiceMailTag;
    414     }
    415 
    416     /**
    417      * Sets the SIM voice message waiting indicator records
    418      * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
    419      * @param countWaiting The number of messages waiting, if known. Use
    420      *                     -1 to indicate that an unknown number of
    421      *                      messages are waiting
    422      */
    423     @Override
    424     public void
    425     setVoiceMessageWaiting(int line, int countWaiting) {
    426         if (line != 1) {
    427             // only profile 1 is supported
    428             return;
    429         }
    430 
    431         try {
    432             if (mEfMWIS != null) {
    433                 // TS 51.011 10.3.45
    434 
    435                 // lsb of byte 0 is 'voicemail' status
    436                 mEfMWIS[0] = (byte)((mEfMWIS[0] & 0xfe)
    437                                     | (countWaiting == 0 ? 0 : 1));
    438 
    439                 // byte 1 is the number of voice messages waiting
    440                 if (countWaiting < 0) {
    441                     // The spec does not define what this should be
    442                     // if we don't know the count
    443                     mEfMWIS[1] = 0;
    444                 } else {
    445                     mEfMWIS[1] = (byte) countWaiting;
    446                 }
    447 
    448                 mFh.updateEFLinearFixed(
    449                     EF_MWIS, 1, mEfMWIS, null,
    450                     obtainMessage (EVENT_UPDATE_DONE, EF_MWIS, 0));
    451             }
    452 
    453             if (mEfCPHS_MWI != null) {
    454                     // Refer CPHS4_2.WW6 B4.2.3
    455                 mEfCPHS_MWI[0] = (byte)((mEfCPHS_MWI[0] & 0xf0)
    456                             | (countWaiting == 0 ? 0x5 : 0xa));
    457                 mFh.updateEFTransparent(
    458                     EF_VOICE_MAIL_INDICATOR_CPHS, mEfCPHS_MWI,
    459                     obtainMessage (EVENT_UPDATE_DONE, EF_VOICE_MAIL_INDICATOR_CPHS));
    460             }
    461         } catch (ArrayIndexOutOfBoundsException ex) {
    462             logw("Error saving voice mail state to SIM. Probably malformed SIM record", ex);
    463         }
    464     }
    465 
    466     // Validate data is not null and not empty.
    467     private boolean validEfCfis(byte[] data) {
    468         if (data != null) {
    469             if (data[0] < 1 || data[0] > 4) {
    470                 // The MSP (Multiple Subscriber Profile) byte should be between
    471                 // 1 and 4 according to ETSI TS 131 102 v11.3.0 section 4.2.64.
    472                 logw("MSP byte: " + data[0] + " is not between 1 and 4", null);
    473             }
    474             // empty EF_CFIS should be considered as call forward disabled
    475             for (byte b : data) {
    476                 if (b != (byte) 0xFF) {
    477                     return true;
    478                 }
    479             }
    480         }
    481         return false;
    482     }
    483 
    484     public int getVoiceMessageCount() {
    485         boolean voiceMailWaiting = false;
    486         int countVoiceMessages = DEFAULT_VOICE_MESSAGE_COUNT;
    487         if (mEfMWIS != null) {
    488             // Use this data if the EF[MWIS] exists and
    489             // has been loaded
    490             // Refer TS 51.011 Section 10.3.45 for the content description
    491             voiceMailWaiting = ((mEfMWIS[0] & 0x01) != 0);
    492             countVoiceMessages = mEfMWIS[1] & 0xff;
    493 
    494             if (voiceMailWaiting && (countVoiceMessages == 0 || countVoiceMessages == 0xff)) {
    495                 // Unknown count = -1
    496                 countVoiceMessages = UNKNOWN_VOICE_MESSAGE_COUNT;
    497             }
    498             if (DBG) log(" VoiceMessageCount from SIM MWIS = " + countVoiceMessages);
    499         } else if (mEfCPHS_MWI != null) {
    500             // use voice mail count from CPHS
    501             int indicator = (int) (mEfCPHS_MWI[0] & 0xf);
    502 
    503             // Refer CPHS4_2.WW6 B4.2.3
    504             if (indicator == 0xA) {
    505                 // Unknown count = -1
    506                 countVoiceMessages = UNKNOWN_VOICE_MESSAGE_COUNT;
    507             } else if (indicator == 0x5) {
    508                 countVoiceMessages = 0;
    509             }
    510             if (DBG) log(" VoiceMessageCount from SIM CPHS = " + countVoiceMessages);
    511         }
    512         return countVoiceMessages;
    513     }
    514 
    515     /**
    516      * {@inheritDoc}
    517      */
    518     @Override
    519     public int getVoiceCallForwardingFlag() {
    520         return mCallForwardingStatus;
    521     }
    522 
    523     /**
    524      * {@inheritDoc}
    525      */
    526     @Override
    527     public void setVoiceCallForwardingFlag(int line, boolean enable, String dialNumber) {
    528 
    529         if (line != 1) return; // only line 1 is supported
    530 
    531         mCallForwardingStatus = enable ? CALL_FORWARDING_STATUS_ENABLED :
    532                 CALL_FORWARDING_STATUS_DISABLED;
    533 
    534         mRecordsEventsRegistrants.notifyResult(EVENT_CFI);
    535 
    536         try {
    537             if (validEfCfis(mEfCfis)) {
    538                 // lsb is of byte f1 is voice status
    539                 if (enable) {
    540                     mEfCfis[1] |= 1;
    541                 } else {
    542                     mEfCfis[1] &= 0xfe;
    543                 }
    544 
    545                 log("setVoiceCallForwardingFlag: enable=" + enable
    546                         + " mEfCfis=" + IccUtils.bytesToHexString(mEfCfis));
    547 
    548                 // Update dialNumber if not empty and CFU is enabled.
    549                 // Spec reference for EF_CFIS contents, TS 51.011 section 10.3.46.
    550                 if (enable && !TextUtils.isEmpty(dialNumber)) {
    551                     logv("EF_CFIS: updating cf number, " + Rlog.pii(LOG_TAG, dialNumber));
    552                     byte[] bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(
    553                             dialNumber, PhoneNumberUtils.BCD_EXTENDED_TYPE_EF_ADN);
    554 
    555                     System.arraycopy(bcdNumber, 0, mEfCfis, CFIS_TON_NPI_OFFSET, bcdNumber.length);
    556 
    557                     mEfCfis[CFIS_BCD_NUMBER_LENGTH_OFFSET] = (byte) (bcdNumber.length);
    558                     mEfCfis[CFIS_ADN_CAPABILITY_ID_OFFSET] = (byte) 0xFF;
    559                     mEfCfis[CFIS_ADN_EXTENSION_ID_OFFSET] = (byte) 0xFF;
    560                 }
    561 
    562                 mFh.updateEFLinearFixed(
    563                         EF_CFIS, 1, mEfCfis, null,
    564                         obtainMessage (EVENT_UPDATE_DONE, EF_CFIS));
    565             } else {
    566                 log("setVoiceCallForwardingFlag: ignoring enable=" + enable
    567                         + " invalid mEfCfis=" + IccUtils.bytesToHexString(mEfCfis));
    568             }
    569 
    570             if (mEfCff != null) {
    571                 if (enable) {
    572                     mEfCff[0] = (byte) ((mEfCff[0] & CFF_LINE1_RESET)
    573                             | CFF_UNCONDITIONAL_ACTIVE);
    574                 } else {
    575                     mEfCff[0] = (byte) ((mEfCff[0] & CFF_LINE1_RESET)
    576                             | CFF_UNCONDITIONAL_DEACTIVE);
    577                 }
    578 
    579                 mFh.updateEFTransparent(
    580                         EF_CFF_CPHS, mEfCff,
    581                         obtainMessage (EVENT_UPDATE_DONE, EF_CFF_CPHS));
    582             }
    583         } catch (ArrayIndexOutOfBoundsException ex) {
    584             logw("Error saving call forwarding flag to SIM. "
    585                             + "Probably malformed SIM record", ex);
    586 
    587         }
    588     }
    589 
    590     /**
    591      * Called by STK Service when REFRESH is received.
    592      * @param fileChanged indicates whether any files changed
    593      * @param fileList if non-null, a list of EF files that changed
    594      */
    595     @Override
    596     public void onRefresh(boolean fileChanged, int[] fileList) {
    597         if (fileChanged) {
    598             // A future optimization would be to inspect fileList and
    599             // only reload those files that we care about.  For now,
    600             // just re-fetch all SIM records that we cache.
    601             fetchSimRecords();
    602         }
    603     }
    604 
    605     /**
    606      * {@inheritDoc}
    607      */
    608     @Override
    609     public String getOperatorNumeric() {
    610         String imsi = getIMSI();
    611         if (imsi == null) {
    612             log("getOperatorNumeric: IMSI == null");
    613             return null;
    614         }
    615         if (mMncLength == UNINITIALIZED || mMncLength == UNKNOWN) {
    616             log("getSIMOperatorNumeric: bad mncLength");
    617             return null;
    618         }
    619 
    620         // Length = length of MCC + length of MNC
    621         // length of mcc = 3 (TS 23.003 Section 2.2)
    622         if (imsi.length() >= 3 + mMncLength) {
    623             return imsi.substring(0, 3 + mMncLength);
    624         } else {
    625             return null;
    626         }
    627     }
    628 
    629     // ***** Overridden from Handler
    630     @Override
    631     public void handleMessage(Message msg) {
    632         AsyncResult ar;
    633         AdnRecord adn;
    634 
    635         byte data[];
    636 
    637         boolean isRecordLoadResponse = false;
    638 
    639         if (mDestroyed.get()) {
    640             loge("Received message " + msg + "[" + msg.what + "] " +
    641                     " while being destroyed. Ignoring.");
    642             return;
    643         }
    644 
    645         try {
    646             switch (msg.what) {
    647                 case EVENT_APP_READY:
    648                     onReady();
    649                     break;
    650 
    651                 case EVENT_APP_LOCKED:
    652                 case EVENT_APP_NETWORK_LOCKED:
    653                     onLocked(msg.what);
    654                     break;
    655 
    656                 /* IO events */
    657                 case EVENT_GET_IMSI_DONE:
    658                     isRecordLoadResponse = true;
    659 
    660                     ar = (AsyncResult) msg.obj;
    661 
    662                     if (ar.exception != null) {
    663                         loge("Exception querying IMSI, Exception:" + ar.exception);
    664                         break;
    665                     }
    666 
    667                     mImsi = (String) ar.result;
    668 
    669                     // IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more
    670                     // than 15 (and usually 15).
    671                     if (mImsi != null && (mImsi.length() < 6 || mImsi.length() > 15)) {
    672                         loge("invalid IMSI " + mImsi);
    673                         mImsi = null;
    674                     }
    675 
    676                     log("IMSI: mMncLength=" + mMncLength);
    677 
    678                     if (mImsi != null && mImsi.length() >= 6) {
    679                         log("IMSI: " + mImsi.substring(0, 6)
    680                                 + Rlog.pii(LOG_TAG, mImsi.substring(6)));
    681                     }
    682 
    683                     String imsi = getIMSI();
    684 
    685                     if (((mMncLength == UNKNOWN) || (mMncLength == 2))
    686                             && ((imsi != null) && (imsi.length() >= 6))) {
    687                         String mccmncCode = imsi.substring(0, 6);
    688                         for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) {
    689                             if (mccmnc.equals(mccmncCode)) {
    690                                 mMncLength = 3;
    691                                 log("IMSI: setting1 mMncLength=" + mMncLength);
    692                                 break;
    693                             }
    694                         }
    695                     }
    696 
    697                     if (mMncLength == UNKNOWN) {
    698                         // the SIM has told us all it knows, but it didn't know the mnc length.
    699                         // guess using the mcc
    700                         try {
    701                             int mcc = Integer.parseInt(imsi.substring(0, 3));
    702                             mMncLength = MccTable.smallestDigitsMccForMnc(mcc);
    703                             log("setting2 mMncLength=" + mMncLength);
    704                         } catch (NumberFormatException e) {
    705                             mMncLength = UNKNOWN;
    706                             loge("Corrupt IMSI! setting3 mMncLength=" + mMncLength);
    707                         }
    708                     }
    709 
    710                     if (mMncLength != UNKNOWN && mMncLength != UNINITIALIZED
    711                             && imsi.length() >= 3 + mMncLength) {
    712                         log("update mccmnc=" + imsi.substring(0, 3 + mMncLength));
    713                         // finally have both the imsi and the mncLength and
    714                         // can parse the imsi properly
    715                         MccTable.updateMccMncConfiguration(mContext,
    716                                 imsi.substring(0, 3 + mMncLength), false);
    717                     }
    718                     mImsiReadyRegistrants.notifyRegistrants();
    719                     break;
    720 
    721                 case EVENT_GET_MBI_DONE:
    722                     boolean isValidMbdn;
    723                     isRecordLoadResponse = true;
    724 
    725                     ar = (AsyncResult) msg.obj;
    726                     data = (byte[]) ar.result;
    727 
    728                     isValidMbdn = false;
    729                     if (ar.exception == null) {
    730                         // Refer TS 51.011 Section 10.3.44 for content details
    731                         log("EF_MBI: " + IccUtils.bytesToHexString(data));
    732 
    733                         // Voice mail record number stored first
    734                         mMailboxIndex = data[0] & 0xff;
    735 
    736                         // check if dailing numbe id valid
    737                         if (mMailboxIndex != 0 && mMailboxIndex != 0xff) {
    738                             log("Got valid mailbox number for MBDN");
    739                             isValidMbdn = true;
    740                         }
    741                     }
    742 
    743                     // one more record to load
    744                     mRecordsToLoad += 1;
    745 
    746                     if (isValidMbdn) {
    747                         // Note: MBDN was not included in NUM_OF_SIM_RECORDS_LOADED
    748                         new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6,
    749                                 mMailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
    750                     } else {
    751                         // If this EF not present, try mailbox as in CPHS standard
    752                         // CPHS (CPHS4_2.WW6) is a european standard.
    753                         new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS,
    754                                 EF_EXT1, 1,
    755                                 obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
    756                     }
    757 
    758                     break;
    759                 case EVENT_GET_CPHS_MAILBOX_DONE:
    760                 case EVENT_GET_MBDN_DONE:
    761                     //Resetting the voice mail number and voice mail tag to null
    762                     //as these should be updated from the data read from EF_MBDN.
    763                     //If they are not reset, incase of invalid data/exception these
    764                     //variables are retaining their previous values and are
    765                     //causing invalid voice mailbox info display to user.
    766                     mVoiceMailNum = null;
    767                     mVoiceMailTag = null;
    768                     isRecordLoadResponse = true;
    769 
    770                     ar = (AsyncResult) msg.obj;
    771 
    772                     if (ar.exception != null) {
    773 
    774                         log("Invalid or missing EF"
    775                                 + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE)
    776                                     ? "[MAILBOX]" : "[MBDN]"));
    777 
    778                         // Bug #645770 fall back to CPHS
    779                         // FIXME should use SST to decide
    780 
    781                         if (msg.what == EVENT_GET_MBDN_DONE) {
    782                             //load CPHS on fail...
    783                             // FIXME right now, only load line1's CPHS voice mail entry
    784 
    785                             mRecordsToLoad += 1;
    786                             new AdnRecordLoader(mFh).loadFromEF(
    787                                     EF_MAILBOX_CPHS, EF_EXT1, 1,
    788                                     obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
    789                         }
    790                         break;
    791                     }
    792 
    793                     adn = (AdnRecord) ar.result;
    794 
    795                     log("VM: " + adn
    796                             + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE)
    797                                 ? " EF[MAILBOX]" : " EF[MBDN]"));
    798 
    799                     if (adn.isEmpty() && msg.what == EVENT_GET_MBDN_DONE) {
    800                         // Bug #645770 fall back to CPHS
    801                         // FIXME should use SST to decide
    802                         // FIXME right now, only load line1's CPHS voice mail entry
    803                         mRecordsToLoad += 1;
    804                         new AdnRecordLoader(mFh).loadFromEF(
    805                                 EF_MAILBOX_CPHS, EF_EXT1, 1,
    806                                 obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
    807 
    808                         break;
    809                     }
    810 
    811                     mVoiceMailNum = adn.getNumber();
    812                     mVoiceMailTag = adn.getAlphaTag();
    813                     break;
    814 
    815                 case EVENT_GET_MSISDN_DONE:
    816                     isRecordLoadResponse = true;
    817 
    818                     ar = (AsyncResult) msg.obj;
    819 
    820                     if (ar.exception != null) {
    821                         log("Invalid or missing EF[MSISDN]");
    822                         break;
    823                     }
    824 
    825                     adn = (AdnRecord) ar.result;
    826 
    827                     mMsisdn = adn.getNumber();
    828                     mMsisdnTag = adn.getAlphaTag();
    829 
    830                     log("MSISDN: " + /*mMsisdn*/ Rlog.pii(LOG_TAG, mMsisdn));
    831                     break;
    832 
    833                 case EVENT_SET_MSISDN_DONE:
    834                     isRecordLoadResponse = false;
    835                     ar = (AsyncResult) msg.obj;
    836 
    837                     if (ar.exception == null) {
    838                         mMsisdn = mNewMsisdn;
    839                         mMsisdnTag = mNewMsisdnTag;
    840                         log("Success to update EF[MSISDN]");
    841                     }
    842 
    843                     if (ar.userObj != null) {
    844                         AsyncResult.forMessage(((Message) ar.userObj)).exception = ar.exception;
    845                         ((Message) ar.userObj).sendToTarget();
    846                     }
    847                     break;
    848 
    849                 case EVENT_GET_MWIS_DONE:
    850                     isRecordLoadResponse = true;
    851 
    852                     ar = (AsyncResult) msg.obj;
    853                     data = (byte[]) ar.result;
    854 
    855                     if (DBG) log("EF_MWIS : " + IccUtils.bytesToHexString(data));
    856 
    857                     if (ar.exception != null) {
    858                         if (DBG) log("EVENT_GET_MWIS_DONE exception = " + ar.exception);
    859                         break;
    860                     }
    861 
    862                     if ((data[0] & 0xff) == 0xff) {
    863                         if (DBG) log("SIMRecords: Uninitialized record MWIS");
    864                         break;
    865                     }
    866 
    867                     mEfMWIS = data;
    868                     break;
    869 
    870                 case EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE:
    871                     isRecordLoadResponse = true;
    872 
    873                     ar = (AsyncResult) msg.obj;
    874                     data = (byte[]) ar.result;
    875 
    876                     if (DBG) log("EF_CPHS_MWI: " + IccUtils.bytesToHexString(data));
    877 
    878                     if (ar.exception != null) {
    879                         if (DBG) {
    880                             log("EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE exception = "
    881                                     + ar.exception);
    882                         }
    883                         break;
    884                     }
    885 
    886                     mEfCPHS_MWI = data;
    887                     break;
    888 
    889                 case EVENT_GET_ICCID_DONE:
    890                     isRecordLoadResponse = true;
    891 
    892                     ar = (AsyncResult) msg.obj;
    893                     data = (byte[]) ar.result;
    894 
    895                     if (ar.exception != null) {
    896                         break;
    897                     }
    898 
    899                     mIccId = IccUtils.bcdToString(data, 0, data.length);
    900                     mFullIccId = IccUtils.bchToString(data, 0, data.length);
    901 
    902                     log("iccid: " + SubscriptionInfo.givePrintableIccid(mFullIccId));
    903                     break;
    904 
    905                 case EVENT_GET_AD_DONE:
    906                     try {
    907                         isRecordLoadResponse = true;
    908 
    909                         if (mCarrierTestOverride.isInTestMode() && getIMSI() != null) {
    910                             imsi = getIMSI();
    911                             try {
    912                                 int mcc = Integer.parseInt(imsi.substring(0, 3));
    913                                 mMncLength = MccTable.smallestDigitsMccForMnc(mcc);
    914                                 log("[TestMode] mMncLength=" + mMncLength);
    915                             } catch (NumberFormatException e) {
    916                                 mMncLength = UNKNOWN;
    917                                 loge("[TestMode] Corrupt IMSI! mMncLength=" + mMncLength);
    918                             }
    919                         } else {
    920                             ar = (AsyncResult) msg.obj;
    921                             data = (byte[]) ar.result;
    922 
    923                             if (ar.exception != null) {
    924                                 break;
    925                             }
    926 
    927                             log("EF_AD: " + IccUtils.bytesToHexString(data));
    928 
    929                             if (data.length < 3) {
    930                                 log("Corrupt AD data on SIM");
    931                                 break;
    932                             }
    933 
    934                             if (data.length == 3) {
    935                                 log("MNC length not present in EF_AD");
    936                                 break;
    937                             }
    938 
    939                             mMncLength = data[3] & 0xf;
    940                             log("setting4 mMncLength=" + mMncLength);
    941                         }
    942 
    943                         if (mMncLength == 0xf) {
    944                             mMncLength = UNKNOWN;
    945                             log("setting5 mMncLength=" + mMncLength);
    946                         } else if (mMncLength != 2 && mMncLength != 3) {
    947                             mMncLength = UNINITIALIZED;
    948                             log("setting5 mMncLength=" + mMncLength);
    949                         }
    950                     } finally {
    951 
    952                         // IMSI could be a value reading from Sim or a fake IMSI if in the test mode
    953                         imsi = getIMSI();
    954 
    955                         if (((mMncLength == UNINITIALIZED) || (mMncLength == UNKNOWN)
    956                                     || (mMncLength == 2)) && ((imsi != null)
    957                                     && (imsi.length() >= 6))) {
    958                             String mccmncCode = imsi.substring(0, 6);
    959                             log("mccmncCode=" + mccmncCode);
    960                             for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) {
    961                                 if (mccmnc.equals(mccmncCode)) {
    962                                     mMncLength = 3;
    963                                     log("setting6 mMncLength=" + mMncLength);
    964                                     break;
    965                                 }
    966                             }
    967                         }
    968 
    969                         if (mMncLength == UNKNOWN || mMncLength == UNINITIALIZED) {
    970                             if (imsi != null) {
    971                                 try {
    972                                     int mcc = Integer.parseInt(imsi.substring(0, 3));
    973 
    974                                     mMncLength = MccTable.smallestDigitsMccForMnc(mcc);
    975                                     log("setting7 mMncLength=" + mMncLength);
    976                                 } catch (NumberFormatException e) {
    977                                     mMncLength = UNKNOWN;
    978                                     loge("Corrupt IMSI! setting8 mMncLength=" + mMncLength);
    979                                 }
    980                             } else {
    981                                 // Indicate we got this info, but it didn't contain the length.
    982                                 mMncLength = UNKNOWN;
    983                                 log("MNC length not present in EF_AD setting9 "
    984                                         + "mMncLength=" + mMncLength);
    985                             }
    986                         }
    987                         if (imsi != null && mMncLength != UNKNOWN
    988                                 && imsi.length() >= 3 + mMncLength) {
    989                             // finally have both imsi and the length of the mnc and can parse
    990                             // the imsi properly
    991                             log("update mccmnc=" + imsi.substring(0, 3 + mMncLength));
    992                             MccTable.updateMccMncConfiguration(mContext,
    993                                     imsi.substring(0, 3 + mMncLength), false);
    994                         }
    995                     }
    996                     break;
    997 
    998                 case EVENT_GET_SPN_DONE:
    999                     isRecordLoadResponse = true;
   1000                     ar = (AsyncResult) msg.obj;
   1001                     getSpnFsm(false, ar);
   1002                     break;
   1003 
   1004                 case EVENT_GET_CFF_DONE:
   1005                     isRecordLoadResponse = true;
   1006 
   1007                     ar = (AsyncResult) msg.obj;
   1008                     data = (byte[]) ar.result;
   1009 
   1010                     if (ar.exception != null) {
   1011                         mEfCff = null;
   1012                     } else {
   1013                         log("EF_CFF_CPHS: " + IccUtils.bytesToHexString(data));
   1014                         mEfCff = data;
   1015                     }
   1016 
   1017                     break;
   1018 
   1019                 case EVENT_GET_SPDI_DONE:
   1020                     isRecordLoadResponse = true;
   1021 
   1022                     ar = (AsyncResult) msg.obj;
   1023                     data = (byte[]) ar.result;
   1024 
   1025                     if (ar.exception != null) {
   1026                         break;
   1027                     }
   1028 
   1029                     parseEfSpdi(data);
   1030                     break;
   1031 
   1032                 case EVENT_UPDATE_DONE:
   1033                     ar = (AsyncResult) msg.obj;
   1034                     if (ar.exception != null) {
   1035                         logw("update failed. ", ar.exception);
   1036                     }
   1037                     break;
   1038 
   1039                 case EVENT_GET_PNN_DONE:
   1040                     isRecordLoadResponse = true;
   1041 
   1042                     ar = (AsyncResult) msg.obj;
   1043                     data = (byte[]) ar.result;
   1044 
   1045                     if (ar.exception != null) {
   1046                         break;
   1047                     }
   1048 
   1049                     SimTlv tlv = new SimTlv(data, 0, data.length);
   1050 
   1051                     for (; tlv.isValidObject(); tlv.nextObject()) {
   1052                         if (tlv.getTag() == TAG_FULL_NETWORK_NAME) {
   1053                             mPnnHomeName = IccUtils.networkNameToString(
   1054                                     tlv.getData(), 0, tlv.getData().length);
   1055                             log("PNN: " + mPnnHomeName);
   1056                             break;
   1057                         }
   1058                     }
   1059                     break;
   1060 
   1061                 case EVENT_GET_ALL_SMS_DONE:
   1062                     isRecordLoadResponse = true;
   1063 
   1064                     ar = (AsyncResult) msg.obj;
   1065                     if (ar.exception != null) {
   1066                         break;
   1067                     }
   1068 
   1069                     handleSmses((ArrayList<byte []>) ar.result);
   1070                     break;
   1071 
   1072                 case EVENT_MARK_SMS_READ_DONE:
   1073                     Rlog.i("ENF", "marked read: sms " + msg.arg1);
   1074                     break;
   1075 
   1076 
   1077                 case EVENT_SMS_ON_SIM:
   1078                     isRecordLoadResponse = false;
   1079 
   1080                     ar = (AsyncResult) msg.obj;
   1081 
   1082                     Integer index = (Integer) ar.result;
   1083 
   1084                     if (ar.exception != null || index == null) {
   1085                         loge("Error on SMS_ON_SIM with exp "
   1086                                 + ar.exception + " index " + index);
   1087                     } else {
   1088                         log("READ EF_SMS RECORD index=" + index);
   1089                         mFh.loadEFLinearFixed(EF_SMS, index, obtainMessage(EVENT_GET_SMS_DONE));
   1090                     }
   1091                     break;
   1092 
   1093                 case EVENT_GET_SMS_DONE:
   1094                     isRecordLoadResponse = false;
   1095                     ar = (AsyncResult) msg.obj;
   1096                     if (ar.exception == null) {
   1097                         handleSms((byte[]) ar.result);
   1098                     } else {
   1099                         loge("Error on GET_SMS with exp " + ar.exception);
   1100                     }
   1101                     break;
   1102                 case EVENT_GET_SST_DONE:
   1103                     isRecordLoadResponse = true;
   1104 
   1105                     ar = (AsyncResult) msg.obj;
   1106                     data = (byte[]) ar.result;
   1107 
   1108                     if (ar.exception != null) {
   1109                         break;
   1110                     }
   1111 
   1112                     mUsimServiceTable = new UsimServiceTable(data);
   1113                     if (DBG) log("SST: " + mUsimServiceTable);
   1114                     break;
   1115 
   1116                 case EVENT_GET_INFO_CPHS_DONE:
   1117                     isRecordLoadResponse = true;
   1118 
   1119                     ar = (AsyncResult) msg.obj;
   1120 
   1121                     if (ar.exception != null) {
   1122                         break;
   1123                     }
   1124 
   1125                     mCphsInfo = (byte[]) ar.result;
   1126 
   1127                     if (DBG) log("iCPHS: " + IccUtils.bytesToHexString(mCphsInfo));
   1128                     break;
   1129 
   1130                 case EVENT_SET_MBDN_DONE:
   1131                     isRecordLoadResponse = false;
   1132                     ar = (AsyncResult) msg.obj;
   1133 
   1134                     if (DBG) log("EVENT_SET_MBDN_DONE ex:" + ar.exception);
   1135                     if (ar.exception == null) {
   1136                         mVoiceMailNum = mNewVoiceMailNum;
   1137                         mVoiceMailTag = mNewVoiceMailTag;
   1138                     }
   1139 
   1140                     if (isCphsMailboxEnabled()) {
   1141                         adn = new AdnRecord(mVoiceMailTag, mVoiceMailNum);
   1142                         Message onCphsCompleted = (Message) ar.userObj;
   1143 
   1144                         /* write to cphs mailbox whenever it is available but
   1145                         * we only need notify caller once if both updating are
   1146                         * successful.
   1147                         *
   1148                         * so if set_mbdn successful, notify caller here and set
   1149                         * onCphsCompleted to null
   1150                         */
   1151                         if (ar.exception == null && ar.userObj != null) {
   1152                             AsyncResult.forMessage(((Message) ar.userObj)).exception = null;
   1153                             ((Message) ar.userObj).sendToTarget();
   1154 
   1155                             if (DBG) log("Callback with MBDN successful.");
   1156 
   1157                             onCphsCompleted = null;
   1158                         }
   1159 
   1160                         new AdnRecordLoader(mFh)
   1161                                 .updateEF(adn, EF_MAILBOX_CPHS, EF_EXT1, 1, null,
   1162                                 obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE,
   1163                                         onCphsCompleted));
   1164                     } else {
   1165                         if (ar.userObj != null) {
   1166                             CarrierConfigManager configLoader = (CarrierConfigManager)
   1167                                     mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
   1168                             if (ar.exception != null && configLoader != null
   1169                                     && configLoader.getConfig().getBoolean(
   1170                                     CarrierConfigManager.KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL)) {
   1171                                 // GsmCdmaPhone will store vm number on device
   1172                                 // when IccVmNotSupportedException occurred
   1173                                 AsyncResult.forMessage(((Message) ar.userObj)).exception =
   1174                                         new IccVmNotSupportedException(
   1175                                             "Update SIM voice mailbox error");
   1176                             } else {
   1177                                 AsyncResult.forMessage(((Message) ar.userObj))
   1178                                     .exception = ar.exception;
   1179                             }
   1180                             ((Message) ar.userObj).sendToTarget();
   1181                         }
   1182                     }
   1183                     break;
   1184                 case EVENT_SET_CPHS_MAILBOX_DONE:
   1185                     isRecordLoadResponse = false;
   1186                     ar = (AsyncResult) msg.obj;
   1187                     if (ar.exception == null) {
   1188                         mVoiceMailNum = mNewVoiceMailNum;
   1189                         mVoiceMailTag = mNewVoiceMailTag;
   1190                     } else {
   1191                         if (DBG) log("Set CPHS MailBox with exception: " + ar.exception);
   1192                     }
   1193                     if (ar.userObj != null) {
   1194                         if (DBG) log("Callback with CPHS MB successful.");
   1195                         AsyncResult.forMessage(((Message) ar.userObj)).exception
   1196                                 = ar.exception;
   1197                         ((Message) ar.userObj).sendToTarget();
   1198                     }
   1199                     break;
   1200                 case EVENT_GET_CFIS_DONE:
   1201                     isRecordLoadResponse = true;
   1202 
   1203                     ar = (AsyncResult) msg.obj;
   1204                     data = (byte[]) ar.result;
   1205 
   1206                     if (ar.exception != null) {
   1207                         mEfCfis = null;
   1208                     } else {
   1209                         log("EF_CFIS: " + IccUtils.bytesToHexString(data));
   1210                         mEfCfis = data;
   1211                     }
   1212 
   1213                     break;
   1214 
   1215                 case EVENT_GET_CSP_CPHS_DONE:
   1216                     isRecordLoadResponse = true;
   1217 
   1218                     ar = (AsyncResult) msg.obj;
   1219 
   1220                     if (ar.exception != null) {
   1221                         loge("Exception in fetching EF_CSP data " + ar.exception);
   1222                         break;
   1223                     }
   1224 
   1225                     data = (byte[]) ar.result;
   1226 
   1227                     log("EF_CSP: " + IccUtils.bytesToHexString(data));
   1228                     handleEfCspData(data);
   1229                     break;
   1230 
   1231                 case EVENT_GET_GID1_DONE:
   1232                     isRecordLoadResponse = true;
   1233 
   1234                     ar = (AsyncResult) msg.obj;
   1235                     data = (byte[]) ar.result;
   1236 
   1237                     if (ar.exception != null) {
   1238                         loge("Exception in get GID1 " + ar.exception);
   1239                         mGid1 = null;
   1240                         break;
   1241                     }
   1242 
   1243                     mGid1 = IccUtils.bytesToHexString(data);
   1244 
   1245                     log("GID1: " + mGid1);
   1246 
   1247                     break;
   1248 
   1249                 case EVENT_GET_GID2_DONE:
   1250                     isRecordLoadResponse = true;
   1251                     ar = (AsyncResult) msg.obj;
   1252                     data = (byte[]) ar.result;
   1253 
   1254                     if (ar.exception != null) {
   1255                         loge("Exception in get GID2 " + ar.exception);
   1256                         mGid2 = null;
   1257                         break;
   1258                     }
   1259 
   1260                     mGid2 = IccUtils.bytesToHexString(data);
   1261 
   1262                     log("GID2: " + mGid2);
   1263 
   1264                     break;
   1265 
   1266                 case EVENT_GET_PLMN_W_ACT_DONE:
   1267                     isRecordLoadResponse = true;
   1268                     ar = (AsyncResult) msg.obj;
   1269                     data = (byte[]) ar.result;
   1270 
   1271                     if (ar.exception != null || data == null) {
   1272                         loge("Failed getting User PLMN with Access Tech Records: " + ar.exception);
   1273                         break;
   1274                     } else {
   1275                         log("Received a PlmnActRecord, raw=" + IccUtils.bytesToHexString(data));
   1276                         mPlmnActRecords = PlmnActRecord.getRecords(data);
   1277                         if (VDBG) log("PlmnActRecords=" + Arrays.toString(mPlmnActRecords));
   1278                     }
   1279                     break;
   1280 
   1281                 case EVENT_GET_OPLMN_W_ACT_DONE:
   1282                     isRecordLoadResponse = true;
   1283                     ar = (AsyncResult) msg.obj;
   1284                     data = (byte[]) ar.result;
   1285 
   1286                     if (ar.exception != null || data == null) {
   1287                         loge("Failed getting Operator PLMN with Access Tech Records: "
   1288                                 + ar.exception);
   1289                         break;
   1290                     } else {
   1291                         log("Received a PlmnActRecord, raw=" + IccUtils.bytesToHexString(data));
   1292                         mOplmnActRecords = PlmnActRecord.getRecords(data);
   1293                         if (VDBG) log("OplmnActRecord[]=" + Arrays.toString(mOplmnActRecords));
   1294                     }
   1295                     break;
   1296 
   1297                 case EVENT_GET_HPLMN_W_ACT_DONE:
   1298                     isRecordLoadResponse = true;
   1299                     ar = (AsyncResult) msg.obj;
   1300                     data = (byte[]) ar.result;
   1301 
   1302                     if (ar.exception != null || data == null) {
   1303                         loge("Failed getting Home PLMN with Access Tech Records: " + ar.exception);
   1304                         break;
   1305                     } else {
   1306                         log("Received a PlmnActRecord, raw=" + IccUtils.bytesToHexString(data));
   1307                         mHplmnActRecords = PlmnActRecord.getRecords(data);
   1308                         log("HplmnActRecord[]=" + Arrays.toString(mHplmnActRecords));
   1309                     }
   1310                     break;
   1311 
   1312                 case EVENT_GET_EHPLMN_DONE:
   1313                     isRecordLoadResponse = true;
   1314                     ar = (AsyncResult) msg.obj;
   1315                     data = (byte[]) ar.result;
   1316                     if (ar.exception != null || data == null) {
   1317                         loge("Failed getting Equivalent Home PLMNs: " + ar.exception);
   1318                         break;
   1319                     } else {
   1320                         mEhplmns = parseBcdPlmnList(data, "Equivalent Home");
   1321                     }
   1322                     break;
   1323 
   1324                 case EVENT_GET_FPLMN_DONE:
   1325                     isRecordLoadResponse = true;
   1326                     ar = (AsyncResult) msg.obj;
   1327                     data = (byte[]) ar.result;
   1328                     if (ar.exception != null || data == null) {
   1329                         loge("Failed getting Forbidden PLMNs: " + ar.exception);
   1330                         break;
   1331                     } else {
   1332                         mFplmns = parseBcdPlmnList(data, "Forbidden");
   1333                     }
   1334                     if (msg.arg1 == HANDLER_ACTION_SEND_RESPONSE) {
   1335                         if (VDBG) logv("getForbiddenPlmns(): send async response");
   1336                         isRecordLoadResponse = false;
   1337                         Message response = retrievePendingResponseMessage(msg.arg2);
   1338                         if (response != null) {
   1339                             AsyncResult.forMessage(
   1340                                     response, Arrays.copyOf(mFplmns, mFplmns.length), null);
   1341                             response.sendToTarget();
   1342                         } else {
   1343                             loge("Failed to retrieve a response message for FPLMN");
   1344                             break;
   1345                         }
   1346                     }
   1347                     break;
   1348 
   1349                 default:
   1350                     super.handleMessage(msg);   // IccRecords handles generic record load responses
   1351             }
   1352         } catch (RuntimeException exc) {
   1353             // I don't want these exceptions to be fatal
   1354             logw("Exception parsing SIM record", exc);
   1355         } finally {
   1356             // Count up record load responses even if they are fails
   1357             if (isRecordLoadResponse) {
   1358                 onRecordLoaded();
   1359             }
   1360         }
   1361     }
   1362 
   1363     private class EfPlLoaded implements IccRecordLoaded {
   1364         public String getEfName() {
   1365             return "EF_PL";
   1366         }
   1367 
   1368         public void onRecordLoaded(AsyncResult ar) {
   1369             mEfPl = (byte[]) ar.result;
   1370             if (DBG) log("EF_PL=" + IccUtils.bytesToHexString(mEfPl));
   1371         }
   1372     }
   1373 
   1374     private class EfUsimLiLoaded implements IccRecordLoaded {
   1375         public String getEfName() {
   1376             return "EF_LI";
   1377         }
   1378 
   1379         public void onRecordLoaded(AsyncResult ar) {
   1380             mEfLi = (byte[]) ar.result;
   1381             if (DBG) log("EF_LI=" + IccUtils.bytesToHexString(mEfLi));
   1382         }
   1383     }
   1384 
   1385     @Override
   1386     protected void handleFileUpdate(int efid) {
   1387         switch(efid) {
   1388             case EF_MBDN:
   1389                 mRecordsToLoad++;
   1390                 new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6,
   1391                         mMailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
   1392                 break;
   1393             case EF_MAILBOX_CPHS:
   1394                 mRecordsToLoad++;
   1395                 new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1,
   1396                         1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
   1397                 break;
   1398             case EF_CSP_CPHS:
   1399                 mRecordsToLoad++;
   1400                 log("[CSP] SIM Refresh for EF_CSP_CPHS");
   1401                 mFh.loadEFTransparent(EF_CSP_CPHS,
   1402                         obtainMessage(EVENT_GET_CSP_CPHS_DONE));
   1403                 break;
   1404             case EF_FDN:
   1405                 if (DBG) log("SIM Refresh called for EF_FDN");
   1406                 mParentApp.queryFdn();
   1407                 mAdnCache.reset();
   1408                 break;
   1409             case EF_MSISDN:
   1410                 mRecordsToLoad++;
   1411                 log("SIM Refresh called for EF_MSISDN");
   1412                 new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, getExtFromEf(EF_MSISDN), 1,
   1413                         obtainMessage(EVENT_GET_MSISDN_DONE));
   1414                 break;
   1415             case EF_CFIS:
   1416             case EF_CFF_CPHS:
   1417                 log("SIM Refresh called for EF_CFIS or EF_CFF_CPHS");
   1418                 loadCallForwardingRecords();
   1419                 break;
   1420             default:
   1421                 // For now, fetch all records if this is not a
   1422                 // voicemail number.
   1423                 // TODO: Handle other cases, instead of fetching all.
   1424                 mAdnCache.reset();
   1425                 fetchSimRecords();
   1426                 break;
   1427         }
   1428     }
   1429 
   1430     /**
   1431      * Dispatch 3GPP format message to registrant ({@code GsmCdmaPhone}) to pass to the 3GPP SMS
   1432      * dispatcher for delivery.
   1433      */
   1434     private int dispatchGsmMessage(SmsMessage message) {
   1435         mNewSmsRegistrants.notifyResult(message);
   1436         return 0;
   1437     }
   1438 
   1439     private void handleSms(byte[] ba) {
   1440         if (ba[0] != 0)
   1441             Rlog.d("ENF", "status : " + ba[0]);
   1442 
   1443         // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
   1444         // 3 == "received by MS from network; message to be read"
   1445         if (ba[0] == 3) {
   1446             int n = ba.length;
   1447 
   1448             // Note: Data may include trailing FF's.  That's OK; message
   1449             // should still parse correctly.
   1450             byte[] pdu = new byte[n - 1];
   1451             System.arraycopy(ba, 1, pdu, 0, n - 1);
   1452             SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP);
   1453 
   1454             dispatchGsmMessage(message);
   1455         }
   1456     }
   1457 
   1458 
   1459     private void handleSmses(ArrayList<byte[]> messages) {
   1460         int count = messages.size();
   1461 
   1462         for (int i = 0; i < count; i++) {
   1463             byte[] ba = messages.get(i);
   1464 
   1465             if (ba[0] != 0)
   1466                 Rlog.i("ENF", "status " + i + ": " + ba[0]);
   1467 
   1468             // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
   1469             // 3 == "received by MS from network; message to be read"
   1470 
   1471             if (ba[0] == 3) {
   1472                 int n = ba.length;
   1473 
   1474                 // Note: Data may include trailing FF's.  That's OK; message
   1475                 // should still parse correctly.
   1476                 byte[] pdu = new byte[n - 1];
   1477                 System.arraycopy(ba, 1, pdu, 0, n - 1);
   1478                 SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP);
   1479 
   1480                 dispatchGsmMessage(message);
   1481 
   1482                 // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
   1483                 // 1 == "received by MS from network; message read"
   1484 
   1485                 ba[0] = 1;
   1486 
   1487                 if (false) { // FIXME: writing seems to crash RdoServD
   1488                     mFh.updateEFLinearFixed(EF_SMS,
   1489                             i, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, i));
   1490                 }
   1491             }
   1492         }
   1493     }
   1494 
   1495     @Override
   1496     protected void onRecordLoaded() {
   1497         // One record loaded successfully or failed, In either case
   1498         // we need to update the recordsToLoad count
   1499         mRecordsToLoad -= 1;
   1500         if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested);
   1501 
   1502         if (getRecordsLoaded()) {
   1503             onAllRecordsLoaded();
   1504         } else if (getLockedRecordsLoaded() || getNetworkLockedRecordsLoaded()) {
   1505             onLockedAllRecordsLoaded();
   1506         } else if (mRecordsToLoad < 0) {
   1507             loge("recordsToLoad <0, programmer error suspected");
   1508             mRecordsToLoad = 0;
   1509         }
   1510     }
   1511 
   1512     private void setVoiceCallForwardingFlagFromSimRecords() {
   1513         if (validEfCfis(mEfCfis)) {
   1514             // Refer TS 51.011 Section 10.3.46 for the content description
   1515             mCallForwardingStatus = (mEfCfis[1] & 0x01);
   1516             log("EF_CFIS: callForwardingEnabled=" + mCallForwardingStatus);
   1517         } else if (mEfCff != null) {
   1518             mCallForwardingStatus =
   1519                     ((mEfCff[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE) ?
   1520                             CALL_FORWARDING_STATUS_ENABLED : CALL_FORWARDING_STATUS_DISABLED;
   1521             log("EF_CFF: callForwardingEnabled=" + mCallForwardingStatus);
   1522         } else {
   1523             mCallForwardingStatus = CALL_FORWARDING_STATUS_UNKNOWN;
   1524             log("EF_CFIS and EF_CFF not valid. callForwardingEnabled=" + mCallForwardingStatus);
   1525         }
   1526     }
   1527 
   1528     private void setSimLanguageFromEF() {
   1529         Resources resource = Resources.getSystem();
   1530         if (resource.getBoolean(com.android.internal.R.bool.config_use_sim_language_file)) {
   1531             setSimLanguage(mEfLi, mEfPl);
   1532         } else {
   1533             if (DBG) log ("Not using EF LI/EF PL");
   1534         }
   1535     }
   1536 
   1537     private void onLockedAllRecordsLoaded() {
   1538         setSimLanguageFromEF();
   1539         if (mLockedRecordsReqReason == LOCKED_RECORDS_REQ_REASON_LOCKED) {
   1540             mLockedRecordsLoadedRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
   1541         } else if (mLockedRecordsReqReason == LOCKED_RECORDS_REQ_REASON_NETWORK_LOCKED) {
   1542             mNetworkLockedRecordsLoadedRegistrants.notifyRegistrants(
   1543                     new AsyncResult(null, null, null));
   1544         } else {
   1545             loge("onLockedAllRecordsLoaded: unexpected mLockedRecordsReqReason "
   1546                     + mLockedRecordsReqReason);
   1547         }
   1548     }
   1549 
   1550     @Override
   1551     protected void onAllRecordsLoaded() {
   1552         if (DBG) log("record load complete");
   1553 
   1554         setSimLanguageFromEF();
   1555         setVoiceCallForwardingFlagFromSimRecords();
   1556 
   1557         // Some fields require more than one SIM record to set
   1558 
   1559         String operator = getOperatorNumeric();
   1560         if (!TextUtils.isEmpty(operator)) {
   1561             log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" +
   1562                     operator + "'");
   1563             mTelephonyManager.setSimOperatorNumericForPhone(
   1564                     mParentApp.getPhoneId(), operator);
   1565         } else {
   1566             log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping");
   1567         }
   1568 
   1569         String imsi = getIMSI();
   1570 
   1571         if (!TextUtils.isEmpty(imsi) && imsi.length() >= 3) {
   1572             log("onAllRecordsLoaded set mcc imsi" + (VDBG ? ("=" + imsi) : ""));
   1573             mTelephonyManager.setSimCountryIsoForPhone(
   1574                     mParentApp.getPhoneId(), MccTable.countryCodeForMcc(
   1575                     Integer.parseInt(imsi.substring(0, 3))));
   1576         } else {
   1577             log("onAllRecordsLoaded empty imsi skipping setting mcc");
   1578         }
   1579 
   1580         setVoiceMailByCountry(operator);
   1581         mLoaded.set(true);
   1582         mRecordsLoadedRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
   1583     }
   1584 
   1585     //***** Private methods
   1586 
   1587     private void setVoiceMailByCountry (String spn) {
   1588         if (mVmConfig.containsCarrier(spn)) {
   1589             mIsVoiceMailFixed = true;
   1590             mVoiceMailNum = mVmConfig.getVoiceMailNumber(spn);
   1591             mVoiceMailTag = mVmConfig.getVoiceMailTag(spn);
   1592         }
   1593     }
   1594 
   1595     /**
   1596      * String[] of forbidden PLMNs will be sent to the Message's handler
   1597      * in the result field of an AsyncResult in the response.obj.
   1598      */
   1599     public void getForbiddenPlmns(Message response) {
   1600         int key = storePendingResponseMessage(response);
   1601         mFh.loadEFTransparent(EF_FPLMN, obtainMessage(
   1602                     EVENT_GET_FPLMN_DONE, HANDLER_ACTION_SEND_RESPONSE, key));
   1603     }
   1604 
   1605     @Override
   1606     public void onReady() {
   1607         fetchSimRecords();
   1608     }
   1609 
   1610     private void onLocked(int msg) {
   1611         if (DBG) log("only fetch EF_LI, EF_PL and EF_ICCID in locked state");
   1612         mLockedRecordsReqReason = msg == EVENT_APP_LOCKED ? LOCKED_RECORDS_REQ_REASON_LOCKED :
   1613                 LOCKED_RECORDS_REQ_REASON_NETWORK_LOCKED;
   1614 
   1615         loadEfLiAndEfPl();
   1616 
   1617         mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
   1618         mRecordsToLoad++;
   1619     }
   1620 
   1621     private void loadEfLiAndEfPl() {
   1622         if (mParentApp.getType() == AppType.APPTYPE_USIM) {
   1623             mFh.loadEFTransparent(EF_LI,
   1624                     obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfUsimLiLoaded()));
   1625             mRecordsToLoad++;
   1626 
   1627             mFh.loadEFTransparent(EF_PL,
   1628                     obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfPlLoaded()));
   1629             mRecordsToLoad++;
   1630         }
   1631     }
   1632 
   1633     private void loadCallForwardingRecords() {
   1634         mRecordsRequested = true;
   1635         mFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE));
   1636         mRecordsToLoad++;
   1637         mFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE));
   1638         mRecordsToLoad++;
   1639     }
   1640 
   1641     protected void fetchSimRecords() {
   1642         mRecordsRequested = true;
   1643 
   1644         if (DBG) log("fetchSimRecords " + mRecordsToLoad);
   1645 
   1646         mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
   1647         mRecordsToLoad++;
   1648 
   1649         mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
   1650         mRecordsToLoad++;
   1651 
   1652         // FIXME should examine EF[MSISDN]'s capability configuration
   1653         // to determine which is the voice/data/fax line
   1654         new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, getExtFromEf(EF_MSISDN), 1,
   1655                     obtainMessage(EVENT_GET_MSISDN_DONE));
   1656         mRecordsToLoad++;
   1657 
   1658         // Record number is subscriber profile
   1659         mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));
   1660         mRecordsToLoad++;
   1661 
   1662         mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
   1663         mRecordsToLoad++;
   1664 
   1665         // Record number is subscriber profile
   1666         mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE));
   1667         mRecordsToLoad++;
   1668 
   1669 
   1670         // Also load CPHS-style voice mail indicator, which stores
   1671         // the same info as EF[MWIS]. If both exist, both are updated
   1672         // but the EF[MWIS] data is preferred
   1673         // Please note this must be loaded after EF[MWIS]
   1674         mFh.loadEFTransparent(
   1675                 EF_VOICE_MAIL_INDICATOR_CPHS,
   1676                 obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE));
   1677         mRecordsToLoad++;
   1678 
   1679         // Same goes for Call Forward Status indicator: fetch both
   1680         // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred.
   1681         loadCallForwardingRecords();
   1682 
   1683         getSpnFsm(true, null);
   1684 
   1685         mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));
   1686         mRecordsToLoad++;
   1687 
   1688         mFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE));
   1689         mRecordsToLoad++;
   1690 
   1691         mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));
   1692         mRecordsToLoad++;
   1693 
   1694         mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));
   1695         mRecordsToLoad++;
   1696 
   1697         mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE));
   1698         mRecordsToLoad++;
   1699 
   1700         mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE));
   1701         mRecordsToLoad++;
   1702 
   1703         mFh.loadEFTransparent(EF_GID2, obtainMessage(EVENT_GET_GID2_DONE));
   1704         mRecordsToLoad++;
   1705 
   1706         mFh.loadEFTransparent(EF_PLMN_W_ACT, obtainMessage(EVENT_GET_PLMN_W_ACT_DONE));
   1707         mRecordsToLoad++;
   1708 
   1709         mFh.loadEFTransparent(EF_OPLMN_W_ACT, obtainMessage(EVENT_GET_OPLMN_W_ACT_DONE));
   1710         mRecordsToLoad++;
   1711 
   1712         mFh.loadEFTransparent(EF_HPLMN_W_ACT, obtainMessage(EVENT_GET_HPLMN_W_ACT_DONE));
   1713         mRecordsToLoad++;
   1714 
   1715         mFh.loadEFTransparent(EF_EHPLMN, obtainMessage(EVENT_GET_EHPLMN_DONE));
   1716         mRecordsToLoad++;
   1717 
   1718         mFh.loadEFTransparent(EF_FPLMN, obtainMessage(
   1719                     EVENT_GET_FPLMN_DONE, HANDLER_ACTION_NONE, -1));
   1720         mRecordsToLoad++;
   1721 
   1722         loadEfLiAndEfPl();
   1723 
   1724         // XXX should seek instead of examining them all
   1725         if (false) { // XXX
   1726             mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));
   1727             mRecordsToLoad++;
   1728         }
   1729 
   1730         if (CRASH_RIL) {
   1731             String sms = "0107912160130310f20404d0110041007030208054832b0120"
   1732                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
   1733                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
   1734                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
   1735                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
   1736                          + "ffffffffffffffffffffffffffffff";
   1737             byte[] ba = IccUtils.hexStringToBytes(sms);
   1738 
   1739             mFh.updateEFLinearFixed(EF_SMS, 1, ba, null,
   1740                             obtainMessage(EVENT_MARK_SMS_READ_DONE, 1));
   1741         }
   1742         if (DBG) log("fetchSimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested);
   1743     }
   1744 
   1745     /**
   1746      * Returns the SpnDisplayRule based on settings on the SIM and the
   1747      * current service state. See TS 22.101 Annex A and TS 51.011 10.3.11
   1748      * for details.
   1749      *
   1750      * If the SPN is not found on the SIM or is empty, the rule is
   1751      * always PLMN_ONLY.
   1752      *
   1753      * @param serviceState Service state
   1754      * @return the display rule
   1755      *
   1756      * @see #SPN_RULE_SHOW_SPN
   1757      * @see #SPN_RULE_SHOW_PLMN
   1758      */
   1759     @Override
   1760     public int getDisplayRule(ServiceState serviceState) {
   1761         int rule;
   1762 
   1763         if (mParentApp != null && mParentApp.getUiccProfile() != null
   1764                 && mParentApp.getUiccProfile().getOperatorBrandOverride() != null) {
   1765         // If the operator has been overridden, treat it as the SPN file on the SIM did not exist.
   1766             rule = SPN_RULE_SHOW_PLMN;
   1767         } else if (TextUtils.isEmpty(getServiceProviderName()) || mSpnDisplayCondition == -1) {
   1768             // No EF_SPN content was found on the SIM, or not yet loaded.  Just show ONS.
   1769             rule = SPN_RULE_SHOW_PLMN;
   1770         } else if (useRoamingFromServiceState() ? !serviceState.getRoaming()
   1771                 : isOnMatchingPlmn(serviceState.getOperatorNumeric())) {
   1772             rule = SPN_RULE_SHOW_SPN;
   1773             if ((mSpnDisplayCondition & 0x01) == 0x01) {
   1774                 // ONS required when registered to HPLMN or PLMN in EF_SPDI
   1775                 rule |= SPN_RULE_SHOW_PLMN;
   1776             }
   1777         } else {
   1778             rule = SPN_RULE_SHOW_PLMN;
   1779             if ((mSpnDisplayCondition & 0x02) == 0x00) {
   1780                 // SPN required if not registered to HPLMN or PLMN in EF_SPDI
   1781                 rule |= SPN_RULE_SHOW_SPN;
   1782             }
   1783         }
   1784         return rule;
   1785     }
   1786 
   1787     private boolean useRoamingFromServiceState() {
   1788         CarrierConfigManager configManager = (CarrierConfigManager)
   1789                 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
   1790         if (configManager != null) {
   1791             PersistableBundle b = configManager.getConfigForSubId(
   1792                     SubscriptionController.getInstance().getSubIdUsingPhoneId(
   1793                     mParentApp.getPhoneId()));
   1794             if (b != null && b.getBoolean(CarrierConfigManager
   1795                     .KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL)) {
   1796                 return true;
   1797             }
   1798         }
   1799         return false;
   1800     }
   1801 
   1802     /**
   1803      * Checks if plmn is HPLMN or on the spdiNetworks list.
   1804      */
   1805     private boolean isOnMatchingPlmn(String plmn) {
   1806         if (plmn == null) return false;
   1807 
   1808         if (plmn.equals(getOperatorNumeric())) {
   1809             return true;
   1810         }
   1811 
   1812         if (mSpdiNetworks != null) {
   1813             for (String spdiNet : mSpdiNetworks) {
   1814                 if (plmn.equals(spdiNet)) {
   1815                     return true;
   1816                 }
   1817             }
   1818         }
   1819         return false;
   1820     }
   1821 
   1822     /**
   1823      * States of Get SPN Finite State Machine which only used by getSpnFsm()
   1824      */
   1825     private enum GetSpnFsmState {
   1826         IDLE,               // No initialized
   1827         INIT,               // Start FSM
   1828         READ_SPN_3GPP,      // Load EF_SPN firstly
   1829         READ_SPN_CPHS,      // Load EF_SPN_CPHS secondly
   1830         READ_SPN_SHORT_CPHS // Load EF_SPN_SHORT_CPHS last
   1831     }
   1832 
   1833     /**
   1834      * Finite State Machine to load Service Provider Name , which can be stored
   1835      * in either EF_SPN (3GPP), EF_SPN_CPHS, or EF_SPN_SHORT_CPHS (CPHS4.2)
   1836      *
   1837      * After starting, FSM will search SPN EFs in order and stop after finding
   1838      * the first valid SPN
   1839      *
   1840      * If the FSM gets restart while waiting for one of
   1841      * SPN EFs results (i.e. a SIM refresh occurs after issuing
   1842      * read EF_CPHS_SPN), it will re-initialize only after
   1843      * receiving and discarding the unfinished SPN EF result.
   1844      *
   1845      * @param start set true only for initialize loading
   1846      * @param ar the AsyncResult from loadEFTransparent
   1847      *        ar.exception holds exception in error
   1848      *        ar.result is byte[] for data in success
   1849      */
   1850     private void getSpnFsm(boolean start, AsyncResult ar) {
   1851         byte[] data;
   1852 
   1853         if (start) {
   1854             // Check previous state to see if there is outstanding
   1855             // SPN read
   1856             if (mSpnState == GetSpnFsmState.READ_SPN_3GPP
   1857                     || mSpnState == GetSpnFsmState.READ_SPN_CPHS
   1858                     || mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS
   1859                     || mSpnState == GetSpnFsmState.INIT) {
   1860                 // Set INIT then return so the INIT code
   1861                 // will run when the outstanding read done.
   1862                 mSpnState = GetSpnFsmState.INIT;
   1863                 return;
   1864             } else {
   1865                 mSpnState = GetSpnFsmState.INIT;
   1866             }
   1867         }
   1868 
   1869         switch(mSpnState){
   1870             case INIT:
   1871                 setServiceProviderName(null);
   1872 
   1873                 mFh.loadEFTransparent(EF_SPN,
   1874                         obtainMessage(EVENT_GET_SPN_DONE));
   1875                 mRecordsToLoad++;
   1876 
   1877                 mSpnState = GetSpnFsmState.READ_SPN_3GPP;
   1878                 break;
   1879             case READ_SPN_3GPP:
   1880                 if (ar != null && ar.exception == null) {
   1881                     data = (byte[]) ar.result;
   1882                     mSpnDisplayCondition = 0xff & data[0];
   1883 
   1884                     setServiceProviderName(IccUtils.adnStringFieldToString(
   1885                                 data, 1, data.length - 1));
   1886                     // for card double-check and brand override
   1887                     // we have to do this:
   1888                     final String spn = getServiceProviderName();
   1889 
   1890                     if (spn == null || spn.length() == 0) {
   1891                         mSpnState = GetSpnFsmState.READ_SPN_CPHS;
   1892                     } else {
   1893                         if (DBG) log("Load EF_SPN: " + spn
   1894                                 + " spnDisplayCondition: " + mSpnDisplayCondition);
   1895                         mTelephonyManager.setSimOperatorNameForPhone(
   1896                                 mParentApp.getPhoneId(), spn);
   1897 
   1898                         mSpnState = GetSpnFsmState.IDLE;
   1899                     }
   1900                 } else {
   1901                     mSpnState = GetSpnFsmState.READ_SPN_CPHS;
   1902                 }
   1903 
   1904                 if (mSpnState == GetSpnFsmState.READ_SPN_CPHS) {
   1905                     mFh.loadEFTransparent( EF_SPN_CPHS,
   1906                             obtainMessage(EVENT_GET_SPN_DONE));
   1907                     mRecordsToLoad++;
   1908 
   1909                     // See TS 51.011 10.3.11.  Basically, default to
   1910                     // show PLMN always, and SPN also if roaming.
   1911                     mSpnDisplayCondition = -1;
   1912                 }
   1913                 break;
   1914             case READ_SPN_CPHS:
   1915                 if (ar != null && ar.exception == null) {
   1916                     data = (byte[]) ar.result;
   1917 
   1918                     setServiceProviderName(IccUtils.adnStringFieldToString(
   1919                                 data, 0, data.length));
   1920                     // for card double-check and brand override
   1921                     // we have to do this:
   1922                     final String spn = getServiceProviderName();
   1923 
   1924                     if (spn == null || spn.length() == 0) {
   1925                         mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS;
   1926                     } else {
   1927                         // Display CPHS Operator Name only when not roaming
   1928                         mSpnDisplayCondition = 2;
   1929 
   1930                         if (DBG) log("Load EF_SPN_CPHS: " + spn);
   1931                         mTelephonyManager.setSimOperatorNameForPhone(
   1932                                 mParentApp.getPhoneId(), spn);
   1933 
   1934                         mSpnState = GetSpnFsmState.IDLE;
   1935                     }
   1936                 } else {
   1937                     mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS;
   1938                 }
   1939 
   1940                 if (mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS) {
   1941                     mFh.loadEFTransparent(
   1942                             EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE));
   1943                     mRecordsToLoad++;
   1944                 }
   1945                 break;
   1946             case READ_SPN_SHORT_CPHS:
   1947                 if (ar != null && ar.exception == null) {
   1948                     data = (byte[]) ar.result;
   1949 
   1950                     setServiceProviderName(IccUtils.adnStringFieldToString(
   1951                                 data, 0, data.length));
   1952                     // for card double-check and brand override
   1953                     // we have to do this:
   1954                     final String spn = getServiceProviderName();
   1955 
   1956                     if (spn == null || spn.length() == 0) {
   1957                         if (DBG) log("No SPN loaded in either CHPS or 3GPP");
   1958                     } else {
   1959                         // Display CPHS Operator Name only when not roaming
   1960                         mSpnDisplayCondition = 2;
   1961 
   1962                         if (DBG) log("Load EF_SPN_SHORT_CPHS: " + spn);
   1963                         mTelephonyManager.setSimOperatorNameForPhone(
   1964                                 mParentApp.getPhoneId(), spn);
   1965                     }
   1966                 } else {
   1967                     setServiceProviderName(null);
   1968                     if (DBG) log("No SPN loaded in either CHPS or 3GPP");
   1969                 }
   1970 
   1971                 mSpnState = GetSpnFsmState.IDLE;
   1972                 break;
   1973             default:
   1974                 mSpnState = GetSpnFsmState.IDLE;
   1975         }
   1976     }
   1977 
   1978     /**
   1979      * Parse TS 51.011 EF[SPDI] record
   1980      * This record contains the list of numeric network IDs that
   1981      * are treated specially when determining SPN display
   1982      */
   1983     private void
   1984     parseEfSpdi(byte[] data) {
   1985         SimTlv tlv = new SimTlv(data, 0, data.length);
   1986 
   1987         byte[] plmnEntries = null;
   1988 
   1989         for ( ; tlv.isValidObject() ; tlv.nextObject()) {
   1990             // Skip SPDI tag, if existant
   1991             if (tlv.getTag() == TAG_SPDI) {
   1992               tlv = new SimTlv(tlv.getData(), 0, tlv.getData().length);
   1993             }
   1994             // There should only be one TAG_SPDI_PLMN_LIST
   1995             if (tlv.getTag() == TAG_SPDI_PLMN_LIST) {
   1996                 plmnEntries = tlv.getData();
   1997                 break;
   1998             }
   1999         }
   2000 
   2001         if (plmnEntries == null) {
   2002             return;
   2003         }
   2004 
   2005         mSpdiNetworks = new ArrayList<String>(plmnEntries.length / 3);
   2006 
   2007         for (int i = 0 ; i + 2 < plmnEntries.length ; i += 3) {
   2008             String plmnCode;
   2009             plmnCode = IccUtils.bcdPlmnToString(plmnEntries, i);
   2010 
   2011             // Valid operator codes are 5 or 6 digits
   2012             if (plmnCode != null && plmnCode.length() >= 5) {
   2013                 log("EF_SPDI network: " + plmnCode);
   2014                 mSpdiNetworks.add(plmnCode);
   2015             }
   2016         }
   2017     }
   2018 
   2019     /**
   2020      * convert a byte array of packed plmns to an array of strings
   2021      */
   2022     private String[] parseBcdPlmnList(byte[] data, String description) {
   2023         final int packedBcdPlmnLenBytes = 3;
   2024         log("Received " + description + " PLMNs, raw=" + IccUtils.bytesToHexString(data));
   2025         if (data.length == 0 || (data.length % packedBcdPlmnLenBytes) != 0) {
   2026             loge("Received invalid " + description + " PLMN list");
   2027             return null;
   2028         }
   2029         int numPlmns = data.length / packedBcdPlmnLenBytes;
   2030         int numValidPlmns = 0;
   2031         String[] parsed = new String[numPlmns];
   2032         for (int i = 0; i < numPlmns; i++) {
   2033             parsed[numValidPlmns] = IccUtils.bcdPlmnToString(data, i * packedBcdPlmnLenBytes);
   2034             // we count the valid (non empty) records and only increment if valid
   2035             if (!TextUtils.isEmpty(parsed[numValidPlmns])) numValidPlmns++;
   2036         }
   2037         String[] ret = Arrays.copyOf(parsed, numValidPlmns);
   2038         if (VDBG) logv(description + " PLMNs: " + Arrays.toString(ret));
   2039         return ret;
   2040     }
   2041 
   2042     /**
   2043      * check to see if Mailbox Number is allocated and activated in CPHS SST
   2044      */
   2045     private boolean isCphsMailboxEnabled() {
   2046         if (mCphsInfo == null)  return false;
   2047         return ((mCphsInfo[1] & CPHS_SST_MBN_MASK) == CPHS_SST_MBN_ENABLED );
   2048     }
   2049 
   2050     @Override
   2051     protected void log(String s) {
   2052         Rlog.d(LOG_TAG, "[SIMRecords] " + s);
   2053     }
   2054 
   2055     @Override
   2056     protected void loge(String s) {
   2057         Rlog.e(LOG_TAG, "[SIMRecords] " + s);
   2058     }
   2059 
   2060     protected void logw(String s, Throwable tr) {
   2061         Rlog.w(LOG_TAG, "[SIMRecords] " + s, tr);
   2062     }
   2063 
   2064     protected void logv(String s) {
   2065         Rlog.v(LOG_TAG, "[SIMRecords] " + s);
   2066     }
   2067 
   2068     /**
   2069      * Return true if "Restriction of menu options for manual PLMN selection"
   2070      * bit is set or EF_CSP data is unavailable, return false otherwise.
   2071      */
   2072     @Override
   2073     public boolean isCspPlmnEnabled() {
   2074         return mCspPlmnEnabled;
   2075     }
   2076 
   2077     /**
   2078      * Parse EF_CSP data and check if
   2079      * "Restriction of menu options for manual PLMN selection" is
   2080      * Enabled/Disabled
   2081      *
   2082      * @param data EF_CSP hex data.
   2083      */
   2084     private void handleEfCspData(byte[] data) {
   2085         // As per spec CPHS4_2.WW6, CPHS B.4.7.1, EF_CSP contains CPHS defined
   2086         // 18 bytes (i.e 9 service groups info) and additional data specific to
   2087         // operator. The valueAddedServicesGroup is not part of standard
   2088         // services. This is operator specific and can be programmed any where.
   2089         // Normally this is programmed as 10th service after the standard
   2090         // services.
   2091         int usedCspGroups = data.length / 2;
   2092         // This is the "Service Group Number" of "Value Added Services Group".
   2093         byte valueAddedServicesGroup = (byte)0xC0;
   2094 
   2095         mCspPlmnEnabled = true;
   2096         for (int i = 0; i < usedCspGroups; i++) {
   2097              if (data[2 * i] == valueAddedServicesGroup) {
   2098                  log("[CSP] found ValueAddedServicesGroup, value " + data[(2 * i) + 1]);
   2099                  if ((data[(2 * i) + 1] & 0x80) == 0x80) {
   2100                      // Bit 8 is for
   2101                      // "Restriction of menu options for manual PLMN selection".
   2102                      // Operator Selection menu should be enabled.
   2103                      mCspPlmnEnabled = true;
   2104                  } else {
   2105                      mCspPlmnEnabled = false;
   2106                      // Operator Selection menu should be disabled.
   2107                      // Operator Selection Mode should be set to Automatic.
   2108                      log("[CSP] Set Automatic Network Selection");
   2109                      mNetworkSelectionModeAutomaticRegistrants.notifyRegistrants();
   2110                  }
   2111                  return;
   2112              }
   2113         }
   2114 
   2115         log("[CSP] Value Added Service Group (0xC0), not found!");
   2116     }
   2117 
   2118     @Override
   2119     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   2120         pw.println("SIMRecords: " + this);
   2121         pw.println(" extends:");
   2122         super.dump(fd, pw, args);
   2123         pw.println(" mVmConfig=" + mVmConfig);
   2124         pw.println(" mCallForwardingStatus=" + mCallForwardingStatus);
   2125         pw.println(" mSpnState=" + mSpnState);
   2126         pw.println(" mCphsInfo=" + mCphsInfo);
   2127         pw.println(" mCspPlmnEnabled=" + mCspPlmnEnabled);
   2128         pw.println(" mEfMWIS[]=" + Arrays.toString(mEfMWIS));
   2129         pw.println(" mEfCPHS_MWI[]=" + Arrays.toString(mEfCPHS_MWI));
   2130         pw.println(" mEfCff[]=" + Arrays.toString(mEfCff));
   2131         pw.println(" mEfCfis[]=" + Arrays.toString(mEfCfis));
   2132         pw.println(" mSpnDisplayCondition=" + mSpnDisplayCondition);
   2133         pw.println(" mSpdiNetworks[]=" + mSpdiNetworks);
   2134         pw.println(" mUsimServiceTable=" + mUsimServiceTable);
   2135         pw.println(" mGid1=" + mGid1);
   2136         if (mCarrierTestOverride.isInTestMode()) {
   2137             pw.println(" mFakeGid1=" + mCarrierTestOverride.getFakeGid1());
   2138         }
   2139         pw.println(" mGid2=" + mGid2);
   2140         if (mCarrierTestOverride.isInTestMode()) {
   2141             pw.println(" mFakeGid2=" + mCarrierTestOverride.getFakeGid2());
   2142         }
   2143         pw.println(" mPnnHomeName=" + mPnnHomeName);
   2144         if (mCarrierTestOverride.isInTestMode()) {
   2145             pw.println(" mFakePnnHomeName=" + mCarrierTestOverride.getFakePnnHomeName());
   2146         }
   2147         pw.println(" mPlmnActRecords[]=" + Arrays.toString(mPlmnActRecords));
   2148         pw.println(" mOplmnActRecords[]=" + Arrays.toString(mOplmnActRecords));
   2149         pw.println(" mHplmnActRecords[]=" + Arrays.toString(mHplmnActRecords));
   2150         pw.println(" mFplmns[]=" + Arrays.toString(mFplmns));
   2151         pw.println(" mEhplmns[]=" + Arrays.toString(mEhplmns));
   2152         pw.flush();
   2153     }
   2154 }
   2155