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