Home | History | Annotate | Download | only in telephony
      1 /*
      2  * Copyright (C) 2014 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 android.telephony;
     18 
     19 import android.annotation.NonNull;
     20 import android.annotation.SdkConstant;
     21 import android.annotation.SystemService;
     22 import android.annotation.SdkConstant.SdkConstantType;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.res.Configuration;
     26 import android.content.res.Resources;
     27 import android.net.Uri;
     28 import android.telephony.Rlog;
     29 import android.os.Handler;
     30 import android.os.Message;
     31 import android.os.ServiceManager;
     32 import android.os.RemoteException;
     33 import android.util.DisplayMetrics;
     34 
     35 import com.android.internal.telephony.ISub;
     36 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
     37 import com.android.internal.telephony.ITelephonyRegistry;
     38 import com.android.internal.telephony.PhoneConstants;
     39 import java.util.ArrayList;
     40 import java.util.List;
     41 
     42 /**
     43  * SubscriptionManager is the application interface to SubscriptionController
     44  * and provides information about the current Telephony Subscriptions.
     45  * <p>
     46  * All SDK public methods require android.Manifest.permission.READ_PHONE_STATE.
     47  */
     48 @SystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
     49 public class SubscriptionManager {
     50     private static final String LOG_TAG = "SubscriptionManager";
     51     private static final boolean DBG = false;
     52     private static final boolean VDBG = false;
     53 
     54     /** An invalid subscription identifier */
     55     public static final int INVALID_SUBSCRIPTION_ID = -1;
     56 
     57     /** Base value for Dummy SUBSCRIPTION_ID's. */
     58     /** FIXME: Remove DummySubId's, but for now have them map just below INVALID_SUBSCRIPTION_ID
     59     /** @hide */
     60     public static final int DUMMY_SUBSCRIPTION_ID_BASE = INVALID_SUBSCRIPTION_ID - 1;
     61 
     62     /** An invalid phone identifier */
     63     /** @hide */
     64     public static final int INVALID_PHONE_INDEX = -1;
     65 
     66     /** An invalid slot identifier */
     67     /** @hide */
     68     public static final int INVALID_SIM_SLOT_INDEX = -1;
     69 
     70     /** Indicates the caller wants the default sub id. */
     71     /** @hide */
     72     public static final int DEFAULT_SUBSCRIPTION_ID = Integer.MAX_VALUE;
     73 
     74     /**
     75      * Indicates the caller wants the default phone id.
     76      * Used in SubscriptionController and Phone but do we really need it???
     77      * @hide
     78      */
     79     public static final int DEFAULT_PHONE_INDEX = Integer.MAX_VALUE;
     80 
     81     /** Indicates the caller wants the default slot id. NOT used remove? */
     82     /** @hide */
     83     public static final int DEFAULT_SIM_SLOT_INDEX = Integer.MAX_VALUE;
     84 
     85     /** Minimum possible subid that represents a subscription */
     86     /** @hide */
     87     public static final int MIN_SUBSCRIPTION_ID_VALUE = 0;
     88 
     89     /** Maximum possible subid that represents a subscription */
     90     /** @hide */
     91     public static final int MAX_SUBSCRIPTION_ID_VALUE = DEFAULT_SUBSCRIPTION_ID - 1;
     92 
     93     /** @hide */
     94     public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
     95 
     96     /**
     97      * TelephonyProvider unique key column name is the subscription id.
     98      * <P>Type: TEXT (String)</P>
     99      */
    100     /** @hide */
    101     public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
    102 
    103     /**
    104      * TelephonyProvider column name for SIM ICC Identifier
    105      * <P>Type: TEXT (String)</P>
    106      */
    107     /** @hide */
    108     public static final String ICC_ID = "icc_id";
    109 
    110     /**
    111      * TelephonyProvider column name for user SIM_SlOT_INDEX
    112      * <P>Type: INTEGER (int)</P>
    113      */
    114     /** @hide */
    115     public static final String SIM_SLOT_INDEX = "sim_id";
    116 
    117     /** SIM is not inserted */
    118     /** @hide */
    119     public static final int SIM_NOT_INSERTED = -1;
    120 
    121     /**
    122      * TelephonyProvider column name for user displayed name.
    123      * <P>Type: TEXT (String)</P>
    124      */
    125     /** @hide */
    126     public static final String DISPLAY_NAME = "display_name";
    127 
    128     /**
    129      * TelephonyProvider column name for the service provider name for the SIM.
    130      * <P>Type: TEXT (String)</P>
    131      */
    132     /** @hide */
    133     public static final String CARRIER_NAME = "carrier_name";
    134 
    135     /**
    136      * Default name resource
    137      * @hide
    138      */
    139     public static final int DEFAULT_NAME_RES = com.android.internal.R.string.unknownName;
    140 
    141     /**
    142      * TelephonyProvider column name for source of the user displayed name.
    143      * <P>Type: INT (int)</P> with one of the NAME_SOURCE_XXXX values below
    144      *
    145      * @hide
    146      */
    147     public static final String NAME_SOURCE = "name_source";
    148 
    149     /**
    150      * The name_source is undefined
    151      * @hide
    152      */
    153     public static final int NAME_SOURCE_UNDEFINDED = -1;
    154 
    155     /**
    156      * The name_source is the default
    157      * @hide
    158      */
    159     public static final int NAME_SOURCE_DEFAULT_SOURCE = 0;
    160 
    161     /**
    162      * The name_source is from the SIM
    163      * @hide
    164      */
    165     public static final int NAME_SOURCE_SIM_SOURCE = 1;
    166 
    167     /**
    168      * The name_source is from the user
    169      * @hide
    170      */
    171     public static final int NAME_SOURCE_USER_INPUT = 2;
    172 
    173     /**
    174      * TelephonyProvider column name for the color of a SIM.
    175      * <P>Type: INTEGER (int)</P>
    176      */
    177     /** @hide */
    178     public static final String COLOR = "color";
    179 
    180     /** @hide */
    181     public static final int COLOR_1 = 0;
    182 
    183     /** @hide */
    184     public static final int COLOR_2 = 1;
    185 
    186     /** @hide */
    187     public static final int COLOR_3 = 2;
    188 
    189     /** @hide */
    190     public static final int COLOR_4 = 3;
    191 
    192     /** @hide */
    193     public static final int COLOR_DEFAULT = COLOR_1;
    194 
    195     /**
    196      * TelephonyProvider column name for the phone number of a SIM.
    197      * <P>Type: TEXT (String)</P>
    198      */
    199     /** @hide */
    200     public static final String NUMBER = "number";
    201 
    202     /**
    203      * TelephonyProvider column name for the number display format of a SIM.
    204      * <P>Type: INTEGER (int)</P>
    205      */
    206     /** @hide */
    207     public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
    208 
    209     /** @hide */
    210     public static final int DISPLAY_NUMBER_NONE = 0;
    211 
    212     /** @hide */
    213     public static final int DISPLAY_NUMBER_FIRST = 1;
    214 
    215     /** @hide */
    216     public static final int DISPLAY_NUMBER_LAST = 2;
    217 
    218     /** @hide */
    219     public static final int DISPLAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST;
    220 
    221     /**
    222      * TelephonyProvider column name for permission for data roaming of a SIM.
    223      * <P>Type: INTEGER (int)</P>
    224      */
    225     /** @hide */
    226     public static final String DATA_ROAMING = "data_roaming";
    227 
    228     /** Indicates that data roaming is enabled for a subscription */
    229     public static final int DATA_ROAMING_ENABLE = 1;
    230 
    231     /** Indicates that data roaming is disabled for a subscription */
    232     public static final int DATA_ROAMING_DISABLE = 0;
    233 
    234     /** @hide */
    235     public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
    236 
    237     /** @hide */
    238     public static final int SIM_PROVISIONED = 0;
    239 
    240     /**
    241      * TelephonyProvider column name for the MCC associated with a SIM.
    242      * <P>Type: INTEGER (int)</P>
    243      * @hide
    244      */
    245     public static final String MCC = "mcc";
    246 
    247     /**
    248      * TelephonyProvider column name for the MNC associated with a SIM.
    249      * <P>Type: INTEGER (int)</P>
    250      * @hide
    251      */
    252     public static final String MNC = "mnc";
    253 
    254     /**
    255      * TelephonyProvider column name for the sim provisioning status associated with a SIM.
    256      * <P>Type: INTEGER (int)</P>
    257      * @hide
    258      */
    259     public static final String SIM_PROVISIONING_STATUS = "sim_provisioning_status";
    260 
    261     /**
    262      *  TelephonyProvider column name for extreme threat in CB settings
    263      * @hide
    264      */
    265     public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
    266 
    267     /**
    268      * TelephonyProvider column name for severe threat in CB settings
    269      *@hide
    270      */
    271     public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
    272 
    273     /**
    274      * TelephonyProvider column name for amber alert in CB settings
    275      *@hide
    276      */
    277     public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
    278 
    279     /**
    280      * TelephonyProvider column name for emergency alert in CB settings
    281      *@hide
    282      */
    283     public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
    284 
    285     /**
    286      * TelephonyProvider column name for alert sound duration in CB settings
    287      *@hide
    288      */
    289     public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
    290 
    291     /**
    292      * TelephonyProvider column name for alert reminder interval in CB settings
    293      *@hide
    294      */
    295     public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
    296 
    297     /**
    298      * TelephonyProvider column name for enabling vibrate in CB settings
    299      *@hide
    300      */
    301     public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
    302 
    303     /**
    304      * TelephonyProvider column name for enabling alert speech in CB settings
    305      *@hide
    306      */
    307     public static final String CB_ALERT_SPEECH = "enable_alert_speech";
    308 
    309     /**
    310      * TelephonyProvider column name for ETWS test alert in CB settings
    311      *@hide
    312      */
    313     public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
    314 
    315     /**
    316      * TelephonyProvider column name for enable channel50 alert in CB settings
    317      *@hide
    318      */
    319     public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
    320 
    321     /**
    322      * TelephonyProvider column name for CMAS test alert in CB settings
    323      *@hide
    324      */
    325     public static final String CB_CMAS_TEST_ALERT= "enable_cmas_test_alerts";
    326 
    327     /**
    328      * TelephonyProvider column name for Opt out dialog in CB settings
    329      *@hide
    330      */
    331     public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
    332 
    333     /**
    334      * Broadcast Action: The user has changed one of the default subs related to
    335      * data, phone calls, or sms</p>
    336      *
    337      * TODO: Change to a listener
    338      * @hide
    339      */
    340     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    341     public static final String SUB_DEFAULT_CHANGED_ACTION =
    342         "android.intent.action.SUB_DEFAULT_CHANGED";
    343 
    344     /**
    345      * Broadcast Action: The default subscription has changed.  This has the following
    346      * extra values:</p>
    347      * The {@link #EXTRA_SUBSCRIPTION_INDEX} extra indicates the current default subscription index
    348      */
    349     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    350     public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED
    351             = "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED";
    352 
    353     /**
    354      * Broadcast Action: The default sms subscription has changed.  This has the following
    355      * extra values:</p>
    356      * {@link #EXTRA_SUBSCRIPTION_INDEX} extra indicates the current default sms
    357      * subscription index
    358      */
    359     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    360     public static final String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED
    361             = "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED";
    362 
    363     /**
    364      * Integer extra used with {@link #ACTION_DEFAULT_SUBSCRIPTION_CHANGED} and
    365      * {@link #ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED} to indicate the subscription
    366      * which has changed.
    367      */
    368     public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
    369 
    370     private final Context mContext;
    371 
    372     /**
    373      * A listener class for monitoring changes to {@link SubscriptionInfo} records.
    374      * <p>
    375      * Override the onSubscriptionsChanged method in the object that extends this
    376      * class and pass it to {@link #addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener)}
    377      * to register your listener and to unregister invoke
    378      * {@link #removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener)}
    379      * <p>
    380      * Permissions android.Manifest.permission.READ_PHONE_STATE is required
    381      * for #onSubscriptionsChanged to be invoked.
    382      */
    383     public static class OnSubscriptionsChangedListener {
    384         private final Handler mHandler  = new Handler() {
    385             @Override
    386             public void handleMessage(Message msg) {
    387                 if (DBG) {
    388                     log("handleMessage: invoke the overriden onSubscriptionsChanged()");
    389                 }
    390                 OnSubscriptionsChangedListener.this.onSubscriptionsChanged();
    391             }
    392         };
    393 
    394         /**
    395          * Callback invoked when there is any change to any SubscriptionInfo. Typically
    396          * this method would invoke {@link #getActiveSubscriptionInfoList}
    397          */
    398         public void onSubscriptionsChanged() {
    399             if (DBG) log("onSubscriptionsChanged: NOT OVERRIDDEN");
    400         }
    401 
    402         /**
    403          * The callback methods need to be called on the handler thread where
    404          * this object was created.  If the binder did that for us it'd be nice.
    405          */
    406         IOnSubscriptionsChangedListener callback = new IOnSubscriptionsChangedListener.Stub() {
    407             @Override
    408             public void onSubscriptionsChanged() {
    409                 if (DBG) log("callback: received, sendEmptyMessage(0) to handler");
    410                 mHandler.sendEmptyMessage(0);
    411             }
    412         };
    413 
    414         private void log(String s) {
    415             Rlog.d(LOG_TAG, s);
    416         }
    417     }
    418 
    419     /** @hide */
    420     public SubscriptionManager(Context context) {
    421         if (DBG) logd("SubscriptionManager created");
    422         mContext = context;
    423     }
    424 
    425     /**
    426      * Get an instance of the SubscriptionManager from the Context.
    427      * This invokes {@link android.content.Context#getSystemService
    428      * Context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)}.
    429      *
    430      * @param context to use.
    431      * @return SubscriptionManager instance
    432      */
    433     public static SubscriptionManager from(Context context) {
    434         return (SubscriptionManager) context.getSystemService(
    435                 Context.TELEPHONY_SUBSCRIPTION_SERVICE);
    436     }
    437 
    438     /**
    439      * Register for changes to the list of active {@link SubscriptionInfo} records or to the
    440      * individual records themselves. When a change occurs the onSubscriptionsChanged method of
    441      * the listener will be invoked immediately if there has been a notification.
    442      *
    443      * @param listener an instance of {@link OnSubscriptionsChangedListener} with
    444      *                 onSubscriptionsChanged overridden.
    445      */
    446     public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
    447         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
    448         if (DBG) {
    449             logd("register OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug
    450                     + " listener=" + listener);
    451         }
    452         try {
    453             // We use the TelephonyRegistry as it runs in the system and thus is always
    454             // available. Where as SubscriptionController could crash and not be available
    455             ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
    456                     "telephony.registry"));
    457             if (tr != null) {
    458                 tr.addOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
    459             }
    460         } catch (RemoteException ex) {
    461             // Should not happen
    462         }
    463     }
    464 
    465     /**
    466      * Unregister the {@link OnSubscriptionsChangedListener}. This is not strictly necessary
    467      * as the listener will automatically be unregistered if an attempt to invoke the listener
    468      * fails.
    469      *
    470      * @param listener that is to be unregistered.
    471      */
    472     public void removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
    473         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
    474         if (DBG) {
    475             logd("unregister OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug
    476                     + " listener=" + listener);
    477         }
    478         try {
    479             // We use the TelephonyRegistry as its runs in the system and thus is always
    480             // available where as SubscriptionController could crash and not be available
    481             ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
    482                     "telephony.registry"));
    483             if (tr != null) {
    484                 tr.removeOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
    485             }
    486         } catch (RemoteException ex) {
    487             // Should not happen
    488         }
    489     }
    490 
    491     /**
    492      * Get the active SubscriptionInfo with the input subId.
    493      *
    494      * @param subId The unique SubscriptionInfo key in database.
    495      * @return SubscriptionInfo, maybe null if its not active.
    496      */
    497     public SubscriptionInfo getActiveSubscriptionInfo(int subId) {
    498         if (VDBG) logd("[getActiveSubscriptionInfo]+ subId=" + subId);
    499         if (!isValidSubscriptionId(subId)) {
    500             if (DBG) {
    501                 logd("[getActiveSubscriptionInfo]- invalid subId");
    502             }
    503             return null;
    504         }
    505 
    506         SubscriptionInfo subInfo = null;
    507 
    508         try {
    509             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    510             if (iSub != null) {
    511                 subInfo = iSub.getActiveSubscriptionInfo(subId, mContext.getOpPackageName());
    512             }
    513         } catch (RemoteException ex) {
    514             // ignore it
    515         }
    516 
    517         return subInfo;
    518 
    519     }
    520 
    521     /**
    522      * Get the active SubscriptionInfo associated with the iccId
    523      * @param iccId the IccId of SIM card
    524      * @return SubscriptionInfo, maybe null if its not active
    525      * @hide
    526      */
    527     public SubscriptionInfo getActiveSubscriptionInfoForIccIndex(String iccId) {
    528         if (VDBG) logd("[getActiveSubscriptionInfoForIccIndex]+ iccId=" + iccId);
    529         if (iccId == null) {
    530             logd("[getActiveSubscriptionInfoForIccIndex]- null iccid");
    531             return null;
    532         }
    533 
    534         SubscriptionInfo result = null;
    535 
    536         try {
    537             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    538             if (iSub != null) {
    539                 result = iSub.getActiveSubscriptionInfoForIccId(iccId, mContext.getOpPackageName());
    540             }
    541         } catch (RemoteException ex) {
    542             // ignore it
    543         }
    544 
    545         return result;
    546     }
    547 
    548     /**
    549      * Get the active SubscriptionInfo associated with the slotIndex
    550      * @param slotIndex the slot which the subscription is inserted
    551      * @return SubscriptionInfo, maybe null if its not active
    552      */
    553     public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex) {
    554         if (VDBG) logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIndex=" + slotIndex);
    555         if (!isValidSlotIndex(slotIndex)) {
    556             logd("[getActiveSubscriptionInfoForSimSlotIndex]- invalid slotIndex");
    557             return null;
    558         }
    559 
    560         SubscriptionInfo result = null;
    561 
    562         try {
    563             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    564             if (iSub != null) {
    565                 result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIndex,
    566                         mContext.getOpPackageName());
    567             }
    568         } catch (RemoteException ex) {
    569             // ignore it
    570         }
    571 
    572         return result;
    573     }
    574 
    575     /**
    576      * @return List of all SubscriptionInfo records in database,
    577      * include those that were inserted before, maybe empty but not null.
    578      * @hide
    579      */
    580     public List<SubscriptionInfo> getAllSubscriptionInfoList() {
    581         if (VDBG) logd("[getAllSubscriptionInfoList]+");
    582 
    583         List<SubscriptionInfo> result = null;
    584 
    585         try {
    586             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    587             if (iSub != null) {
    588                 result = iSub.getAllSubInfoList(mContext.getOpPackageName());
    589             }
    590         } catch (RemoteException ex) {
    591             // ignore it
    592         }
    593 
    594         if (result == null) {
    595             result = new ArrayList<SubscriptionInfo>();
    596         }
    597         return result;
    598     }
    599 
    600     /**
    601      * Get the SubscriptionInfo(s) of the currently inserted SIM(s). The records will be sorted
    602      * by {@link SubscriptionInfo#getSimSlotIndex} then by {@link SubscriptionInfo#getSubscriptionId}.
    603      *
    604      * @return Sorted list of the currently {@link SubscriptionInfo} records available on the device.
    605      * <ul>
    606      * <li>
    607      * If null is returned the current state is unknown but if a {@link OnSubscriptionsChangedListener}
    608      * has been registered {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be
    609      * invoked in the future.
    610      * </li>
    611      * <li>
    612      * If the list is empty then there are no {@link SubscriptionInfo} records currently available.
    613      * </li>
    614      * <li>
    615      * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex}
    616      * then by {@link SubscriptionInfo#getSubscriptionId}.
    617      * </li>
    618      * </ul>
    619      */
    620     public List<SubscriptionInfo> getActiveSubscriptionInfoList() {
    621         List<SubscriptionInfo> result = null;
    622 
    623         try {
    624             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    625             if (iSub != null) {
    626                 result = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName());
    627             }
    628         } catch (RemoteException ex) {
    629             // ignore it
    630         }
    631         return result;
    632     }
    633 
    634     /**
    635      * @return the count of all subscriptions in the database, this includes
    636      * all subscriptions that have been seen.
    637      * @hide
    638      */
    639     public int getAllSubscriptionInfoCount() {
    640         if (VDBG) logd("[getAllSubscriptionInfoCount]+");
    641 
    642         int result = 0;
    643 
    644         try {
    645             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    646             if (iSub != null) {
    647                 result = iSub.getAllSubInfoCount(mContext.getOpPackageName());
    648             }
    649         } catch (RemoteException ex) {
    650             // ignore it
    651         }
    652 
    653         return result;
    654     }
    655 
    656     /**
    657      * @return the current number of active subscriptions. There is no guarantee the value
    658      * returned by this method will be the same as the length of the list returned by
    659      * {@link #getActiveSubscriptionInfoList}.
    660      */
    661     public int getActiveSubscriptionInfoCount() {
    662         int result = 0;
    663 
    664         try {
    665             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    666             if (iSub != null) {
    667                 result = iSub.getActiveSubInfoCount(mContext.getOpPackageName());
    668             }
    669         } catch (RemoteException ex) {
    670             // ignore it
    671         }
    672 
    673         return result;
    674     }
    675 
    676     /**
    677      * @return the maximum number of active subscriptions that will be returned by
    678      * {@link #getActiveSubscriptionInfoList} and the value returned by
    679      * {@link #getActiveSubscriptionInfoCount}.
    680      */
    681     public int getActiveSubscriptionInfoCountMax() {
    682         int result = 0;
    683 
    684         try {
    685             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    686             if (iSub != null) {
    687                 result = iSub.getActiveSubInfoCountMax();
    688             }
    689         } catch (RemoteException ex) {
    690             // ignore it
    691         }
    692 
    693         return result;
    694     }
    695 
    696     /**
    697      * Add a new SubscriptionInfo to SubscriptionInfo database if needed
    698      * @param iccId the IccId of the SIM card
    699      * @param slotIndex the slot which the SIM is inserted
    700      * @return the URL of the newly created row or the updated row
    701      * @hide
    702      */
    703     public Uri addSubscriptionInfoRecord(String iccId, int slotIndex) {
    704         if (VDBG) logd("[addSubscriptionInfoRecord]+ iccId:" + iccId + " slotIndex:" + slotIndex);
    705         if (iccId == null) {
    706             logd("[addSubscriptionInfoRecord]- null iccId");
    707         }
    708         if (!isValidSlotIndex(slotIndex)) {
    709             logd("[addSubscriptionInfoRecord]- invalid slotIndex");
    710         }
    711 
    712         try {
    713             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    714             if (iSub != null) {
    715                 // FIXME: This returns 1 on success, 0 on error should should we return it?
    716                 iSub.addSubInfoRecord(iccId, slotIndex);
    717             }
    718         } catch (RemoteException ex) {
    719             // ignore it
    720         }
    721 
    722         // FIXME: Always returns null?
    723         return null;
    724 
    725     }
    726 
    727     /**
    728      * Set SIM icon tint color by simInfo index
    729      * @param tint the RGB value of icon tint color of the SIM
    730      * @param subId the unique SubInfoRecord index in database
    731      * @return the number of records updated
    732      * @hide
    733      */
    734     public int setIconTint(int tint, int subId) {
    735         if (VDBG) logd("[setIconTint]+ tint:" + tint + " subId:" + subId);
    736         if (!isValidSubscriptionId(subId)) {
    737             logd("[setIconTint]- fail");
    738             return -1;
    739         }
    740 
    741         int result = 0;
    742 
    743         try {
    744             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    745             if (iSub != null) {
    746                 result = iSub.setIconTint(tint, subId);
    747             }
    748         } catch (RemoteException ex) {
    749             // ignore it
    750         }
    751 
    752         return result;
    753 
    754     }
    755 
    756     /**
    757      * Set display name by simInfo index
    758      * @param displayName the display name of SIM card
    759      * @param subId the unique SubscriptionInfo index in database
    760      * @return the number of records updated
    761      * @hide
    762      */
    763     public int setDisplayName(String displayName, int subId) {
    764         return setDisplayName(displayName, subId, NAME_SOURCE_UNDEFINDED);
    765     }
    766 
    767     /**
    768      * Set display name by simInfo index with name source
    769      * @param displayName the display name of SIM card
    770      * @param subId the unique SubscriptionInfo index in database
    771      * @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE,
    772      *                   2: NAME_SOURCE_USER_INPUT, -1 NAME_SOURCE_UNDEFINED
    773      * @return the number of records updated or < 0 if invalid subId
    774      * @hide
    775      */
    776     public int setDisplayName(String displayName, int subId, long nameSource) {
    777         if (VDBG) {
    778             logd("[setDisplayName]+  displayName:" + displayName + " subId:" + subId
    779                     + " nameSource:" + nameSource);
    780         }
    781         if (!isValidSubscriptionId(subId)) {
    782             logd("[setDisplayName]- fail");
    783             return -1;
    784         }
    785 
    786         int result = 0;
    787 
    788         try {
    789             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    790             if (iSub != null) {
    791                 result = iSub.setDisplayNameUsingSrc(displayName, subId, nameSource);
    792             }
    793         } catch (RemoteException ex) {
    794             // ignore it
    795         }
    796 
    797         return result;
    798 
    799     }
    800 
    801     /**
    802      * Set phone number by subId
    803      * @param number the phone number of the SIM
    804      * @param subId the unique SubscriptionInfo index in database
    805      * @return the number of records updated
    806      * @hide
    807      */
    808     public int setDisplayNumber(String number, int subId) {
    809         if (number == null || !isValidSubscriptionId(subId)) {
    810             logd("[setDisplayNumber]- fail");
    811             return -1;
    812         }
    813 
    814         int result = 0;
    815 
    816         try {
    817             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    818             if (iSub != null) {
    819                 result = iSub.setDisplayNumber(number, subId);
    820             }
    821         } catch (RemoteException ex) {
    822             // ignore it
    823         }
    824 
    825         return result;
    826 
    827     }
    828 
    829     /**
    830      * Set data roaming by simInfo index
    831      * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming
    832      * @param subId the unique SubscriptionInfo index in database
    833      * @return the number of records updated
    834      * @hide
    835      */
    836     public int setDataRoaming(int roaming, int subId) {
    837         if (VDBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId);
    838         if (roaming < 0 || !isValidSubscriptionId(subId)) {
    839             logd("[setDataRoaming]- fail");
    840             return -1;
    841         }
    842 
    843         int result = 0;
    844 
    845         try {
    846             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    847             if (iSub != null) {
    848                 result = iSub.setDataRoaming(roaming, subId);
    849             }
    850         } catch (RemoteException ex) {
    851             // ignore it
    852         }
    853 
    854         return result;
    855     }
    856 
    857     /**
    858      * Get slotIndex associated with the subscription.
    859      * @return slotIndex as a positive integer or a negative value if an error either
    860      * SIM_NOT_INSERTED or < 0 if an invalid slot index
    861      * @hide
    862      */
    863     public static int getSlotIndex(int subId) {
    864         if (!isValidSubscriptionId(subId)) {
    865             if (DBG) {
    866                 logd("[getSlotIndex]- fail");
    867             }
    868         }
    869 
    870         int result = INVALID_SIM_SLOT_INDEX;
    871 
    872         try {
    873             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    874             if (iSub != null) {
    875                 result = iSub.getSlotIndex(subId);
    876             }
    877         } catch (RemoteException ex) {
    878             // ignore it
    879         }
    880 
    881         return result;
    882 
    883     }
    884 
    885     /** @hide */
    886     public static int[] getSubId(int slotIndex) {
    887         if (!isValidSlotIndex(slotIndex)) {
    888             logd("[getSubId]- fail");
    889             return null;
    890         }
    891 
    892         int[] subId = null;
    893 
    894         try {
    895             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    896             if (iSub != null) {
    897                 subId = iSub.getSubId(slotIndex);
    898             }
    899         } catch (RemoteException ex) {
    900             // ignore it
    901         }
    902 
    903         return subId;
    904     }
    905 
    906     /** @hide */
    907     public static int getPhoneId(int subId) {
    908         if (!isValidSubscriptionId(subId)) {
    909             if (DBG) {
    910                 logd("[getPhoneId]- fail");
    911             }
    912             return INVALID_PHONE_INDEX;
    913         }
    914 
    915         int result = INVALID_PHONE_INDEX;
    916 
    917         try {
    918             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    919             if (iSub != null) {
    920                 result = iSub.getPhoneId(subId);
    921             }
    922         } catch (RemoteException ex) {
    923             // ignore it
    924         }
    925 
    926         if (VDBG) logd("[getPhoneId]- phoneId=" + result);
    927         return result;
    928 
    929     }
    930 
    931     private static void logd(String msg) {
    932         Rlog.d(LOG_TAG, msg);
    933     }
    934 
    935     /**
    936      * Returns the system's default subscription id.
    937      *
    938      * For a voice capable device, it will return getDefaultVoiceSubscriptionId.
    939      * For a data only device, it will return the getDefaultDataSubscriptionId.
    940      * May return an INVALID_SUBSCRIPTION_ID on error.
    941      *
    942      * @return the "system" default subscription id.
    943      */
    944     public static int getDefaultSubscriptionId() {
    945         int subId = INVALID_SUBSCRIPTION_ID;
    946 
    947         try {
    948             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    949             if (iSub != null) {
    950                 subId = iSub.getDefaultSubId();
    951             }
    952         } catch (RemoteException ex) {
    953             // ignore it
    954         }
    955 
    956         if (VDBG) logd("getDefaultSubId=" + subId);
    957         return subId;
    958     }
    959 
    960     /**
    961      * Returns the system's default voice subscription id.
    962      *
    963      * On a data only device or on error, will return INVALID_SUBSCRIPTION_ID.
    964      *
    965      * @return the default voice subscription Id.
    966      */
    967     public static int getDefaultVoiceSubscriptionId() {
    968         int subId = INVALID_SUBSCRIPTION_ID;
    969 
    970         try {
    971             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    972             if (iSub != null) {
    973                 subId = iSub.getDefaultVoiceSubId();
    974             }
    975         } catch (RemoteException ex) {
    976             // ignore it
    977         }
    978 
    979         if (VDBG) logd("getDefaultVoiceSubscriptionId, sub id = " + subId);
    980         return subId;
    981     }
    982 
    983     /** @hide */
    984     public void setDefaultVoiceSubId(int subId) {
    985         if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId);
    986         try {
    987             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    988             if (iSub != null) {
    989                 iSub.setDefaultVoiceSubId(subId);
    990             }
    991         } catch (RemoteException ex) {
    992             // ignore it
    993         }
    994     }
    995 
    996     /**
    997      * Return the SubscriptionInfo for default voice subscription.
    998      *
    999      * Will return null on data only devices, or on error.
   1000      *
   1001      * @return the SubscriptionInfo for the default voice subscription.
   1002      * @hide
   1003      */
   1004     public SubscriptionInfo getDefaultVoiceSubscriptionInfo() {
   1005         return getActiveSubscriptionInfo(getDefaultVoiceSubscriptionId());
   1006     }
   1007 
   1008     /** @hide */
   1009     public static int getDefaultVoicePhoneId() {
   1010         return getPhoneId(getDefaultVoiceSubscriptionId());
   1011     }
   1012 
   1013     /**
   1014      * Returns the system's default SMS subscription id.
   1015      *
   1016      * On a data only device or on error, will return INVALID_SUBSCRIPTION_ID.
   1017      *
   1018      * @return the default SMS subscription Id.
   1019      */
   1020     public static int getDefaultSmsSubscriptionId() {
   1021         int subId = INVALID_SUBSCRIPTION_ID;
   1022 
   1023         try {
   1024             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
   1025             if (iSub != null) {
   1026                 subId = iSub.getDefaultSmsSubId();
   1027             }
   1028         } catch (RemoteException ex) {
   1029             // ignore it
   1030         }
   1031 
   1032         if (VDBG) logd("getDefaultSmsSubscriptionId, sub id = " + subId);
   1033         return subId;
   1034     }
   1035 
   1036     /** @hide */
   1037     public void setDefaultSmsSubId(int subId) {
   1038         if (VDBG) logd("setDefaultSmsSubId sub id = " + subId);
   1039         try {
   1040             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
   1041             if (iSub != null) {
   1042                 iSub.setDefaultSmsSubId(subId);
   1043             }
   1044         } catch (RemoteException ex) {
   1045             // ignore it
   1046         }
   1047     }
   1048 
   1049     /**
   1050      * Return the SubscriptionInfo for default voice subscription.
   1051      *
   1052      * Will return null on data only devices, or on error.
   1053      *
   1054      * @return the SubscriptionInfo for the default SMS subscription.
   1055      * @hide
   1056      */
   1057     public SubscriptionInfo getDefaultSmsSubscriptionInfo() {
   1058         return getActiveSubscriptionInfo(getDefaultSmsSubscriptionId());
   1059     }
   1060 
   1061     /** @hide */
   1062     public int getDefaultSmsPhoneId() {
   1063         return getPhoneId(getDefaultSmsSubscriptionId());
   1064     }
   1065 
   1066     /**
   1067      * Returns the system's default data subscription id.
   1068      *
   1069      * On a voice only device or on error, will return INVALID_SUBSCRIPTION_ID.
   1070      *
   1071      * @return the default data subscription Id.
   1072      */
   1073     public static int getDefaultDataSubscriptionId() {
   1074         int subId = INVALID_SUBSCRIPTION_ID;
   1075 
   1076         try {
   1077             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
   1078             if (iSub != null) {
   1079                 subId = iSub.getDefaultDataSubId();
   1080             }
   1081         } catch (RemoteException ex) {
   1082             // ignore it
   1083         }
   1084 
   1085         if (VDBG) logd("getDefaultDataSubscriptionId, sub id = " + subId);
   1086         return subId;
   1087     }
   1088 
   1089     /** @hide */
   1090     public void setDefaultDataSubId(int subId) {
   1091         if (VDBG) logd("setDataSubscription sub id = " + subId);
   1092         try {
   1093             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
   1094             if (iSub != null) {
   1095                 iSub.setDefaultDataSubId(subId);
   1096             }
   1097         } catch (RemoteException ex) {
   1098             // ignore it
   1099         }
   1100     }
   1101 
   1102     /**
   1103      * Return the SubscriptionInfo for default data subscription.
   1104      *
   1105      * Will return null on voice only devices, or on error.
   1106      *
   1107      * @return the SubscriptionInfo for the default data subscription.
   1108      * @hide
   1109      */
   1110     public SubscriptionInfo getDefaultDataSubscriptionInfo() {
   1111         return getActiveSubscriptionInfo(getDefaultDataSubscriptionId());
   1112     }
   1113 
   1114     /** @hide */
   1115     public int getDefaultDataPhoneId() {
   1116         return getPhoneId(getDefaultDataSubscriptionId());
   1117     }
   1118 
   1119     /** @hide */
   1120     public void clearSubscriptionInfo() {
   1121         try {
   1122             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
   1123             if (iSub != null) {
   1124                 iSub.clearSubInfo();
   1125             }
   1126         } catch (RemoteException ex) {
   1127             // ignore it
   1128         }
   1129 
   1130         return;
   1131     }
   1132 
   1133     //FIXME this is vulnerable to race conditions
   1134     /** @hide */
   1135     public boolean allDefaultsSelected() {
   1136         if (!isValidSubscriptionId(getDefaultDataSubscriptionId())) {
   1137             return false;
   1138         }
   1139         if (!isValidSubscriptionId(getDefaultSmsSubscriptionId())) {
   1140             return false;
   1141         }
   1142         if (!isValidSubscriptionId(getDefaultVoiceSubscriptionId())) {
   1143             return false;
   1144         }
   1145         return true;
   1146     }
   1147 
   1148     /**
   1149      * If a default is set to subscription which is not active, this will reset that default back to
   1150      * an invalid subscription id, i.e. < 0.
   1151      * @hide
   1152      */
   1153     public void clearDefaultsForInactiveSubIds() {
   1154         if (VDBG) logd("clearDefaultsForInactiveSubIds");
   1155         try {
   1156             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
   1157             if (iSub != null) {
   1158                 iSub.clearDefaultsForInactiveSubIds();
   1159             }
   1160         } catch (RemoteException ex) {
   1161             // ignore it
   1162         }
   1163     }
   1164 
   1165     /**
   1166      * @return true if a valid subId else false
   1167      * @hide
   1168      */
   1169     public static boolean isValidSubscriptionId(int subId) {
   1170         return subId > INVALID_SUBSCRIPTION_ID ;
   1171     }
   1172 
   1173     /**
   1174      * @return true if subId is an usable subId value else false. A
   1175      * usable subId means its neither a INVALID_SUBSCRIPTION_ID nor a DEFAULT_SUB_ID.
   1176      * @hide
   1177      */
   1178     public static boolean isUsableSubIdValue(int subId) {
   1179         return subId >= MIN_SUBSCRIPTION_ID_VALUE && subId <= MAX_SUBSCRIPTION_ID_VALUE;
   1180     }
   1181 
   1182     /** @hide */
   1183     public static boolean isValidSlotIndex(int slotIndex) {
   1184         return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getSimCount();
   1185     }
   1186 
   1187     /** @hide */
   1188     public static boolean isValidPhoneId(int phoneId) {
   1189         return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount();
   1190     }
   1191 
   1192     /** @hide */
   1193     public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) {
   1194         int[] subIds = SubscriptionManager.getSubId(phoneId);
   1195         if (subIds != null && subIds.length > 0) {
   1196             putPhoneIdAndSubIdExtra(intent, phoneId, subIds[0]);
   1197         } else {
   1198             logd("putPhoneIdAndSubIdExtra: no valid subs");
   1199         }
   1200     }
   1201 
   1202     /** @hide */
   1203     public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId, int subId) {
   1204         if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId);
   1205         intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
   1206         intent.putExtra(EXTRA_SUBSCRIPTION_INDEX, subId);
   1207         intent.putExtra(PhoneConstants.PHONE_KEY, phoneId);
   1208         //FIXME this is using phoneId and slotIndex interchangeably
   1209         //Eventually, this should be removed as it is not the slot id
   1210         intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);
   1211     }
   1212 
   1213     /**
   1214      * @return the list of subId's that are active,
   1215      *         is never null but the length maybe 0.
   1216      * @hide
   1217      */
   1218     public @NonNull int[] getActiveSubscriptionIdList() {
   1219         int[] subId = null;
   1220 
   1221         try {
   1222             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
   1223             if (iSub != null) {
   1224                 subId = iSub.getActiveSubIdList();
   1225             }
   1226         } catch (RemoteException ex) {
   1227             // ignore it
   1228         }
   1229 
   1230         if (subId == null) {
   1231             subId = new int[0];
   1232         }
   1233 
   1234         return subId;
   1235 
   1236     }
   1237 
   1238     /**
   1239      * Returns true if the device is considered roaming on the current
   1240      * network for a subscription.
   1241      * <p>
   1242      * Availability: Only when user registered to a network.
   1243      *
   1244      * @param subId The subscription ID
   1245      * @return true if the network for the subscription is roaming, false otherwise
   1246      */
   1247     public boolean isNetworkRoaming(int subId) {
   1248         final int phoneId = getPhoneId(subId);
   1249         if (phoneId < 0) {
   1250             // What else can we do?
   1251             return false;
   1252         }
   1253         return TelephonyManager.getDefault().isNetworkRoaming(subId);
   1254     }
   1255 
   1256     /**
   1257      * Returns a constant indicating the state of sim for the slot index.
   1258      *
   1259      * @param slotIndex
   1260      *
   1261      * {@See TelephonyManager#SIM_STATE_UNKNOWN}
   1262      * {@See TelephonyManager#SIM_STATE_ABSENT}
   1263      * {@See TelephonyManager#SIM_STATE_PIN_REQUIRED}
   1264      * {@See TelephonyManager#SIM_STATE_PUK_REQUIRED}
   1265      * {@See TelephonyManager#SIM_STATE_NETWORK_LOCKED}
   1266      * {@See TelephonyManager#SIM_STATE_READY}
   1267      * {@See TelephonyManager#SIM_STATE_NOT_READY}
   1268      * {@See TelephonyManager#SIM_STATE_PERM_DISABLED}
   1269      * {@See TelephonyManager#SIM_STATE_CARD_IO_ERROR}
   1270      *
   1271      * {@hide}
   1272      */
   1273     public static int getSimStateForSlotIndex(int slotIndex) {
   1274         int simState = TelephonyManager.SIM_STATE_UNKNOWN;
   1275 
   1276         try {
   1277             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
   1278             if (iSub != null) {
   1279                 simState = iSub.getSimStateForSlotIndex(slotIndex);
   1280             }
   1281         } catch (RemoteException ex) {
   1282         }
   1283 
   1284         return simState;
   1285     }
   1286 
   1287     /**
   1288      * Store properties associated with SubscriptionInfo in database
   1289      * @param subId Subscription Id of Subscription
   1290      * @param propKey Column name in database associated with SubscriptionInfo
   1291      * @param propValue Value to store in DB for particular subId & column name
   1292      * @hide
   1293      */
   1294     public static void setSubscriptionProperty(int subId, String propKey, String propValue) {
   1295         try {
   1296             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
   1297             if (iSub != null) {
   1298                 iSub.setSubscriptionProperty(subId, propKey, propValue);
   1299             }
   1300         } catch (RemoteException ex) {
   1301             // ignore it
   1302         }
   1303     }
   1304 
   1305     /**
   1306      * Store properties associated with SubscriptionInfo in database
   1307      * @param subId Subscription Id of Subscription
   1308      * @param propKey Column name in SubscriptionInfo database
   1309      * @return Value associated with subId and propKey column in database
   1310      * @hide
   1311      */
   1312     private static String getSubscriptionProperty(int subId, String propKey,
   1313             Context context) {
   1314         String resultValue = null;
   1315         try {
   1316             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
   1317             if (iSub != null) {
   1318                 resultValue = iSub.getSubscriptionProperty(subId, propKey,
   1319                     context.getOpPackageName());
   1320             }
   1321         } catch (RemoteException ex) {
   1322             // ignore it
   1323         }
   1324         return resultValue;
   1325     }
   1326 
   1327     /**
   1328      * Returns boolean value corresponding to query result.
   1329      * @param subId Subscription Id of Subscription
   1330      * @param propKey Column name in SubscriptionInfo database
   1331      * @param defValue Default boolean value to be returned
   1332      * @return boolean result value to be returned
   1333      * @hide
   1334      */
   1335     public static boolean getBooleanSubscriptionProperty(int subId, String propKey,
   1336             boolean defValue, Context context) {
   1337         String result = getSubscriptionProperty(subId, propKey, context);
   1338         if (result != null) {
   1339             try {
   1340                 return Integer.parseInt(result) == 1;
   1341             } catch (NumberFormatException err) {
   1342                 logd("getBooleanSubscriptionProperty NumberFormat exception");
   1343             }
   1344         }
   1345         return defValue;
   1346     }
   1347 
   1348     /**
   1349      * Returns integer value corresponding to query result.
   1350      * @param subId Subscription Id of Subscription
   1351      * @param propKey Column name in SubscriptionInfo database
   1352      * @param defValue Default integer value to be returned
   1353      * @return integer result value to be returned
   1354      * @hide
   1355      */
   1356     public static int getIntegerSubscriptionProperty(int subId, String propKey, int defValue,
   1357             Context context) {
   1358         String result = getSubscriptionProperty(subId, propKey, context);
   1359         if (result != null) {
   1360             try {
   1361                 return Integer.parseInt(result);
   1362             } catch (NumberFormatException err) {
   1363                 logd("getBooleanSubscriptionProperty NumberFormat exception");
   1364             }
   1365         }
   1366         return defValue;
   1367     }
   1368 
   1369     /**
   1370      * Returns the resources associated with Subscription.
   1371      * @param context Context object
   1372      * @param subId Subscription Id of Subscription who's resources are required
   1373      * @return Resources associated with Subscription.
   1374      * @hide
   1375      */
   1376     public static Resources getResourcesForSubId(Context context, int subId) {
   1377         final SubscriptionInfo subInfo =
   1378                 SubscriptionManager.from(context).getActiveSubscriptionInfo(subId);
   1379 
   1380         Configuration config = context.getResources().getConfiguration();
   1381         Configuration newConfig = new Configuration();
   1382         newConfig.setTo(config);
   1383         if (subInfo != null) {
   1384             newConfig.mcc = subInfo.getMcc();
   1385             newConfig.mnc = subInfo.getMnc();
   1386             if (newConfig.mnc == 0) newConfig.mnc = Configuration.MNC_ZERO;
   1387         }
   1388         DisplayMetrics metrics = context.getResources().getDisplayMetrics();
   1389         DisplayMetrics newMetrics = new DisplayMetrics();
   1390         newMetrics.setTo(metrics);
   1391         return new Resources(context.getResources().getAssets(), newMetrics, newConfig);
   1392     }
   1393 
   1394     /**
   1395      * @return true if the sub ID is active. i.e. The sub ID corresponds to a known subscription
   1396      * and the SIM providing the subscription is present in a slot and in "LOADED" state.
   1397      * @hide
   1398      */
   1399     public boolean isActiveSubId(int subId) {
   1400         try {
   1401             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
   1402             if (iSub != null) {
   1403                 return iSub.isActiveSubId(subId);
   1404             }
   1405         } catch (RemoteException ex) {
   1406         }
   1407         return false;
   1408     }
   1409 }
   1410