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