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