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