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