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