UiccCard.java revision 062a2a3838c8d8adf16f4d9fbde8d52450da0336
1/*
2 * Copyright (C) 2006, 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.telephony.uicc;
18
19import static android.Manifest.permission.READ_PHONE_STATE;
20import android.app.ActivityManagerNative;
21import android.app.AlertDialog;
22import android.content.Context;
23import android.content.DialogInterface;
24import android.content.Intent;
25import android.content.SharedPreferences;
26import android.content.pm.PackageManager;
27import android.content.pm.Signature;
28import android.content.res.Resources;
29import android.os.AsyncResult;
30import android.os.Handler;
31import android.os.Message;
32import android.os.PowerManager;
33import android.os.Registrant;
34import android.os.RegistrantList;
35import android.preference.PreferenceManager;
36import android.telephony.Rlog;
37import android.telephony.TelephonyManager;
38import android.text.TextUtils;
39import android.view.WindowManager;
40
41import com.android.internal.telephony.CommandsInterface;
42import com.android.internal.telephony.PhoneBase;
43import com.android.internal.telephony.CommandsInterface.RadioState;
44import com.android.internal.telephony.IccCardConstants.State;
45import com.android.internal.telephony.gsm.GSMPhone;
46import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
47import com.android.internal.telephony.uicc.IccCardStatus.CardState;
48import com.android.internal.telephony.uicc.IccCardStatus.PinState;
49import com.android.internal.telephony.cat.CatService;
50import com.android.internal.telephony.cdma.CDMALTEPhone;
51import com.android.internal.telephony.cdma.CDMAPhone;
52import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
53
54import android.os.SystemProperties;
55
56import com.android.internal.R;
57
58import java.io.FileDescriptor;
59import java.io.PrintWriter;
60import java.util.List;
61
62/**
63 * {@hide}
64 */
65public class UiccCard {
66    protected static final String LOG_TAG = "UiccCard";
67    protected static final boolean DBG = true;
68
69    private static final String OPERATOR_BRAND_OVERRIDE_PREFIX = "operator_branding_";
70
71    private final Object mLock = new Object();
72    private CardState mCardState;
73    private PinState mUniversalPinState;
74    private int mGsmUmtsSubscriptionAppIndex;
75    private int mCdmaSubscriptionAppIndex;
76    private int mImsSubscriptionAppIndex;
77    private UiccCardApplication[] mUiccApplications =
78            new UiccCardApplication[IccCardStatus.CARD_MAX_APPS];
79    private Context mContext;
80    private CommandsInterface mCi;
81    private CatService mCatService;
82    private RadioState mLastRadioState =  RadioState.RADIO_UNAVAILABLE;
83    private UiccCarrierPrivilegeRules mCarrierPrivilegeRules;
84
85    private RegistrantList mAbsentRegistrants = new RegistrantList();
86    private RegistrantList mCarrierPrivilegeRegistrants = new RegistrantList();
87
88    private static final int EVENT_CARD_REMOVED = 13;
89    private static final int EVENT_CARD_ADDED = 14;
90    private static final int EVENT_OPEN_LOGICAL_CHANNEL_DONE = 15;
91    private static final int EVENT_CLOSE_LOGICAL_CHANNEL_DONE = 16;
92    private static final int EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE = 17;
93    private static final int EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE = 18;
94    private static final int EVENT_SIM_IO_DONE = 19;
95    private static final int EVENT_CARRIER_PRIVILIGES_LOADED = 20;
96
97    private int mPhoneId;
98
99    public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics) {
100        if (DBG) log("Creating");
101        mCardState = ics.mCardState;
102        update(c, ci, ics);
103    }
104
105    public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId) {
106        mCardState = ics.mCardState;
107        mPhoneId = phoneId;
108        update(c, ci, ics);
109    }
110
111    protected UiccCard() {
112    }
113
114    public void dispose() {
115        synchronized (mLock) {
116            if (DBG) log("Disposing card");
117            if (mCatService != null) mCatService.dispose();
118            for (UiccCardApplication app : mUiccApplications) {
119                if (app != null) {
120                    app.dispose();
121                }
122            }
123            mCatService = null;
124            mUiccApplications = null;
125            mCarrierPrivilegeRules = null;
126        }
127    }
128
129    public void update(Context c, CommandsInterface ci, IccCardStatus ics) {
130        synchronized (mLock) {
131            CardState oldState = mCardState;
132            mCardState = ics.mCardState;
133            mUniversalPinState = ics.mUniversalPinState;
134            mGsmUmtsSubscriptionAppIndex = ics.mGsmUmtsSubscriptionAppIndex;
135            mCdmaSubscriptionAppIndex = ics.mCdmaSubscriptionAppIndex;
136            mImsSubscriptionAppIndex = ics.mImsSubscriptionAppIndex;
137            mContext = c;
138            mCi = ci;
139
140            //update applications
141            if (DBG) log(ics.mApplications.length + " applications");
142            for ( int i = 0; i < mUiccApplications.length; i++) {
143                if (mUiccApplications[i] == null) {
144                    //Create newly added Applications
145                    if (i < ics.mApplications.length) {
146                        mUiccApplications[i] = new UiccCardApplication(this,
147                                ics.mApplications[i], mContext, mCi);
148                    }
149                } else if (i >= ics.mApplications.length) {
150                    //Delete removed applications
151                    mUiccApplications[i].dispose();
152                    mUiccApplications[i] = null;
153                } else {
154                    //Update the rest
155                    mUiccApplications[i].update(ics.mApplications[i], mContext, mCi);
156                }
157            }
158
159            createAndUpdateCatService();
160
161            // Reload the carrier privilege rules if necessary.
162            log("Before privilege rules: " + mCarrierPrivilegeRules + " : " + mCardState);
163            if (mCarrierPrivilegeRules == null && mCardState == CardState.CARDSTATE_PRESENT) {
164                mCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(this,
165                        mHandler.obtainMessage(EVENT_CARRIER_PRIVILIGES_LOADED));
166            } else if (mCarrierPrivilegeRules != null && mCardState != CardState.CARDSTATE_PRESENT) {
167                mCarrierPrivilegeRules = null;
168            }
169
170            sanitizeApplicationIndexes();
171
172            RadioState radioState = mCi.getRadioState();
173            if (DBG) log("update: radioState=" + radioState + " mLastRadioState="
174                    + mLastRadioState);
175            // No notifications while radio is off or we just powering up
176            if (radioState == RadioState.RADIO_ON && mLastRadioState == RadioState.RADIO_ON) {
177                if (oldState != CardState.CARDSTATE_ABSENT &&
178                        mCardState == CardState.CARDSTATE_ABSENT) {
179                    if (DBG) log("update: notify card removed");
180                    mAbsentRegistrants.notifyRegistrants();
181                    mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_REMOVED, null));
182                } else if (oldState == CardState.CARDSTATE_ABSENT &&
183                        mCardState != CardState.CARDSTATE_ABSENT) {
184                    if (DBG) log("update: notify card added");
185                    mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_ADDED, null));
186                }
187            }
188            mLastRadioState = radioState;
189        }
190    }
191
192    protected void createAndUpdateCatService() {
193        if (mUiccApplications.length > 0 && mUiccApplications[0] != null) {
194            // Initialize or Reinitialize CatService
195            if (mCatService == null) {
196                mCatService = CatService.getInstance(mCi, mContext, this, mPhoneId);
197            } else {
198                ((CatService)mCatService).update(mCi, mContext, this);
199            }
200        } else {
201            if (mCatService != null) {
202                mCatService.dispose();
203            }
204            mCatService = null;
205        }
206    }
207
208    public CatService getCatService() {
209        return mCatService;
210    }
211
212    @Override
213    protected void finalize() {
214        if (DBG) log("UiccCard finalized");
215    }
216
217    /**
218     * This function makes sure that application indexes are valid
219     * and resets invalid indexes. (This should never happen, but in case
220     * RIL misbehaves we need to manage situation gracefully)
221     */
222    private void sanitizeApplicationIndexes() {
223        mGsmUmtsSubscriptionAppIndex =
224                checkIndex(mGsmUmtsSubscriptionAppIndex, AppType.APPTYPE_SIM, AppType.APPTYPE_USIM);
225        mCdmaSubscriptionAppIndex =
226                checkIndex(mCdmaSubscriptionAppIndex, AppType.APPTYPE_RUIM, AppType.APPTYPE_CSIM);
227        mImsSubscriptionAppIndex =
228                checkIndex(mImsSubscriptionAppIndex, AppType.APPTYPE_ISIM, null);
229    }
230
231    private int checkIndex(int index, AppType expectedAppType, AppType altExpectedAppType) {
232        if (mUiccApplications == null || index >= mUiccApplications.length) {
233            loge("App index " + index + " is invalid since there are no applications");
234            return -1;
235        }
236
237        if (index < 0) {
238            // This is normal. (i.e. no application of this type)
239            return -1;
240        }
241
242        if (mUiccApplications[index].getType() != expectedAppType &&
243            mUiccApplications[index].getType() != altExpectedAppType) {
244            loge("App index " + index + " is invalid since it's not " +
245                    expectedAppType + " and not " + altExpectedAppType);
246            return -1;
247        }
248
249        // Seems to be valid
250        return index;
251    }
252
253    /**
254     * Notifies handler of any transition into State.ABSENT
255     */
256    public void registerForAbsent(Handler h, int what, Object obj) {
257        synchronized (mLock) {
258            Registrant r = new Registrant (h, what, obj);
259
260            mAbsentRegistrants.add(r);
261
262            if (mCardState == CardState.CARDSTATE_ABSENT) {
263                r.notifyRegistrant();
264            }
265        }
266    }
267
268    public void unregisterForAbsent(Handler h) {
269        synchronized (mLock) {
270            mAbsentRegistrants.remove(h);
271        }
272    }
273
274    /**
275     * Notifies handler when carrier privilege rules are loaded.
276     */
277    public void registerForCarrierPrivilegeRulesLoaded(Handler h, int what, Object obj) {
278        synchronized (mLock) {
279            Registrant r = new Registrant (h, what, obj);
280
281            mCarrierPrivilegeRegistrants.add(r);
282
283            if (areCarrierPriviligeRulesLoaded()) {
284                r.notifyRegistrant();
285            }
286        }
287    }
288
289    public void unregisterForCarrierPrivilegeRulesLoaded(Handler h) {
290        synchronized (mLock) {
291            mCarrierPrivilegeRegistrants.remove(h);
292        }
293    }
294
295    private void onIccSwap(boolean isAdded) {
296
297        boolean isHotSwapSupported = mContext.getResources().getBoolean(
298                com.android.internal.R.bool.config_hotswapCapable);
299
300        if (isHotSwapSupported) {
301            log("onIccSwap: isHotSwapSupported is true, don't prompt for rebooting");
302            return;
303        }
304        log("onIccSwap: isHotSwapSupported is false, prompt for rebooting");
305
306        synchronized (mLock) {
307            // TODO: Here we assume the device can't handle SIM hot-swap
308            //      and has to reboot. We may want to add a property,
309            //      e.g. REBOOT_ON_SIM_SWAP, to indicate if modem support
310            //      hot-swap.
311            DialogInterface.OnClickListener listener = null;
312
313
314            // TODO: SimRecords is not reset while SIM ABSENT (only reset while
315            //       Radio_off_or_not_available). Have to reset in both both
316            //       added or removed situation.
317            listener = new DialogInterface.OnClickListener() {
318                @Override
319                public void onClick(DialogInterface dialog, int which) {
320                    synchronized (mLock) {
321                        if (which == DialogInterface.BUTTON_POSITIVE) {
322                            if (DBG) log("Reboot due to SIM swap");
323                            PowerManager pm = (PowerManager) mContext
324                                    .getSystemService(Context.POWER_SERVICE);
325                            pm.reboot("SIM is added.");
326                        }
327                    }
328                }
329
330            };
331
332            Resources r = Resources.getSystem();
333
334            String title = (isAdded) ? r.getString(R.string.sim_added_title) :
335                r.getString(R.string.sim_removed_title);
336            String message = (isAdded) ? r.getString(R.string.sim_added_message) :
337                r.getString(R.string.sim_removed_message);
338            String buttonTxt = r.getString(R.string.sim_restart_button);
339
340            AlertDialog dialog = new AlertDialog.Builder(mContext)
341            .setTitle(title)
342            .setMessage(message)
343            .setPositiveButton(buttonTxt, listener)
344            .create();
345            dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
346            dialog.show();
347        }
348    }
349
350    protected Handler mHandler = new Handler() {
351        @Override
352        public void handleMessage(Message msg){
353            switch (msg.what) {
354                case EVENT_CARD_REMOVED:
355                    onIccSwap(false);
356                    break;
357                case EVENT_CARD_ADDED:
358                    onIccSwap(true);
359                    break;
360                case EVENT_OPEN_LOGICAL_CHANNEL_DONE:
361                case EVENT_CLOSE_LOGICAL_CHANNEL_DONE:
362                case EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE:
363                case EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE:
364                case EVENT_SIM_IO_DONE:
365                    AsyncResult ar = (AsyncResult)msg.obj;
366                    if (ar.exception != null) {
367                       if (DBG)
368                         log("Error in SIM access with exception" + ar.exception);
369                    }
370                    AsyncResult.forMessage((Message)ar.userObj, ar.result, ar.exception);
371                    ((Message)ar.userObj).sendToTarget();
372                    break;
373                case EVENT_CARRIER_PRIVILIGES_LOADED:
374                    onCarrierPriviligesLoadedMessage();
375                    break;
376                default:
377                    loge("Unknown Event " + msg.what);
378            }
379        }
380    };
381
382    private void onCarrierPriviligesLoadedMessage() {
383        synchronized (mLock) {
384            mCarrierPrivilegeRegistrants.notifyRegistrants();
385        }
386    }
387
388    public boolean isApplicationOnIcc(IccCardApplicationStatus.AppType type) {
389        synchronized (mLock) {
390            for (int i = 0 ; i < mUiccApplications.length; i++) {
391                if (mUiccApplications[i] != null && mUiccApplications[i].getType() == type) {
392                    return true;
393                }
394            }
395            return false;
396        }
397    }
398
399    public CardState getCardState() {
400        synchronized (mLock) {
401            return mCardState;
402        }
403    }
404
405    public PinState getUniversalPinState() {
406        synchronized (mLock) {
407            return mUniversalPinState;
408        }
409    }
410
411    public UiccCardApplication getApplication(int family) {
412        synchronized (mLock) {
413            int index = IccCardStatus.CARD_MAX_APPS;
414            switch (family) {
415                case UiccController.APP_FAM_3GPP:
416                    index = mGsmUmtsSubscriptionAppIndex;
417                    break;
418                case UiccController.APP_FAM_3GPP2:
419                    index = mCdmaSubscriptionAppIndex;
420                    break;
421                case UiccController.APP_FAM_IMS:
422                    index = mImsSubscriptionAppIndex;
423                    break;
424            }
425            if (index >= 0 && index < mUiccApplications.length) {
426                return mUiccApplications[index];
427            }
428            return null;
429        }
430    }
431
432    public UiccCardApplication getApplicationIndex(int index) {
433        synchronized (mLock) {
434            if (index >= 0 && index < mUiccApplications.length) {
435                return mUiccApplications[index];
436            }
437            return null;
438        }
439    }
440
441    /**
442     * Returns the SIM application of the specified type.
443     *
444     * @param type ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
445     * @return application corresponding to type or a null if no match found
446     */
447    public UiccCardApplication getApplicationByType(int type) {
448        synchronized (mLock) {
449            for (int i = 0 ; i < mUiccApplications.length; i++) {
450                if (mUiccApplications[i] != null &&
451                        mUiccApplications[i].getType().ordinal() == type) {
452                    return mUiccApplications[i];
453                }
454            }
455            return null;
456        }
457    }
458
459    /**
460     * Resets the application with the input AID. Returns true if any changes were made.
461     */
462    public boolean resetAppWithAid(String aid) {
463        synchronized (mLock) {
464            for (int i = 0; i < mUiccApplications.length; i++) {
465                if (mUiccApplications[i] != null && aid.equals(mUiccApplications[i].getAid())) {
466                    // Delete removed applications
467                    mUiccApplications[i].dispose();
468                    mUiccApplications[i] = null;
469                    return true;
470                }
471            }
472            return false;
473        }
474    }
475
476    /**
477     * Exposes {@link CommandsInterface.iccOpenLogicalChannel}
478     */
479    public void iccOpenLogicalChannel(String AID, Message response) {
480        mCi.iccOpenLogicalChannel(AID,
481                mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, response));
482    }
483
484    /**
485     * Exposes {@link CommandsInterface.iccCloseLogicalChannel}
486     */
487    public void iccCloseLogicalChannel(int channel, Message response) {
488        mCi.iccCloseLogicalChannel(channel,
489                mHandler.obtainMessage(EVENT_CLOSE_LOGICAL_CHANNEL_DONE, response));
490    }
491
492    /**
493     * Exposes {@link CommandsInterface.iccTransmitApduLogicalChannel}
494     */
495    public void iccTransmitApduLogicalChannel(int channel, int cla, int command,
496            int p1, int p2, int p3, String data, Message response) {
497        mCi.iccTransmitApduLogicalChannel(channel, cla, command, p1, p2, p3,
498                data, mHandler.obtainMessage(EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE, response));
499    }
500
501    /**
502     * Exposes {@link CommandsInterface.iccTransmitApduBasicChannel}
503     */
504    public void iccTransmitApduBasicChannel(int cla, int command,
505            int p1, int p2, int p3, String data, Message response) {
506        mCi.iccTransmitApduBasicChannel(cla, command, p1, p2, p3,
507                data, mHandler.obtainMessage(EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE, response));
508    }
509
510    /**
511     * Exposes {@link CommandsInterface.iccIO}
512     */
513    public void iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
514            String pathID, Message response) {
515        mCi.iccIO(command, fileID, pathID, p1, p2, p3, null, null,
516                mHandler.obtainMessage(EVENT_SIM_IO_DONE, response));
517    }
518
519    /**
520     * Exposes {@link CommandsInterface.sendEnvelopeWithStatus}
521     */
522    public void sendEnvelopeWithStatus(String contents, Message response) {
523        mCi.sendEnvelopeWithStatus(contents, response);
524    }
525
526    /* Returns number of applications on this card */
527    public int getNumApplications() {
528        int count = 0;
529        for (UiccCardApplication a : mUiccApplications) {
530            if (a != null) {
531                count++;
532            }
533        }
534        return count;
535    }
536
537    public int getPhoneId() {
538        return mPhoneId;
539    }
540
541    /**
542     * Returns true iff carrier priveleges rules are null (dont need to be loaded) or loaded.
543     */
544    public boolean areCarrierPriviligeRulesLoaded() {
545        return mCarrierPrivilegeRules == null
546            || mCarrierPrivilegeRules.areCarrierPriviligeRulesLoaded();
547    }
548
549    /**
550     * Exposes {@link UiccCarrierPrivilegeRules.getCarrierPrivilegeStatus}.
551     */
552    public int getCarrierPrivilegeStatus(Signature signature, String packageName) {
553        return mCarrierPrivilegeRules == null ?
554            TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED :
555            mCarrierPrivilegeRules.getCarrierPrivilegeStatus(signature, packageName);
556    }
557
558    /**
559     * Exposes {@link UiccCarrierPrivilegeRules.getCarrierPrivilegeStatus}.
560     */
561    public int getCarrierPrivilegeStatus(PackageManager packageManager, String packageName) {
562        return mCarrierPrivilegeRules == null ?
563            TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED :
564            mCarrierPrivilegeRules.getCarrierPrivilegeStatus(packageManager, packageName);
565    }
566
567    /**
568     * Exposes {@link UiccCarrierPrivilegeRules.getCarrierPrivilegeStatusForCurrentTransaction}.
569     */
570    public int getCarrierPrivilegeStatusForCurrentTransaction(PackageManager packageManager) {
571        return mCarrierPrivilegeRules == null ?
572            TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED :
573            mCarrierPrivilegeRules.getCarrierPrivilegeStatusForCurrentTransaction(packageManager);
574    }
575
576    /**
577     * Exposes {@link UiccCarrierPrivilegeRules.getCarrierPackageNamesForIntent}.
578     */
579    public List<String> getCarrierPackageNamesForIntent(
580            PackageManager packageManager, Intent intent) {
581        return mCarrierPrivilegeRules == null ? null :
582            mCarrierPrivilegeRules.getCarrierPackageNamesForIntent(
583                    packageManager, intent);
584    }
585
586    public boolean setOperatorBrandOverride(String brand) {
587        log("setOperatorBrandOverride: " + brand);
588        log("current iccId: " + getIccId());
589
590        String iccId = getIccId();
591        if (TextUtils.isEmpty(iccId)) {
592            return false;
593        }
594
595        SharedPreferences.Editor spEditor =
596                PreferenceManager.getDefaultSharedPreferences(mContext).edit();
597        String key = OPERATOR_BRAND_OVERRIDE_PREFIX + iccId;
598        if (brand == null) {
599            spEditor.remove(key).commit();
600        } else {
601            spEditor.putString(key, brand).commit();
602        }
603        return true;
604    }
605
606    public String getOperatorBrandOverride() {
607        String iccId = getIccId();
608        if (TextUtils.isEmpty(iccId)) {
609            return null;
610        }
611        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
612        return sp.getString(OPERATOR_BRAND_OVERRIDE_PREFIX + iccId, null);
613    }
614
615    public String getIccId() {
616        // ICCID should be same across all the apps.
617        for (UiccCardApplication app : mUiccApplications) {
618            if (app != null) {
619                IccRecords ir = app.getIccRecords();
620                if (ir != null && ir.getIccId() != null) {
621                    return ir.getIccId();
622                }
623            }
624        }
625        return null;
626    }
627
628    private void log(String msg) {
629        Rlog.d(LOG_TAG, msg);
630    }
631
632    private void loge(String msg) {
633        Rlog.e(LOG_TAG, msg);
634    }
635
636    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
637        pw.println("UiccCard:");
638        pw.println(" mCi=" + mCi);
639        pw.println(" mLastRadioState=" + mLastRadioState);
640        pw.println(" mCatService=" + mCatService);
641        pw.println(" mAbsentRegistrants: size=" + mAbsentRegistrants.size());
642        for (int i = 0; i < mAbsentRegistrants.size(); i++) {
643            pw.println("  mAbsentRegistrants[" + i + "]="
644                    + ((Registrant)mAbsentRegistrants.get(i)).getHandler());
645        }
646        for (int i = 0; i < mCarrierPrivilegeRegistrants.size(); i++) {
647            pw.println("  mCarrierPrivilegeRegistrants[" + i + "]="
648                    + ((Registrant)mCarrierPrivilegeRegistrants.get(i)).getHandler());
649        }
650        pw.println(" mCardState=" + mCardState);
651        pw.println(" mUniversalPinState=" + mUniversalPinState);
652        pw.println(" mGsmUmtsSubscriptionAppIndex=" + mGsmUmtsSubscriptionAppIndex);
653        pw.println(" mCdmaSubscriptionAppIndex=" + mCdmaSubscriptionAppIndex);
654        pw.println(" mImsSubscriptionAppIndex=" + mImsSubscriptionAppIndex);
655        pw.println(" mImsSubscriptionAppIndex=" + mImsSubscriptionAppIndex);
656        pw.println(" mUiccApplications: length=" + mUiccApplications.length);
657        for (int i = 0; i < mUiccApplications.length; i++) {
658            if (mUiccApplications[i] == null) {
659                pw.println("  mUiccApplications[" + i + "]=" + null);
660            } else {
661                pw.println("  mUiccApplications[" + i + "]="
662                        + mUiccApplications[i].getType() + " " + mUiccApplications[i]);
663            }
664        }
665        pw.println();
666        // Print details of all applications
667        for (UiccCardApplication app : mUiccApplications) {
668            if (app != null) {
669                app.dump(fd, pw, args);
670                pw.println();
671            }
672        }
673        // Print details of all IccRecords
674        for (UiccCardApplication app : mUiccApplications) {
675            if (app != null) {
676                IccRecords ir = app.getIccRecords();
677                if (ir != null) {
678                    ir.dump(fd, pw, args);
679                    pw.println();
680                }
681            }
682        }
683        // Print UiccCarrierPrivilegeRules and registrants.
684        if (mCarrierPrivilegeRules == null) {
685            pw.println(" mCarrierPrivilegeRules: null");
686        } else {
687            pw.println(" mCarrierPrivilegeRules: " + mCarrierPrivilegeRules);
688            mCarrierPrivilegeRules.dump(fd, pw, args);
689        }
690        pw.println(" mCarrierPrivilegeRegistrants: size=" + mCarrierPrivilegeRegistrants.size());
691        for (int i = 0; i < mCarrierPrivilegeRegistrants.size(); i++) {
692            pw.println("  mCarrierPrivilegeRegistrants[" + i + "]="
693                    + ((Registrant)mCarrierPrivilegeRegistrants.get(i)).getHandler());
694        }
695        pw.flush();
696    }
697}
698