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