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