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