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