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