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