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.annotation.IntDef;
20 import android.annotation.UnsupportedAppUsage;
21 import android.content.Context;
22 import android.os.AsyncResult;
23 import android.os.Handler;
24 import android.os.Message;
25 import android.os.Registrant;
26 import android.os.RegistrantList;
27 import android.telephony.Rlog;
28 import android.telephony.SubscriptionInfo;
29 import android.telephony.TelephonyManager;
30 import android.text.TextUtils;
31 
32 import com.android.internal.telephony.CommandsInterface;
33 import com.android.internal.telephony.MccTable;
34 import com.android.internal.util.ArrayUtils;
35 
36 import java.io.FileDescriptor;
37 import java.io.PrintWriter;
38 import java.io.UnsupportedEncodingException;
39 import java.lang.annotation.Retention;
40 import java.lang.annotation.RetentionPolicy;
41 import java.util.Arrays;
42 import java.util.HashMap;
43 import java.util.Objects;
44 import java.util.concurrent.atomic.AtomicBoolean;
45 import java.util.concurrent.atomic.AtomicInteger;
46 
47 /**
48  * {@hide}
49  */
50 public abstract class IccRecords extends Handler implements IccConstants {
51     protected static final boolean DBG = true;
52     protected static final boolean VDBG = false; // STOPSHIP if true
53 
54     // Lookup table for carriers known to produce SIMs which incorrectly indicate MNC length.
55     private static final String[] MCCMNC_CODES_HAVING_3DIGITS_MNC = {
56         "302370", "302720", "310260",
57         "405025", "405026", "405027", "405028", "405029", "405030", "405031", "405032",
58         "405033", "405034", "405035", "405036", "405037", "405038", "405039", "405040",
59         "405041", "405042", "405043", "405044", "405045", "405046", "405047", "405750",
60         "405751", "405752", "405753", "405754", "405755", "405756", "405799", "405800",
61         "405801", "405802", "405803", "405804", "405805", "405806", "405807", "405808",
62         "405809", "405810", "405811", "405812", "405813", "405814", "405815", "405816",
63         "405817", "405818", "405819", "405820", "405821", "405822", "405823", "405824",
64         "405825", "405826", "405827", "405828", "405829", "405830", "405831", "405832",
65         "405833", "405834", "405835", "405836", "405837", "405838", "405839", "405840",
66         "405841", "405842", "405843", "405844", "405845", "405846", "405847", "405848",
67         "405849", "405850", "405851", "405852", "405853", "405854", "405855", "405856",
68         "405857", "405858", "405859", "405860", "405861", "405862", "405863", "405864",
69         "405865", "405866", "405867", "405868", "405869", "405870", "405871", "405872",
70         "405873", "405874", "405875", "405876", "405877", "405878", "405879", "405880",
71         "405881", "405882", "405883", "405884", "405885", "405886", "405908", "405909",
72         "405910", "405911", "405912", "405913", "405914", "405915", "405916", "405917",
73         "405918", "405919", "405920", "405921", "405922", "405923", "405924", "405925",
74         "405926", "405927", "405928", "405929", "405930", "405931", "405932", "502142",
75         "502143", "502145", "502146", "502147", "502148"
76     };
77 
78     // ***** Instance Variables
79     @UnsupportedAppUsage
80     protected AtomicBoolean mDestroyed = new AtomicBoolean(false);
81     protected AtomicBoolean mLoaded = new AtomicBoolean(false);
82     @UnsupportedAppUsage
83     protected Context mContext;
84     @UnsupportedAppUsage
85     protected CommandsInterface mCi;
86     @UnsupportedAppUsage
87     protected IccFileHandler mFh;
88     @UnsupportedAppUsage
89     protected UiccCardApplication mParentApp;
90     @UnsupportedAppUsage
91     protected TelephonyManager mTelephonyManager;
92 
93     protected RegistrantList mRecordsLoadedRegistrants = new RegistrantList();
94     protected RegistrantList mLockedRecordsLoadedRegistrants = new RegistrantList();
95     protected RegistrantList mNetworkLockedRecordsLoadedRegistrants = new RegistrantList();
96     protected RegistrantList mImsiReadyRegistrants = new RegistrantList();
97     @UnsupportedAppUsage
98     protected RegistrantList mRecordsEventsRegistrants = new RegistrantList();
99     protected RegistrantList mNewSmsRegistrants = new RegistrantList();
100     protected RegistrantList mNetworkSelectionModeAutomaticRegistrants = new RegistrantList();
101     protected RegistrantList mSpnUpdatedRegistrants = new RegistrantList();
102     protected RegistrantList mRecordsOverrideRegistrants = new RegistrantList();
103 
104     @UnsupportedAppUsage
105     protected int mRecordsToLoad;  // number of pending load requests
106 
107     @UnsupportedAppUsage
108     protected AdnRecordCache mAdnCache;
109 
110     // ***** Cached SIM State; cleared on channel close
111 
112     // SIM is not locked
113     protected static final int LOCKED_RECORDS_REQ_REASON_NONE = 0;
114     // Records requested for PIN or PUK locked SIM
115     protected static final int LOCKED_RECORDS_REQ_REASON_LOCKED = 1;
116     // Records requested for network locked SIM
117     protected static final int LOCKED_RECORDS_REQ_REASON_NETWORK_LOCKED = 2;
118 
119     protected boolean mRecordsRequested = false; // true if we've made requests for the sim records
120     protected int mLockedRecordsReqReason = LOCKED_RECORDS_REQ_REASON_NONE;
121 
122     @UnsupportedAppUsage
123     protected String mIccId;  // Includes only decimals (no hex)
124 
125     protected String mFullIccId;  // Includes hex characters in ICCID
126     protected String mMsisdn = null;  // My mobile number
127     protected String mMsisdnTag = null;
128     protected String mNewMsisdn = null;
129     protected String mNewMsisdnTag = null;
130     @UnsupportedAppUsage
131     protected String mVoiceMailNum = null;
132     protected String mVoiceMailTag = null;
133     protected String mNewVoiceMailNum = null;
134     protected String mNewVoiceMailTag = null;
135     @UnsupportedAppUsage
136     protected boolean mIsVoiceMailFixed = false;
137     @UnsupportedAppUsage
138     protected String mImsi; // IMSI must be only valid numeric characters 0-9 without padding 'f's
139     @UnsupportedAppUsage
140     private IccIoResult auth_rsp;
141 
142     @UnsupportedAppUsage
143     protected int mMncLength = UNINITIALIZED;
144     protected int mMailboxIndex = 0; // 0 is no mailbox dailing number associated
145 
146     @UnsupportedAppUsage
147     private String mSpn;
148 
149     @UnsupportedAppUsage
150     protected String mGid1;
151     protected String mGid2;
152 
153     protected String mPnnHomeName;
154 
155     protected String mPrefLang;
156 
157     protected PlmnActRecord[] mHplmnActRecords;
158     protected PlmnActRecord[] mOplmnActRecords;
159     protected PlmnActRecord[] mPlmnActRecords;
160 
161     // A list of PLMN in which the SPN shall be displayed.
162     // Reference: 3GPP TS 31.102 Section 4.2.66
163     protected String[] mSpdi;
164 
165 
166     // Carrier name display condition bitmask
167     // Reference: 3GPP TS 131.102 section 4.2.12 EF_SPN Display Condition
168     protected int mCarrierNameDisplayCondition;
169 
170     protected String[] mEhplmns;
171     protected String[] mFplmns;
172 
173     @UnsupportedAppUsage
174     private final Object mLock = new Object();
175 
176     CarrierTestOverride mCarrierTestOverride;
177 
178     //Arbitrary offset for the Handler
179     protected static final int HANDLER_ACTION_BASE = 0x12E500;
180     protected static final int HANDLER_ACTION_NONE = HANDLER_ACTION_BASE + 0;
181     protected static final int HANDLER_ACTION_SEND_RESPONSE = HANDLER_ACTION_BASE + 1;
182     protected static AtomicInteger sNextRequestId = new AtomicInteger(1);
183     protected final HashMap<Integer, Message> mPendingResponses = new HashMap<>();
184 
185     // ***** Constants
186 
187     // Markers for mncLength
188     protected static final int UNINITIALIZED = -1;
189     protected static final int UNKNOWN = 0;
190 
191     // Bitmask for carrier name display condition.
192     @Retention(RetentionPolicy.SOURCE)
193     @IntDef(prefix = {"CARRIER_NAME_DISPLAY_CONDITION_BITMASK_"},
194             value = {CARRIER_NAME_DISPLAY_CONDITION_BITMASK_PLMN,
195                     CARRIER_NAME_DISPLAY_CONDITION_BITMASK_SPN},
196             flag = true)
197     public @interface CarrierNameDisplayConditionBitmask {}
198     public static final int CARRIER_NAME_DISPLAY_CONDITION_BITMASK_PLMN = 1;
199     public static final int CARRIER_NAME_DISPLAY_CONDITION_BITMASK_SPN = 2;
200 
201 
202     // See {@link CarrierConfigManager#KEY_SPN_DISPLAY_CONDITION_OVERRIDE_INT}.
203     public static final int INVALID_CARRIER_NAME_DISPLAY_CONDITION_BITMASK = -1;
204 
205     // Display SPN only and only if registered to Home PLMNs.
206     // Display PLMN only and only if registered to Non-Home PLMNs.
207     public static final int DEFAULT_CARRIER_NAME_DISPLAY_CONDITION = 0;
208 
209     // ***** Event Constants
210     public static final int EVENT_MWI = 0; // Message Waiting indication
211     public static final int EVENT_CFI = 1; // Call Forwarding indication
212     public static final int EVENT_SPN = 2; // Service Provider Name
213 
214     public static final int EVENT_GET_ICC_RECORD_DONE = 100;
215     public static final int EVENT_REFRESH = 31; // ICC refresh occurred
216     protected static final int EVENT_APP_READY = 1;
217     private static final int EVENT_AKA_AUTHENTICATE_DONE          = 90;
218 
219     public static final int CALL_FORWARDING_STATUS_DISABLED = 0;
220     public static final int CALL_FORWARDING_STATUS_ENABLED = 1;
221     public static final int CALL_FORWARDING_STATUS_UNKNOWN = -1;
222 
223     public static final int DEFAULT_VOICE_MESSAGE_COUNT = -2;
224     public static final int UNKNOWN_VOICE_MESSAGE_COUNT = -1;
225 
226     @Override
toString()227     public String toString() {
228         String iccIdToPrint = SubscriptionInfo.givePrintableIccid(mFullIccId);
229         return "mDestroyed=" + mDestroyed
230                 + " mContext=" + mContext
231                 + " mCi=" + mCi
232                 + " mFh=" + mFh
233                 + " mParentApp=" + mParentApp
234                 + " recordsToLoad=" + mRecordsToLoad
235                 + " adnCache=" + mAdnCache
236                 + " recordsRequested=" + mRecordsRequested
237                 + " lockedRecordsReqReason=" + mLockedRecordsReqReason
238                 + " iccid=" + iccIdToPrint
239                 + (mCarrierTestOverride.isInTestMode() ? "mFakeIccid="
240                 + mCarrierTestOverride.getFakeIccid() : "")
241                 + " msisdnTag=" + mMsisdnTag
242                 + " voiceMailNum=" + Rlog.pii(VDBG, mVoiceMailNum)
243                 + " voiceMailTag=" + mVoiceMailTag
244                 + " voiceMailNum=" + Rlog.pii(VDBG, mNewVoiceMailNum)
245                 + " newVoiceMailTag=" + mNewVoiceMailTag
246                 + " isVoiceMailFixed=" + mIsVoiceMailFixed
247                 + " mImsi=" + ((mImsi != null) ?
248                 mImsi.substring(0, 6) + Rlog.pii(VDBG, mImsi.substring(6)) : "null")
249                 + (mCarrierTestOverride.isInTestMode() ? " mFakeImsi="
250                 + mCarrierTestOverride.getFakeIMSI() : "")
251                 + " mncLength=" + mMncLength
252                 + " mailboxIndex=" + mMailboxIndex
253                 + " spn=" + mSpn
254                 + (mCarrierTestOverride.isInTestMode() ? " mFakeSpn="
255                 + mCarrierTestOverride.getFakeSpn() : "");
256     }
257 
258     /**
259      * Generic ICC record loaded callback. Subclasses can call EF load methods on
260      * {@link IccFileHandler} passing a Message for onLoaded with the what field set to
261      * {@link #EVENT_GET_ICC_RECORD_DONE} and the obj field set to an instance
262      * of this interface. The {@link #handleMessage} method in this class will print a
263      * log message using {@link #getEfName()} and decrement {@link #mRecordsToLoad}.
264      *
265      * If the record load was successful, {@link #onRecordLoaded} will be called with the result.
266      * Otherwise, an error log message will be output by {@link #handleMessage} and
267      * {@link #onRecordLoaded} will not be called.
268      */
269     public interface IccRecordLoaded {
getEfName()270         String getEfName();
onRecordLoaded(AsyncResult ar)271         void onRecordLoaded(AsyncResult ar);
272     }
273 
274     // ***** Constructor
IccRecords(UiccCardApplication app, Context c, CommandsInterface ci)275     public IccRecords(UiccCardApplication app, Context c, CommandsInterface ci) {
276         mContext = c;
277         mCi = ci;
278         mFh = app.getIccFileHandler();
279         mParentApp = app;
280         mTelephonyManager = (TelephonyManager) mContext.getSystemService(
281                 Context.TELEPHONY_SERVICE);
282 
283         mCarrierTestOverride = new CarrierTestOverride();
284         mCi.registerForIccRefresh(this, EVENT_REFRESH, null);
285     }
286 
287     // Override IccRecords for testing
setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1, String gid2, String pnn, String spn)288     public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1,
289             String gid2, String pnn, String spn)  {
290         mCarrierTestOverride.override(mccmnc, imsi, iccid, gid1, gid2, pnn, spn);
291         mTelephonyManager.setSimOperatorNameForPhone(mParentApp.getPhoneId(), spn);
292         mTelephonyManager.setSimOperatorNumericForPhone(mParentApp.getPhoneId(), mccmnc);
293         mRecordsOverrideRegistrants.notifyRegistrants();
294     }
295 
296     /**
297      * Call when the IccRecords object is no longer going to be used.
298      */
dispose()299     public void dispose() {
300         mDestroyed.set(true);
301 
302         // It is possible that there is another thread waiting for the response
303         // to requestIccSimAuthentication() in getIccSimChallengeResponse().
304         auth_rsp = null;
305         synchronized (mLock) {
306             mLock.notifyAll();
307         }
308 
309         mCi.unregisterForIccRefresh(this);
310         mParentApp = null;
311         mFh = null;
312         mCi = null;
313         mContext = null;
314         if (mAdnCache != null) {
315             mAdnCache.reset();
316         }
317         mLoaded.set(false);
318     }
319 
onReady()320     public abstract void onReady();
321 
322     //***** Public Methods
getAdnCache()323     public AdnRecordCache getAdnCache() {
324         return mAdnCache;
325     }
326 
327     /**
328      * Adds a message to the pending requests list by generating a unique
329      * (integer) hash key and returning it. The message should never be null.
330      */
storePendingResponseMessage(Message msg)331     public int storePendingResponseMessage(Message msg) {
332         int key = sNextRequestId.getAndIncrement();
333         synchronized (mPendingResponses) {
334             mPendingResponses.put(key, msg);
335         }
336         return key;
337     }
338 
339     /**
340      * Returns the pending request, if any or null
341      */
retrievePendingResponseMessage(Integer key)342     public Message retrievePendingResponseMessage(Integer key) {
343         Message m;
344         synchronized (mPendingResponses) {
345             return mPendingResponses.remove(key);
346         }
347     }
348 
349     /**
350      * Returns the ICC ID stripped at the first hex character. Some SIMs have ICC IDs
351      * containing hex digits; {@link #getFullIccId()} should be used to get the full ID including
352      * hex digits.
353      * @return ICC ID without hex digits
354      */
355     @UnsupportedAppUsage
getIccId()356     public String getIccId() {
357         if (mCarrierTestOverride.isInTestMode() && mCarrierTestOverride.getFakeIccid() != null) {
358             return mCarrierTestOverride.getFakeIccid();
359         } else {
360             return mIccId;
361         }
362     }
363 
364     /**
365      * Returns the full ICC ID including hex digits.
366      * @return full ICC ID including hex digits
367      */
getFullIccId()368     public String getFullIccId() {
369         return mFullIccId;
370     }
371 
372     @UnsupportedAppUsage
registerForRecordsLoaded(Handler h, int what, Object obj)373     public void registerForRecordsLoaded(Handler h, int what, Object obj) {
374         if (mDestroyed.get()) {
375             return;
376         }
377 
378         Registrant r = new Registrant(h, what, obj);
379         mRecordsLoadedRegistrants.add(r);
380 
381         if (getRecordsLoaded()) {
382             r.notifyRegistrant(new AsyncResult(null, null, null));
383         }
384     }
385     @UnsupportedAppUsage
unregisterForRecordsLoaded(Handler h)386     public void unregisterForRecordsLoaded(Handler h) {
387         mRecordsLoadedRegistrants.remove(h);
388     }
389 
unregisterForRecordsOverride(Handler h)390     public void unregisterForRecordsOverride(Handler h) {
391         mRecordsOverrideRegistrants.remove(h);
392     }
393 
registerForRecordsOverride(Handler h, int what, Object obj)394     public void registerForRecordsOverride(Handler h, int what, Object obj) {
395         if (mDestroyed.get()) {
396             return;
397         }
398 
399         Registrant r = new Registrant(h, what, obj);
400         mRecordsOverrideRegistrants.add(r);
401 
402         if (getRecordsLoaded()) {
403             r.notifyRegistrant(new AsyncResult(null, null, null));
404         }
405     }
406 
407     /**
408      * Register to be notified when records are loaded for a PIN or PUK locked SIM
409      */
registerForLockedRecordsLoaded(Handler h, int what, Object obj)410     public void registerForLockedRecordsLoaded(Handler h, int what, Object obj) {
411         if (mDestroyed.get()) {
412             return;
413         }
414 
415         Registrant r = new Registrant(h, what, obj);
416         mLockedRecordsLoadedRegistrants.add(r);
417 
418         if (getLockedRecordsLoaded()) {
419             r.notifyRegistrant(new AsyncResult(null, null, null));
420         }
421     }
422 
423     /**
424      * Unregister corresponding to registerForLockedRecordsLoaded()
425      */
unregisterForLockedRecordsLoaded(Handler h)426     public void unregisterForLockedRecordsLoaded(Handler h) {
427         mLockedRecordsLoadedRegistrants.remove(h);
428     }
429 
430     /**
431      * Register to be notified when records are loaded for a network locked SIM
432      */
registerForNetworkLockedRecordsLoaded(Handler h, int what, Object obj)433     public void registerForNetworkLockedRecordsLoaded(Handler h, int what, Object obj) {
434         if (mDestroyed.get()) {
435             return;
436         }
437 
438         Registrant r = new Registrant(h, what, obj);
439         mNetworkLockedRecordsLoadedRegistrants.add(r);
440 
441         if (getNetworkLockedRecordsLoaded()) {
442             r.notifyRegistrant(new AsyncResult(null, null, null));
443         }
444     }
445 
446     /**
447      * Unregister corresponding to registerForLockedRecordsLoaded()
448      */
unregisterForNetworkLockedRecordsLoaded(Handler h)449     public void unregisterForNetworkLockedRecordsLoaded(Handler h) {
450         mNetworkLockedRecordsLoadedRegistrants.remove(h);
451     }
452 
registerForImsiReady(Handler h, int what, Object obj)453     public void registerForImsiReady(Handler h, int what, Object obj) {
454         if (mDestroyed.get()) {
455             return;
456         }
457 
458         Registrant r = new Registrant(h, what, obj);
459         mImsiReadyRegistrants.add(r);
460 
461         if (getIMSI() != null) {
462             r.notifyRegistrant(new AsyncResult(null, null, null));
463         }
464     }
unregisterForImsiReady(Handler h)465     public void unregisterForImsiReady(Handler h) {
466         mImsiReadyRegistrants.remove(h);
467     }
468 
registerForSpnUpdate(Handler h, int what, Object obj)469     public void registerForSpnUpdate(Handler h, int what, Object obj) {
470         if (mDestroyed.get()) {
471             return;
472         }
473 
474         Registrant r = new Registrant(h, what, obj);
475         mSpnUpdatedRegistrants.add(r);
476 
477         if (!TextUtils.isEmpty(mSpn)) {
478             r.notifyRegistrant(new AsyncResult(null, null, null));
479         }
480     }
unregisterForSpnUpdate(Handler h)481     public void unregisterForSpnUpdate(Handler h) {
482         mSpnUpdatedRegistrants.remove(h);
483     }
484 
485     @UnsupportedAppUsage
registerForRecordsEvents(Handler h, int what, Object obj)486     public void registerForRecordsEvents(Handler h, int what, Object obj) {
487         Registrant r = new Registrant (h, what, obj);
488         mRecordsEventsRegistrants.add(r);
489 
490         /* Notify registrant of all the possible events. This is to make sure registrant is
491         notified even if event occurred in the past. */
492         r.notifyResult(EVENT_MWI);
493         r.notifyResult(EVENT_CFI);
494     }
495     @UnsupportedAppUsage
unregisterForRecordsEvents(Handler h)496     public void unregisterForRecordsEvents(Handler h) {
497         mRecordsEventsRegistrants.remove(h);
498     }
499 
500     @UnsupportedAppUsage
registerForNewSms(Handler h, int what, Object obj)501     public void registerForNewSms(Handler h, int what, Object obj) {
502         Registrant r = new Registrant (h, what, obj);
503         mNewSmsRegistrants.add(r);
504     }
505     @UnsupportedAppUsage
unregisterForNewSms(Handler h)506     public void unregisterForNewSms(Handler h) {
507         mNewSmsRegistrants.remove(h);
508     }
509 
510     @UnsupportedAppUsage
registerForNetworkSelectionModeAutomatic( Handler h, int what, Object obj)511     public void registerForNetworkSelectionModeAutomatic(
512             Handler h, int what, Object obj) {
513         Registrant r = new Registrant (h, what, obj);
514         mNetworkSelectionModeAutomaticRegistrants.add(r);
515     }
516     @UnsupportedAppUsage
unregisterForNetworkSelectionModeAutomatic(Handler h)517     public void unregisterForNetworkSelectionModeAutomatic(Handler h) {
518         mNetworkSelectionModeAutomaticRegistrants.remove(h);
519     }
520 
521     /**
522      * Get the International Mobile Subscriber ID (IMSI) on a SIM
523      * for GSM, UMTS and like networks. Default is null if IMSI is
524      * not supported or unavailable.
525      *
526      * @return null if SIM is not yet ready or unavailable
527      */
528     @UnsupportedAppUsage
getIMSI()529     public String getIMSI() {
530         if (mCarrierTestOverride.isInTestMode() && mCarrierTestOverride.getFakeIMSI() != null) {
531             return mCarrierTestOverride.getFakeIMSI();
532         } else {
533             return mImsi;
534         }
535     }
536 
537     /**
538      * Update IMSI record and try to extract the PLMN information and notify registrants.
539      * @param inImsi the IMSI value
540      */
setImsi(String inImsi)541     public void setImsi(String inImsi) {
542         // Remove trailing F's if present in IMSI.
543         mImsi = IccUtils.stripTrailingFs(inImsi);
544         if (!Objects.equals(mImsi, inImsi)) {
545             loge("Invalid IMSI padding digits received.");
546         }
547 
548         if (TextUtils.isEmpty(mImsi)) mImsi = null;
549 
550         if (mImsi != null && !mImsi.matches("[0-9]+")) {
551             loge("Invalid non-numeric IMSI digits received.");
552             mImsi = null;
553         }
554 
555         // IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more
556         // than 15 (and usually 15).
557         // This will also handle un-set IMSI records (all Fs)
558         if (mImsi != null && (mImsi.length() < 6 || mImsi.length() > 15)) {
559             loge("invalid IMSI " + mImsi);
560             mImsi = null;
561         }
562 
563         log("IMSI: mMncLength=" + mMncLength);
564 
565         if (mImsi != null && mImsi.length() >= 6) {
566             log("IMSI: " + mImsi.substring(0, 6) + Rlog.pii(VDBG, mImsi.substring(6)));
567         }
568 
569         // IMSI has changed so the PLMN might have changed as well
570         updateOperatorPlmn();
571 
572         mImsiReadyRegistrants.notifyRegistrants();
573     }
574 
updateOperatorPlmn()575     protected void updateOperatorPlmn() {
576         // In case of a test override, use the test IMSI
577         String imsi = getIMSI();
578 
579         if (imsi != null) {
580             // First try to guess the length based on a table of known 3-digit MNCs.
581             if (((mMncLength == UNKNOWN) || (mMncLength == 2)) && imsi.length() >= 6) {
582                 String mccmncCode = imsi.substring(0, 6);
583                 for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) {
584                     if (mccmnc.equals(mccmncCode)) {
585                         mMncLength = 3;
586                         log("IMSI: setting1 mMncLength=" + mMncLength);
587                         break;
588                     }
589                 }
590             }
591 
592             // If still unknown, guess using the MCC.
593             if (mMncLength == UNKNOWN) {
594                 try {
595                     int mcc = Integer.parseInt(imsi.substring(0, 3));
596                     mMncLength = MccTable.smallestDigitsMccForMnc(mcc);
597                     log("setting2 mMncLength=" + mMncLength);
598                 } catch (NumberFormatException e) {
599                     loge("Corrupt IMSI! setting3 mMncLength=" + mMncLength);
600                 }
601             }
602 
603             if (mMncLength != UNKNOWN && mMncLength != UNINITIALIZED
604                     && imsi.length() >= 3 + mMncLength) {
605                 log("update mccmnc=" + imsi.substring(0, 3 + mMncLength));
606                 // finally have both the imsi and the mncLength and
607                 // can parse the imsi properly
608                 MccTable.updateMccMncConfiguration(mContext, imsi.substring(0, 3 + mMncLength));
609             }
610         }
611     }
612 
613     /**
614      * Get the Network Access ID (NAI) on a CSIM for CDMA like networks. Default is null if IMSI is
615      * not supported or unavailable.
616      *
617      * @return null if NAI is not yet ready or unavailable
618      */
getNAI()619     public String getNAI() {
620         return null;
621     }
622 
623     @UnsupportedAppUsage
getMsisdnNumber()624     public String getMsisdnNumber() {
625         return mMsisdn;
626     }
627 
628     /**
629      * Get the Group Identifier Level 1 (GID1) on a SIM for GSM.
630      * @return null if SIM is not yet ready
631      */
632     @UnsupportedAppUsage
getGid1()633     public String getGid1() {
634         if (mCarrierTestOverride.isInTestMode() && mCarrierTestOverride.getFakeGid1() != null) {
635             return mCarrierTestOverride.getFakeGid1();
636         } else {
637             return mGid1;
638         }
639     }
640 
641     /**
642      * Get the Group Identifier Level 2 (GID2) on a SIM.
643      * @return null if SIM is not yet ready
644      */
getGid2()645     public String getGid2() {
646         if (mCarrierTestOverride.isInTestMode() && mCarrierTestOverride.getFakeGid2() != null) {
647             return mCarrierTestOverride.getFakeGid2();
648         } else {
649             return mGid2;
650         }
651     }
652 
653     /**
654      * Get the PLMN network name on a SIM.
655      * @return null if SIM is not yet ready
656      */
getPnnHomeName()657     public String getPnnHomeName() {
658         if (mCarrierTestOverride.isInTestMode()
659                 && mCarrierTestOverride.getFakePnnHomeName() != null) {
660             return mCarrierTestOverride.getFakePnnHomeName();
661         } else {
662             return mPnnHomeName;
663         }
664     }
665 
666     @UnsupportedAppUsage
setMsisdnNumber(String alphaTag, String number, Message onComplete)667     public void setMsisdnNumber(String alphaTag, String number,
668             Message onComplete) {
669         loge("setMsisdn() should not be invoked on base IccRecords");
670         // synthesize a "File Not Found" exception and return it
671         AsyncResult.forMessage(onComplete).exception =
672             (new IccIoResult(0x6A, 0x82, (byte[]) null)).getException();
673         onComplete.sendToTarget();
674     }
675 
getMsisdnAlphaTag()676     public String getMsisdnAlphaTag() {
677         return mMsisdnTag;
678     }
679 
getVoiceMailNumber()680     public String getVoiceMailNumber() {
681         return mVoiceMailNum;
682     }
683 
684     /**
685      * Return Service Provider Name stored in SIM (EF_SPN=0x6F46) or in RUIM (EF_RUIM_SPN=0x6F41).
686      *
687      * @return null if SIM is not yet ready or no RUIM entry
688      */
689     @UnsupportedAppUsage
getServiceProviderName()690     public String getServiceProviderName() {
691         if (mCarrierTestOverride.isInTestMode() && mCarrierTestOverride.getFakeSpn() != null) {
692             return mCarrierTestOverride.getFakeSpn();
693         }
694         return mSpn;
695     }
696 
setServiceProviderName(String spn)697     protected void setServiceProviderName(String spn) {
698         if (!TextUtils.equals(mSpn, spn)) {
699             mSpn = spn != null ? spn.trim() : null;
700             mSpnUpdatedRegistrants.notifyRegistrants();
701         }
702     }
703 
704     /**
705      * Set voice mail number to SIM record
706      *
707      * The voice mail number can be stored either in EF_MBDN (TS 51.011) or
708      * EF_MAILBOX_CPHS (CPHS 4.2)
709      *
710      * If EF_MBDN is available, store the voice mail number to EF_MBDN
711      *
712      * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS
713      *
714      * So the voice mail number will be stored in both EFs if both are available
715      *
716      * Return error only if both EF_MBDN and EF_MAILBOX_CPHS fail.
717      *
718      * When the operation is complete, onComplete will be sent to its handler
719      *
720      * @param alphaTag alpha-tagging of the dailing nubmer (upto 10 characters)
721      * @param voiceNumber dailing nubmer (upto 20 digits)
722      *        if the number is start with '+', then set to international TOA
723      * @param onComplete
724      *        onComplete.obj will be an AsyncResult
725      *        ((AsyncResult)onComplete.obj).exception == null on success
726      *        ((AsyncResult)onComplete.obj).exception != null on fail
727      */
setVoiceMailNumber(String alphaTag, String voiceNumber, Message onComplete)728     public abstract void setVoiceMailNumber(String alphaTag, String voiceNumber,
729             Message onComplete);
730 
getVoiceMailAlphaTag()731     public String getVoiceMailAlphaTag() {
732         return mVoiceMailTag;
733     }
734 
735     /**
736      * Sets the SIM voice message waiting indicator records
737      * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
738      * @param countWaiting The number of messages waiting, if known. Use
739      *                     -1 to indicate that an unknown number of
740      *                      messages are waiting
741      */
setVoiceMessageWaiting(int line, int countWaiting)742     public abstract void setVoiceMessageWaiting(int line, int countWaiting);
743 
744     /**
745      * Called by GsmCdmaPhone to update VoiceMail count
746      */
getVoiceMessageCount()747     public abstract int getVoiceMessageCount();
748 
749     /**
750      * Called by STK Service when REFRESH is received.
751      * @param fileChanged indicates whether any files changed
752      * @param fileList if non-null, a list of EF files that changed
753      */
onRefresh(boolean fileChanged, int[] fileList)754     public abstract void onRefresh(boolean fileChanged, int[] fileList);
755 
756     @UnsupportedAppUsage
getRecordsLoaded()757     public boolean getRecordsLoaded() {
758         return mRecordsToLoad == 0 && mRecordsRequested;
759     }
760 
getLockedRecordsLoaded()761     protected boolean getLockedRecordsLoaded() {
762         return mRecordsToLoad == 0
763                 && mLockedRecordsReqReason == LOCKED_RECORDS_REQ_REASON_LOCKED;
764     }
765 
getNetworkLockedRecordsLoaded()766     protected boolean getNetworkLockedRecordsLoaded() {
767         return mRecordsToLoad == 0
768                 && mLockedRecordsReqReason == LOCKED_RECORDS_REQ_REASON_NETWORK_LOCKED;
769     }
770 
771     //***** Overridden from Handler
772     @Override
handleMessage(Message msg)773     public void handleMessage(Message msg) {
774         AsyncResult ar;
775 
776         switch (msg.what) {
777             case EVENT_GET_ICC_RECORD_DONE:
778                 try {
779                     ar = (AsyncResult) msg.obj;
780                     IccRecordLoaded recordLoaded = (IccRecordLoaded) ar.userObj;
781                     if (DBG) log(recordLoaded.getEfName() + " LOADED");
782 
783                     if (ar.exception != null) {
784                         loge("Record Load Exception: " + ar.exception);
785                     } else {
786                         recordLoaded.onRecordLoaded(ar);
787                     }
788                 }catch (RuntimeException exc) {
789                     // I don't want these exceptions to be fatal
790                     loge("Exception parsing SIM record: " + exc);
791                 } finally {
792                     // Count up record load responses even if they are fails
793                     onRecordLoaded();
794                 }
795                 break;
796 
797             case EVENT_REFRESH:
798                 ar = (AsyncResult)msg.obj;
799                 if (DBG) log("Card REFRESH occurred: ");
800                 if (ar.exception == null) {
801                     handleRefresh((IccRefreshResponse)ar.result);
802                 } else {
803                     loge("Icc refresh Exception: " + ar.exception);
804                 }
805                 break;
806 
807             case EVENT_AKA_AUTHENTICATE_DONE:
808                 ar = (AsyncResult)msg.obj;
809                 auth_rsp = null;
810                 if (DBG) log("EVENT_AKA_AUTHENTICATE_DONE");
811                 if (ar.exception != null) {
812                     loge("Exception ICC SIM AKA: " + ar.exception);
813                 } else {
814                     try {
815                         auth_rsp = (IccIoResult)ar.result;
816                         if (DBG) log("ICC SIM AKA: auth_rsp = " + auth_rsp);
817                     } catch (Exception e) {
818                         loge("Failed to parse ICC SIM AKA contents: " + e);
819                     }
820                 }
821                 synchronized (mLock) {
822                     mLock.notifyAll();
823                 }
824 
825                 break;
826 
827             default:
828                 super.handleMessage(msg);
829         }
830     }
831 
832     /**
833      * Returns the SIM language derived from the EF-LI and EF-PL sim records.
834      */
getSimLanguage()835     public String getSimLanguage() {
836         return mPrefLang;
837     }
838 
setSimLanguage(byte[] efLi, byte[] efPl)839     protected void setSimLanguage(byte[] efLi, byte[] efPl) {
840         String[] locales = mContext.getAssets().getLocales();
841         try {
842             mPrefLang = findBestLanguage(efLi, locales);
843         } catch (UnsupportedEncodingException uee) {
844             log("Unable to parse EF-LI: " + Arrays.toString(efLi));
845         }
846 
847         if (mPrefLang == null) {
848             try {
849                 mPrefLang = findBestLanguage(efPl, locales);
850             } catch (UnsupportedEncodingException uee) {
851                 log("Unable to parse EF-PL: " + Arrays.toString(efLi));
852             }
853         }
854     }
855 
findBestLanguage(byte[] languages, String[] locales)856     protected static String findBestLanguage(byte[] languages, String[] locales)
857             throws UnsupportedEncodingException {
858         if ((languages == null) || (locales == null)) return null;
859 
860         // Each 2-bytes consists of one language
861         for (int i = 0; (i + 1) < languages.length; i += 2) {
862             String lang = new String(languages, i, 2, "ISO-8859-1");
863             for (int j = 0; j < locales.length; j++) {
864                 if (locales[j] != null && locales[j].length() >= 2 &&
865                         locales[j].substring(0, 2).equalsIgnoreCase(lang)) {
866                     return lang;
867                 }
868             }
869         }
870 
871         // no match found. return null
872         return null;
873     }
874 
handleFileUpdate(int efid)875     protected abstract void handleFileUpdate(int efid);
876 
877     @UnsupportedAppUsage
handleRefresh(IccRefreshResponse refreshResponse)878     protected void handleRefresh(IccRefreshResponse refreshResponse){
879         if (refreshResponse == null) {
880             if (DBG) log("handleRefresh received without input");
881             return;
882         }
883 
884         if (!TextUtils.isEmpty(refreshResponse.aid) &&
885                 !refreshResponse.aid.equals(mParentApp.getAid())) {
886             // This is for different app. Ignore.
887             return;
888         }
889 
890         switch (refreshResponse.refreshResult) {
891             case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE:
892                 if (DBG) log("handleRefresh with SIM_FILE_UPDATED");
893                 handleFileUpdate(refreshResponse.efId);
894                 break;
895             default:
896                 // unknown refresh operation
897                 if (DBG) log("handleRefresh with unknown operation");
898                 break;
899         }
900     }
901 
onRecordLoaded()902     protected abstract void onRecordLoaded();
903 
onAllRecordsLoaded()904     protected abstract void onAllRecordsLoaded();
905 
906     /**
907      * Retrieves the SPN/PLMN display condition from UICC.
908      *
909      * Display of service provider name is required when registered PLMN is neither HPLMN nor a PLMN
910      * in the service provider PLMN list(EF_SPDI).
911      *
912      * Display of PLMN network name is required when registered PLMN is either HPLMN or a PLMN in
913      * the service provider PLMN list(EF_SPDI).
914      *
915      * Reference: 3GPP TS 131.102 section 4.2.12 EF_SPN Display Condition
916      *
917      * @return a bitmask represent the carrier name display condition.
918      */
919     @CarrierNameDisplayConditionBitmask
getCarrierNameDisplayCondition()920     public int getCarrierNameDisplayCondition() {
921         return mCarrierNameDisplayCondition;
922     }
923 
924     /**
925      * Retrieves the service provider display information. This is a list of PLMNs in which the
926      * service provider name shall be displayed.
927      *
928      * Reference: 3GPP TS 131.102 section 4.2.66 EF_SPDI
929      *
930      * @return a list of PLMN(mcc+mnc) if EF_SPDI is existed, otherwise return null.
931      */
getServiceProviderDisplayInformation()932     public String[] getServiceProviderDisplayInformation() {
933         return mSpdi;
934     }
935 
936     /**
937      * Get home PLMN list.
938      *
939      * @see #getEhplmns()
940      * @see #getServiceProviderDisplayInformation()
941      *
942      * @return a list of HPLMN if existed, otherwise return null.
943      */
getHomePlmns()944     public String[] getHomePlmns() {
945         // hplmn from imsi.
946         String hplmn = getOperatorNumeric();
947 
948         // hplmn from ehplmn list.
949         String[] hplmns = getEhplmns();
950 
951         // plmn from ef_spdi.
952         String[] spdi = getServiceProviderDisplayInformation();
953 
954         // Use the plmn from imsi as the hplmn if Ehplmn not present.
955         if (ArrayUtils.isEmpty(hplmns)) {
956             hplmns = new String[] {hplmn};
957         }
958 
959         if (!ArrayUtils.isEmpty(spdi)) {
960             hplmns = ArrayUtils.concatElements(String.class, hplmns, spdi);
961         }
962         return hplmns;
963     }
964 
965     /**
966      * Return true if "Restriction of menu options for manual PLMN selection"
967      * bit is set or EF_CSP data is unavailable, return false otherwise.
968      * Generally used for GSM/UMTS and the like SIMs.
969      */
isCspPlmnEnabled()970     public boolean isCspPlmnEnabled() {
971         return false;
972     }
973 
974     /**
975      * Returns the 5 or 6 digit MCC/MNC of the operator that
976      * provided the SIM card. Returns null of SIM is not yet ready
977      * or is not valid for the type of IccCard. Generally used for
978      * GSM/UMTS and the like SIMS
979      */
980     @UnsupportedAppUsage
getOperatorNumeric()981     public String getOperatorNumeric() {
982         return null;
983     }
984 
985     /**
986      * Get the current Voice call forwarding flag for GSM/UMTS and the like SIMs
987      *
988      * @return CALL_FORWARDING_STATUS_XXX (DISABLED/ENABLED/UNKNOWN)
989      */
getVoiceCallForwardingFlag()990     public int getVoiceCallForwardingFlag() {
991         return CALL_FORWARDING_STATUS_UNKNOWN;
992     }
993 
994     /**
995      * Set the voice call forwarding flag for GSM/UMTS and the like SIMs
996      *
997      * @param line to enable/disable
998      * @param enable
999      * @param number to which CFU is enabled
1000      */
1001     @UnsupportedAppUsage
setVoiceCallForwardingFlag(int line, boolean enable, String number)1002     public void setVoiceCallForwardingFlag(int line, boolean enable, String number) {
1003     }
1004 
1005     /**
1006      * Indicates wether the ICC records have been loaded or not
1007      *
1008      * @return true if the records have been loaded, false otherwise.
1009      */
isLoaded()1010     public boolean isLoaded() {
1011         return mLoaded.get();
1012     }
1013 
1014     /**
1015      * Indicates wether SIM is in provisioned state or not.
1016      * Overridden only if SIM can be dynamically provisioned via OTA.
1017      *
1018      * @return true if provisioned
1019      */
isProvisioned()1020     public boolean isProvisioned () {
1021         return true;
1022     }
1023 
1024     /**
1025      * Write string to log file
1026      *
1027      * @param s is the string to write
1028      */
1029     @UnsupportedAppUsage
log(String s)1030     protected abstract void log(String s);
1031 
1032     /**
1033      * Write error string to log file.
1034      *
1035      * @param s is the string to write
1036      */
loge(String s)1037     protected abstract void loge(String s);
1038 
1039     /**
1040      * @return String array containing EHPLMNs associated with the card.
1041      */
getEhplmns()1042     public String[] getEhplmns() {
1043         return mEhplmns;
1044     }
1045 
1046     /**
1047      * @return String array containing PLMN from HplmnActRecord.
1048      */
getPlmnsFromHplmnActRecord()1049     public String[] getPlmnsFromHplmnActRecord() {
1050         if (mHplmnActRecords == null) return null;
1051         String[] hplmns = new String[mHplmnActRecords.length];
1052         for (int i = 0; i < mHplmnActRecords.length; i++) {
1053             hplmns[i] = mHplmnActRecords[i].plmn;
1054         }
1055         return hplmns;
1056     }
1057 
1058     /**
1059      * Return an interface to retrieve the ISIM records for IMS, if available.
1060      * @return the interface to retrieve the ISIM records, or null if not supported
1061      */
getIsimRecords()1062     public IsimRecords getIsimRecords() {
1063         return null;
1064     }
1065 
1066     @UnsupportedAppUsage
getUsimServiceTable()1067     public UsimServiceTable getUsimServiceTable() {
1068         return null;
1069     }
1070 
setSystemProperty(String key, String val)1071     protected void setSystemProperty(String key, String val) {
1072         TelephonyManager.getDefault().setTelephonyProperty(mParentApp.getPhoneId(), key, val);
1073 
1074         log("[key, value]=" + key + ", " +  val);
1075     }
1076 
1077     /**
1078      * Returns the response of the SIM application on the UICC to authentication
1079      * challenge/response algorithm. The data string and challenge response are
1080      * Base64 encoded Strings.
1081      * Can support EAP-SIM, EAP-AKA with results encoded per 3GPP TS 31.102.
1082      *
1083      * @param authContext parameter P2 that specifies the authentication context per 3GPP TS 31.102 (Section 7.1.2)
1084      * @param data authentication challenge data
1085      * @return challenge response
1086      */
1087     @UnsupportedAppUsage
getIccSimChallengeResponse(int authContext, String data)1088     public String getIccSimChallengeResponse(int authContext, String data) {
1089         if (DBG) log("getIccSimChallengeResponse:");
1090 
1091         try {
1092             synchronized(mLock) {
1093                 CommandsInterface ci = mCi;
1094                 UiccCardApplication parentApp = mParentApp;
1095                 if (ci != null && parentApp != null) {
1096                     ci.requestIccSimAuthentication(authContext, data,
1097                             parentApp.getAid(),
1098                             obtainMessage(EVENT_AKA_AUTHENTICATE_DONE));
1099                     try {
1100                         mLock.wait();
1101                     } catch (InterruptedException e) {
1102                         loge("getIccSimChallengeResponse: Fail, interrupted"
1103                                 + " while trying to request Icc Sim Auth");
1104                         return null;
1105                     }
1106                 } else {
1107                     loge( "getIccSimChallengeResponse: "
1108                             + "Fail, ci or parentApp is null");
1109                     return null;
1110                 }
1111             }
1112         } catch(Exception e) {
1113             loge( "getIccSimChallengeResponse: "
1114                     + "Fail while trying to request Icc Sim Auth");
1115             return null;
1116         }
1117 
1118         if (auth_rsp == null) {
1119             loge("getIccSimChallengeResponse: No authentication response");
1120             return null;
1121         }
1122 
1123         if (DBG) log("getIccSimChallengeResponse: return auth_rsp");
1124 
1125         return android.util.Base64.encodeToString(auth_rsp.payload, android.util.Base64.NO_WRAP);
1126     }
1127 
1128     /**
1129      * Convert the spn display condition to a bitmask
1130      * {@link com.android.internal.telephony.uicc.IccRecords.CarrierNameDisplayConditionBitmask}.
1131      *
1132      * b1 is the last bit of the display condition which is used to determine whether display of
1133      * PLMN network name is required when registered PLMN is **either** HPLMN or a PLMN in the
1134      * service provider PLMN list.
1135      *
1136      * b2 is the second last bit of the display condtion which is used to determine
1137      * whether display of Service Provider Name is required when registered PLMN is
1138      * **neither** HPLMN nor PLMN in the service provider PLMN list.
1139      *
1140      * Reference: 3GPP TS 31.102 section 4.2.12 EF_SPN
1141      *
1142      * @return a carrier name display condtion bitmask.
1143      */
1144     @CarrierNameDisplayConditionBitmask
convertSpnDisplayConditionToBitmask(int condition)1145     public static int convertSpnDisplayConditionToBitmask(int condition) {
1146         int carrierNameDisplayCondition = 0;
1147         // b1 = 0: display of registered PLMN name not required when registered PLMN is
1148         // either HPLMN or a PLMN in the service provider PLMN list.
1149         // b1 = 1: display of registered PLMN name required when registered PLMN is
1150         // either HPLMN or a PLMN in the service provider PLMN list.
1151         if ((condition & 0x1) == 0x1) {
1152             carrierNameDisplayCondition |= CARRIER_NAME_DISPLAY_CONDITION_BITMASK_PLMN;
1153         }
1154 
1155         // b2 = 0: display of the service provider name is **required** when registered
1156         // PLMN is neither HPLMN nor a PLMN in the service provider PLMN list.
1157         // b2 = 1: display of the servier provider name is **not required** when
1158         // registered PLMN is neither HPLMN nor PLMN in the service provider PLMN list.
1159         if ((condition & 0x2) == 0) {
1160             carrierNameDisplayCondition |= CARRIER_NAME_DISPLAY_CONDITION_BITMASK_SPN;
1161         }
1162 
1163         return carrierNameDisplayCondition;
1164     }
1165 
dump(FileDescriptor fd, PrintWriter pw, String[] args)1166     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1167         pw.println("IccRecords: " + this);
1168         pw.println(" mDestroyed=" + mDestroyed);
1169         pw.println(" mCi=" + mCi);
1170         pw.println(" mFh=" + mFh);
1171         pw.println(" mParentApp=" + mParentApp);
1172         pw.println(" recordsLoadedRegistrants: size=" + mRecordsLoadedRegistrants.size());
1173         for (int i = 0; i < mRecordsLoadedRegistrants.size(); i++) {
1174             pw.println("  recordsLoadedRegistrants[" + i + "]="
1175                     + ((Registrant)mRecordsLoadedRegistrants.get(i)).getHandler());
1176         }
1177         pw.println(" mLockedRecordsLoadedRegistrants: size="
1178                 + mLockedRecordsLoadedRegistrants.size());
1179         for (int i = 0; i < mLockedRecordsLoadedRegistrants.size(); i++) {
1180             pw.println("  mLockedRecordsLoadedRegistrants[" + i + "]="
1181                     + ((Registrant) mLockedRecordsLoadedRegistrants.get(i)).getHandler());
1182         }
1183         pw.println(" mNetworkLockedRecordsLoadedRegistrants: size="
1184                 + mNetworkLockedRecordsLoadedRegistrants.size());
1185         for (int i = 0; i < mNetworkLockedRecordsLoadedRegistrants.size(); i++) {
1186             pw.println("  mLockedRecordsLoadedRegistrants[" + i + "]="
1187                     + ((Registrant) mNetworkLockedRecordsLoadedRegistrants.get(i)).getHandler());
1188         }
1189         pw.println(" mImsiReadyRegistrants: size=" + mImsiReadyRegistrants.size());
1190         for (int i = 0; i < mImsiReadyRegistrants.size(); i++) {
1191             pw.println("  mImsiReadyRegistrants[" + i + "]="
1192                     + ((Registrant)mImsiReadyRegistrants.get(i)).getHandler());
1193         }
1194         pw.println(" mRecordsEventsRegistrants: size=" + mRecordsEventsRegistrants.size());
1195         for (int i = 0; i < mRecordsEventsRegistrants.size(); i++) {
1196             pw.println("  mRecordsEventsRegistrants[" + i + "]="
1197                     + ((Registrant)mRecordsEventsRegistrants.get(i)).getHandler());
1198         }
1199         pw.println(" mNewSmsRegistrants: size=" + mNewSmsRegistrants.size());
1200         for (int i = 0; i < mNewSmsRegistrants.size(); i++) {
1201             pw.println("  mNewSmsRegistrants[" + i + "]="
1202                     + ((Registrant)mNewSmsRegistrants.get(i)).getHandler());
1203         }
1204         pw.println(" mNetworkSelectionModeAutomaticRegistrants: size="
1205                 + mNetworkSelectionModeAutomaticRegistrants.size());
1206         for (int i = 0; i < mNetworkSelectionModeAutomaticRegistrants.size(); i++) {
1207             pw.println("  mNetworkSelectionModeAutomaticRegistrants[" + i + "]="
1208                     + ((Registrant)mNetworkSelectionModeAutomaticRegistrants.get(i)).getHandler());
1209         }
1210         pw.println(" mRecordsRequested=" + mRecordsRequested);
1211         pw.println(" mLockedRecordsReqReason=" + mLockedRecordsReqReason);
1212         pw.println(" mRecordsToLoad=" + mRecordsToLoad);
1213         pw.println(" mRdnCache=" + mAdnCache);
1214 
1215         String iccIdToPrint = SubscriptionInfo.givePrintableIccid(mFullIccId);
1216         pw.println(" iccid=" + iccIdToPrint);
1217         pw.println(" mMsisdn=" + Rlog.pii(VDBG, mMsisdn));
1218         pw.println(" mMsisdnTag=" + mMsisdnTag);
1219         pw.println(" mVoiceMailNum=" + Rlog.pii(VDBG, mVoiceMailNum));
1220         pw.println(" mVoiceMailTag=" + mVoiceMailTag);
1221         pw.println(" mNewVoiceMailNum=" + Rlog.pii(VDBG, mNewVoiceMailNum));
1222         pw.println(" mNewVoiceMailTag=" + mNewVoiceMailTag);
1223         pw.println(" mIsVoiceMailFixed=" + mIsVoiceMailFixed);
1224         pw.println(" mImsi=" + ((mImsi != null) ?
1225                 mImsi.substring(0, 6) + Rlog.pii(VDBG, mImsi.substring(6)) : "null"));
1226         if (mCarrierTestOverride.isInTestMode()) {
1227             pw.println(" mFakeImsi=" + mCarrierTestOverride.getFakeIMSI());
1228         }
1229         pw.println(" mMncLength=" + mMncLength);
1230         pw.println(" mMailboxIndex=" + mMailboxIndex);
1231         pw.println(" mSpn=" + mSpn);
1232         if (mCarrierTestOverride.isInTestMode()) {
1233             pw.println(" mFakeSpn=" + mCarrierTestOverride.getFakeSpn());
1234         }
1235         pw.flush();
1236     }
1237 
1238     /**
1239      * Operator PLMN information. This contains the location area information or tracking area
1240      * that are used to associate a specific name contained in EF_PNN.
1241      *
1242      * Reference: 3GPP TS 31.102 section 4.2.59 EF_OPL
1243      */
1244     public static final class OperatorPlmnInfo {
1245         // PLMN numeric that may contains wildcard character ".".
1246         // For example, the pattern "123..." could match all PLMN which mcc is 123.
1247         public final String plmnNumericPattern;
1248 
1249         public final int lacTacStart;
1250         public final int lacTacEnd;
1251 
1252         public final int plmnNetworkNameIndex;
OperatorPlmnInfo(String plmnNumericPattern, int lacTacStart, int lacTacEnd, int plmnNetworkNameIndex)1253         public OperatorPlmnInfo(String plmnNumericPattern, int lacTacStart, int lacTacEnd,
1254                                 int plmnNetworkNameIndex) {
1255             this.plmnNumericPattern = plmnNumericPattern;
1256             this.lacTacStart = lacTacStart;
1257             this.lacTacEnd = lacTacEnd;
1258             this.plmnNetworkNameIndex = plmnNetworkNameIndex;
1259         }
1260 
1261         @Override
toString()1262         public String toString() {
1263             return "{ plmnNumericPattern = " + plmnNumericPattern
1264                     + "lacTacStart = " + lacTacStart
1265                     + "lacTacEnd = " + lacTacEnd
1266                     + "plmnNetworkNameIndex = " + plmnNetworkNameIndex
1267                     + " }";
1268         }
1269     }
1270 
1271     /**
1272      * Full and short version of PLMN network name.
1273      */
1274     public static final class PlmnNetworkName {
1275         public final String fullName;
1276         public final String shortName;
1277 
PlmnNetworkName(String fullName, String shortName)1278         public PlmnNetworkName(String fullName, String shortName) {
1279             this.fullName = fullName;
1280             this.shortName = shortName;
1281         }
1282 
1283         @Override
toString()1284         public String toString() {
1285             return "{ fullName = " + fullName + " shortName = " + shortName + " }";
1286         }
1287     }
1288 }
1289