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