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