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