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