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