Revert "Telephony: Voice mail notification related changes"
[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 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
28
29 import java.io.FileDescriptor;
30 import java.io.PrintWriter;
31 import java.util.concurrent.atomic.AtomicBoolean;
32
33 /**
34  * {@hide}
35  */
36 public abstract class IccRecords extends Handler implements IccConstants {
37     protected static final boolean DBG = true;
38
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 mRecordsLoadedRegistrants = 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 mRecordsToLoad;  // number of pending load requests
53
54     protected AdnRecordCache mAdnCache;
55
56     // ***** Cached SIM State; cleared on channel close
57
58     protected boolean mRecordsRequested = false; // true if we've made requests for the sim records
59
60     protected String mIccId;
61     protected String mMsisdn = null;  // My mobile number
62     protected String mMsisdnTag = null;
63     protected String mVoiceMailNum = null;
64     protected String mVoiceMailTag = null;
65     protected String mNewVoiceMailNum = null;
66     protected String mNewVoiceMailTag = null;
67     protected boolean mIsVoiceMailFixed = false;
68     protected int mCountVoiceMessages = 0;
69     protected String mImsi;
70     private IccIoResult auth_rsp;
71
72     protected int mMncLength = UNINITIALIZED;
73     protected int mMailboxIndex = 0; // 0 is no mailbox dailing number associated
74
75     private String mSpn;
76
77     protected String mGid1;
78
79     private final Object mLock = new Object();
80
81     // ***** Constants
82
83     // Markers for mncLength
84     protected static final int UNINITIALIZED = -1;
85     protected static final int UNKNOWN = 0;
86
87     // Bitmasks for SPN display rules.
88     public static final int SPN_RULE_SHOW_SPN  = 0x01;
89     public static final int SPN_RULE_SHOW_PLMN = 0x02;
90
91     // ***** Event Constants
92     protected static final int EVENT_SET_MSISDN_DONE = 30;
93     public static final int EVENT_MWI = 0; // Message Waiting indication
94     public static final int EVENT_CFI = 1; // Call Forwarding indication
95     public static final int EVENT_SPN = 2; // Service Provider Name
96
97     public static final int EVENT_GET_ICC_RECORD_DONE = 100;
98     protected static final int EVENT_APP_READY = 1;
99     private static final int EVENT_AKA_AUTHENTICATE_DONE          = 90;
100
101     @Override
102     public String toString() {
103         return "mDestroyed=" + mDestroyed
104                 + " mContext=" + mContext
105                 + " mCi=" + mCi
106                 + " mFh=" + mFh
107                 + " mParentApp=" + mParentApp
108                 + " recordsLoadedRegistrants=" + mRecordsLoadedRegistrants
109                 + " mImsiReadyRegistrants=" + mImsiReadyRegistrants
110                 + " mRecordsEventsRegistrants=" + mRecordsEventsRegistrants
111                 + " mNewSmsRegistrants=" + mNewSmsRegistrants
112                 + " mNetworkSelectionModeAutomaticRegistrants="
113                         + mNetworkSelectionModeAutomaticRegistrants
114                 + " recordsToLoad=" + mRecordsToLoad
115                 + " adnCache=" + mAdnCache
116                 + " recordsRequested=" + mRecordsRequested
117                 + " iccid=" + mIccId
118                 + " msisdn=" + mMsisdn
119                 + " msisdnTag=" + mMsisdnTag
120                 + " voiceMailNum=" + mVoiceMailNum
121                 + " voiceMailTag=" + mVoiceMailTag
122                 + " newVoiceMailNum=" + mNewVoiceMailNum
123                 + " newVoiceMailTag=" + mNewVoiceMailTag
124                 + " isVoiceMailFixed=" + mIsVoiceMailFixed
125                 + " countVoiceMessages=" + mCountVoiceMessages
126                 + " mImsi=" + mImsi
127                 + " mncLength=" + mMncLength
128                 + " mailboxIndex=" + mMailboxIndex
129                 + " spn=" + mSpn;
130
131     }
132
133     /**
134      * Generic ICC record loaded callback. Subclasses can call EF load methods on
135      * {@link IccFileHandler} passing a Message for onLoaded with the what field set to
136      * {@link #EVENT_GET_ICC_RECORD_DONE} and the obj field set to an instance
137      * of this interface. The {@link #handleMessage} method in this class will print a
138      * log message using {@link #getEfName()} and decrement {@link #mRecordsToLoad}.
139      *
140      * If the record load was successful, {@link #onRecordLoaded} will be called with the result.
141      * Otherwise, an error log message will be output by {@link #handleMessage} and
142      * {@link #onRecordLoaded} will not be called.
143      */
144     public interface IccRecordLoaded {
145         String getEfName();
146         void onRecordLoaded(AsyncResult ar);
147     }
148
149     // ***** Constructor
150     public IccRecords(UiccCardApplication app, Context c, CommandsInterface ci) {
151         mContext = c;
152         mCi = ci;
153         mFh = app.getIccFileHandler();
154         mParentApp = app;
155     }
156
157     /**
158      * Call when the IccRecords object is no longer going to be used.
159      */
160     public void dispose() {
161         mDestroyed.set(true);
162         mParentApp = null;
163         mFh = null;
164         mCi = null;
165         mContext = null;
166     }
167
168     public abstract void onReady();
169
170     //***** Public Methods
171     public AdnRecordCache getAdnCache() {
172         return mAdnCache;
173     }
174
175     public String getIccId() {
176         return mIccId;
177     }
178
179     public void registerForRecordsLoaded(Handler h, int what, Object obj) {
180         if (mDestroyed.get()) {
181             return;
182         }
183
184         Registrant r = new Registrant(h, what, obj);
185         mRecordsLoadedRegistrants.add(r);
186
187         if (mRecordsToLoad == 0 && mRecordsRequested == true) {
188             r.notifyRegistrant(new AsyncResult(null, null, null));
189         }
190     }
191     public void unregisterForRecordsLoaded(Handler h) {
192         mRecordsLoadedRegistrants.remove(h);
193     }
194
195     public void registerForImsiReady(Handler h, int what, Object obj) {
196         if (mDestroyed.get()) {
197             return;
198         }
199
200         Registrant r = new Registrant(h, what, obj);
201         mImsiReadyRegistrants.add(r);
202
203         if (mImsi != null) {
204             r.notifyRegistrant(new AsyncResult(null, null, null));
205         }
206     }
207     public void unregisterForImsiReady(Handler h) {
208         mImsiReadyRegistrants.remove(h);
209     }
210
211     public void registerForRecordsEvents(Handler h, int what, Object obj) {
212         Registrant r = new Registrant (h, what, obj);
213         mRecordsEventsRegistrants.add(r);
214
215         /* Notify registrant of all the possible events. This is to make sure registrant is
216         notified even if event occurred in the past. */
217         r.notifyResult(EVENT_MWI);
218         r.notifyResult(EVENT_CFI);
219     }
220     public void unregisterForRecordsEvents(Handler h) {
221         mRecordsEventsRegistrants.remove(h);
222     }
223
224     public void registerForNewSms(Handler h, int what, Object obj) {
225         Registrant r = new Registrant (h, what, obj);
226         mNewSmsRegistrants.add(r);
227     }
228     public void unregisterForNewSms(Handler h) {
229         mNewSmsRegistrants.remove(h);
230     }
231
232     public void registerForNetworkSelectionModeAutomatic(
233             Handler h, int what, Object obj) {
234         Registrant r = new Registrant (h, what, obj);
235         mNetworkSelectionModeAutomaticRegistrants.add(r);
236     }
237     public void unregisterForNetworkSelectionModeAutomatic(Handler h) {
238         mNetworkSelectionModeAutomaticRegistrants.remove(h);
239     }
240
241     /**
242      * Get the International Mobile Subscriber ID (IMSI) on a SIM
243      * for GSM, UMTS and like networks. Default is null if IMSI is
244      * not supported or unavailable.
245      *
246      * @return null if SIM is not yet ready or unavailable
247      */
248     public String getIMSI() {
249         return null;
250     }
251
252     /**
253      * Imsi could be set by ServiceStateTrackers in case of cdma
254      * @param imsi
255      */
256     public void setImsi(String imsi) {
257         mImsi = imsi;
258         mImsiReadyRegistrants.notifyRegistrants();
259     }
260
261     public String getMsisdnNumber() {
262         return mMsisdn;
263     }
264
265     /**
266      * Get the Group Identifier Level 1 (GID1) on a SIM for GSM.
267      * @return null if SIM is not yet ready
268      */
269     public String getGid1() {
270         return null;
271     }
272
273     /**
274      * Set subscriber number to SIM record
275      *
276      * The subscriber number is stored in EF_MSISDN (TS 51.011)
277      *
278      * When the operation is complete, onComplete will be sent to its handler
279      *
280      * @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters)
281      * @param number dailing nubmer (up to 20 digits)
282      *        if the number starts with '+', then set to international TOA
283      * @param onComplete
284      *        onComplete.obj will be an AsyncResult
285      *        ((AsyncResult)onComplete.obj).exception == null on success
286      *        ((AsyncResult)onComplete.obj).exception != null on fail
287      */
288     public void setMsisdnNumber(String alphaTag, String number,
289             Message onComplete) {
290
291         mMsisdn = number;
292         mMsisdnTag = alphaTag;
293
294         if (DBG) log("Set MSISDN: " + mMsisdnTag +" " + mMsisdn);
295
296
297         AdnRecord adn = new AdnRecord(mMsisdnTag, mMsisdn);
298
299         new AdnRecordLoader(mFh).updateEF(adn, EF_MSISDN, EF_EXT1, 1, null,
300                 obtainMessage(EVENT_SET_MSISDN_DONE, onComplete));
301     }
302
303     public String getMsisdnAlphaTag() {
304         return mMsisdnTag;
305     }
306
307     public String getVoiceMailNumber() {
308         return mVoiceMailNum;
309     }
310
311     /**
312      * Return Service Provider Name stored in SIM (EF_SPN=0x6F46) or in RUIM (EF_RUIM_SPN=0x6F41).
313      *
314      * @return null if SIM is not yet ready or no RUIM entry
315      */
316     public String getServiceProviderName() {
317         String providerName = mSpn;
318
319         // Check for null pointers, mParentApp can be null after dispose,
320         // which did occur after removing a SIM.
321         UiccCardApplication parentApp = mParentApp;
322         if (parentApp != null) {
323             UiccCard card = parentApp.getUiccCard();
324             if (card != null) {
325                 String brandOverride = card.getOperatorBrandOverride();
326                 if (brandOverride != null) {
327                     log("getServiceProviderName: override");
328                     providerName = brandOverride;
329                 } else {
330                     log("getServiceProviderName: no brandOverride");
331                 }
332             } else {
333                 log("getServiceProviderName: card is null");
334             }
335         } else {
336             log("getServiceProviderName: mParentApp is null");
337         }
338         log("getServiceProviderName: providerName=" + providerName);
339         return providerName;
340     }
341
342     protected void setServiceProviderName(String spn) {
343         mSpn = spn;
344     }
345
346     /**
347      * Set voice mail number to SIM record
348      *
349      * The voice mail number can be stored either in EF_MBDN (TS 51.011) or
350      * EF_MAILBOX_CPHS (CPHS 4.2)
351      *
352      * If EF_MBDN is available, store the voice mail number to EF_MBDN
353      *
354      * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS
355      *
356      * So the voice mail number will be stored in both EFs if both are available
357      *
358      * Return error only if both EF_MBDN and EF_MAILBOX_CPHS fail.
359      *
360      * When the operation is complete, onComplete will be sent to its handler
361      *
362      * @param alphaTag alpha-tagging of the dailing nubmer (upto 10 characters)
363      * @param voiceNumber dailing nubmer (upto 20 digits)
364      *        if the number is start with '+', then set to international TOA
365      * @param onComplete
366      *        onComplete.obj will be an AsyncResult
367      *        ((AsyncResult)onComplete.obj).exception == null on success
368      *        ((AsyncResult)onComplete.obj).exception != null on fail
369      */
370     public abstract void setVoiceMailNumber(String alphaTag, String voiceNumber,
371             Message onComplete);
372
373     public String getVoiceMailAlphaTag() {
374         return mVoiceMailTag;
375     }
376
377     /**
378      * Sets the SIM voice message waiting indicator records
379      * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
380      * @param countWaiting The number of messages waiting, if known. Use
381      *                     -1 to indicate that an unknown number of
382      *                      messages are waiting
383      */
384     public abstract void setVoiceMessageWaiting(int line, int countWaiting);
385
386     /** @return  true if there are messages waiting, false otherwise. */
387     public boolean getVoiceMessageWaiting() {
388         return mCountVoiceMessages != 0;
389     }
390
391     /**
392      * Returns number of voice messages waiting, if available
393      * If not available (eg, on an older CPHS SIM) -1 is returned if
394      * getVoiceMessageWaiting() is true
395      */
396     public int getVoiceMessageCount() {
397         return mCountVoiceMessages;
398     }
399
400     /**
401      * Called by STK Service when REFRESH is received.
402      * @param fileChanged indicates whether any files changed
403      * @param fileList if non-null, a list of EF files that changed
404      */
405     public abstract void onRefresh(boolean fileChanged, int[] fileList);
406
407     /**
408      * Called by subclasses (SimRecords and RuimRecords) whenever
409      * IccRefreshResponse.REFRESH_RESULT_INIT event received
410      */
411     protected void onIccRefreshInit() {
412         mAdnCache.reset();
413         UiccCardApplication parentApp = mParentApp;
414         if ((parentApp != null) &&
415                 (parentApp.getState() == AppState.APPSTATE_READY)) {
416             // This will cause files to be reread
417             sendMessage(obtainMessage(EVENT_APP_READY));
418         }
419     }
420
421     public boolean getRecordsLoaded() {
422         if (mRecordsToLoad == 0 && mRecordsRequested == true) {
423             return true;
424         } else {
425             return false;
426         }
427     }
428
429     //***** Overridden from Handler
430     @Override
431     public void handleMessage(Message msg) {
432         AsyncResult ar;
433
434         switch (msg.what) {
435             case EVENT_GET_ICC_RECORD_DONE:
436                 try {
437                     ar = (AsyncResult) msg.obj;
438                     IccRecordLoaded recordLoaded = (IccRecordLoaded) ar.userObj;
439                     if (DBG) log(recordLoaded.getEfName() + " LOADED");
440
441                     if (ar.exception != null) {
442                         loge("Record Load Exception: " + ar.exception);
443                     } else {
444                         recordLoaded.onRecordLoaded(ar);
445                     }
446                 }catch (RuntimeException exc) {
447                     // I don't want these exceptions to be fatal
448                     loge("Exception parsing SIM record: " + exc);
449                 } finally {
450                     // Count up record load responses even if they are fails
451                     onRecordLoaded();
452                 }
453                 break;
454
455             case EVENT_AKA_AUTHENTICATE_DONE:
456                 ar = (AsyncResult)msg.obj;
457                 auth_rsp = null;
458                 if (DBG) log("EVENT_AKA_AUTHENTICATE_DONE");
459                 if (ar.exception != null) {
460                     loge("Exception ICC SIM AKA: " + ar.exception);
461                 } else {
462                     try {
463                         auth_rsp = (IccIoResult)ar.result;
464                         if (DBG) log("ICC SIM AKA: auth_rsp = " + auth_rsp);
465                     } catch (Exception e) {
466                         loge("Failed to parse ICC SIM AKA contents: " + e);
467                     }
468                 }
469                 synchronized (mLock) {
470                     mLock.notifyAll();
471                 }
472
473                 break;
474
475             default:
476                 super.handleMessage(msg);
477         }
478     }
479
480     protected abstract void onRecordLoaded();
481
482     protected abstract void onAllRecordsLoaded();
483
484     /**
485      * Returns the SpnDisplayRule based on settings on the SIM and the
486      * specified plmn (currently-registered PLMN).  See TS 22.101 Annex A
487      * and TS 51.011 10.3.11 for details.
488      *
489      * If the SPN is not found on the SIM, the rule is always PLMN_ONLY.
490      * Generally used for GSM/UMTS and the like SIMs.
491      */
492     public abstract int getDisplayRule(String plmn);
493
494     /**
495      * Return true if "Restriction of menu options for manual PLMN selection"
496      * bit is set or EF_CSP data is unavailable, return false otherwise.
497      * Generally used for GSM/UMTS and the like SIMs.
498      */
499     public boolean isCspPlmnEnabled() {
500         return false;
501     }
502
503     /**
504      * Returns the 5 or 6 digit MCC/MNC of the operator that
505      * provided the SIM card. Returns null of SIM is not yet ready
506      * or is not valid for the type of IccCard. Generally used for
507      * GSM/UMTS and the like SIMS
508      */
509     public String getOperatorNumeric() {
510         return null;
511     }
512
513     /**
514      * Get the current Voice call forwarding flag for GSM/UMTS and the like SIMs
515      *
516      * @return true if enabled
517      */
518     public boolean getVoiceCallForwardingFlag() {
519         return false;
520     }
521
522     /**
523      * Set the voice call forwarding flag for GSM/UMTS and the like SIMs
524      *
525      * @param line to enable/disable
526      * @param enable
527      * @param number to which CFU is enabled
528      */
529     public void setVoiceCallForwardingFlag(int line, boolean enable, String number) {
530     }
531
532     /**
533      * Indicates wether SIM is in provisioned state or not.
534      * Overridden only if SIM can be dynamically provisioned via OTA.
535      *
536      * @return true if provisioned
537      */
538     public boolean isProvisioned () {
539         return true;
540     }
541
542     /**
543      * Write string to log file
544      *
545      * @param s is the string to write
546      */
547     protected abstract void log(String s);
548
549     /**
550      * Write error string to log file.
551      *
552      * @param s is the string to write
553      */
554     protected abstract void loge(String s);
555
556     /**
557      * Return an interface to retrieve the ISIM records for IMS, if available.
558      * @return the interface to retrieve the ISIM records, or null if not supported
559      */
560     public IsimRecords getIsimRecords() {
561         return null;
562     }
563
564     public UsimServiceTable getUsimServiceTable() {
565         return null;
566     }
567
568     /**
569      * Returns the response of the SIM application on the UICC to authentication
570      * challenge/response algorithm. The data string and challenge response are
571      * Base64 encoded Strings.
572      * Can support EAP-SIM, EAP-AKA with results encoded per 3GPP TS 31.102.
573      *
574      * @param authContext parameter P2 that specifies the authentication context per 3GPP TS 31.102 (Section 7.1.2)
575      * @param data authentication challenge data
576      * @return challenge response
577      */
578     public String getIccSimChallengeResponse(int authContext, String data) {
579         if (DBG) log("getIccSimChallengeResponse:");
580
581         try {
582             synchronized(mLock) {
583                 CommandsInterface ci = mCi;
584                 UiccCardApplication parentApp = mParentApp;
585                 if (ci != null && parentApp != null) {
586                     ci.requestIccSimAuthentication(authContext, data,
587                             parentApp.getAid(),
588                             obtainMessage(EVENT_AKA_AUTHENTICATE_DONE));
589                     try {
590                         mLock.wait();
591                     } catch (InterruptedException e) {
592                         loge("getIccSimChallengeResponse: Fail, interrupted"
593                                 + " while trying to request Icc Sim Auth");
594                         return null;
595                     }
596                 } else {
597                     loge( "getIccSimChallengeResponse: "
598                             + "Fail, ci or parentApp is null");
599                     return null;
600                 }
601             }
602         } catch(Exception e) {
603             loge( "getIccSimChallengeResponse: "
604                     + "Fail while trying to request Icc Sim Auth");
605             return null;
606         }
607
608         if (DBG) log("getIccSimChallengeResponse: return auth_rsp");
609
610         return android.util.Base64.encodeToString(auth_rsp.payload, android.util.Base64.NO_WRAP);
611     }
612
613     protected boolean requirePowerOffOnSimRefreshReset() {
614         return mContext.getResources().getBoolean(
615             com.android.internal.R.bool.config_requireRadioPowerOffOnSimRefreshReset);
616     }
617
618     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
619         pw.println("IccRecords: " + this);
620         pw.println(" mDestroyed=" + mDestroyed);
621         pw.println(" mCi=" + mCi);
622         pw.println(" mFh=" + mFh);
623         pw.println(" mParentApp=" + mParentApp);
624         pw.println(" recordsLoadedRegistrants: size=" + mRecordsLoadedRegistrants.size());
625         for (int i = 0; i < mRecordsLoadedRegistrants.size(); i++) {
626             pw.println("  recordsLoadedRegistrants[" + i + "]="
627                     + ((Registrant)mRecordsLoadedRegistrants.get(i)).getHandler());
628         }
629         pw.println(" mImsiReadyRegistrants: size=" + mImsiReadyRegistrants.size());
630         for (int i = 0; i < mImsiReadyRegistrants.size(); i++) {
631             pw.println("  mImsiReadyRegistrants[" + i + "]="
632                     + ((Registrant)mImsiReadyRegistrants.get(i)).getHandler());
633         }
634         pw.println(" mRecordsEventsRegistrants: size=" + mRecordsEventsRegistrants.size());
635         for (int i = 0; i < mRecordsEventsRegistrants.size(); i++) {
636             pw.println("  mRecordsEventsRegistrants[" + i + "]="
637                     + ((Registrant)mRecordsEventsRegistrants.get(i)).getHandler());
638         }
639         pw.println(" mNewSmsRegistrants: size=" + mNewSmsRegistrants.size());
640         for (int i = 0; i < mNewSmsRegistrants.size(); i++) {
641             pw.println("  mNewSmsRegistrants[" + i + "]="
642                     + ((Registrant)mNewSmsRegistrants.get(i)).getHandler());
643         }
644         pw.println(" mNetworkSelectionModeAutomaticRegistrants: size="
645                 + mNetworkSelectionModeAutomaticRegistrants.size());
646         for (int i = 0; i < mNetworkSelectionModeAutomaticRegistrants.size(); i++) {
647             pw.println("  mNetworkSelectionModeAutomaticRegistrants[" + i + "]="
648                     + ((Registrant)mNetworkSelectionModeAutomaticRegistrants.get(i)).getHandler());
649         }
650         pw.println(" mRecordsRequested=" + mRecordsRequested);
651         pw.println(" mRecordsToLoad=" + mRecordsToLoad);
652         pw.println(" mRdnCache=" + mAdnCache);
653         pw.println(" iccid=" + mIccId);
654         pw.println(" mMsisdn=" + mMsisdn);
655         pw.println(" mMsisdnTag=" + mMsisdnTag);
656         pw.println(" mVoiceMailNum=" + mVoiceMailNum);
657         pw.println(" mVoiceMailTag=" + mVoiceMailTag);
658         pw.println(" mNewVoiceMailNum=" + mNewVoiceMailNum);
659         pw.println(" mNewVoiceMailTag=" + mNewVoiceMailTag);
660         pw.println(" mIsVoiceMailFixed=" + mIsVoiceMailFixed);
661         pw.println(" mCountVoiceMessages=" + mCountVoiceMessages);
662         pw.println(" mImsi=" + mImsi);
663         pw.println(" mMncLength=" + mMncLength);
664         pw.println(" mMailboxIndex=" + mMailboxIndex);
665         pw.println(" mSpn=" + mSpn);
666         pw.flush();
667     }
668 }