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