1c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville/* 2c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Copyright (C) 2006 The Android Open Source Project 3c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 4c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Licensed under the Apache License, Version 2.0 (the "License"); 5c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * you may not use this file except in compliance with the License. 6c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * You may obtain a copy of the License at 7c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 8c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * http://www.apache.org/licenses/LICENSE-2.0 9c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 10c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Unless required by applicable law or agreed to in writing, software 11c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * distributed under the License is distributed on an "AS IS" BASIS, 12c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * See the License for the specific language governing permissions and 14c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * limitations under the License. 15c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 16c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 17c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savillepackage com.android.internal.telephony; 18c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 19c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.content.Context; 20c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.os.AsyncResult; 21c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.os.Handler; 22c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.os.Message; 23c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.os.Registrant; 24c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.os.RegistrantList; 25c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 26c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.gsm.UsimServiceTable; 27c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.ims.IsimRecords; 28c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 29bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenkaimport java.util.concurrent.atomic.AtomicBoolean; 30bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka 31c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville/** 32c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * {@hide} 33c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 34c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savillepublic abstract class IccRecords extends Handler implements IccConstants { 35c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 36c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected static final boolean DBG = true; 37c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // ***** Instance Variables 38bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka protected AtomicBoolean mDestroyed = new AtomicBoolean(false); 39c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected Context mContext; 40c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected CommandsInterface mCi; 41c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected IccFileHandler mFh; 42e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka protected UiccCardApplication mParentApp; 43c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 44c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected RegistrantList recordsLoadedRegistrants = new RegistrantList(); 45e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka protected RegistrantList mImsiReadyRegistrants = new RegistrantList(); 46c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected RegistrantList mRecordsEventsRegistrants = new RegistrantList(); 47c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected RegistrantList mNewSmsRegistrants = new RegistrantList(); 48c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected RegistrantList mNetworkSelectionModeAutomaticRegistrants = new RegistrantList(); 49c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 50c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected int recordsToLoad; // number of pending load requests 51c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 52c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected AdnRecordCache adnCache; 53c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 54c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // ***** Cached SIM State; cleared on channel close 55c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 56c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected boolean recordsRequested = false; // true if we've made requests for the sim records 57c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 58c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public String iccid; 59c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected String msisdn = null; // My mobile number 60c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected String msisdnTag = null; 61c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected String voiceMailNum = null; 62c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected String voiceMailTag = null; 63c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected String newVoiceMailNum = null; 64c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected String newVoiceMailTag = null; 65c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected boolean isVoiceMailFixed = false; 66c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected int countVoiceMessages = 0; 67e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka protected String mImsi; 68c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 69c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected int mncLength = UNINITIALIZED; 70c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected int mailboxIndex = 0; // 0 is no mailbox dailing number associated 71c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 72c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected String spn; 73c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 74c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // ***** Constants 75c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 76c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Markers for mncLength 77c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected static final int UNINITIALIZED = -1; 78c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected static final int UNKNOWN = 0; 79c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 80c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Bitmasks for SPN display rules. 81c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected static final int SPN_RULE_SHOW_SPN = 0x01; 82c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected static final int SPN_RULE_SHOW_PLMN = 0x02; 83c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 84c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // ***** Event Constants 85c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected static final int EVENT_SET_MSISDN_DONE = 30; 86bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka public static final int EVENT_MWI = 0; // Message Waiting indication 87bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka public static final int EVENT_CFI = 1; // Call Forwarding indication 88bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka public static final int EVENT_SPN = 2; // Service Provider Name 89c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 90c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public static final int EVENT_GET_ICC_RECORD_DONE = 100; 91c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 92c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 93c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Generic ICC record loaded callback. Subclasses can call EF load methods on 94c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * {@link IccFileHandler} passing a Message for onLoaded with the what field set to 95c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * {@link #EVENT_GET_ICC_RECORD_DONE} and the obj field set to an instance 96c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * of this interface. The {@link #handleMessage} method in this class will print a 97c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * log message using {@link #getEfName()} and decrement {@link #recordsToLoad}. 98c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 99c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * If the record load was successful, {@link #onRecordLoaded} will be called with the result. 100c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Otherwise, an error log message will be output by {@link #handleMessage} and 101c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * {@link #onRecordLoaded} will not be called. 102c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 103c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public interface IccRecordLoaded { 104c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String getEfName(); 105c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville void onRecordLoaded(AsyncResult ar); 106c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 107c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 108c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // ***** Constructor 109e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka public IccRecords(UiccCardApplication app, Context c, CommandsInterface ci) { 110c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mContext = c; 111c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mCi = ci; 112e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka mFh = app.getIccFileHandler(); 113e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka mParentApp = app; 114c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 115c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 116c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 117c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Call when the IccRecords object is no longer going to be used. 118c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 119c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public void dispose() { 120bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka mDestroyed.set(true); 121e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka mParentApp = null; 122c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mFh = null; 123c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mCi = null; 124c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mContext = null; 125c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 126c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 127c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public abstract void onReady(); 128c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 129c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville //***** Public Methods 130c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public AdnRecordCache getAdnCache() { 131c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return adnCache; 132c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 133c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 134c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public void registerForRecordsLoaded(Handler h, int what, Object obj) { 135bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka if (mDestroyed.get()) { 136c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return; 137c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 138c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 139c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Registrant r = new Registrant(h, what, obj); 140c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville recordsLoadedRegistrants.add(r); 141c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 142c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (recordsToLoad == 0 && recordsRequested == true) { 143c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville r.notifyRegistrant(new AsyncResult(null, null, null)); 144c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 145c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 146c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public void unregisterForRecordsLoaded(Handler h) { 147c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville recordsLoadedRegistrants.remove(h); 148c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 149c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 150e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka public void registerForImsiReady(Handler h, int what, Object obj) { 151e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka if (mDestroyed.get()) { 152e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka return; 153e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka } 154e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka 155e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka Registrant r = new Registrant(h, what, obj); 156e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka mImsiReadyRegistrants.add(r); 157e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka 158e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka if (mImsi != null) { 159e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka r.notifyRegistrant(new AsyncResult(null, null, null)); 160e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka } 161e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka } 162e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka public void unregisterForImsiReady(Handler h) { 163e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka mImsiReadyRegistrants.remove(h); 164e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka } 165e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka 166c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public void registerForRecordsEvents(Handler h, int what, Object obj) { 167c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Registrant r = new Registrant (h, what, obj); 168c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mRecordsEventsRegistrants.add(r); 169c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 170c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public void unregisterForRecordsEvents(Handler h) { 171c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mRecordsEventsRegistrants.remove(h); 172c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 173c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 174c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public void registerForNewSms(Handler h, int what, Object obj) { 175c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Registrant r = new Registrant (h, what, obj); 176c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mNewSmsRegistrants.add(r); 177c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 178c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public void unregisterForNewSms(Handler h) { 179c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mNewSmsRegistrants.remove(h); 180c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 181c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 182c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public void registerForNetworkSelectionModeAutomatic( 183c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Handler h, int what, Object obj) { 184c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Registrant r = new Registrant (h, what, obj); 185c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mNetworkSelectionModeAutomaticRegistrants.add(r); 186c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 187c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public void unregisterForNetworkSelectionModeAutomatic(Handler h) { 188c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mNetworkSelectionModeAutomaticRegistrants.remove(h); 189c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 190c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 191c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 192c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Get the International Mobile Subscriber ID (IMSI) on a SIM 193c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * for GSM, UMTS and like networks. Default is null if IMSI is 194c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * not supported or unavailable. 195c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 196c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return null if SIM is not yet ready or unavailable 197c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 198c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public String getIMSI() { 199c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 200c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 201c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 202e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka /** 203e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka * Imsi could be set by ServiceStateTrackers in case of cdma 204e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka * @param imsi 205e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka */ 206e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka public void setImsi(String imsi) { 207e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka this.mImsi = imsi; 208e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka mImsiReadyRegistrants.notifyRegistrants(); 209e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka } 210e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka 211c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public String getMsisdnNumber() { 212c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return msisdn; 213c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 214c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 215c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 216c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Set subscriber number to SIM record 217c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 218c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * The subscriber number is stored in EF_MSISDN (TS 51.011) 219c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 220c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * When the operation is complete, onComplete will be sent to its handler 221c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 222c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters) 223c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param number dailing nubmer (up to 20 digits) 224c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * if the number starts with '+', then set to international TOA 225c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param onComplete 226c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * onComplete.obj will be an AsyncResult 227c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * ((AsyncResult)onComplete.obj).exception == null on success 228c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * ((AsyncResult)onComplete.obj).exception != null on fail 229c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 230c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public void setMsisdnNumber(String alphaTag, String number, 231c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Message onComplete) { 232c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 233c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville msisdn = number; 234c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville msisdnTag = alphaTag; 235c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 236c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if(DBG) log("Set MSISDN: " + msisdnTag +" " + msisdn); 237c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 238c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 239c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville AdnRecord adn = new AdnRecord(msisdnTag, msisdn); 240c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 241c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville new AdnRecordLoader(mFh).updateEF(adn, EF_MSISDN, EF_EXT1, 1, null, 242c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville obtainMessage(EVENT_SET_MSISDN_DONE, onComplete)); 243c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 244c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 245c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public String getMsisdnAlphaTag() { 246c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return msisdnTag; 247c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 248c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 249c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public String getVoiceMailNumber() { 250c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return voiceMailNum; 251c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 252c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 253c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 254c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Return Service Provider Name stored in SIM (EF_SPN=0x6F46) or in RUIM (EF_RUIM_SPN=0x6F41) 255c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return null if SIM is not yet ready or no RUIM entry 256c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 257c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public String getServiceProviderName() { 258c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return spn; 259c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 260c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 261c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 262c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Set voice mail number to SIM record 263c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 264c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * The voice mail number can be stored either in EF_MBDN (TS 51.011) or 265c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * EF_MAILBOX_CPHS (CPHS 4.2) 266c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 267c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * If EF_MBDN is available, store the voice mail number to EF_MBDN 268c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 269c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS 270c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 271c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * So the voice mail number will be stored in both EFs if both are available 272c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 273c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Return error only if both EF_MBDN and EF_MAILBOX_CPHS fail. 274c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 275c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * When the operation is complete, onComplete will be sent to its handler 276c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 277c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param alphaTag alpha-tagging of the dailing nubmer (upto 10 characters) 278c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param voiceNumber dailing nubmer (upto 20 digits) 279c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * if the number is start with '+', then set to international TOA 280c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param onComplete 281c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * onComplete.obj will be an AsyncResult 282c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * ((AsyncResult)onComplete.obj).exception == null on success 283c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * ((AsyncResult)onComplete.obj).exception != null on fail 284c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 285c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public abstract void setVoiceMailNumber(String alphaTag, String voiceNumber, 286c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Message onComplete); 287c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 288c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public String getVoiceMailAlphaTag() { 289c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return voiceMailTag; 290c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 291c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 292c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 293c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Sets the SIM voice message waiting indicator records 294c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported 295c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param countWaiting The number of messages waiting, if known. Use 296c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * -1 to indicate that an unknown number of 297c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * messages are waiting 298c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 299c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public abstract void setVoiceMessageWaiting(int line, int countWaiting); 300c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 301c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** @return true if there are messages waiting, false otherwise. */ 302c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean getVoiceMessageWaiting() { 303c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return countVoiceMessages != 0; 304c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 305c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 306c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 307c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns number of voice messages waiting, if available 308c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * If not available (eg, on an older CPHS SIM) -1 is returned if 309c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * getVoiceMessageWaiting() is true 310c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 311c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public int getVoiceMessageCount() { 312c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return countVoiceMessages; 313c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 314c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 315c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 316c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Called by STK Service when REFRESH is received. 317c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param fileChanged indicates whether any files changed 318c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param fileList if non-null, a list of EF files that changed 319c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 320c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public abstract void onRefresh(boolean fileChanged, int[] fileList); 321c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 322c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 323c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean getRecordsLoaded() { 324c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (recordsToLoad == 0 && recordsRequested == true) { 325c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return true; 326c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 327c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return false; 328c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 329c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 330c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 331c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville //***** Overridden from Handler 332c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 333c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public void handleMessage(Message msg) { 334c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville switch (msg.what) { 335c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case EVENT_GET_ICC_RECORD_DONE: 336c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 337c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville AsyncResult ar = (AsyncResult) msg.obj; 338c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville IccRecordLoaded recordLoaded = (IccRecordLoaded) ar.userObj; 339c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (DBG) log(recordLoaded.getEfName() + " LOADED"); 340c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 341c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (ar.exception != null) { 342c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville loge("Record Load Exception: " + ar.exception); 343c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 344c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville recordLoaded.onRecordLoaded(ar); 345c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 346c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville }catch (RuntimeException exc) { 347c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // I don't want these exceptions to be fatal 348c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville loge("Exception parsing SIM record: " + exc); 349c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } finally { 350c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Count up record load responses even if they are fails 351c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville onRecordLoaded(); 352c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 353c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 354c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 355c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville default: 356c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville super.handleMessage(msg); 357c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 358c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 359c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 360c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected abstract void onRecordLoaded(); 361c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 362c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected abstract void onAllRecordsLoaded(); 363c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 364c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 365c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns the SpnDisplayRule based on settings on the SIM and the 366c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * specified plmn (currently-registered PLMN). See TS 22.101 Annex A 367c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * and TS 51.011 10.3.11 for details. 368c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 369c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * If the SPN is not found on the SIM, the rule is always PLMN_ONLY. 370c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Generally used for GSM/UMTS and the like SIMs. 371c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 372c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public abstract int getDisplayRule(String plmn); 373c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 374c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 375c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Return true if "Restriction of menu options for manual PLMN selection" 376c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * bit is set or EF_CSP data is unavailable, return false otherwise. 377c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Generally used for GSM/UMTS and the like SIMs. 378c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 379c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isCspPlmnEnabled() { 380c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return false; 381c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 382c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 383c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 384c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Returns the 5 or 6 digit MCC/MNC of the operator that 385c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * provided the SIM card. Returns null of SIM is not yet ready 386c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * or is not valid for the type of IccCard. Generally used for 387c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * GSM/UMTS and the like SIMS 388c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 389c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public String getOperatorNumeric() { 390c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 391c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 392c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 393c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 394c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Get the current Voice call forwarding flag for GSM/UMTS and the like SIMs 395c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 396c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return true if enabled 397c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 398c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean getVoiceCallForwardingFlag() { 399c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return false; 400c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 401c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 402c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 403c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Set the voice call forwarding flag for GSM/UMTS and the like SIMs 404c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 405c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param line to enable/disable 406c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param enable 407c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 408c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public void setVoiceCallForwardingFlag(int line, boolean enable) { 409c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 410c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 411c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 412c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Indicates wether SIM is in provisioned state or not. 413c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Overridden only if SIM can be dynamically provisioned via OTA. 414c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 415c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return true if provisioned 416c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 417c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean isProvisioned () { 418c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return true; 419c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 420c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 421c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 422c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Write string to log file 423c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 424c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param s is the string to write 425c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 426c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected abstract void log(String s); 427c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 428c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 429c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Write error string to log file. 430c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 431c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param s is the string to write 432c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 433c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected abstract void loge(String s); 434c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 435c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 436c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Return an interface to retrieve the ISIM records for IMS, if available. 437c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return the interface to retrieve the ISIM records, or null if not supported 438c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 439c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public IsimRecords getIsimRecords() { 440c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 441c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 442c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 443c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public UsimServiceTable getUsimServiceTable() { 444c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return null; 445c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 446c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville} 447