SIMRecords.java revision d6a0c111d4737b4bd233ae6d2efcbc0a0cd1d755
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.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 SIM_RECORD_EVENT_BASE = 0x00;
142    private static final int EVENT_GET_IMSI_DONE = 3 + SIM_RECORD_EVENT_BASE;
143    private static final int EVENT_GET_ICCID_DONE = 4 + SIM_RECORD_EVENT_BASE;
144    private static final int EVENT_GET_MBI_DONE = 5 + SIM_RECORD_EVENT_BASE;
145    private static final int EVENT_GET_MBDN_DONE = 6 + SIM_RECORD_EVENT_BASE;
146    private static final int EVENT_GET_MWIS_DONE = 7 + SIM_RECORD_EVENT_BASE;
147    private static final int EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE = 8 + SIM_RECORD_EVENT_BASE;
148    private static final int EVENT_GET_AD_DONE = 9 + SIM_RECORD_EVENT_BASE; // Admin data on SIM
149    private static final int EVENT_GET_MSISDN_DONE = 10 + SIM_RECORD_EVENT_BASE;
150    private static final int EVENT_GET_CPHS_MAILBOX_DONE = 11 + SIM_RECORD_EVENT_BASE;
151    private static final int EVENT_GET_SPN_DONE = 12 + SIM_RECORD_EVENT_BASE;
152    private static final int EVENT_GET_SPDI_DONE = 13 + SIM_RECORD_EVENT_BASE;
153    private static final int EVENT_UPDATE_DONE = 14 + SIM_RECORD_EVENT_BASE;
154    private static final int EVENT_GET_PNN_DONE = 15 + SIM_RECORD_EVENT_BASE;
155    private static final int EVENT_GET_SST_DONE = 17 + SIM_RECORD_EVENT_BASE;
156    private static final int EVENT_GET_ALL_SMS_DONE = 18 + SIM_RECORD_EVENT_BASE;
157    private static final int EVENT_MARK_SMS_READ_DONE = 19 + SIM_RECORD_EVENT_BASE;
158    private static final int EVENT_SET_MBDN_DONE = 20 + SIM_RECORD_EVENT_BASE;
159    private static final int EVENT_SMS_ON_SIM = 21 + SIM_RECORD_EVENT_BASE;
160    private static final int EVENT_GET_SMS_DONE = 22 + SIM_RECORD_EVENT_BASE;
161    private static final int EVENT_GET_CFF_DONE = 24 + SIM_RECORD_EVENT_BASE;
162    private static final int EVENT_SET_CPHS_MAILBOX_DONE = 25 + SIM_RECORD_EVENT_BASE;
163    private static final int EVENT_GET_INFO_CPHS_DONE = 26 + SIM_RECORD_EVENT_BASE;
164    private static final int EVENT_SET_MSISDN_DONE = 30 + SIM_RECORD_EVENT_BASE;
165    private static final int EVENT_GET_CFIS_DONE = 32 + SIM_RECORD_EVENT_BASE;
166    private static final int EVENT_GET_CSP_CPHS_DONE = 33 + SIM_RECORD_EVENT_BASE;
167    private static final int EVENT_GET_GID1_DONE = 34 + SIM_RECORD_EVENT_BASE;
168    private static final int EVENT_GET_GID2_DONE = 36 + SIM_RECORD_EVENT_BASE;
169
170    // TODO: Possibly move these to IccRecords.java
171    private static final int SYSTEM_EVENT_BASE = 0x100;
172    private static final int EVENT_CARRIER_CONFIG_CHANGED = 1 + SYSTEM_EVENT_BASE;
173    private static final int EVENT_APP_LOCKED = 2 + SYSTEM_EVENT_BASE;
174    private static final int EVENT_SIM_REFRESH = 3 + SYSTEM_EVENT_BASE;
175
176
177
178    // Lookup table for carriers known to produce SIMs which incorrectly indicate MNC length.
179
180    private static final String[] MCCMNC_CODES_HAVING_3DIGITS_MNC = {
181        "302370", "302720", "310260",
182        "405025", "405026", "405027", "405028", "405029", "405030", "405031", "405032",
183        "405033", "405034", "405035", "405036", "405037", "405038", "405039", "405040",
184        "405041", "405042", "405043", "405044", "405045", "405046", "405047", "405750",
185        "405751", "405752", "405753", "405754", "405755", "405756", "405799", "405800",
186        "405801", "405802", "405803", "405804", "405805", "405806", "405807", "405808",
187        "405809", "405810", "405811", "405812", "405813", "405814", "405815", "405816",
188        "405817", "405818", "405819", "405820", "405821", "405822", "405823", "405824",
189        "405825", "405826", "405827", "405828", "405829", "405830", "405831", "405832",
190        "405833", "405834", "405835", "405836", "405837", "405838", "405839", "405840",
191        "405841", "405842", "405843", "405844", "405845", "405846", "405847", "405848",
192        "405849", "405850", "405851", "405852", "405853", "405854", "405855", "405856",
193        "405857", "405858", "405859", "405860", "405861", "405862", "405863", "405864",
194        "405865", "405866", "405867", "405868", "405869", "405870", "405871", "405872",
195        "405873", "405874", "405875", "405876", "405877", "405878", "405879", "405880",
196        "405881", "405882", "405883", "405884", "405885", "405886", "405908", "405909",
197        "405910", "405911", "405912", "405913", "405914", "405915", "405916", "405917",
198        "405918", "405919", "405920", "405921", "405922", "405923", "405924", "405925",
199        "405926", "405927", "405928", "405929", "405930", "405931", "405932", "502142",
200        "502143", "502145", "502146", "502147", "502148"
201    };
202
203    // ***** Constructor
204
205    public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) {
206        super(app, c, ci);
207
208        mAdnCache = new AdnRecordCache(mFh);
209
210        mVmConfig = new VoiceMailConstants();
211        mSpnOverride = new SpnOverride();
212
213        mRecordsRequested = false;  // No load request is made till SIM ready
214
215        // recordsToLoad is set to 0 because no requests are made yet
216        mRecordsToLoad = 0;
217
218        mCi.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null);
219        mCi.registerForIccRefresh(this, EVENT_SIM_REFRESH, null);
220
221        // Start off by setting empty state
222        resetRecords();
223        mParentApp.registerForReady(this, EVENT_APP_READY, null);
224        mParentApp.registerForLocked(this, EVENT_APP_LOCKED, null);
225        if (DBG) log("SIMRecords X ctor this=" + this);
226
227        IntentFilter intentfilter = new IntentFilter();
228        intentfilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
229        c.registerReceiver(mReceiver, intentfilter);
230    }
231
232    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
233        @Override
234        public void onReceive(Context context, Intent intent) {
235            if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
236                sendMessage(obtainMessage(EVENT_CARRIER_CONFIG_CHANGED));
237            }
238        }
239    };
240
241    @Override
242    public void dispose() {
243        if (DBG) log("Disposing SIMRecords this=" + this);
244        //Unregister for all events
245        mCi.unregisterForIccRefresh(this);
246        mCi.unSetOnSmsOnSim(this);
247        mParentApp.unregisterForReady(this);
248        mParentApp.unregisterForLocked(this);
249        resetRecords();
250        super.dispose();
251    }
252
253    @Override
254    protected void finalize() {
255        if(DBG) log("finalized");
256    }
257
258    protected void resetRecords() {
259        mImsi = null;
260        mMsisdn = null;
261        mVoiceMailNum = null;
262        mMncLength = UNINITIALIZED;
263        log("setting0 mMncLength" + mMncLength);
264        mIccId = null;
265        mFullIccId = null;
266        // -1 means no EF_SPN found; treat accordingly.
267        mSpnDisplayCondition = -1;
268        mEfMWIS = null;
269        mEfCPHS_MWI = null;
270        mSpdiNetworks = null;
271        mPnnHomeName = null;
272        mGid1 = null;
273        mGid2 = null;
274
275        mAdnCache.reset();
276
277        log("SIMRecords: onRadioOffOrNotAvailable set 'gsm.sim.operator.numeric' to operator=null");
278        log("update icc_operator_numeric=" + null);
279        mTelephonyManager.setSimOperatorNumericForPhone(mParentApp.getPhoneId(), "");
280        mTelephonyManager.setSimOperatorNameForPhone(mParentApp.getPhoneId(), "");
281        mTelephonyManager.setSimCountryIsoForPhone(mParentApp.getPhoneId(), "");
282
283        // recordsRequested is set to false indicating that the SIM
284        // read requests made so far are not valid. This is set to
285        // true only when fresh set of read requests are made.
286        mRecordsRequested = false;
287    }
288
289
290    //***** Public Methods
291
292    /**
293     * {@inheritDoc}
294     */
295    @Override
296    public String getIMSI() {
297        return mImsi;
298    }
299
300    @Override
301    public String getMsisdnNumber() {
302        return mMsisdn;
303    }
304
305    @Override
306    public String getGid1() {
307        return mGid1;
308    }
309
310    @Override
311    public String getGid2() {
312        return mGid2;
313    }
314
315    @Override
316    public UsimServiceTable getUsimServiceTable() {
317        return mUsimServiceTable;
318    }
319
320    private int getExtFromEf(int ef) {
321        int ext;
322        switch (ef) {
323            case EF_MSISDN:
324                /* For USIM apps use EXT5. (TS 31.102 Section 4.2.37) */
325                if (mParentApp.getType() == AppType.APPTYPE_USIM) {
326                    ext = EF_EXT5;
327                } else {
328                    ext = EF_EXT1;
329                }
330                break;
331            default:
332                ext = EF_EXT1;
333        }
334        return ext;
335    }
336
337    /**
338     * Set subscriber number to SIM record
339     *
340     * The subscriber number is stored in EF_MSISDN (TS 51.011)
341     *
342     * When the operation is complete, onComplete will be sent to its handler
343     *
344     * @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters)
345     * @param number dailing nubmer (up to 20 digits)
346     *        if the number starts with '+', then set to international TOA
347     * @param onComplete
348     *        onComplete.obj will be an AsyncResult
349     *        ((AsyncResult)onComplete.obj).exception == null on success
350     *        ((AsyncResult)onComplete.obj).exception != null on fail
351     */
352    @Override
353    public void setMsisdnNumber(String alphaTag, String number,
354            Message onComplete) {
355
356        // If the SIM card is locked by PIN, we will set EF_MSISDN fail.
357        // In that case, msisdn and msisdnTag should not be update.
358        mNewMsisdn = number;
359        mNewMsisdnTag = alphaTag;
360
361        if(DBG) log("Set MSISDN: " + mNewMsisdnTag + " " + /*mNewMsisdn*/ "xxxxxxx");
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 1 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                    log("EF_CFIS: updating cf number, " + 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) + "xxxxxxx");
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*/ "xxxxxxx");
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                break;
1315            case EF_MSISDN:
1316                mRecordsToLoad++;
1317                log("SIM Refresh called for EF_MSISDN");
1318                new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, getExtFromEf(EF_MSISDN), 1,
1319                        obtainMessage(EVENT_GET_MSISDN_DONE));
1320                break;
1321            case EF_CFIS:
1322            case EF_CFF_CPHS:
1323                log("SIM Refresh called for EF_CFIS or EF_CFF_CPHS");
1324                loadCallForwardingRecords();
1325                break;
1326            default:
1327                // For now, fetch all records if this is not a
1328                // voicemail number.
1329                // TODO: Handle other cases, instead of fetching all.
1330                mAdnCache.reset();
1331                fetchSimRecords();
1332                break;
1333        }
1334    }
1335
1336    private void handleSimRefresh(IccRefreshResponse refreshResponse){
1337        if (refreshResponse == null) {
1338            if (DBG) log("handleSimRefresh received without input");
1339            return;
1340        }
1341
1342        if (refreshResponse.aid != null &&
1343                !refreshResponse.aid.equals(mParentApp.getAid())) {
1344            // This is for different app. Ignore.
1345            return;
1346        }
1347
1348        switch (refreshResponse.refreshResult) {
1349            case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE:
1350                if (DBG) log("handleSimRefresh with SIM_FILE_UPDATED");
1351                handleFileUpdate(refreshResponse.efId);
1352                break;
1353            case IccRefreshResponse.REFRESH_RESULT_INIT:
1354                if (DBG) log("handleSimRefresh with SIM_REFRESH_INIT");
1355                // need to reload all files (that we care about)
1356                onIccRefreshInit();
1357                break;
1358            case IccRefreshResponse.REFRESH_RESULT_RESET:
1359                // Refresh reset is handled by the UiccCard object.
1360                if (DBG) log("handleSimRefresh with SIM_REFRESH_RESET");
1361                break;
1362            default:
1363                // unknown refresh operation
1364                if (DBG) log("handleSimRefresh with unknown operation");
1365                break;
1366        }
1367    }
1368
1369    /**
1370     * Dispatch 3GPP format message to registrant ({@code GsmCdmaPhone}) to pass to the 3GPP SMS
1371     * dispatcher for delivery.
1372     */
1373    private int dispatchGsmMessage(SmsMessage message) {
1374        mNewSmsRegistrants.notifyResult(message);
1375        return 0;
1376    }
1377
1378    private void handleSms(byte[] ba) {
1379        if (ba[0] != 0)
1380            Rlog.d("ENF", "status : " + ba[0]);
1381
1382        // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
1383        // 3 == "received by MS from network; message to be read"
1384        if (ba[0] == 3) {
1385            int n = ba.length;
1386
1387            // Note: Data may include trailing FF's.  That's OK; message
1388            // should still parse correctly.
1389            byte[] pdu = new byte[n - 1];
1390            System.arraycopy(ba, 1, pdu, 0, n - 1);
1391            SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP);
1392
1393            dispatchGsmMessage(message);
1394        }
1395    }
1396
1397
1398    private void handleSmses(ArrayList<byte[]> messages) {
1399        int count = messages.size();
1400
1401        for (int i = 0; i < count; i++) {
1402            byte[] ba = messages.get(i);
1403
1404            if (ba[0] != 0)
1405                Rlog.i("ENF", "status " + i + ": " + ba[0]);
1406
1407            // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
1408            // 3 == "received by MS from network; message to be read"
1409
1410            if (ba[0] == 3) {
1411                int n = ba.length;
1412
1413                // Note: Data may include trailing FF's.  That's OK; message
1414                // should still parse correctly.
1415                byte[] pdu = new byte[n - 1];
1416                System.arraycopy(ba, 1, pdu, 0, n - 1);
1417                SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP);
1418
1419                dispatchGsmMessage(message);
1420
1421                // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
1422                // 1 == "received by MS from network; message read"
1423
1424                ba[0] = 1;
1425
1426                if (false) { // FIXME: writing seems to crash RdoServD
1427                    mFh.updateEFLinearFixed(EF_SMS,
1428                            i, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, i));
1429                }
1430            }
1431        }
1432    }
1433
1434    @Override
1435    protected void onRecordLoaded() {
1436        // One record loaded successfully or failed, In either case
1437        // we need to update the recordsToLoad count
1438        mRecordsToLoad -= 1;
1439        if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested);
1440
1441        if (mRecordsToLoad == 0 && mRecordsRequested == true) {
1442            onAllRecordsLoaded();
1443        } else if (mRecordsToLoad < 0) {
1444            loge("recordsToLoad <0, programmer error suspected");
1445            mRecordsToLoad = 0;
1446        }
1447    }
1448
1449    private void setVoiceCallForwardingFlagFromSimRecords() {
1450        if (validEfCfis(mEfCfis)) {
1451            // Refer TS 51.011 Section 10.3.46 for the content description
1452            mCallForwardingStatus = (mEfCfis[1] & 0x01);
1453            log("EF_CFIS: callForwardingEnabled=" + mCallForwardingStatus);
1454        } else if (mEfCff != null) {
1455            mCallForwardingStatus =
1456                    ((mEfCff[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE) ?
1457                            CALL_FORWARDING_STATUS_ENABLED : CALL_FORWARDING_STATUS_DISABLED;
1458            log("EF_CFF: callForwardingEnabled=" + mCallForwardingStatus);
1459        } else {
1460            mCallForwardingStatus = CALL_FORWARDING_STATUS_UNKNOWN;
1461            log("EF_CFIS and EF_CFF not valid. callForwardingEnabled=" + mCallForwardingStatus);
1462        }
1463    }
1464
1465    @Override
1466    protected void onAllRecordsLoaded() {
1467        if (DBG) log("record load complete");
1468
1469        Resources resource = Resources.getSystem();
1470        if (resource.getBoolean(com.android.internal.R.bool.config_use_sim_language_file)) {
1471            setSimLanguage(mEfLi, mEfPl);
1472        } else {
1473            if (DBG) log ("Not using EF LI/EF PL");
1474        }
1475
1476        setVoiceCallForwardingFlagFromSimRecords();
1477
1478        if (mParentApp.getState() == AppState.APPSTATE_PIN ||
1479               mParentApp.getState() == AppState.APPSTATE_PUK) {
1480            // reset recordsRequested, since sim is not loaded really
1481            mRecordsRequested = false;
1482            // lock state, only update language
1483            return ;
1484        }
1485
1486        // Some fields require more than one SIM record to set
1487
1488        String operator = getOperatorNumeric();
1489        if (!TextUtils.isEmpty(operator)) {
1490            log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" +
1491                    operator + "'");
1492            log("update icc_operator_numeric=" + operator);
1493            mTelephonyManager.setSimOperatorNumericForPhone(
1494                    mParentApp.getPhoneId(), operator);
1495            final SubscriptionController subController = SubscriptionController.getInstance();
1496            subController.setMccMnc(operator, subController.getDefaultSubId());
1497        } else {
1498            log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping");
1499        }
1500
1501        if (!TextUtils.isEmpty(mImsi)) {
1502            log("onAllRecordsLoaded set mcc imsi" + (VDBG ? ("=" + mImsi) : ""));
1503            mTelephonyManager.setSimCountryIsoForPhone(
1504                    mParentApp.getPhoneId(), MccTable.countryCodeForMcc(
1505                    Integer.parseInt(mImsi.substring(0,3))));
1506        } else {
1507            log("onAllRecordsLoaded empty imsi skipping setting mcc");
1508        }
1509
1510        setVoiceMailByCountry(operator);
1511
1512        mRecordsLoadedRegistrants.notifyRegistrants(
1513            new AsyncResult(null, null, null));
1514    }
1515
1516    //***** Private methods
1517
1518    private void handleCarrierNameOverride() {
1519        CarrierConfigManager configLoader = (CarrierConfigManager)
1520                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1521        if (configLoader != null && configLoader.getConfig().getBoolean(
1522                CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL)) {
1523            String carrierName = configLoader.getConfig().getString(
1524                    CarrierConfigManager.KEY_CARRIER_NAME_STRING);
1525            setServiceProviderName(carrierName);
1526            mTelephonyManager.setSimOperatorNameForPhone(mParentApp.getPhoneId(),
1527                    carrierName);
1528        } else {
1529            setSpnFromConfig(getOperatorNumeric());
1530        }
1531    }
1532
1533    private void setSpnFromConfig(String carrier) {
1534        if (mSpnOverride.containsCarrier(carrier)) {
1535            setServiceProviderName(mSpnOverride.getSpn(carrier));
1536            mTelephonyManager.setSimOperatorNameForPhone(
1537                    mParentApp.getPhoneId(), getServiceProviderName());
1538        }
1539    }
1540
1541
1542    private void setVoiceMailByCountry (String spn) {
1543        if (mVmConfig.containsCarrier(spn)) {
1544            mIsVoiceMailFixed = true;
1545            mVoiceMailNum = mVmConfig.getVoiceMailNumber(spn);
1546            mVoiceMailTag = mVmConfig.getVoiceMailTag(spn);
1547        }
1548    }
1549
1550    @Override
1551    public void onReady() {
1552        fetchSimRecords();
1553    }
1554
1555    private void onLocked() {
1556        if (DBG) log("only fetch EF_LI and EF_PL in lock state");
1557        loadEfLiAndEfPl();
1558    }
1559
1560    private void loadEfLiAndEfPl() {
1561        if (mParentApp.getType() == AppType.APPTYPE_USIM) {
1562            mRecordsRequested = true;
1563            mFh.loadEFTransparent(EF_LI,
1564                    obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfUsimLiLoaded()));
1565            mRecordsToLoad++;
1566
1567            mFh.loadEFTransparent(EF_PL,
1568                    obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfPlLoaded()));
1569            mRecordsToLoad++;
1570        }
1571    }
1572
1573    private void loadCallForwardingRecords() {
1574        mRecordsRequested = true;
1575        mFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE));
1576        mRecordsToLoad++;
1577        mFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE));
1578        mRecordsToLoad++;
1579    }
1580
1581    protected void fetchSimRecords() {
1582        mRecordsRequested = true;
1583
1584        if (DBG) log("fetchSimRecords " + mRecordsToLoad);
1585
1586        mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
1587        mRecordsToLoad++;
1588
1589        mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
1590        mRecordsToLoad++;
1591
1592        // FIXME should examine EF[MSISDN]'s capability configuration
1593        // to determine which is the voice/data/fax line
1594        new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, getExtFromEf(EF_MSISDN), 1,
1595                    obtainMessage(EVENT_GET_MSISDN_DONE));
1596        mRecordsToLoad++;
1597
1598        // Record number is subscriber profile
1599        mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));
1600        mRecordsToLoad++;
1601
1602        mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
1603        mRecordsToLoad++;
1604
1605        // Record number is subscriber profile
1606        mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE));
1607        mRecordsToLoad++;
1608
1609
1610        // Also load CPHS-style voice mail indicator, which stores
1611        // the same info as EF[MWIS]. If both exist, both are updated
1612        // but the EF[MWIS] data is preferred
1613        // Please note this must be loaded after EF[MWIS]
1614        mFh.loadEFTransparent(
1615                EF_VOICE_MAIL_INDICATOR_CPHS,
1616                obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE));
1617        mRecordsToLoad++;
1618
1619        // Same goes for Call Forward Status indicator: fetch both
1620        // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred.
1621        loadCallForwardingRecords();
1622
1623        getSpnFsm(true, null);
1624
1625        mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));
1626        mRecordsToLoad++;
1627
1628        mFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE));
1629        mRecordsToLoad++;
1630
1631        mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));
1632        mRecordsToLoad++;
1633
1634        mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));
1635        mRecordsToLoad++;
1636
1637        mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE));
1638        mRecordsToLoad++;
1639
1640        mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE));
1641        mRecordsToLoad++;
1642
1643        mFh.loadEFTransparent(EF_GID2, obtainMessage(EVENT_GET_GID2_DONE));
1644        mRecordsToLoad++;
1645
1646        loadEfLiAndEfPl();
1647
1648        // XXX should seek instead of examining them all
1649        if (false) { // XXX
1650            mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));
1651            mRecordsToLoad++;
1652        }
1653
1654        if (CRASH_RIL) {
1655            String sms = "0107912160130310f20404d0110041007030208054832b0120"
1656                         + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1657                         + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1658                         + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1659                         + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1660                         + "ffffffffffffffffffffffffffffff";
1661            byte[] ba = IccUtils.hexStringToBytes(sms);
1662
1663            mFh.updateEFLinearFixed(EF_SMS, 1, ba, null,
1664                            obtainMessage(EVENT_MARK_SMS_READ_DONE, 1));
1665        }
1666        if (DBG) log("fetchSimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested);
1667    }
1668
1669    /**
1670     * Returns the SpnDisplayRule based on settings on the SIM and the
1671     * specified plmn (currently-registered PLMN).  See TS 22.101 Annex A
1672     * and TS 51.011 10.3.11 for details.
1673     *
1674     * If the SPN is not found on the SIM or is empty, the rule is
1675     * always PLMN_ONLY.
1676     */
1677    @Override
1678    public int getDisplayRule(String plmn) {
1679        int rule;
1680
1681        if (mParentApp != null && mParentApp.getUiccCard() != null &&
1682            mParentApp.getUiccCard().getOperatorBrandOverride() != null) {
1683        // If the operator has been overridden, treat it as the SPN file on the SIM did not exist.
1684            rule = SPN_RULE_SHOW_PLMN;
1685        } else if (TextUtils.isEmpty(getServiceProviderName()) || mSpnDisplayCondition == -1) {
1686            // No EF_SPN content was found on the SIM, or not yet loaded.  Just show ONS.
1687            rule = SPN_RULE_SHOW_PLMN;
1688        } else if (isOnMatchingPlmn(plmn)) {
1689            rule = SPN_RULE_SHOW_SPN;
1690            if ((mSpnDisplayCondition & 0x01) == 0x01) {
1691                // ONS required when registered to HPLMN or PLMN in EF_SPDI
1692                rule |= SPN_RULE_SHOW_PLMN;
1693            }
1694        } else {
1695            rule = SPN_RULE_SHOW_PLMN;
1696            if ((mSpnDisplayCondition & 0x02) == 0x00) {
1697                // SPN required if not registered to HPLMN or PLMN in EF_SPDI
1698                rule |= SPN_RULE_SHOW_SPN;
1699            }
1700        }
1701        return rule;
1702    }
1703
1704    /**
1705     * Checks if plmn is HPLMN or on the spdiNetworks list.
1706     */
1707    private boolean isOnMatchingPlmn(String plmn) {
1708        if (plmn == null) return false;
1709
1710        if (plmn.equals(getOperatorNumeric())) {
1711            return true;
1712        }
1713
1714        if (mSpdiNetworks != null) {
1715            for (String spdiNet : mSpdiNetworks) {
1716                if (plmn.equals(spdiNet)) {
1717                    return true;
1718                }
1719            }
1720        }
1721        return false;
1722    }
1723
1724    /**
1725     * States of Get SPN Finite State Machine which only used by getSpnFsm()
1726     */
1727    private enum GetSpnFsmState {
1728        IDLE,               // No initialized
1729        INIT,               // Start FSM
1730        READ_SPN_3GPP,      // Load EF_SPN firstly
1731        READ_SPN_CPHS,      // Load EF_SPN_CPHS secondly
1732        READ_SPN_SHORT_CPHS // Load EF_SPN_SHORT_CPHS last
1733    }
1734
1735    /**
1736     * Finite State Machine to load Service Provider Name , which can be stored
1737     * in either EF_SPN (3GPP), EF_SPN_CPHS, or EF_SPN_SHORT_CPHS (CPHS4.2)
1738     *
1739     * After starting, FSM will search SPN EFs in order and stop after finding
1740     * the first valid SPN
1741     *
1742     * If the FSM gets restart while waiting for one of
1743     * SPN EFs results (i.e. a SIM refresh occurs after issuing
1744     * read EF_CPHS_SPN), it will re-initialize only after
1745     * receiving and discarding the unfinished SPN EF result.
1746     *
1747     * @param start set true only for initialize loading
1748     * @param ar the AsyncResult from loadEFTransparent
1749     *        ar.exception holds exception in error
1750     *        ar.result is byte[] for data in success
1751     */
1752    private void getSpnFsm(boolean start, AsyncResult ar) {
1753        byte[] data;
1754
1755        if (start) {
1756            // Check previous state to see if there is outstanding
1757            // SPN read
1758            if(mSpnState == GetSpnFsmState.READ_SPN_3GPP ||
1759               mSpnState == GetSpnFsmState.READ_SPN_CPHS ||
1760               mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS ||
1761               mSpnState == GetSpnFsmState.INIT) {
1762                // Set INIT then return so the INIT code
1763                // will run when the outstanding read done.
1764                mSpnState = GetSpnFsmState.INIT;
1765                return;
1766            } else {
1767                mSpnState = GetSpnFsmState.INIT;
1768            }
1769        }
1770
1771        switch(mSpnState){
1772            case INIT:
1773                setServiceProviderName(null);
1774
1775                mFh.loadEFTransparent(EF_SPN,
1776                        obtainMessage(EVENT_GET_SPN_DONE));
1777                mRecordsToLoad++;
1778
1779                mSpnState = GetSpnFsmState.READ_SPN_3GPP;
1780                break;
1781            case READ_SPN_3GPP:
1782                if (ar != null && ar.exception == null) {
1783                    data = (byte[]) ar.result;
1784                    mSpnDisplayCondition = 0xff & data[0];
1785
1786                    setServiceProviderName(IccUtils.adnStringFieldToString(
1787                            data, 1, data.length - 1));
1788                    // for card double-check and brand override
1789                    // we have to do this:
1790                    final String spn = getServiceProviderName();
1791
1792                    if (spn == null || spn.length() == 0) {
1793                        mSpnState = GetSpnFsmState.READ_SPN_CPHS;
1794                    } else {
1795                        if (DBG) log("Load EF_SPN: " + spn
1796                                + " spnDisplayCondition: " + mSpnDisplayCondition);
1797                        mTelephonyManager.setSimOperatorNameForPhone(
1798                                mParentApp.getPhoneId(), spn);
1799
1800                        mSpnState = GetSpnFsmState.IDLE;
1801                    }
1802                } else {
1803                    mSpnState = GetSpnFsmState.READ_SPN_CPHS;
1804                }
1805
1806                if (mSpnState == GetSpnFsmState.READ_SPN_CPHS) {
1807                    mFh.loadEFTransparent( EF_SPN_CPHS,
1808                            obtainMessage(EVENT_GET_SPN_DONE));
1809                    mRecordsToLoad++;
1810
1811                    // See TS 51.011 10.3.11.  Basically, default to
1812                    // show PLMN always, and SPN also if roaming.
1813                    mSpnDisplayCondition = -1;
1814                }
1815                break;
1816            case READ_SPN_CPHS:
1817                if (ar != null && ar.exception == null) {
1818                    data = (byte[]) ar.result;
1819
1820                    setServiceProviderName(IccUtils.adnStringFieldToString(
1821                            data, 0, data.length));
1822                    // for card double-check and brand override
1823                    // we have to do this:
1824                    final String spn = getServiceProviderName();
1825
1826                    if (spn == null || spn.length() == 0) {
1827                        mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS;
1828                    } else {
1829                        // Display CPHS Operator Name only when not roaming
1830                        mSpnDisplayCondition = 2;
1831
1832                        if (DBG) log("Load EF_SPN_CPHS: " + spn);
1833                        mTelephonyManager.setSimOperatorNameForPhone(
1834                                mParentApp.getPhoneId(), spn);
1835
1836                        mSpnState = GetSpnFsmState.IDLE;
1837                    }
1838                } else {
1839                    mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS;
1840                }
1841
1842                if (mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS) {
1843                    mFh.loadEFTransparent(
1844                            EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE));
1845                    mRecordsToLoad++;
1846                }
1847                break;
1848            case READ_SPN_SHORT_CPHS:
1849                if (ar != null && ar.exception == null) {
1850                    data = (byte[]) ar.result;
1851
1852                    setServiceProviderName(IccUtils.adnStringFieldToString(
1853                            data, 0, data.length));
1854                    // for card double-check and brand override
1855                    // we have to do this:
1856                    final String spn = getServiceProviderName();
1857
1858                    if (spn == null || spn.length() == 0) {
1859                        if (DBG) log("No SPN loaded in either CHPS or 3GPP");
1860                    } else {
1861                        // Display CPHS Operator Name only when not roaming
1862                        mSpnDisplayCondition = 2;
1863
1864                        if (DBG) log("Load EF_SPN_SHORT_CPHS: " + spn);
1865                        mTelephonyManager.setSimOperatorNameForPhone(
1866                                mParentApp.getPhoneId(), spn);
1867                    }
1868                } else {
1869                    setServiceProviderName(null);
1870                    if (DBG) log("No SPN loaded in either CHPS or 3GPP");
1871                }
1872
1873                mSpnState = GetSpnFsmState.IDLE;
1874                break;
1875            default:
1876                mSpnState = GetSpnFsmState.IDLE;
1877        }
1878    }
1879
1880    /**
1881     * Parse TS 51.011 EF[SPDI] record
1882     * This record contains the list of numeric network IDs that
1883     * are treated specially when determining SPN display
1884     */
1885    private void
1886    parseEfSpdi(byte[] data) {
1887        SimTlv tlv = new SimTlv(data, 0, data.length);
1888
1889        byte[] plmnEntries = null;
1890
1891        for ( ; tlv.isValidObject() ; tlv.nextObject()) {
1892            // Skip SPDI tag, if existant
1893            if (tlv.getTag() == TAG_SPDI) {
1894              tlv = new SimTlv(tlv.getData(), 0, tlv.getData().length);
1895            }
1896            // There should only be one TAG_SPDI_PLMN_LIST
1897            if (tlv.getTag() == TAG_SPDI_PLMN_LIST) {
1898                plmnEntries = tlv.getData();
1899                break;
1900            }
1901        }
1902
1903        if (plmnEntries == null) {
1904            return;
1905        }
1906
1907        mSpdiNetworks = new ArrayList<String>(plmnEntries.length / 3);
1908
1909        for (int i = 0 ; i + 2 < plmnEntries.length ; i += 3) {
1910            String plmnCode;
1911            plmnCode = IccUtils.bcdToString(plmnEntries, i, 3);
1912
1913            // Valid operator codes are 5 or 6 digits
1914            if (plmnCode.length() >= 5) {
1915                log("EF_SPDI network: " + plmnCode);
1916                mSpdiNetworks.add(plmnCode);
1917            }
1918        }
1919    }
1920
1921    /**
1922     * check to see if Mailbox Number is allocated and activated in CPHS SST
1923     */
1924    private boolean isCphsMailboxEnabled() {
1925        if (mCphsInfo == null)  return false;
1926        return ((mCphsInfo[1] & CPHS_SST_MBN_MASK) == CPHS_SST_MBN_ENABLED );
1927    }
1928
1929    @Override
1930    protected void log(String s) {
1931        Rlog.d(LOG_TAG, "[SIMRecords] " + s);
1932    }
1933
1934    @Override
1935    protected void loge(String s) {
1936        Rlog.e(LOG_TAG, "[SIMRecords] " + s);
1937    }
1938
1939    protected void logw(String s, Throwable tr) {
1940        Rlog.w(LOG_TAG, "[SIMRecords] " + s, tr);
1941    }
1942
1943    protected void logv(String s) {
1944        Rlog.v(LOG_TAG, "[SIMRecords] " + s);
1945    }
1946
1947    /**
1948     * Return true if "Restriction of menu options for manual PLMN selection"
1949     * bit is set or EF_CSP data is unavailable, return false otherwise.
1950     */
1951    @Override
1952    public boolean isCspPlmnEnabled() {
1953        return mCspPlmnEnabled;
1954    }
1955
1956    /**
1957     * Parse EF_CSP data and check if
1958     * "Restriction of menu options for manual PLMN selection" is
1959     * Enabled/Disabled
1960     *
1961     * @param data EF_CSP hex data.
1962     */
1963    private void handleEfCspData(byte[] data) {
1964        // As per spec CPHS4_2.WW6, CPHS B.4.7.1, EF_CSP contains CPHS defined
1965        // 18 bytes (i.e 9 service groups info) and additional data specific to
1966        // operator. The valueAddedServicesGroup is not part of standard
1967        // services. This is operator specific and can be programmed any where.
1968        // Normally this is programmed as 10th service after the standard
1969        // services.
1970        int usedCspGroups = data.length / 2;
1971        // This is the "Service Group Number" of "Value Added Services Group".
1972        byte valueAddedServicesGroup = (byte)0xC0;
1973
1974        mCspPlmnEnabled = true;
1975        for (int i = 0; i < usedCspGroups; i++) {
1976             if (data[2 * i] == valueAddedServicesGroup) {
1977                 log("[CSP] found ValueAddedServicesGroup, value " + data[(2 * i) + 1]);
1978                 if ((data[(2 * i) + 1] & 0x80) == 0x80) {
1979                     // Bit 8 is for
1980                     // "Restriction of menu options for manual PLMN selection".
1981                     // Operator Selection menu should be enabled.
1982                     mCspPlmnEnabled = true;
1983                 } else {
1984                     mCspPlmnEnabled = false;
1985                     // Operator Selection menu should be disabled.
1986                     // Operator Selection Mode should be set to Automatic.
1987                     log("[CSP] Set Automatic Network Selection");
1988                     mNetworkSelectionModeAutomaticRegistrants.notifyRegistrants();
1989                 }
1990                 return;
1991             }
1992        }
1993
1994        log("[CSP] Value Added Service Group (0xC0), not found!");
1995    }
1996
1997    @Override
1998    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1999        pw.println("SIMRecords: " + this);
2000        pw.println(" extends:");
2001        super.dump(fd, pw, args);
2002        pw.println(" mVmConfig=" + mVmConfig);
2003        pw.println(" mSpnOverride=" + mSpnOverride);
2004        pw.println(" mCallForwardingStatus=" + mCallForwardingStatus);
2005        pw.println(" mSpnState=" + mSpnState);
2006        pw.println(" mCphsInfo=" + mCphsInfo);
2007        pw.println(" mCspPlmnEnabled=" + mCspPlmnEnabled);
2008        pw.println(" mEfMWIS[]=" + Arrays.toString(mEfMWIS));
2009        pw.println(" mEfCPHS_MWI[]=" + Arrays.toString(mEfCPHS_MWI));
2010        pw.println(" mEfCff[]=" + Arrays.toString(mEfCff));
2011        pw.println(" mEfCfis[]=" + Arrays.toString(mEfCfis));
2012        pw.println(" mSpnDisplayCondition=" + mSpnDisplayCondition);
2013        pw.println(" mSpdiNetworks[]=" + mSpdiNetworks);
2014        pw.println(" mPnnHomeName=" + mPnnHomeName);
2015        pw.println(" mUsimServiceTable=" + mUsimServiceTable);
2016        pw.println(" mGid1=" + mGid1);
2017        pw.println(" mGid2=" + mGid2);
2018        pw.flush();
2019    }
2020}
2021