UiccCard.java revision fab72cdd47510766a6e6c1ebaa32d9a948e5bde1
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 android.app.AlertDialog;
20import android.app.usage.UsageStatsManager;
21import android.content.ActivityNotFoundException;
22import android.content.ComponentName;
23import android.content.Context;
24import android.content.DialogInterface;
25import android.content.Intent;
26import android.content.SharedPreferences;
27import android.content.pm.PackageInfo;
28import android.content.pm.PackageManager;
29import android.content.pm.Signature;
30import android.content.res.Resources;
31import android.net.Uri;
32import android.os.AsyncResult;
33import android.os.Binder;
34import android.os.Handler;
35import android.os.Message;
36import android.os.PowerManager;
37import android.os.Registrant;
38import android.os.RegistrantList;
39import android.preference.PreferenceManager;
40import android.provider.Settings;
41import android.telephony.Rlog;
42import android.telephony.TelephonyManager;
43import android.text.TextUtils;
44import android.util.LocalLog;
45import android.view.WindowManager;
46
47import com.android.internal.R;
48import com.android.internal.telephony.CommandsInterface;
49import com.android.internal.telephony.CommandsInterface.RadioState;
50import com.android.internal.telephony.cat.CatService;
51import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
52import com.android.internal.telephony.uicc.IccCardStatus.CardState;
53import com.android.internal.telephony.uicc.IccCardStatus.PinState;
54
55import java.io.FileDescriptor;
56import java.io.PrintWriter;
57import java.util.Arrays;
58import java.util.HashSet;
59import java.util.List;
60
61/**
62 * {@hide}
63 */
64public class UiccCard {
65    protected static final String LOG_TAG = "UiccCard";
66    protected static final boolean DBG = true;
67
68    public static final String EXTRA_ICC_CARD_ADDED =
69            "com.android.internal.telephony.uicc.ICC_CARD_ADDED";
70
71    private static final String OPERATOR_BRAND_OVERRIDE_PREFIX = "operator_branding_";
72
73    private final Object mLock = new Object();
74    private CardState mCardState;
75    private PinState mUniversalPinState;
76    private int mGsmUmtsSubscriptionAppIndex;
77    private int mCdmaSubscriptionAppIndex;
78    private int mImsSubscriptionAppIndex;
79    private UiccCardApplication[] mUiccApplications =
80            new UiccCardApplication[IccCardStatus.CARD_MAX_APPS];
81    private Context mContext;
82    private CommandsInterface mCi;
83    private CatService mCatService;
84    private RadioState mLastRadioState =  RadioState.RADIO_UNAVAILABLE;
85    private UiccCarrierPrivilegeRules mCarrierPrivilegeRules;
86
87    private RegistrantList mAbsentRegistrants = new RegistrantList();
88    private RegistrantList mCarrierPrivilegeRegistrants = new RegistrantList();
89
90    private static final int EVENT_CARD_REMOVED = 13;
91    private static final int EVENT_CARD_ADDED = 14;
92    private static final int EVENT_OPEN_LOGICAL_CHANNEL_DONE = 15;
93    private static final int EVENT_CLOSE_LOGICAL_CHANNEL_DONE = 16;
94    private static final int EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE = 17;
95    private static final int EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE = 18;
96    private static final int EVENT_SIM_IO_DONE = 19;
97    private static final int EVENT_CARRIER_PRIVILIGES_LOADED = 20;
98
99    private static final LocalLog mLocalLog = new LocalLog(100);
100
101    private final int mPhoneId;
102
103    public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId) {
104        if (DBG) log("Creating");
105        mCardState = ics.mCardState;
106        mPhoneId = phoneId;
107        update(c, ci, ics);
108    }
109
110    public void dispose() {
111        synchronized (mLock) {
112            if (DBG) log("Disposing card");
113            if (mCatService != null) mCatService.dispose();
114            for (UiccCardApplication app : mUiccApplications) {
115                if (app != null) {
116                    app.dispose();
117                }
118            }
119            mCatService = null;
120            mUiccApplications = null;
121            mCarrierPrivilegeRules = null;
122        }
123    }
124
125    public void update(Context c, CommandsInterface ci, IccCardStatus ics) {
126        synchronized (mLock) {
127            CardState oldState = mCardState;
128            mCardState = ics.mCardState;
129            mUniversalPinState = ics.mUniversalPinState;
130            mGsmUmtsSubscriptionAppIndex = ics.mGsmUmtsSubscriptionAppIndex;
131            mCdmaSubscriptionAppIndex = ics.mCdmaSubscriptionAppIndex;
132            mImsSubscriptionAppIndex = ics.mImsSubscriptionAppIndex;
133            mContext = c;
134            mCi = ci;
135
136            //update applications
137            if (DBG) log(ics.mApplications.length + " applications");
138            for ( int i = 0; i < mUiccApplications.length; i++) {
139                if (mUiccApplications[i] == null) {
140                    //Create newly added Applications
141                    if (i < ics.mApplications.length) {
142                        mUiccApplications[i] = new UiccCardApplication(this,
143                                ics.mApplications[i], mContext, mCi);
144                    }
145                } else if (i >= ics.mApplications.length) {
146                    //Delete removed applications
147                    mUiccApplications[i].dispose();
148                    mUiccApplications[i] = null;
149                } else {
150                    //Update the rest
151                    mUiccApplications[i].update(ics.mApplications[i], mContext, mCi);
152                }
153            }
154
155            createAndUpdateCatServiceLocked();
156
157            // Reload the carrier privilege rules if necessary.
158            log("Before privilege rules: " + mCarrierPrivilegeRules + " : " + mCardState);
159            if (mCarrierPrivilegeRules == null && mCardState == CardState.CARDSTATE_PRESENT) {
160                mCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(this,
161                        mHandler.obtainMessage(EVENT_CARRIER_PRIVILIGES_LOADED));
162            } else if (mCarrierPrivilegeRules != null
163                    && mCardState != CardState.CARDSTATE_PRESENT) {
164                mCarrierPrivilegeRules = null;
165            }
166
167            sanitizeApplicationIndexesLocked();
168
169            RadioState radioState = mCi.getRadioState();
170            if (DBG) log("update: radioState=" + radioState + " mLastRadioState="
171                    + mLastRadioState);
172            // No notifications while radio is off or we just powering up
173            if (radioState == RadioState.RADIO_ON && mLastRadioState == RadioState.RADIO_ON) {
174                if (oldState != CardState.CARDSTATE_ABSENT &&
175                        mCardState == CardState.CARDSTATE_ABSENT) {
176                    if (DBG) log("update: notify card removed");
177                    mAbsentRegistrants.notifyRegistrants();
178                    mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_REMOVED, null));
179                } else if (oldState == CardState.CARDSTATE_ABSENT &&
180                        mCardState != CardState.CARDSTATE_ABSENT) {
181                    if (DBG) log("update: notify card added");
182                    mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_ADDED, null));
183                }
184            }
185            mLastRadioState = radioState;
186        }
187    }
188
189    private void createAndUpdateCatServiceLocked() {
190        if (mUiccApplications.length > 0 && mUiccApplications[0] != null) {
191            // Initialize or Reinitialize CatService
192            if (mCatService == null) {
193                mCatService = CatService.getInstance(mCi, mContext, this, mPhoneId);
194            } else {
195                mCatService.update(mCi, mContext, this);
196            }
197        } else {
198            if (mCatService != null) {
199                mCatService.dispose();
200            }
201            mCatService = null;
202        }
203    }
204
205    @Override
206    protected void finalize() {
207        if (DBG) log("UiccCard finalized");
208    }
209
210    /**
211     * This function makes sure that application indexes are valid
212     * and resets invalid indexes. (This should never happen, but in case
213     * RIL misbehaves we need to manage situation gracefully)
214     */
215    private void sanitizeApplicationIndexesLocked() {
216        mGsmUmtsSubscriptionAppIndex =
217                checkIndexLocked(
218                        mGsmUmtsSubscriptionAppIndex, AppType.APPTYPE_SIM, AppType.APPTYPE_USIM);
219        mCdmaSubscriptionAppIndex =
220                checkIndexLocked(
221                        mCdmaSubscriptionAppIndex, AppType.APPTYPE_RUIM, AppType.APPTYPE_CSIM);
222        mImsSubscriptionAppIndex =
223                checkIndexLocked(mImsSubscriptionAppIndex, AppType.APPTYPE_ISIM, null);
224    }
225
226    private int checkIndexLocked(int index, AppType expectedAppType, AppType altExpectedAppType) {
227        if (mUiccApplications == null || index >= mUiccApplications.length) {
228            loge("App index " + index + " is invalid since there are no applications");
229            return -1;
230        }
231
232        if (index < 0) {
233            // This is normal. (i.e. no application of this type)
234            return -1;
235        }
236
237        if (mUiccApplications[index].getType() != expectedAppType &&
238            mUiccApplications[index].getType() != altExpectedAppType) {
239            loge("App index " + index + " is invalid since it's not " +
240                    expectedAppType + " and not " + altExpectedAppType);
241            return -1;
242        }
243
244        // Seems to be valid
245        return index;
246    }
247
248    /**
249     * Notifies handler of any transition into State.ABSENT
250     */
251    public void registerForAbsent(Handler h, int what, Object obj) {
252        synchronized (mLock) {
253            Registrant r = new Registrant (h, what, obj);
254
255            mAbsentRegistrants.add(r);
256
257            if (mCardState == CardState.CARDSTATE_ABSENT) {
258                r.notifyRegistrant();
259            }
260        }
261    }
262
263    public void unregisterForAbsent(Handler h) {
264        synchronized (mLock) {
265            mAbsentRegistrants.remove(h);
266        }
267    }
268
269    /**
270     * Notifies handler when carrier privilege rules are loaded.
271     */
272    public void registerForCarrierPrivilegeRulesLoaded(Handler h, int what, Object obj) {
273        synchronized (mLock) {
274            Registrant r = new Registrant (h, what, obj);
275
276            mCarrierPrivilegeRegistrants.add(r);
277
278            if (areCarrierPriviligeRulesLoaded()) {
279                r.notifyRegistrant();
280            }
281        }
282    }
283
284    public void unregisterForCarrierPrivilegeRulesLoaded(Handler h) {
285        synchronized (mLock) {
286            mCarrierPrivilegeRegistrants.remove(h);
287        }
288    }
289
290    private void onIccSwap(boolean isAdded) {
291
292        boolean isHotSwapSupported = mContext.getResources().getBoolean(
293                R.bool.config_hotswapCapable);
294
295        if (isHotSwapSupported) {
296            log("onIccSwap: isHotSwapSupported is true, don't prompt for rebooting");
297            return;
298        }
299        log("onIccSwap: isHotSwapSupported is false, prompt for rebooting");
300
301        promptForRestart(isAdded);
302    }
303
304    private void promptForRestart(boolean isAdded) {
305        synchronized (mLock) {
306            final Resources res = mContext.getResources();
307            final String dialogComponent = res.getString(
308                    R.string.config_iccHotswapPromptForRestartDialogComponent);
309            if (dialogComponent != null) {
310                Intent intent = new Intent().setComponent(ComponentName.unflattenFromString(
311                        dialogComponent)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
312                        .putExtra(EXTRA_ICC_CARD_ADDED, isAdded);
313                try {
314                    mContext.startActivity(intent);
315                    return;
316                } catch (ActivityNotFoundException e) {
317                    loge("Unable to find ICC hotswap prompt for restart activity: " + e);
318                }
319            }
320
321            // TODO: Here we assume the device can't handle SIM hot-swap
322            //      and has to reboot. We may want to add a property,
323            //      e.g. REBOOT_ON_SIM_SWAP, to indicate if modem support
324            //      hot-swap.
325            DialogInterface.OnClickListener listener = null;
326
327
328            // TODO: SimRecords is not reset while SIM ABSENT (only reset while
329            //       Radio_off_or_not_available). Have to reset in both both
330            //       added or removed situation.
331            listener = new DialogInterface.OnClickListener() {
332                @Override
333                public void onClick(DialogInterface dialog, int which) {
334                    synchronized (mLock) {
335                        if (which == DialogInterface.BUTTON_POSITIVE) {
336                            if (DBG) log("Reboot due to SIM swap");
337                            PowerManager pm = (PowerManager) mContext
338                                    .getSystemService(Context.POWER_SERVICE);
339                            pm.reboot("SIM is added.");
340                        }
341                    }
342                }
343
344            };
345
346            Resources r = Resources.getSystem();
347
348            String title = (isAdded) ? r.getString(R.string.sim_added_title) :
349                r.getString(R.string.sim_removed_title);
350            String message = (isAdded) ? r.getString(R.string.sim_added_message) :
351                r.getString(R.string.sim_removed_message);
352            String buttonTxt = r.getString(R.string.sim_restart_button);
353
354            AlertDialog dialog = new AlertDialog.Builder(mContext)
355            .setTitle(title)
356            .setMessage(message)
357            .setPositiveButton(buttonTxt, listener)
358            .create();
359            dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
360            dialog.show();
361        }
362    }
363
364    protected Handler mHandler = new Handler() {
365        @Override
366        public void handleMessage(Message msg){
367            switch (msg.what) {
368                case EVENT_CARD_REMOVED:
369                    onIccSwap(false);
370                    break;
371                case EVENT_CARD_ADDED:
372                    onIccSwap(true);
373                    break;
374                case EVENT_OPEN_LOGICAL_CHANNEL_DONE:
375                case EVENT_CLOSE_LOGICAL_CHANNEL_DONE:
376                case EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE:
377                case EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE:
378                case EVENT_SIM_IO_DONE:
379                    AsyncResult ar = (AsyncResult)msg.obj;
380                    if (ar.exception != null) {
381                        loglocal("Exception: " + ar.exception);
382                        log("Error in SIM access with exception" + ar.exception);
383                    }
384                    AsyncResult.forMessage((Message)ar.userObj, ar.result, ar.exception);
385                    ((Message)ar.userObj).sendToTarget();
386                    break;
387                case EVENT_CARRIER_PRIVILIGES_LOADED:
388                    onCarrierPriviligesLoadedMessage();
389                    break;
390                default:
391                    loge("Unknown Event " + msg.what);
392            }
393        }
394    };
395
396    private boolean isPackageInstalled(String pkgName) {
397        PackageManager pm = mContext.getPackageManager();
398        try {
399            pm.getPackageInfo(pkgName, PackageManager.GET_ACTIVITIES);
400            if (DBG) log(pkgName + " is installed.");
401            return true;
402        } catch (PackageManager.NameNotFoundException e) {
403            if (DBG) log(pkgName + " is not installed.");
404            return false;
405        }
406    }
407
408    private class ClickListener implements DialogInterface.OnClickListener {
409        String pkgName;
410        public ClickListener(String pkgName) {
411            this.pkgName = pkgName;
412        }
413        @Override
414        public void onClick(DialogInterface dialog, int which) {
415            synchronized (mLock) {
416                if (which == DialogInterface.BUTTON_POSITIVE) {
417                    Intent market = new Intent(Intent.ACTION_VIEW);
418                    market.setData(Uri.parse("market://details?id=" + pkgName));
419                    market.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
420                    mContext.startActivity(market);
421                } else if (which == DialogInterface.BUTTON_NEGATIVE) {
422                    if (DBG) log("Not now clicked for carrier app dialog.");
423                }
424            }
425        }
426    }
427
428    private void promptInstallCarrierApp(String pkgName) {
429        DialogInterface.OnClickListener listener = new ClickListener(pkgName);
430
431        Resources r = Resources.getSystem();
432        String message = r.getString(R.string.carrier_app_dialog_message);
433        String buttonTxt = r.getString(R.string.carrier_app_dialog_button);
434        String notNowTxt = r.getString(R.string.carrier_app_dialog_not_now);
435
436        AlertDialog dialog = new AlertDialog.Builder(mContext)
437        .setMessage(message)
438        .setNegativeButton(notNowTxt, listener)
439        .setPositiveButton(buttonTxt, listener)
440        .create();
441        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
442        dialog.show();
443    }
444
445    private void onCarrierPriviligesLoadedMessage() {
446        UsageStatsManager usm = (UsageStatsManager) mContext.getSystemService(
447                Context.USAGE_STATS_SERVICE);
448        if (usm != null) {
449            usm.onCarrierPrivilegedAppsChanged();
450        }
451        synchronized (mLock) {
452            mCarrierPrivilegeRegistrants.notifyRegistrants();
453            String whitelistSetting = Settings.Global.getString(mContext.getContentResolver(),
454                    Settings.Global.CARRIER_APP_WHITELIST);
455            if (TextUtils.isEmpty(whitelistSetting)) {
456                return;
457            }
458            HashSet<String> carrierAppSet = new HashSet<String>(
459                    Arrays.asList(whitelistSetting.split("\\s*;\\s*")));
460            if (carrierAppSet.isEmpty()) {
461                return;
462            }
463
464            List<String> pkgNames = mCarrierPrivilegeRules.getPackageNames();
465            for (String pkgName : pkgNames) {
466                if (!TextUtils.isEmpty(pkgName) && carrierAppSet.contains(pkgName)
467                        && !isPackageInstalled(pkgName)) {
468                    promptInstallCarrierApp(pkgName);
469                }
470            }
471        }
472    }
473
474    public boolean isApplicationOnIcc(IccCardApplicationStatus.AppType type) {
475        synchronized (mLock) {
476            for (int i = 0 ; i < mUiccApplications.length; i++) {
477                if (mUiccApplications[i] != null && mUiccApplications[i].getType() == type) {
478                    return true;
479                }
480            }
481            return false;
482        }
483    }
484
485    public CardState getCardState() {
486        synchronized (mLock) {
487            return mCardState;
488        }
489    }
490
491    public PinState getUniversalPinState() {
492        synchronized (mLock) {
493            return mUniversalPinState;
494        }
495    }
496
497    public UiccCardApplication getApplication(int family) {
498        synchronized (mLock) {
499            int index = IccCardStatus.CARD_MAX_APPS;
500            switch (family) {
501                case UiccController.APP_FAM_3GPP:
502                    index = mGsmUmtsSubscriptionAppIndex;
503                    break;
504                case UiccController.APP_FAM_3GPP2:
505                    index = mCdmaSubscriptionAppIndex;
506                    break;
507                case UiccController.APP_FAM_IMS:
508                    index = mImsSubscriptionAppIndex;
509                    break;
510            }
511            if (index >= 0 && index < mUiccApplications.length) {
512                return mUiccApplications[index];
513            }
514            return null;
515        }
516    }
517
518    public UiccCardApplication getApplicationIndex(int index) {
519        synchronized (mLock) {
520            if (index >= 0 && index < mUiccApplications.length) {
521                return mUiccApplications[index];
522            }
523            return null;
524        }
525    }
526
527    /**
528     * Returns the SIM application of the specified type.
529     *
530     * @param type ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
531     * @return application corresponding to type or a null if no match found
532     */
533    public UiccCardApplication getApplicationByType(int type) {
534        synchronized (mLock) {
535            for (int i = 0 ; i < mUiccApplications.length; i++) {
536                if (mUiccApplications[i] != null &&
537                        mUiccApplications[i].getType().ordinal() == type) {
538                    return mUiccApplications[i];
539                }
540            }
541            return null;
542        }
543    }
544
545    /**
546     * Resets the application with the input AID. Returns true if any changes were made.
547     *
548     * A null aid implies a card level reset - all applications must be reset.
549     */
550    public boolean resetAppWithAid(String aid) {
551        synchronized (mLock) {
552            boolean changed = false;
553            for (int i = 0; i < mUiccApplications.length; i++) {
554                if (mUiccApplications[i] != null
555                        && (TextUtils.isEmpty(aid) || aid.equals(mUiccApplications[i].getAid()))) {
556                    // Delete removed applications
557                    mUiccApplications[i].dispose();
558                    mUiccApplications[i] = null;
559                    changed = true;
560                }
561            }
562            if (TextUtils.isEmpty(aid)) {
563                if (mCarrierPrivilegeRules != null) {
564                    mCarrierPrivilegeRules = null;
565                    changed = true;
566                }
567                if (mCatService != null) {
568                    mCatService.dispose();
569                    mCatService = null;
570                    changed = true;
571                }
572            }
573            return changed;
574        }
575    }
576
577    /**
578     * Exposes {@link CommandsInterface#iccOpenLogicalChannel}
579     */
580    public void iccOpenLogicalChannel(String AID, int p2, Message response) {
581        loglocal("Open Logical Channel: " + AID + " , " + p2 + " by pid:" + Binder.getCallingPid()
582                + " uid:" + Binder.getCallingUid());
583        mCi.iccOpenLogicalChannel(AID, p2,
584                mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, response));
585    }
586
587    /**
588     * Exposes {@link CommandsInterface#iccCloseLogicalChannel}
589     */
590    public void iccCloseLogicalChannel(int channel, Message response) {
591        loglocal("Close Logical Channel: " + channel);
592        mCi.iccCloseLogicalChannel(channel,
593                mHandler.obtainMessage(EVENT_CLOSE_LOGICAL_CHANNEL_DONE, response));
594    }
595
596    /**
597     * Exposes {@link CommandsInterface#iccTransmitApduLogicalChannel}
598     */
599    public void iccTransmitApduLogicalChannel(int channel, int cla, int command,
600            int p1, int p2, int p3, String data, Message response) {
601        mCi.iccTransmitApduLogicalChannel(channel, cla, command, p1, p2, p3,
602                data, mHandler.obtainMessage(EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE, response));
603    }
604
605    /**
606     * Exposes {@link CommandsInterface#iccTransmitApduBasicChannel}
607     */
608    public void iccTransmitApduBasicChannel(int cla, int command,
609            int p1, int p2, int p3, String data, Message response) {
610        mCi.iccTransmitApduBasicChannel(cla, command, p1, p2, p3,
611                data, mHandler.obtainMessage(EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE, response));
612    }
613
614    /**
615     * Exposes {@link CommandsInterface#iccIO}
616     */
617    public void iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
618            String pathID, Message response) {
619        mCi.iccIO(command, fileID, pathID, p1, p2, p3, null, null,
620                mHandler.obtainMessage(EVENT_SIM_IO_DONE, response));
621    }
622
623    /**
624     * Exposes {@link CommandsInterface#sendEnvelopeWithStatus}
625     */
626    public void sendEnvelopeWithStatus(String contents, Message response) {
627        mCi.sendEnvelopeWithStatus(contents, response);
628    }
629
630    /* Returns number of applications on this card */
631    public int getNumApplications() {
632        int count = 0;
633        for (UiccCardApplication a : mUiccApplications) {
634            if (a != null) {
635                count++;
636            }
637        }
638        return count;
639    }
640
641    public int getPhoneId() {
642        return mPhoneId;
643    }
644
645    /**
646     * Returns true iff carrier privileges rules are null (dont need to be loaded) or loaded.
647     */
648    public boolean areCarrierPriviligeRulesLoaded() {
649        UiccCarrierPrivilegeRules carrierPrivilegeRules = getCarrierPrivilegeRules();
650        return carrierPrivilegeRules == null
651                || carrierPrivilegeRules.areCarrierPriviligeRulesLoaded();
652    }
653
654    /**
655     * Returns true if there are some carrier privilege rules loaded and specified.
656     */
657    public boolean hasCarrierPrivilegeRules() {
658        UiccCarrierPrivilegeRules carrierPrivilegeRules = getCarrierPrivilegeRules();
659        return carrierPrivilegeRules != null && carrierPrivilegeRules.hasCarrierPrivilegeRules();
660    }
661
662    /**
663     * Exposes {@link UiccCarrierPrivilegeRules#getCarrierPrivilegeStatus}.
664     */
665    public int getCarrierPrivilegeStatus(Signature signature, String packageName) {
666        UiccCarrierPrivilegeRules carrierPrivilegeRules = getCarrierPrivilegeRules();
667        return carrierPrivilegeRules == null
668                ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED :
669                carrierPrivilegeRules.getCarrierPrivilegeStatus(signature, packageName);
670    }
671
672    /**
673     * Exposes {@link UiccCarrierPrivilegeRules#getCarrierPrivilegeStatus}.
674     */
675    public int getCarrierPrivilegeStatus(PackageManager packageManager, String packageName) {
676        UiccCarrierPrivilegeRules carrierPrivilegeRules = getCarrierPrivilegeRules();
677        return carrierPrivilegeRules == null
678                ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED :
679                carrierPrivilegeRules.getCarrierPrivilegeStatus(packageManager, packageName);
680    }
681
682    /**
683     * Exposes {@link UiccCarrierPrivilegeRules#getCarrierPrivilegeStatus}.
684     */
685    public int getCarrierPrivilegeStatus(PackageInfo packageInfo) {
686        UiccCarrierPrivilegeRules carrierPrivilegeRules = getCarrierPrivilegeRules();
687        return carrierPrivilegeRules == null
688                ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED :
689                carrierPrivilegeRules.getCarrierPrivilegeStatus(packageInfo);
690    }
691
692    /**
693     * Exposes {@link UiccCarrierPrivilegeRules#getCarrierPrivilegeStatusForCurrentTransaction}.
694     */
695    public int getCarrierPrivilegeStatusForCurrentTransaction(PackageManager packageManager) {
696        UiccCarrierPrivilegeRules carrierPrivilegeRules = getCarrierPrivilegeRules();
697        return carrierPrivilegeRules == null
698                ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED :
699                carrierPrivilegeRules.getCarrierPrivilegeStatusForCurrentTransaction(
700                        packageManager);
701    }
702
703    /**
704     * Exposes {@link UiccCarrierPrivilegeRules#getCarrierPackageNamesForIntent}.
705     */
706    public List<String> getCarrierPackageNamesForIntent(
707            PackageManager packageManager, Intent intent) {
708        UiccCarrierPrivilegeRules carrierPrivilegeRules = getCarrierPrivilegeRules();
709        return carrierPrivilegeRules == null ? null :
710                carrierPrivilegeRules.getCarrierPackageNamesForIntent(
711                        packageManager, intent);
712    }
713
714    /** Returns a reference to the current {@link UiccCarrierPrivilegeRules}. */
715    private UiccCarrierPrivilegeRules getCarrierPrivilegeRules() {
716        synchronized (mLock) {
717            return mCarrierPrivilegeRules;
718        }
719    }
720
721    public boolean setOperatorBrandOverride(String brand) {
722        log("setOperatorBrandOverride: " + brand);
723        log("current iccId: " + getIccId());
724
725        String iccId = getIccId();
726        if (TextUtils.isEmpty(iccId)) {
727            return false;
728        }
729
730        SharedPreferences.Editor spEditor =
731                PreferenceManager.getDefaultSharedPreferences(mContext).edit();
732        String key = OPERATOR_BRAND_OVERRIDE_PREFIX + iccId;
733        if (brand == null) {
734            spEditor.remove(key).commit();
735        } else {
736            spEditor.putString(key, brand).commit();
737        }
738        return true;
739    }
740
741    public String getOperatorBrandOverride() {
742        String iccId = getIccId();
743        if (TextUtils.isEmpty(iccId)) {
744            return null;
745        }
746        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
747        return sp.getString(OPERATOR_BRAND_OVERRIDE_PREFIX + iccId, null);
748    }
749
750    public String getIccId() {
751        // ICCID should be same across all the apps.
752        for (UiccCardApplication app : mUiccApplications) {
753            if (app != null) {
754                IccRecords ir = app.getIccRecords();
755                if (ir != null && ir.getIccId() != null) {
756                    return ir.getIccId();
757                }
758            }
759        }
760        return null;
761    }
762
763    private void log(String msg) {
764        Rlog.d(LOG_TAG, msg);
765    }
766
767    private void loge(String msg) {
768        Rlog.e(LOG_TAG, msg);
769    }
770
771    private void loglocal(String msg) {
772        if (DBG) mLocalLog.log(msg);
773    }
774
775    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
776        pw.println("UiccCard:");
777        pw.println(" mCi=" + mCi);
778        pw.println(" mLastRadioState=" + mLastRadioState);
779        pw.println(" mCatService=" + mCatService);
780        pw.println(" mAbsentRegistrants: size=" + mAbsentRegistrants.size());
781        for (int i = 0; i < mAbsentRegistrants.size(); i++) {
782            pw.println("  mAbsentRegistrants[" + i + "]="
783                    + ((Registrant)mAbsentRegistrants.get(i)).getHandler());
784        }
785        for (int i = 0; i < mCarrierPrivilegeRegistrants.size(); i++) {
786            pw.println("  mCarrierPrivilegeRegistrants[" + i + "]="
787                    + ((Registrant)mCarrierPrivilegeRegistrants.get(i)).getHandler());
788        }
789        pw.println(" mCardState=" + mCardState);
790        pw.println(" mUniversalPinState=" + mUniversalPinState);
791        pw.println(" mGsmUmtsSubscriptionAppIndex=" + mGsmUmtsSubscriptionAppIndex);
792        pw.println(" mCdmaSubscriptionAppIndex=" + mCdmaSubscriptionAppIndex);
793        pw.println(" mImsSubscriptionAppIndex=" + mImsSubscriptionAppIndex);
794        pw.println(" mImsSubscriptionAppIndex=" + mImsSubscriptionAppIndex);
795        pw.println(" mUiccApplications: length=" + mUiccApplications.length);
796        for (int i = 0; i < mUiccApplications.length; i++) {
797            if (mUiccApplications[i] == null) {
798                pw.println("  mUiccApplications[" + i + "]=" + null);
799            } else {
800                pw.println("  mUiccApplications[" + i + "]="
801                        + mUiccApplications[i].getType() + " " + mUiccApplications[i]);
802            }
803        }
804        pw.println();
805        // Print details of all applications
806        for (UiccCardApplication app : mUiccApplications) {
807            if (app != null) {
808                app.dump(fd, pw, args);
809                pw.println();
810            }
811        }
812        // Print details of all IccRecords
813        for (UiccCardApplication app : mUiccApplications) {
814            if (app != null) {
815                IccRecords ir = app.getIccRecords();
816                if (ir != null) {
817                    ir.dump(fd, pw, args);
818                    pw.println();
819                }
820            }
821        }
822        // Print UiccCarrierPrivilegeRules and registrants.
823        if (mCarrierPrivilegeRules == null) {
824            pw.println(" mCarrierPrivilegeRules: null");
825        } else {
826            pw.println(" mCarrierPrivilegeRules: " + mCarrierPrivilegeRules);
827            mCarrierPrivilegeRules.dump(fd, pw, args);
828        }
829        pw.println(" mCarrierPrivilegeRegistrants: size=" + mCarrierPrivilegeRegistrants.size());
830        for (int i = 0; i < mCarrierPrivilegeRegistrants.size(); i++) {
831            pw.println("  mCarrierPrivilegeRegistrants[" + i + "]="
832                    + ((Registrant)mCarrierPrivilegeRegistrants.get(i)).getHandler());
833        }
834        pw.flush();
835        pw.println("mLocalLog:");
836        mLocalLog.dump(fd, pw, args);
837        pw.flush();
838    }
839}
840