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