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