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