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