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