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 
UiccCard(Context c, CommandsInterface ci, IccCardStatus ics)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 
UiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId)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 
UiccCard()115     protected UiccCard() {
116     }
117 
dispose()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 
update(Context c, CommandsInterface ci, IccCardStatus ics)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 
createAndUpdateCatService()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 
getCatService()212     public CatService getCatService() {
213         return mCatService;
214     }
215 
216     @Override
finalize()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      */
sanitizeApplicationIndexes()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 
checkIndex(int index, AppType expectedAppType, AppType altExpectedAppType)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      */
registerForAbsent(Handler h, int what, Object obj)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 
unregisterForAbsent(Handler h)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      */
registerForCarrierPrivilegeRulesLoaded(Handler h, int what, Object obj)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 
unregisterForCarrierPrivilegeRulesLoaded(Handler h)293     public void unregisterForCarrierPrivilegeRulesLoaded(Handler h) {
294         synchronized (mLock) {
295             mCarrierPrivilegeRegistrants.remove(h);
296         }
297     }
298 
onIccSwap(boolean isAdded)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 
promptForRestart(boolean isAdded)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 
isPackageInstalled(String pkgName)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;
ClickListener(String pkgName)419         public ClickListener(String pkgName) {
420             this.pkgName = pkgName;
421         }
422         @Override
onClick(DialogInterface dialog, int which)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 
promptInstallCarrierApp(String pkgName)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 
onCarrierPriviligesLoadedMessage()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 
isApplicationOnIcc(IccCardApplicationStatus.AppType type)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 
getCardState()494     public CardState getCardState() {
495         synchronized (mLock) {
496             return mCardState;
497         }
498     }
499 
getUniversalPinState()500     public PinState getUniversalPinState() {
501         synchronized (mLock) {
502             return mUniversalPinState;
503         }
504     }
505 
getApplication(int family)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 
getApplicationIndex(int index)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      */
getApplicationByType(int type)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      */
resetAppWithAid(String aid)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      */
iccOpenLogicalChannel(String AID, int p2, Message response)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      */
iccCloseLogicalChannel(int channel, Message response)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      */
iccTransmitApduLogicalChannel(int channel, int cla, int command, int p1, int p2, int p3, String data, Message response)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      */
iccTransmitApduBasicChannel(int cla, int command, int p1, int p2, int p3, String data, Message response)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      */
iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3, String pathID, Message response)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      */
sendEnvelopeWithStatus(String contents, Message response)626     public void sendEnvelopeWithStatus(String contents, Message response) {
627         mCi.sendEnvelopeWithStatus(contents, response);
628     }
629 
630     /* Returns number of applications on this card */
getNumApplications()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 
getPhoneId()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      */
areCarrierPriviligeRulesLoaded()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      */
hasCarrierPrivilegeRules()656     public boolean hasCarrierPrivilegeRules() {
657         return mCarrierPrivilegeRules != null
658                 && mCarrierPrivilegeRules.hasCarrierPrivilegeRules();
659     }
660 
661     /**
662      * Exposes {@link UiccCarrierPrivilegeRules.getCarrierPrivilegeStatus}.
663      */
getCarrierPrivilegeStatus(Signature signature, String packageName)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      */
getCarrierPrivilegeStatus(PackageManager packageManager, String packageName)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      */
getCarrierPrivilegeStatus(PackageInfo packageInfo)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      */
getCarrierPrivilegeStatusForCurrentTransaction(PackageManager packageManager)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      */
getCarrierPackageNamesForIntent( PackageManager packageManager, Intent intent)700     public List<String> getCarrierPackageNamesForIntent(
701             PackageManager packageManager, Intent intent) {
702         return mCarrierPrivilegeRules == null ? null :
703             mCarrierPrivilegeRules.getCarrierPackageNamesForIntent(
704                     packageManager, intent);
705     }
706 
setOperatorBrandOverride(String brand)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 
getOperatorBrandOverride()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 
getIccId()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 
log(String msg)749     private void log(String msg) {
750         Rlog.d(LOG_TAG, msg);
751     }
752 
loge(String msg)753     private void loge(String msg) {
754         Rlog.e(LOG_TAG, msg);
755     }
756 
loglocal(String msg)757     private void loglocal(String msg) {
758         if (DBG) mLocalLog.log(msg);
759     }
760 
dump(FileDescriptor fd, PrintWriter pw, String[] args)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