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