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