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