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