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