SIMRecords.java revision ba34751426d87fe714b9eb89228fe835e4bc0a80
1392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann/*
2392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * Copyright (C) 2006 The Android Open Source Project
3392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann *
4392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * Licensed under the Apache License, Version 2.0 (the "License");
5392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * you may not use this file except in compliance with the License.
6392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * You may obtain a copy of the License at
7392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann *
8392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann *      http://www.apache.org/licenses/LICENSE-2.0
9392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann *
10392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * Unless required by applicable law or agreed to in writing, software
11392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * distributed under the License is distributed on an "AS IS" BASIS,
12392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * See the License for the specific language governing permissions and
14392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * limitations under the License.
15392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann */
16392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
1718ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovpackage com.android.internal.telephony.gsm;
18392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
19392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
20392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
214597c92d655d45447780b32c7572acef110b6ed1Dmitri Plotnikovimport static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
22405671a7b42d97ebf7ae7c0eeb4721f881139673Daisuke Miyakawaimport android.content.Context;
23392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.os.AsyncResult;
24392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.os.Message;
25da5bf1cf60beef3de5e651a569fa544293683926Dave Santoroimport android.os.SystemProperties;
26392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.util.Log;
27392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
28392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.internal.telephony.AdnRecord;
29392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.internal.telephony.AdnRecordCache;
30da5bf1cf60beef3de5e651a569fa544293683926Dave Santoroimport com.android.internal.telephony.AdnRecordLoader;
31392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.internal.telephony.CommandsInterface;
32392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.internal.telephony.IccFileHandler;
33a2d4a9652fb4db9ee222abc7a637366c6c50427cKatherine Kuanimport com.android.internal.telephony.IccRecords;
34392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.internal.telephony.IccUtils;
35392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.internal.telephony.IccVmFixedException;
36392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.internal.telephony.IccVmNotSupportedException;
37da5bf1cf60beef3de5e651a569fa544293683926Dave Santoroimport com.android.internal.telephony.MccTable;
381b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan
39392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport java.util.ArrayList;
40da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
41392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
42392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann/**
43392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * {@hide}
4463ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan */
45392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannpublic final class SIMRecords extends IccRecords {
4612a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan    static final String LOG_TAG = "GSM";
47392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
48da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro    private static final boolean CRASH_RIL = false;
49da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
50392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final boolean DBG = true;
51392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
5263ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    // ***** Instance Variables
5363ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan
5463ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    VoiceMailConstants mVmConfig;
55392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
56392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
57392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    SpnOverride mSpnOverride;
5863ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan
5912a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan    // ***** Cached SIM State; cleared on channel close
6012a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan
61392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    String imsi;
62392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    boolean callForwardingEnabled;
63392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
64392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
65392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
66392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * States only used by getSpnFsm FSM
67392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
68392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private Get_Spn_Fsm_State spnState;
69392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
70392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /** CPHS service information (See CPHS 4.2 B.3.1.1)
71392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     *  It will be set in onSimReady if reading GET_CPHS_INFO successfully
72392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     *  mCphsInfo[0] is CPHS Phase
73392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     *  mCphsInfo[1] and mCphsInfo[2] is CPHS Service Table
74392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
75392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private byte[] mCphsInfo = null;
7663ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan
7791d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    byte[] efMWIS = null;
7863ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    byte[] efCPHS_MWI =null;
7963ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    byte[] mEfCff = null;
8063ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    byte[] mEfCfis = null;
8163ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan
8263ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan
8363ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    int spnDisplayCondition;
8463ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    // Numeric network codes listed in TS 51.011 EF[SPDI]
8512a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan    ArrayList<String> spdiNetworks = null;
8612a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan
8712a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan    String pnnHomeName = null;
8863ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan
8963ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    // ***** Constants
9063ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan
9163ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    // Bitmasks for SPN display rules.
9263ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    static final int SPN_RULE_SHOW_SPN  = 0x01;
9363ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    static final int SPN_RULE_SHOW_PLMN = 0x02;
9463ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan
9563ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    // From TS 51.011 EF[SPDI] section
9663ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    static final int TAG_SPDI_PLMN_LIST = 0x80;
9763ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan
9863ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    // Full Name IEI from TS 24.008
9963ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    static final int TAG_FULL_NETWORK_NAME = 0x43;
10063ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan
10163ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    // Short Name IEI from TS 24.008
10263ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    static final int TAG_SHORT_NETWORK_NAME = 0x45;
10363ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan
104392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    // active CFF from CPHS 4.2 B.4.5
10563ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    static final int CFF_UNCONDITIONAL_ACTIVE = 0x0a;
106392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    static final int CFF_UNCONDITIONAL_DEACTIVE = 0x05;
10763ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    static final int CFF_LINE1_MASK = 0x0f;
108392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    static final int CFF_LINE1_RESET = 0xf0;
109392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
110392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    // CPHS Service Table (See CPHS 4.2 B.3.1)
111392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int CPHS_SST_MBN_MASK = 0x30;
112392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int CPHS_SST_MBN_ENABLED = 0x30;
113392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
114392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    // ***** Event Constants
115392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
11602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    private static final int EVENT_SIM_READY = 1;
117392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 2;
118392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_GET_IMSI_DONE = 3;
11912a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan    private static final int EVENT_GET_ICCID_DONE = 4;
120392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_GET_MBI_DONE = 5;
121392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_GET_MBDN_DONE = 6;
122392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_GET_MWIS_DONE = 7;
123392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE = 8;
124392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_GET_AD_DONE = 9; // Admin data on SIM
12512a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan    private static final int EVENT_GET_MSISDN_DONE = 10;
126392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_GET_CPHS_MAILBOX_DONE = 11;
12712a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan    private static final int EVENT_GET_SPN_DONE = 12;
12812a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan    private static final int EVENT_GET_SPDI_DONE = 13;
129915ffc5ae1d10a7ed06d5541fe81da023fa3228fDaniel Lehmann    private static final int EVENT_UPDATE_DONE = 14;
130915ffc5ae1d10a7ed06d5541fe81da023fa3228fDaniel Lehmann    private static final int EVENT_GET_PNN_DONE = 15;
13163ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    private static final int EVENT_GET_SST_DONE = 17;
13212a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan    private static final int EVENT_GET_ALL_SMS_DONE = 18;
133392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_MARK_SMS_READ_DONE = 19;
134392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_SET_MBDN_DONE = 20;
135392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_SMS_ON_SIM = 21;
136392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_GET_SMS_DONE = 22;
137392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_GET_CFF_DONE = 24;
138392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_SET_CPHS_MAILBOX_DONE = 25;
139392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_GET_INFO_CPHS_DONE = 26;
140392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_SET_MSISDN_DONE = 30;
141392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_SIM_REFRESH = 31;
142392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int EVENT_GET_CFIS_DONE = 32;
143392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
144392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    // Lookup table for carriers known to produce SIMs which incorrectly indicate MNC length.
145392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
146392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final String[] MCCMNC_CODES_HAVING_3DIGITS_MNC = {
147392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        "405025", "405026", "405027", "405028", "405029", "405030", "405031", "405032",
148392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        "405033", "405034", "405035", "405036", "405037", "405038", "405039", "405040",
149392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        "405041", "405042", "405043", "405044", "405045", "405046", "405047", "405750",
150392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        "405751", "405752", "405753", "405754", "405755", "405756", "405799", "405800",
151392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        "405801", "405802", "405803", "405804", "405805", "405806", "405807", "405808",
152392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        "405809", "405810", "405811", "405812", "405813", "405814", "405815", "405816",
153392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        "405817", "405818", "405819", "405820", "405821", "405822", "405823", "405824",
154392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        "405825", "405826", "405827", "405828", "405829", "405830", "405831", "405832",
155392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        "405833", "405834", "405835", "405836", "405837", "405838", "405839", "405840",
156392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        "405841", "405842", "405843", "405844", "405845", "405846", "405847", "405848",
157392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        "405849", "405850", "405851", "405852", "405853", "405875", "405876", "405877",
158392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        "405878", "405879", "405880", "405881", "405882", "405883", "405884", "405885",
159392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        "405886", "405908", "405909", "405910", "405911", "405925", "405926", "405927",
160392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        "405928", "405929", "405932"
161392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    };
162392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
16363ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    // ***** Constructor
164392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
165392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    SIMRecords(GSMPhone p) {
166392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        super(p);
167392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
168392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        adnCache = new AdnRecordCache(phone);
169392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
170392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mVmConfig = new VoiceMailConstants();
171392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mSpnOverride = new SpnOverride();
172392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
173392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        recordsRequested = false;  // No load request is made till SIM ready
174392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
175a2d4a9652fb4db9ee222abc7a637366c6c50427cKatherine Kuan        // recordsToLoad is set to 0 because no requests are made yet
176392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        recordsToLoad = 0;
177392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
178392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
179392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        p.mCM.registerForSIMReady(this, EVENT_SIM_READY, null);
180392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        p.mCM.registerForOffOrNotAvailable(
181392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                        this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
182392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        p.mCM.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null);
183392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        p.mCM.setOnIccRefresh(this, EVENT_SIM_REFRESH, null);
184da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
185da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        // Start off by setting empty state
186da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        onRadioOffOrNotAvailable();
187392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
188392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
189392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
190392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public void dispose() {
191392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        //Unregister for all events
192392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        phone.mCM.unregisterForSIMReady(this);
193392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        phone.mCM.unregisterForOffOrNotAvailable( this);
194392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        phone.mCM.unSetOnIccRefresh(this);
195392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
196392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
197392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected void finalize() {
1985e330ed98f1c2711b4cd3b375a1c0f76bedaf3e1Katherine Kuan        if(DBG) Log.d(LOG_TAG, "SIMRecords finalized");
1995e330ed98f1c2711b4cd3b375a1c0f76bedaf3e1Katherine Kuan    }
2005e330ed98f1c2711b4cd3b375a1c0f76bedaf3e1Katherine Kuan
201392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected void onRadioOffOrNotAvailable() {
202392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        imsi = null;
203392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        msisdn = null;
204392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        voiceMailNum = null;
205392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        countVoiceMessages = 0;
206392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mncLength = UNINITIALIZED;
207392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        iccid = null;
208392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        // -1 means no EF_SPN found; treat accordingly.
209392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        spnDisplayCondition = -1;
210392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        efMWIS = null;
211392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        efCPHS_MWI = null;
212392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        spdiNetworks = null;
213392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        pnnHomeName = null;
214392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
215392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        adnCache.reset();
216392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
217392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, null);
21802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, null);
219392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, null);
220392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
221392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        // recordsRequested is set to false indicating that the SIM
222392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        // read requests made so far are not valid. This is set to
223392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        // true only when fresh set of read requests are made.
224392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        recordsRequested = false;
225392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
226392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
227392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
228392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    //***** Public Methods
229392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
230392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /** Returns null if SIM is not yet ready */
231392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public String getIMSI() {
232392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return imsi;
233392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
234392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
235392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public String getMsisdnNumber() {
23663ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        return msisdn;
237392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
238392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
239392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
24012a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan     * Set subscriber number to SIM record
24112a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan     *
242392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * The subscriber number is stored in EF_MSISDN (TS 51.011)
243392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     *
2442591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan     * When the operation is complete, onComplete will be sent to its handler
2452591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan     *
2461b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan     * @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters)
2471b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan     * @param number dailing nubmer (up to 20 digits)
2482591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan     *        if the number starts with '+', then set to international TOA
2492591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan     * @param onComplete
2501b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan     *        onComplete.obj will be an AsyncResult
2511b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan     *        ((AsyncResult)onComplete.obj).exception == null on success
2522591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan     *        ((AsyncResult)onComplete.obj).exception != null on fail
2531b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan     */
2541b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan    public void setMsisdnNumber(String alphaTag, String number,
255392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            Message onComplete) {
256392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
257392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        msisdn = number;
258392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        msisdnTag = alphaTag;
259392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
260392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if(DBG) log("Set MSISDN: " + msisdnTag + " " + /*msisdn*/ "xxxxxxx");
261392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
262392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
263392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        AdnRecord adn = new AdnRecord(msisdnTag, msisdn);
264392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
265392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        new AdnRecordLoader(phone).updateEF(adn, EF_MSISDN, EF_EXT1, 1, null,
266392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                obtainMessage(EVENT_SET_MSISDN_DONE, onComplete));
267392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
268392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
269392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public String getMsisdnAlphaTag() {
270392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return msisdnTag;
271392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
272392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
273392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public String getVoiceMailNumber() {
274392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return voiceMailNum;
275392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
276392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
277392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
278392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Set voice mail number to SIM record
279392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     *
280392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * The voice mail number can be stored either in EF_MBDN (TS 51.011) or
281392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * EF_MAILBOX_CPHS (CPHS 4.2)
282392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     *
283392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * If EF_MBDN is available, store the voice mail number to EF_MBDN
284392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     *
285392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS
286392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     *
287392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * So the voice mail number will be stored in both EFs if both are available
288392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     *
289392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Return error only if both EF_MBDN and EF_MAILBOX_CPHS fail.
290392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     *
291392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * When the operation is complete, onComplete will be sent to its handler
2925ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov     *
293392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * @param alphaTag alpha-tagging of the dailing nubmer (upto 10 characters)
294392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * @param voiceNumber dailing nubmer (upto 20 digits)
295392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     *        if the number is start with '+', then set to international TOA
296392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * @param onComplete
297392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     *        onComplete.obj will be an AsyncResult
298392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     *        ((AsyncResult)onComplete.obj).exception == null on success
299392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     *        ((AsyncResult)onComplete.obj).exception != null on fail
300392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
301392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public void setVoiceMailNumber(String alphaTag, String voiceNumber,
302392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            Message onComplete) {
303392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (isVoiceMailFixed) {
304392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            AsyncResult.forMessage((onComplete)).exception =
305392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    new IccVmFixedException("Voicemail number is fixed by operator");
306392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            onComplete.sendToTarget();
307392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            return;
308392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
309392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
310392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        newVoiceMailNum = voiceNumber;
311392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        newVoiceMailTag = alphaTag;
312392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
313392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        AdnRecord adn = new AdnRecord(newVoiceMailTag, newVoiceMailNum);
314392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
315392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (mailboxIndex != 0 && mailboxIndex != 0xff) {
316392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
317392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            new AdnRecordLoader(phone).updateEF(adn, EF_MBDN, EF_EXT6,
318392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    mailboxIndex, null,
319392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    obtainMessage(EVENT_SET_MBDN_DONE, onComplete));
320392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
321392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        } else if (isCphsMailboxEnabled()) {
322392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
323392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            new AdnRecordLoader(phone).updateEF(adn, EF_MAILBOX_CPHS,
324392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    EF_EXT1, 1, null,
325392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE, onComplete));
326392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
327392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        } else {
328392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            AsyncResult.forMessage((onComplete)).exception =
329392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    new IccVmNotSupportedException("Update SIM voice mailbox error");
330392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            onComplete.sendToTarget();
331392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
332392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
333392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
334392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public String getVoiceMailAlphaTag()
335392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    {
336392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return voiceMailTag;
337392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
338cfb525b3f18d71d6cc5d4ef36d704b3ba9e9a6f3Daniel Lehmann
339392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
340392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Sets the SIM voice message waiting indicator records
341392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
342392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * @param countWaiting The number of messages waiting, if known. Use
343392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     *                     -1 to indicate that an unknown number of
344392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     *                      messages are waiting
345392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
346392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public void
347392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    setVoiceMessageWaiting(int line, int countWaiting) {
348392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (line != 1) {
349392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            // only profile 1 is supported
350392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            return;
351392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
352da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
353da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        // range check
354da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        if (countWaiting < 0) {
355da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro            countWaiting = -1;
356da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        } else if (countWaiting > 0xff) {
357da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro            // TS 23.040 9.2.3.24.2
358da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro            // "The value 255 shall be taken to mean 255 or greater"
359da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro            countWaiting = 0xff;
360da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        }
361da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
362da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        countVoiceMessages = countWaiting;
363da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
364da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        ((GSMPhone) phone).notifyMessageWaitingIndicator();
365da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
366da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        try {
367da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro            if (efMWIS != null) {
368da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                // TS 51.011 10.3.45
369da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
370da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                // lsb of byte 0 is 'voicemail' status
371da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                efMWIS[0] = (byte)((efMWIS[0] & 0xfe)
372da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                                    | (countVoiceMessages == 0 ? 0 : 1));
373da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
374da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                // byte 1 is the number of voice messages waiting
375da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                if (countWaiting < 0) {
376da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    // The spec does not define what this should be
377da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    // if we don't know the count
378da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    efMWIS[1] = 0;
379da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                } else {
380da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    efMWIS[1] = (byte) countWaiting;
381da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                }
382da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
383da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                phone.getIccFileHandler().updateEFLinearFixed(
384da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    EF_MWIS, 1, efMWIS, null,
385da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    obtainMessage (EVENT_UPDATE_DONE, EF_MWIS));
386da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro            }
387da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
388da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro            if (efCPHS_MWI != null) {
389da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    // Refer CPHS4_2.WW6 B4.2.3
390da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                efCPHS_MWI[0] = (byte)((efCPHS_MWI[0] & 0xf0)
391da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                            | (countVoiceMessages == 0 ? 0x5 : 0xa));
392da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
393da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                phone.getIccFileHandler().updateEFTransparent(
394da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    EF_VOICE_MAIL_INDICATOR_CPHS, efCPHS_MWI,
395da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    obtainMessage (EVENT_UPDATE_DONE, EF_VOICE_MAIL_INDICATOR_CPHS));
396da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro            }
397da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        } catch (ArrayIndexOutOfBoundsException ex) {
398da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro            Log.w(LOG_TAG,
399da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                "Error saving voice mail state to SIM. Probably malformed SIM record", ex);
400da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        }
401da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro    }
402da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
403da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro    public boolean getVoiceCallForwardingFlag() {
404da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        return callForwardingEnabled;
405da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro    }
406da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
407da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro    public void setVoiceCallForwardingFlag(int line, boolean enable) {
408392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
409        if (line != 1) return; // only line 1 is supported
410
411        callForwardingEnabled = enable;
412
413        ((GSMPhone) phone).notifyCallForwardingIndicator();
414
415        try {
416            if (mEfCfis != null) {
417                // lsb is of byte 1 is voice status
418                if (enable) {
419                    mEfCfis[1] |= 1;
420                } else {
421                    mEfCfis[1] &= 0xfe;
422                }
423
424                // TODO: Should really update other fields in EF_CFIS, eg,
425                // dialing number.  We don't read or use it right now.
426
427                phone.getIccFileHandler().updateEFLinearFixed(
428                        EF_CFIS, 1, mEfCfis, null,
429                        obtainMessage (EVENT_UPDATE_DONE, EF_CFIS));
430            }
431
432            if (mEfCff != null) {
433                if (enable) {
434                    mEfCff[0] = (byte) ((mEfCff[0] & CFF_LINE1_RESET)
435                            | CFF_UNCONDITIONAL_ACTIVE);
436                } else {
437                    mEfCff[0] = (byte) ((mEfCff[0] & CFF_LINE1_RESET)
438                            | CFF_UNCONDITIONAL_DEACTIVE);
439                }
440
441                phone.getIccFileHandler().updateEFTransparent(
442                        EF_CFF_CPHS, mEfCff,
443                        obtainMessage (EVENT_UPDATE_DONE, EF_CFF_CPHS));
444            }
445        } catch (ArrayIndexOutOfBoundsException ex) {
446            Log.w(LOG_TAG,
447                    "Error saving call fowarding flag to SIM. "
448                            + "Probably malformed SIM record", ex);
449
450        }
451    }
452
453    /**
454     * Called by STK Service when REFRESH is received.
455     * @param fileChanged indicates whether any files changed
456     * @param fileList if non-null, a list of EF files that changed
457     */
458    public void onRefresh(boolean fileChanged, int[] fileList) {
459        if (fileChanged) {
460            // A future optimization would be to inspect fileList and
461            // only reload those files that we care about.  For now,
462            // just re-fetch all SIM records that we cache.
463            fetchSimRecords();
464        }
465    }
466
467    /** Returns the 5 or 6 digit MCC/MNC of the operator that
468     *  provided the SIM card. Returns null of SIM is not yet ready
469     */
470    String getSIMOperatorNumeric() {
471        if (imsi == null || mncLength == UNINITIALIZED || mncLength == UNKNOWN) {
472            return null;
473        }
474
475        // Length = length of MCC + length of MNC
476        // length of mcc = 3 (TS 23.003 Section 2.2)
477        return imsi.substring(0, 3 + mncLength);
478    }
479
480    // ***** Overridden from Handler
481    public void handleMessage(Message msg) {
482        AsyncResult ar;
483        AdnRecord adn;
484
485        byte data[];
486
487        boolean isRecordLoadResponse = false;
488
489        try { switch (msg.what) {
490            case EVENT_SIM_READY:
491                onSimReady();
492            break;
493
494            case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
495                onRadioOffOrNotAvailable();
496            break;
497
498            /* IO events */
499            case EVENT_GET_IMSI_DONE:
500                isRecordLoadResponse = true;
501
502                ar = (AsyncResult)msg.obj;
503
504                if (ar.exception != null) {
505                    Log.e(LOG_TAG, "Exception querying IMSI, Exception:" + ar.exception);
506                    break;
507                }
508
509                imsi = (String) ar.result;
510
511                // IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more
512                // than 15 (and usually 15).
513                if (imsi != null && (imsi.length() < 6 || imsi.length() > 15)) {
514                    Log.e(LOG_TAG, "invalid IMSI " + imsi);
515                    imsi = null;
516                }
517
518                Log.d(LOG_TAG, "IMSI: " + imsi.substring(0, 6) + "xxxxxxx");
519
520                if (((mncLength == UNKNOWN) || (mncLength == 2)) &&
521                        ((imsi != null) && (imsi.length() >= 6))) {
522                    String mccmncCode = imsi.substring(0, 6);
523                    for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) {
524                        if (mccmnc.equals(mccmncCode)) {
525                            mncLength = 3;
526                            break;
527                        }
528                    }
529                }
530
531                if (mncLength == UNKNOWN) {
532                    // the SIM has told us all it knows, but it didn't know the mnc length.
533                    // guess using the mcc
534                    try {
535                        int mcc = Integer.parseInt(imsi.substring(0,3));
536                        mncLength = MccTable.smallestDigitsMccForMnc(mcc);
537                    } catch (NumberFormatException e) {
538                        mncLength = UNKNOWN;
539                        Log.e(LOG_TAG, "SIMRecords: Corrupt IMSI!");
540                    }
541                }
542
543                if (mncLength != UNKNOWN && mncLength != UNINITIALIZED) {
544                    // finally have both the imsi and the mncLength and can parse the imsi properly
545                    MccTable.updateMccMncConfiguration(phone, imsi.substring(0, 3 + mncLength));
546                }
547                ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
548                        SimCard.INTENT_VALUE_ICC_IMSI, null);
549            break;
550
551            case EVENT_GET_MBI_DONE:
552                boolean isValidMbdn;
553                isRecordLoadResponse = true;
554
555                ar = (AsyncResult)msg.obj;
556                data = (byte[]) ar.result;
557
558                isValidMbdn = false;
559                if (ar.exception == null) {
560                    // Refer TS 51.011 Section 10.3.44 for content details
561                    Log.d(LOG_TAG, "EF_MBI: " +
562                            IccUtils.bytesToHexString(data));
563
564                    // Voice mail record number stored first
565                    mailboxIndex = (int)data[0] & 0xff;
566
567                    // check if dailing numbe id valid
568                    if (mailboxIndex != 0 && mailboxIndex != 0xff) {
569                        Log.d(LOG_TAG, "Got valid mailbox number for MBDN");
570                        isValidMbdn = true;
571                    }
572                }
573
574                // one more record to load
575                recordsToLoad += 1;
576
577                if (isValidMbdn) {
578                    // Note: MBDN was not included in NUM_OF_SIM_RECORDS_LOADED
579                    new AdnRecordLoader(phone).loadFromEF(EF_MBDN, EF_EXT6,
580                            mailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
581                } else {
582                    // If this EF not present, try mailbox as in CPHS standard
583                    // CPHS (CPHS4_2.WW6) is a european standard.
584                    new AdnRecordLoader(phone).loadFromEF(EF_MAILBOX_CPHS,
585                            EF_EXT1, 1,
586                            obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
587                }
588
589                break;
590            case EVENT_GET_CPHS_MAILBOX_DONE:
591            case EVENT_GET_MBDN_DONE:
592                isRecordLoadResponse = true;
593
594                ar = (AsyncResult)msg.obj;
595
596                if (ar.exception != null) {
597
598                    Log.d(LOG_TAG, "Invalid or missing EF"
599                        + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? "[MAILBOX]" : "[MBDN]"));
600
601                    // Bug #645770 fall back to CPHS
602                    // FIXME should use SST to decide
603
604                    if (msg.what == EVENT_GET_MBDN_DONE) {
605                        //load CPHS on fail...
606                        // FIXME right now, only load line1's CPHS voice mail entry
607
608                        recordsToLoad += 1;
609                        new AdnRecordLoader(phone).loadFromEF(
610                                EF_MAILBOX_CPHS, EF_EXT1, 1,
611                                obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
612                    }
613                    break;
614                }
615
616                adn = (AdnRecord)ar.result;
617
618                Log.d(LOG_TAG, "VM: " + adn +
619                        ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? " EF[MAILBOX]" : " EF[MBDN]"));
620
621                if (adn.isEmpty() && msg.what == EVENT_GET_MBDN_DONE) {
622                    // Bug #645770 fall back to CPHS
623                    // FIXME should use SST to decide
624                    // FIXME right now, only load line1's CPHS voice mail entry
625                    recordsToLoad += 1;
626                    new AdnRecordLoader(phone).loadFromEF(
627                            EF_MAILBOX_CPHS, EF_EXT1, 1,
628                            obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
629
630                    break;
631                }
632
633                voiceMailNum = adn.getNumber();
634                voiceMailTag = adn.getAlphaTag();
635            break;
636
637            case EVENT_GET_MSISDN_DONE:
638                isRecordLoadResponse = true;
639
640                ar = (AsyncResult)msg.obj;
641
642                if (ar.exception != null) {
643                    Log.d(LOG_TAG, "Invalid or missing EF[MSISDN]");
644                    break;
645                }
646
647                adn = (AdnRecord)ar.result;
648
649                msisdn = adn.getNumber();
650                msisdnTag = adn.getAlphaTag();
651
652                Log.d(LOG_TAG, "MSISDN: " + /*msisdn*/ "xxxxxxx");
653            break;
654
655            case EVENT_SET_MSISDN_DONE:
656                isRecordLoadResponse = false;
657                ar = (AsyncResult)msg.obj;
658
659                if (ar.userObj != null) {
660                    AsyncResult.forMessage(((Message) ar.userObj)).exception
661                            = ar.exception;
662                    ((Message) ar.userObj).sendToTarget();
663                }
664                break;
665
666            case EVENT_GET_MWIS_DONE:
667                isRecordLoadResponse = true;
668
669                ar = (AsyncResult)msg.obj;
670                data = (byte[])ar.result;
671
672                if (ar.exception != null) {
673                    break;
674                }
675
676                Log.d(LOG_TAG, "EF_MWIS: " +
677                   IccUtils.bytesToHexString(data));
678
679                efMWIS = data;
680
681                if ((data[0] & 0xff) == 0xff) {
682                    Log.d(LOG_TAG, "SIMRecords: Uninitialized record MWIS");
683                    break;
684                }
685
686                // Refer TS 51.011 Section 10.3.45 for the content description
687                boolean voiceMailWaiting = ((data[0] & 0x01) != 0);
688                countVoiceMessages = data[1] & 0xff;
689
690                if (voiceMailWaiting && countVoiceMessages == 0) {
691                    // Unknown count = -1
692                    countVoiceMessages = -1;
693                }
694
695                ((GSMPhone) phone).notifyMessageWaitingIndicator();
696            break;
697
698            case EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE:
699                isRecordLoadResponse = true;
700
701                ar = (AsyncResult)msg.obj;
702                data = (byte[])ar.result;
703
704                if (ar.exception != null) {
705                    break;
706                }
707
708                efCPHS_MWI = data;
709
710                // Use this data if the EF[MWIS] exists and
711                // has been loaded
712
713                if (efMWIS == null) {
714                    int indicator = (int)(data[0] & 0xf);
715
716                    // Refer CPHS4_2.WW6 B4.2.3
717                    if (indicator == 0xA) {
718                        // Unknown count = -1
719                        countVoiceMessages = -1;
720                    } else if (indicator == 0x5) {
721                        countVoiceMessages = 0;
722                    }
723
724                    ((GSMPhone) phone).notifyMessageWaitingIndicator();
725                }
726            break;
727
728            case EVENT_GET_ICCID_DONE:
729                isRecordLoadResponse = true;
730
731                ar = (AsyncResult)msg.obj;
732                data = (byte[])ar.result;
733
734                if (ar.exception != null) {
735                    break;
736                }
737
738                iccid = IccUtils.bcdToString(data, 0, data.length);
739
740                Log.d(LOG_TAG, "iccid: " + iccid);
741
742            break;
743
744
745            case EVENT_GET_AD_DONE:
746                try {
747                    isRecordLoadResponse = true;
748
749                    ar = (AsyncResult)msg.obj;
750                    data = (byte[])ar.result;
751
752                    if (ar.exception != null) {
753                        break;
754                    }
755
756                    Log.d(LOG_TAG, "EF_AD: " +
757                            IccUtils.bytesToHexString(data));
758
759                    if (data.length < 3) {
760                        Log.d(LOG_TAG, "SIMRecords: Corrupt AD data on SIM");
761                        break;
762                    }
763
764                    if (data.length == 3) {
765                        Log.d(LOG_TAG, "SIMRecords: MNC length not present in EF_AD");
766                        break;
767                    }
768
769                    mncLength = (int)data[3] & 0xf;
770
771                    if (mncLength == 0xf) {
772                        mncLength = UNKNOWN;
773                    }
774                } finally {
775                    if (((mncLength == UNINITIALIZED) || (mncLength == UNKNOWN) ||
776                            (mncLength == 2)) && ((imsi != null) && (imsi.length() >= 6))) {
777                        String mccmncCode = imsi.substring(0, 6);
778                        for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) {
779                            if (mccmnc.equals(mccmncCode)) {
780                                mncLength = 3;
781                                break;
782                            }
783                        }
784                    }
785
786                    if (mncLength == UNKNOWN || mncLength == UNINITIALIZED) {
787                        if (imsi != null) {
788                            try {
789                                int mcc = Integer.parseInt(imsi.substring(0,3));
790
791                                mncLength = MccTable.smallestDigitsMccForMnc(mcc);
792                            } catch (NumberFormatException e) {
793                                mncLength = UNKNOWN;
794                                Log.e(LOG_TAG, "SIMRecords: Corrupt IMSI!");
795                            }
796                        } else {
797                            // Indicate we got this info, but it didn't contain the length.
798                            mncLength = UNKNOWN;
799
800                            Log.d(LOG_TAG, "SIMRecords: MNC length not present in EF_AD");
801                        }
802                    }
803                    if (imsi != null && mncLength != UNKNOWN) {
804                        // finally have both imsi and the length of the mnc and can parse
805                        // the imsi properly
806                        MccTable.updateMccMncConfiguration(phone, imsi.substring(0, 3 + mncLength));
807                    }
808                }
809            break;
810
811            case EVENT_GET_SPN_DONE:
812                isRecordLoadResponse = true;
813                ar = (AsyncResult) msg.obj;
814                getSpnFsm(false, ar);
815            break;
816
817            case EVENT_GET_CFF_DONE:
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.d(LOG_TAG, "EF_CFF_CPHS: " +
828                        IccUtils.bytesToHexString(data));
829                mEfCff = data;
830
831                if (mEfCfis == null) {
832                    callForwardingEnabled =
833                        ((data[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE);
834
835                    ((GSMPhone) phone).notifyCallForwardingIndicator();
836                }
837                break;
838
839            case EVENT_GET_SPDI_DONE:
840                isRecordLoadResponse = true;
841
842                ar = (AsyncResult)msg.obj;
843                data = (byte[])ar.result;
844
845                if (ar.exception != null) {
846                    break;
847                }
848
849                parseEfSpdi(data);
850            break;
851
852            case EVENT_UPDATE_DONE:
853                ar = (AsyncResult)msg.obj;
854                if (ar.exception != null) {
855                    Log.i(LOG_TAG, "SIMRecords update failed", ar.exception);
856                }
857            break;
858
859            case EVENT_GET_PNN_DONE:
860                isRecordLoadResponse = true;
861
862                ar = (AsyncResult)msg.obj;
863                data = (byte[])ar.result;
864
865                if (ar.exception != null) {
866                    break;
867                }
868
869                SimTlv tlv = new SimTlv(data, 0, data.length);
870
871                for ( ; tlv.isValidObject() ; tlv.nextObject()) {
872                    if (tlv.getTag() == TAG_FULL_NETWORK_NAME) {
873                        pnnHomeName
874                            = IccUtils.networkNameToString(
875                                tlv.getData(), 0, tlv.getData().length);
876                        break;
877                    }
878                }
879            break;
880
881            case EVENT_GET_ALL_SMS_DONE:
882                isRecordLoadResponse = true;
883
884                ar = (AsyncResult)msg.obj;
885                if (ar.exception != null)
886                    break;
887
888                handleSmses((ArrayList) ar.result);
889                break;
890
891            case EVENT_MARK_SMS_READ_DONE:
892                Log.i("ENF", "marked read: sms " + msg.arg1);
893                break;
894
895
896            case EVENT_SMS_ON_SIM:
897                isRecordLoadResponse = false;
898
899                ar = (AsyncResult)msg.obj;
900
901                int[] index = (int[])ar.result;
902
903                if (ar.exception != null || index.length != 1) {
904                    Log.e(LOG_TAG, "[SIMRecords] Error on SMS_ON_SIM with exp "
905                            + ar.exception + " length " + index.length);
906                } else {
907                    Log.d(LOG_TAG, "READ EF_SMS RECORD index=" + index[0]);
908                    phone.getIccFileHandler().loadEFLinearFixed(EF_SMS,index[0],
909                            obtainMessage(EVENT_GET_SMS_DONE));
910                }
911                break;
912
913            case EVENT_GET_SMS_DONE:
914                isRecordLoadResponse = false;
915                ar = (AsyncResult)msg.obj;
916                if (ar.exception == null) {
917                    handleSms((byte[])ar.result);
918                } else {
919                    Log.e(LOG_TAG, "[SIMRecords] Error on GET_SMS with exp "
920                            + ar.exception);
921                }
922                break;
923            case EVENT_GET_SST_DONE:
924                isRecordLoadResponse = true;
925
926                ar = (AsyncResult)msg.obj;
927                data = (byte[])ar.result;
928
929                if (ar.exception != null) {
930                    break;
931                }
932
933                //Log.d(LOG_TAG, "SST: " + IccUtils.bytesToHexString(data));
934            break;
935
936            case EVENT_GET_INFO_CPHS_DONE:
937                isRecordLoadResponse = true;
938
939                ar = (AsyncResult)msg.obj;
940
941                if (ar.exception != null) {
942                    break;
943                }
944
945                mCphsInfo = (byte[])ar.result;
946
947                if (DBG) log("iCPHS: " + IccUtils.bytesToHexString(mCphsInfo));
948            break;
949
950            case EVENT_SET_MBDN_DONE:
951                isRecordLoadResponse = false;
952                ar = (AsyncResult)msg.obj;
953
954                if (ar.exception == null) {
955                    voiceMailNum = newVoiceMailNum;
956                    voiceMailTag = newVoiceMailTag;
957                }
958
959                if (isCphsMailboxEnabled()) {
960                    adn = new AdnRecord(voiceMailTag, voiceMailNum);
961                    Message onCphsCompleted = (Message) ar.userObj;
962
963                    /* write to cphs mailbox whenever it is available but
964                    * we only need notify caller once if both updating are
965                    * successful.
966                    *
967                    * so if set_mbdn successful, notify caller here and set
968                    * onCphsCompleted to null
969                    */
970                    if (ar.exception == null && ar.userObj != null) {
971                        AsyncResult.forMessage(((Message) ar.userObj)).exception
972                                = null;
973                        ((Message) ar.userObj).sendToTarget();
974
975                        if (DBG) log("Callback with MBDN successful.");
976
977                        onCphsCompleted = null;
978                    }
979
980                    new AdnRecordLoader(phone).
981                            updateEF(adn, EF_MAILBOX_CPHS, EF_EXT1, 1, null,
982                            obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE,
983                                    onCphsCompleted));
984                } else {
985                    if (ar.userObj != null) {
986                        AsyncResult.forMessage(((Message) ar.userObj)).exception
987                                = ar.exception;
988                        ((Message) ar.userObj).sendToTarget();
989                    }
990                }
991                break;
992            case EVENT_SET_CPHS_MAILBOX_DONE:
993                isRecordLoadResponse = false;
994                ar = (AsyncResult)msg.obj;
995                if(ar.exception == null) {
996                    voiceMailNum = newVoiceMailNum;
997                    voiceMailTag = newVoiceMailTag;
998                } else {
999                    if (DBG) log("Set CPHS MailBox with exception: "
1000                            + ar.exception);
1001                }
1002                if (ar.userObj != null) {
1003                    if (DBG) log("Callback with CPHS MB successful.");
1004                    AsyncResult.forMessage(((Message) ar.userObj)).exception
1005                            = ar.exception;
1006                    ((Message) ar.userObj).sendToTarget();
1007                }
1008                break;
1009            case EVENT_SIM_REFRESH:
1010                isRecordLoadResponse = false;
1011                ar = (AsyncResult)msg.obj;
1012		if (DBG) log("Sim REFRESH with exception: " + ar.exception);
1013                if (ar.exception == null) {
1014                    handleSimRefresh((int[])(ar.result));
1015                }
1016                break;
1017            case EVENT_GET_CFIS_DONE:
1018                isRecordLoadResponse = true;
1019
1020                ar = (AsyncResult)msg.obj;
1021                data = (byte[])ar.result;
1022
1023                if (ar.exception != null) {
1024                    break;
1025                }
1026
1027                Log.d(LOG_TAG, "EF_CFIS: " +
1028                   IccUtils.bytesToHexString(data));
1029
1030                mEfCfis = data;
1031
1032                // Refer TS 51.011 Section 10.3.46 for the content description
1033                callForwardingEnabled = ((data[1] & 0x01) != 0);
1034
1035                ((GSMPhone) phone).notifyCallForwardingIndicator();
1036                break;
1037
1038        }}catch (RuntimeException exc) {
1039            // I don't want these exceptions to be fatal
1040            Log.w(LOG_TAG, "Exception parsing SIM record", exc);
1041        } finally {
1042            // Count up record load responses even if they are fails
1043            if (isRecordLoadResponse) {
1044                onRecordLoaded();
1045            }
1046        }
1047    }
1048
1049    private void handleFileUpdate(int efid) {
1050        switch(efid) {
1051            case EF_MBDN:
1052                recordsToLoad++;
1053                new AdnRecordLoader(phone).loadFromEF(EF_MBDN, EF_EXT6,
1054                        mailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
1055                break;
1056            case EF_MAILBOX_CPHS:
1057                recordsToLoad++;
1058                new AdnRecordLoader(phone).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1,
1059                        1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
1060                break;
1061            default:
1062                // For now, fetch all records if this is not a
1063                // voicemail number.
1064                // TODO: Handle other cases, instead of fetching all.
1065                adnCache.reset();
1066                fetchSimRecords();
1067                break;
1068        }
1069    }
1070
1071    private void handleSimRefresh(int[] result) {
1072        if (result == null || result.length == 0) {
1073	    if (DBG) log("handleSimRefresh without input");
1074            return;
1075        }
1076
1077        switch ((result[0])) {
1078            case CommandsInterface.SIM_REFRESH_FILE_UPDATED:
1079 		if (DBG) log("handleSimRefresh with SIM_REFRESH_FILE_UPDATED");
1080                // result[1] contains the EFID of the updated file.
1081                int efid = result[1];
1082                handleFileUpdate(efid);
1083                break;
1084            case CommandsInterface.SIM_REFRESH_INIT:
1085		if (DBG) log("handleSimRefresh with SIM_REFRESH_INIT");
1086                // need to reload all files (that we care about)
1087                adnCache.reset();
1088                fetchSimRecords();
1089                break;
1090            case CommandsInterface.SIM_REFRESH_RESET:
1091		if (DBG) log("handleSimRefresh with SIM_REFRESH_RESET");
1092                phone.mCM.setRadioPower(false, null);
1093                /* Note: no need to call setRadioPower(true).  Assuming the desired
1094                * radio power state is still ON (as tracked by ServiceStateTracker),
1095                * ServiceStateTracker will call setRadioPower when it receives the
1096                * RADIO_STATE_CHANGED notification for the power off.  And if the
1097                * desired power state has changed in the interim, we don't want to
1098                * override it with an unconditional power on.
1099                */
1100                break;
1101            default:
1102                // unknown refresh operation
1103		if (DBG) log("handleSimRefresh with unknown operation");
1104                break;
1105        }
1106    }
1107
1108    private void handleSms(byte[] ba) {
1109        if (ba[0] != 0)
1110            Log.d("ENF", "status : " + ba[0]);
1111
1112        // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
1113        // 3 == "received by MS from network; message to be read"
1114        if (ba[0] == 3) {
1115            int n = ba.length;
1116
1117            // Note: Data may include trailing FF's.  That's OK; message
1118            // should still parse correctly.
1119            byte[] pdu = new byte[n - 1];
1120            System.arraycopy(ba, 1, pdu, 0, n - 1);
1121            SmsMessage message = SmsMessage.createFromPdu(pdu);
1122
1123            ((GSMPhone) phone).mSMS.dispatchMessage(message);
1124        }
1125    }
1126
1127
1128    private void handleSmses(ArrayList messages) {
1129        int count = messages.size();
1130
1131        for (int i = 0; i < count; i++) {
1132            byte[] ba = (byte[]) messages.get(i);
1133
1134            if (ba[0] != 0)
1135                Log.i("ENF", "status " + i + ": " + ba[0]);
1136
1137            // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
1138            // 3 == "received by MS from network; message to be read"
1139
1140            if (ba[0] == 3) {
1141                int n = ba.length;
1142
1143                // Note: Data may include trailing FF's.  That's OK; message
1144                // should still parse correctly.
1145                byte[] pdu = new byte[n - 1];
1146                System.arraycopy(ba, 1, pdu, 0, n - 1);
1147                SmsMessage message = SmsMessage.createFromPdu(pdu);
1148
1149                ((GSMPhone) phone).mSMS.dispatchMessage(message);
1150
1151                // 3GPP TS 51.011 v5.0.0 (20011-12)  10.5.3
1152                // 1 == "received by MS from network; message read"
1153
1154                ba[0] = 1;
1155
1156                if (false) { // XXX writing seems to crash RdoServD
1157                    phone.getIccFileHandler().updateEFLinearFixed(EF_SMS,
1158                            i, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, i));
1159                }
1160            }
1161        }
1162    }
1163
1164    protected void onRecordLoaded() {
1165        // One record loaded successfully or failed, In either case
1166        // we need to update the recordsToLoad count
1167        recordsToLoad -= 1;
1168
1169        if (recordsToLoad == 0 && recordsRequested == true) {
1170            onAllRecordsLoaded();
1171        } else if (recordsToLoad < 0) {
1172            Log.e(LOG_TAG, "SIMRecords: recordsToLoad <0, programmer error suspected");
1173            recordsToLoad = 0;
1174        }
1175    }
1176
1177    protected void onAllRecordsLoaded() {
1178        Log.d(LOG_TAG, "SIMRecords: record load complete");
1179
1180        String operator = getSIMOperatorNumeric();
1181
1182        // Some fields require more than one SIM record to set
1183
1184        phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, operator);
1185
1186        if (imsi != null) {
1187            phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY,
1188                    MccTable.countryCodeForMcc(Integer.parseInt(imsi.substring(0,3))));
1189        }
1190        else {
1191            Log.e("SIM", "[SIMRecords] onAllRecordsLoaded: imsi is NULL!");
1192        }
1193
1194        setVoiceMailByCountry(operator);
1195        setSpnFromConfig(operator);
1196
1197        recordsLoadedRegistrants.notifyRegistrants(
1198            new AsyncResult(null, null, null));
1199        ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
1200                SimCard.INTENT_VALUE_ICC_LOADED, null);
1201    }
1202
1203    //***** Private methods
1204
1205    private void setSpnFromConfig(String carrier) {
1206        if (mSpnOverride.containsCarrier(carrier)) {
1207            spn = mSpnOverride.getSpn(carrier);
1208        }
1209    }
1210
1211
1212    private void setVoiceMailByCountry (String spn) {
1213        if (mVmConfig.containsCarrier(spn)) {
1214            isVoiceMailFixed = true;
1215            voiceMailNum = mVmConfig.getVoiceMailNumber(spn);
1216            voiceMailTag = mVmConfig.getVoiceMailTag(spn);
1217        }
1218    }
1219
1220    private void onSimReady() {
1221        /* broadcast intent SIM_READY here so that we can make sure
1222          READY is sent before IMSI ready
1223        */
1224        ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
1225                SimCard.INTENT_VALUE_ICC_READY, null);
1226
1227        fetchSimRecords();
1228    }
1229
1230    private void fetchSimRecords() {
1231        recordsRequested = true;
1232        IccFileHandler iccFh = phone.getIccFileHandler();
1233
1234        Log.v(LOG_TAG, "SIMRecords:fetchSimRecords " + recordsToLoad);
1235
1236        phone.mCM.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE));
1237        recordsToLoad++;
1238
1239        iccFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
1240        recordsToLoad++;
1241
1242        // FIXME should examine EF[MSISDN]'s capability configuration
1243        // to determine which is the voice/data/fax line
1244        new AdnRecordLoader(phone).loadFromEF(EF_MSISDN, EF_EXT1, 1,
1245                    obtainMessage(EVENT_GET_MSISDN_DONE));
1246        recordsToLoad++;
1247
1248        // Record number is subscriber profile
1249        iccFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));
1250        recordsToLoad++;
1251
1252        iccFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
1253        recordsToLoad++;
1254
1255        // Record number is subscriber profile
1256        iccFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE));
1257        recordsToLoad++;
1258
1259
1260        // Also load CPHS-style voice mail indicator, which stores
1261        // the same info as EF[MWIS]. If both exist, both are updated
1262        // but the EF[MWIS] data is preferred
1263        // Please note this must be loaded after EF[MWIS]
1264        iccFh.loadEFTransparent(
1265                EF_VOICE_MAIL_INDICATOR_CPHS,
1266                obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE));
1267        recordsToLoad++;
1268
1269        // Same goes for Call Forward Status indicator: fetch both
1270        // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred.
1271        iccFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE));
1272        recordsToLoad++;
1273        iccFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE));
1274        recordsToLoad++;
1275
1276
1277        getSpnFsm(true, null);
1278
1279        iccFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));
1280        recordsToLoad++;
1281
1282        iccFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE));
1283        recordsToLoad++;
1284
1285        iccFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));
1286        recordsToLoad++;
1287
1288        iccFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));
1289        recordsToLoad++;
1290
1291        // XXX should seek instead of examining them all
1292        if (false) { // XXX
1293            iccFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));
1294            recordsToLoad++;
1295        }
1296
1297        if (CRASH_RIL) {
1298            String sms = "0107912160130310f20404d0110041007030208054832b0120"
1299                         + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1300                         + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1301                         + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1302                         + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1303                         + "ffffffffffffffffffffffffffffff";
1304            byte[] ba = IccUtils.hexStringToBytes(sms);
1305
1306            iccFh.updateEFLinearFixed(EF_SMS, 1, ba, null,
1307                            obtainMessage(EVENT_MARK_SMS_READ_DONE, 1));
1308        }
1309    }
1310
1311    /**
1312     * Returns the SpnDisplayRule based on settings on the SIM and the
1313     * specified plmn (currently-registered PLMN).  See TS 22.101 Annex A
1314     * and TS 51.011 10.3.11 for details.
1315     *
1316     * If the SPN is not found on the SIM, the rule is always PLMN_ONLY.
1317     */
1318    protected int getDisplayRule(String plmn) {
1319        int rule;
1320        if (spn == null || spnDisplayCondition == -1) {
1321            // EF_SPN was not found on the SIM, or not yet loaded.  Just show ONS.
1322            rule = SPN_RULE_SHOW_PLMN;
1323        } else if (isOnMatchingPlmn(plmn)) {
1324            rule = SPN_RULE_SHOW_SPN;
1325            if ((spnDisplayCondition & 0x01) == 0x01) {
1326                // ONS required when registered to HPLMN or PLMN in EF_SPDI
1327                rule |= SPN_RULE_SHOW_PLMN;
1328            }
1329        } else {
1330            rule = SPN_RULE_SHOW_PLMN;
1331            if ((spnDisplayCondition & 0x02) == 0x00) {
1332                // SPN required if not registered to HPLMN or PLMN in EF_SPDI
1333                rule |= SPN_RULE_SHOW_SPN;
1334            }
1335        }
1336        return rule;
1337    }
1338
1339    /**
1340     * Checks if plmn is HPLMN or on the spdiNetworks list.
1341     */
1342    private boolean isOnMatchingPlmn(String plmn) {
1343        if (plmn == null) return false;
1344
1345        if (plmn.equals(getSIMOperatorNumeric())) {
1346            return true;
1347        }
1348
1349        if (spdiNetworks != null) {
1350            for (String spdiNet : spdiNetworks) {
1351                if (plmn.equals(spdiNet)) {
1352                    return true;
1353                }
1354            }
1355        }
1356        return false;
1357    }
1358
1359    /**
1360     * States of Get SPN Finite State Machine which only used by getSpnFsm()
1361     */
1362    private enum Get_Spn_Fsm_State {
1363        IDLE,               // No initialized
1364        INIT,               // Start FSM
1365        READ_SPN_3GPP,      // Load EF_SPN firstly
1366        READ_SPN_CPHS,      // Load EF_SPN_CPHS secondly
1367        READ_SPN_SHORT_CPHS // Load EF_SPN_SHORT_CPHS last
1368    }
1369
1370    /**
1371     * Finite State Machine to load Service Provider Name , which can be stored
1372     * in either EF_SPN (3GPP), EF_SPN_CPHS, or EF_SPN_SHORT_CPHS (CPHS4.2)
1373     *
1374     * After starting, FSM will search SPN EFs in order and stop after finding
1375     * the first valid SPN
1376     *
1377     * @param start set true only for initialize loading
1378     * @param ar the AsyncResult from loadEFTransparent
1379     *        ar.exception holds exception in error
1380     *        ar.result is byte[] for data in success
1381     */
1382    private void getSpnFsm(boolean start, AsyncResult ar) {
1383        byte[] data;
1384
1385        if (start) {
1386            spnState = Get_Spn_Fsm_State.INIT;
1387        }
1388
1389        switch(spnState){
1390            case INIT:
1391                spn = null;
1392
1393                phone.getIccFileHandler().loadEFTransparent( EF_SPN,
1394                        obtainMessage(EVENT_GET_SPN_DONE));
1395                recordsToLoad++;
1396
1397                spnState = Get_Spn_Fsm_State.READ_SPN_3GPP;
1398                break;
1399            case READ_SPN_3GPP:
1400                if (ar != null && ar.exception == null) {
1401                    data = (byte[]) ar.result;
1402                    spnDisplayCondition = 0xff & data[0];
1403                    spn = IccUtils.adnStringFieldToString(data, 1, data.length - 1);
1404
1405                    if (DBG) log("Load EF_SPN: " + spn
1406                            + " spnDisplayCondition: " + spnDisplayCondition);
1407                    phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn);
1408
1409                    spnState = Get_Spn_Fsm_State.IDLE;
1410                } else {
1411                    phone.getIccFileHandler().loadEFTransparent( EF_SPN_CPHS,
1412                            obtainMessage(EVENT_GET_SPN_DONE));
1413                    recordsToLoad++;
1414
1415                    spnState = Get_Spn_Fsm_State.READ_SPN_CPHS;
1416
1417                    // See TS 51.011 10.3.11.  Basically, default to
1418                    // show PLMN always, and SPN also if roaming.
1419                    spnDisplayCondition = -1;
1420                }
1421                break;
1422            case READ_SPN_CPHS:
1423                if (ar != null && ar.exception == null) {
1424                    data = (byte[]) ar.result;
1425                    spn = IccUtils.adnStringFieldToString(
1426                            data, 0, data.length - 1 );
1427
1428                    if (DBG) log("Load EF_SPN_CPHS: " + spn);
1429                    phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn);
1430
1431                    spnState = Get_Spn_Fsm_State.IDLE;
1432                } else {
1433                    phone.getIccFileHandler().loadEFTransparent(
1434                            EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE));
1435                    recordsToLoad++;
1436
1437                    spnState = Get_Spn_Fsm_State.READ_SPN_SHORT_CPHS;
1438                }
1439                break;
1440            case READ_SPN_SHORT_CPHS:
1441                if (ar != null && ar.exception == null) {
1442                    data = (byte[]) ar.result;
1443                    spn = IccUtils.adnStringFieldToString(
1444                            data, 0, data.length - 1);
1445
1446                    if (DBG) log("Load EF_SPN_SHORT_CPHS: " + spn);
1447                    phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn);
1448                }else {
1449                    if (DBG) log("No SPN loaded in either CHPS or 3GPP");
1450                }
1451
1452                spnState = Get_Spn_Fsm_State.IDLE;
1453                break;
1454            default:
1455                spnState = Get_Spn_Fsm_State.IDLE;
1456        }
1457    }
1458
1459    /**
1460     * Parse TS 51.011 EF[SPDI] record
1461     * This record contains the list of numeric network IDs that
1462     * are treated specially when determining SPN display
1463     */
1464    private void
1465    parseEfSpdi(byte[] data) {
1466        SimTlv tlv = new SimTlv(data, 0, data.length);
1467
1468        byte[] plmnEntries = null;
1469
1470        // There should only be one TAG_SPDI_PLMN_LIST
1471        for ( ; tlv.isValidObject() ; tlv.nextObject()) {
1472            if (tlv.getTag() == TAG_SPDI_PLMN_LIST) {
1473                plmnEntries = tlv.getData();
1474                break;
1475            }
1476        }
1477
1478        if (plmnEntries == null) {
1479            return;
1480        }
1481
1482        spdiNetworks = new ArrayList<String>(plmnEntries.length / 3);
1483
1484        for (int i = 0 ; i + 2 < plmnEntries.length ; i += 3) {
1485            String plmnCode;
1486            plmnCode = IccUtils.bcdToString(plmnEntries, i, 3);
1487
1488            // Valid operator codes are 5 or 6 digits
1489            if (plmnCode.length() >= 5) {
1490                log("EF_SPDI network: " + plmnCode);
1491                spdiNetworks.add(plmnCode);
1492            }
1493        }
1494    }
1495
1496    /**
1497     * check to see if Mailbox Number is allocated and activated in CPHS SST
1498     */
1499    private boolean isCphsMailboxEnabled() {
1500        if (mCphsInfo == null)  return false;
1501        return ((mCphsInfo[1] & CPHS_SST_MBN_MASK) == CPHS_SST_MBN_ENABLED );
1502    }
1503
1504    protected void log(String s) {
1505        Log.d(LOG_TAG, "[SIMRecords] " + s);
1506    }
1507
1508}
1509