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