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