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.SdkConstant.SdkConstantType;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.net.Uri;
     25 import android.telephony.Rlog;
     26 import android.os.Handler;
     27 import android.os.Message;
     28 import android.os.ServiceManager;
     29 import android.os.RemoteException;
     30 
     31 import com.android.internal.telephony.ISub;
     32 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
     33 import com.android.internal.telephony.ITelephonyRegistry;
     34 import com.android.internal.telephony.PhoneConstants;
     35 import com.android.internal.telephony.TelephonyProperties;
     36 
     37 import java.util.ArrayList;
     38 import java.util.List;
     39 
     40 /**
     41  * SubscriptionManager is the application interface to SubscriptionController
     42  * and provides information about the current Telephony Subscriptions.
     43  * * <p>
     44  * You do not instantiate this class directly; instead, you retrieve
     45  * a reference to an instance through {@link #from}.
     46  * <p>
     47  * All SDK public methods require android.Manifest.permission.READ_PHONE_STATE.
     48  */
     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     /** @hide */
     56     public static final int INVALID_SUBSCRIPTION_ID = -1;
     57 
     58     /** Base value for Dummy SUBSCRIPTION_ID's. */
     59     /** FIXME: Remove DummySubId's, but for now have them map just below INVALID_SUBSCRIPTION_ID
     60     /** @hide */
     61     public static final int DUMMY_SUBSCRIPTION_ID_BASE = INVALID_SUBSCRIPTION_ID - 1;
     62 
     63     /** An invalid phone identifier */
     64     /** @hide */
     65     public static final int INVALID_PHONE_INDEX = -1;
     66 
     67     /** An invalid slot identifier */
     68     /** @hide */
     69     public static final int INVALID_SIM_SLOT_INDEX = -1;
     70 
     71     /** Indicates the caller wants the default sub id. */
     72     /** @hide */
     73     public static final int DEFAULT_SUBSCRIPTION_ID = Integer.MAX_VALUE;
     74 
     75     /**
     76      * Indicates the caller wants the default phone id.
     77      * Used in SubscriptionController and PhoneBase but do we really need it???
     78      * @hide
     79      */
     80     public static final int DEFAULT_PHONE_INDEX = Integer.MAX_VALUE;
     81 
     82     /** Indicates the caller wants the default slot id. NOT used remove? */
     83     /** @hide */
     84     public static final int DEFAULT_SIM_SLOT_INDEX = Integer.MAX_VALUE;
     85 
     86     /** Minimum possible subid that represents a subscription */
     87     /** @hide */
     88     public static final int MIN_SUBSCRIPTION_ID_VALUE = 0;
     89 
     90     /** Maximum possible subid that represents a subscription */
     91     /** @hide */
     92     public static final int MAX_SUBSCRIPTION_ID_VALUE = DEFAULT_SUBSCRIPTION_ID - 1;
     93 
     94     /** @hide */
     95     public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
     96 
     97     /**
     98      * TelephonyProvider unique key column name is the subscription id.
     99      * <P>Type: TEXT (String)</P>
    100      */
    101     /** @hide */
    102     public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
    103 
    104     /**
    105      * TelephonyProvider column name for SIM ICC Identifier
    106      * <P>Type: TEXT (String)</P>
    107      */
    108     /** @hide */
    109     public static final String ICC_ID = "icc_id";
    110 
    111     /**
    112      * TelephonyProvider column name for user SIM_SlOT_INDEX
    113      * <P>Type: INTEGER (int)</P>
    114      */
    115     /** @hide */
    116     public static final String SIM_SLOT_INDEX = "sim_id";
    117 
    118     /** SIM is not inserted */
    119     /** @hide */
    120     public static final int SIM_NOT_INSERTED = -1;
    121 
    122     /**
    123      * TelephonyProvider column name for user displayed name.
    124      * <P>Type: TEXT (String)</P>
    125      */
    126     /** @hide */
    127     public static final String DISPLAY_NAME = "display_name";
    128 
    129     /**
    130      * TelephonyProvider column name for the service provider name for the SIM.
    131      * <P>Type: TEXT (String)</P>
    132      */
    133     /** @hide */
    134     public static final String CARRIER_NAME = "carrier_name";
    135 
    136     /**
    137      * Default name resource
    138      * @hide
    139      */
    140     public static final int DEFAULT_NAME_RES = com.android.internal.R.string.unknownName;
    141 
    142     /**
    143      * TelephonyProvider column name for source of the user displayed name.
    144      * <P>Type: INT (int)</P> with one of the NAME_SOURCE_XXXX values below
    145      *
    146      * @hide
    147      */
    148     public static final String NAME_SOURCE = "name_source";
    149 
    150     /**
    151      * The name_source is undefined
    152      * @hide
    153      */
    154     public static final int NAME_SOURCE_UNDEFINDED = -1;
    155 
    156     /**
    157      * The name_source is the default
    158      * @hide
    159      */
    160     public static final int NAME_SOURCE_DEFAULT_SOURCE = 0;
    161 
    162     /**
    163      * The name_source is from the SIM
    164      * @hide
    165      */
    166     public static final int NAME_SOURCE_SIM_SOURCE = 1;
    167 
    168     /**
    169      * The name_source is from the user
    170      * @hide
    171      */
    172     public static final int NAME_SOURCE_USER_INPUT = 2;
    173 
    174     /**
    175      * TelephonyProvider column name for the color of a SIM.
    176      * <P>Type: INTEGER (int)</P>
    177      */
    178     /** @hide */
    179     public static final String COLOR = "color";
    180 
    181     /** @hide */
    182     public static final int COLOR_1 = 0;
    183 
    184     /** @hide */
    185     public static final int COLOR_2 = 1;
    186 
    187     /** @hide */
    188     public static final int COLOR_3 = 2;
    189 
    190     /** @hide */
    191     public static final int COLOR_4 = 3;
    192 
    193     /** @hide */
    194     public static final int COLOR_DEFAULT = COLOR_1;
    195 
    196     /**
    197      * TelephonyProvider column name for the phone number of a SIM.
    198      * <P>Type: TEXT (String)</P>
    199      */
    200     /** @hide */
    201     public static final String NUMBER = "number";
    202 
    203     /**
    204      * TelephonyProvider column name for the number display format of a SIM.
    205      * <P>Type: INTEGER (int)</P>
    206      */
    207     /** @hide */
    208     public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
    209 
    210     /** @hide */
    211     public static final int DISPLAY_NUMBER_NONE = 0;
    212 
    213     /** @hide */
    214     public static final int DISPLAY_NUMBER_FIRST = 1;
    215 
    216     /** @hide */
    217     public static final int DISPLAY_NUMBER_LAST = 2;
    218 
    219     /** @hide */
    220     public static final int DISPLAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST;
    221 
    222     /**
    223      * TelephonyProvider column name for permission for data roaming of a SIM.
    224      * <P>Type: INTEGER (int)</P>
    225      */
    226     /** @hide */
    227     public static final String DATA_ROAMING = "data_roaming";
    228 
    229     /** Indicates that data roaming is enabled for a subscription */
    230     public static final int DATA_ROAMING_ENABLE = 1;
    231 
    232     /** Indicates that data roaming is disabled for a subscription */
    233     public static final int DATA_ROAMING_DISABLE = 0;
    234 
    235     /** @hide */
    236     public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
    237 
    238     /**
    239      * TelephonyProvider column name for the MCC associated with a SIM.
    240      * <P>Type: INTEGER (int)</P>
    241      * @hide
    242      */
    243     public static final String MCC = "mcc";
    244 
    245     /**
    246      * TelephonyProvider column name for the MNC associated with a SIM.
    247      * <P>Type: INTEGER (int)</P>
    248      * @hide
    249      */
    250     public static final String MNC = "mnc";
    251 
    252     /**
    253      * Broadcast Action: The user has changed one of the default subs related to
    254      * data, phone calls, or sms</p>
    255      *
    256      * TODO: Change to a listener
    257      * @hide
    258      */
    259     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    260     public static final String SUB_DEFAULT_CHANGED_ACTION =
    261         "android.intent.action.SUB_DEFAULT_CHANGED";
    262 
    263     private final Context mContext;
    264 
    265     /**
    266      * A listener class for monitoring changes to {@link SubscriptionInfo} records.
    267      * <p>
    268      * Override the onSubscriptionsChanged method in the object that extends this
    269      * class and pass it to {@link #addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener)}
    270      * to register your listener and to unregister invoke
    271      * {@link #removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener)}
    272      * <p>
    273      * Permissions android.Manifest.permission.READ_PHONE_STATE is required
    274      * for #onSubscriptionsChanged to be invoked.
    275      */
    276     public static class OnSubscriptionsChangedListener {
    277         /** @hide */
    278         public static final String PERMISSION_ON_SUBSCRIPTIONS_CHANGED =
    279                 android.Manifest.permission.READ_PHONE_STATE;
    280 
    281         private final Handler mHandler  = new Handler() {
    282             @Override
    283             public void handleMessage(Message msg) {
    284                 if (DBG) {
    285                     log("handleMessage: invoke the overriden onSubscriptionsChanged()");
    286                 }
    287                 OnSubscriptionsChangedListener.this.onSubscriptionsChanged();
    288             }
    289         };
    290 
    291         /**
    292          * Callback invoked when there is any change to any SubscriptionInfo. Typically
    293          * this method would invoke {@link #getActiveSubscriptionInfoList}
    294          */
    295         public void onSubscriptionsChanged() {
    296             if (DBG) log("onSubscriptionsChanged: NOT OVERRIDDEN");
    297         }
    298 
    299         /**
    300          * The callback methods need to be called on the handler thread where
    301          * this object was created.  If the binder did that for us it'd be nice.
    302          */
    303         IOnSubscriptionsChangedListener callback = new IOnSubscriptionsChangedListener.Stub() {
    304             @Override
    305             public void onSubscriptionsChanged() {
    306                 if (DBG) log("callback: received, sendEmptyMessage(0) to handler");
    307                 mHandler.sendEmptyMessage(0);
    308             }
    309         };
    310 
    311         private void log(String s) {
    312             Rlog.d(LOG_TAG, s);
    313         }
    314     }
    315 
    316     /** @hide */
    317     public SubscriptionManager(Context context) {
    318         if (DBG) logd("SubscriptionManager created");
    319         mContext = context;
    320     }
    321 
    322     /**
    323      * Get an instance of the SubscriptionManager from the Context.
    324      * This invokes {@link android.content.Context#getSystemService
    325      * Context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)}.
    326      *
    327      * @param context to use.
    328      * @return SubscriptionManager instance
    329      */
    330     public static SubscriptionManager from(Context context) {
    331         return (SubscriptionManager) context.getSystemService(
    332                 Context.TELEPHONY_SUBSCRIPTION_SERVICE);
    333     }
    334 
    335     /**
    336      * Register for changes to the list of active {@link SubscriptionInfo} records or to the
    337      * individual records themselves. When a change occurs the onSubscriptionsChanged method of
    338      * the listener will be invoked immediately if there has been a notification.
    339      *
    340      * @param listener an instance of {@link OnSubscriptionsChangedListener} with
    341      *                 onSubscriptionsChanged overridden.
    342      */
    343     public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
    344         String pkgForDebug = mContext != null ? mContext.getPackageName() : "<unknown>";
    345         if (DBG) {
    346             logd("register OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug
    347                     + " listener=" + listener);
    348         }
    349         try {
    350             // We use the TelephonyRegistry as it runs in the system and thus is always
    351             // available. Where as SubscriptionController could crash and not be available
    352             ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
    353                     "telephony.registry"));
    354             if (tr != null) {
    355                 tr.addOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
    356             }
    357         } catch (RemoteException ex) {
    358             // Should not happen
    359         }
    360     }
    361 
    362     /**
    363      * Unregister the {@link OnSubscriptionsChangedListener}. This is not strictly necessary
    364      * as the listener will automatically be unregistered if an attempt to invoke the listener
    365      * fails.
    366      *
    367      * @param listener that is to be unregistered.
    368      */
    369     public void removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
    370         String pkgForDebug = mContext != null ? mContext.getPackageName() : "<unknown>";
    371         if (DBG) {
    372             logd("unregister OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug
    373                     + " listener=" + listener);
    374         }
    375         try {
    376             // We use the TelephonyRegistry as its runs in the system and thus is always
    377             // available where as SubscriptionController could crash and not be available
    378             ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
    379                     "telephony.registry"));
    380             if (tr != null) {
    381                 tr.removeOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
    382             }
    383         } catch (RemoteException ex) {
    384             // Should not happen
    385         }
    386     }
    387 
    388     /**
    389      * Get the active SubscriptionInfo with the subId key
    390      * @param subId The unique SubscriptionInfo key in database
    391      * @return SubscriptionInfo, maybe null if its not active.
    392      */
    393     public SubscriptionInfo getActiveSubscriptionInfo(int subId) {
    394         if (VDBG) logd("[getActiveSubscriptionInfo]+ subId=" + subId);
    395         if (!isValidSubscriptionId(subId)) {
    396             logd("[getActiveSubscriptionInfo]- invalid subId");
    397             return null;
    398         }
    399 
    400         SubscriptionInfo subInfo = null;
    401 
    402         try {
    403             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    404             if (iSub != null) {
    405                 subInfo = iSub.getActiveSubscriptionInfo(subId);
    406             }
    407         } catch (RemoteException ex) {
    408             // ignore it
    409         }
    410 
    411         return subInfo;
    412 
    413     }
    414 
    415     /**
    416      * Get the active SubscriptionInfo associated with the iccId
    417      * @param iccId the IccId of SIM card
    418      * @return SubscriptionInfo, maybe null if its not active
    419      * @hide
    420      */
    421     public SubscriptionInfo getActiveSubscriptionInfoForIccIndex(String iccId) {
    422         if (VDBG) logd("[getActiveSubscriptionInfoForIccIndex]+ iccId=" + iccId);
    423         if (iccId == null) {
    424             logd("[getActiveSubscriptionInfoForIccIndex]- null iccid");
    425             return null;
    426         }
    427 
    428         SubscriptionInfo result = null;
    429 
    430         try {
    431             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    432             if (iSub != null) {
    433                 result = iSub.getActiveSubscriptionInfoForIccId(iccId);
    434             }
    435         } catch (RemoteException ex) {
    436             // ignore it
    437         }
    438 
    439         return result;
    440     }
    441 
    442     /**
    443      * Get the active SubscriptionInfo associated with the slotIdx
    444      * @param slotIdx the slot which the subscription is inserted
    445      * @return SubscriptionInfo, maybe null if its not active
    446      */
    447     public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIdx) {
    448         if (VDBG) logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIdx=" + slotIdx);
    449         if (!isValidSlotId(slotIdx)) {
    450             logd("[getActiveSubscriptionInfoForSimSlotIndex]- invalid slotIdx");
    451             return null;
    452         }
    453 
    454         SubscriptionInfo result = null;
    455 
    456         try {
    457             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    458             if (iSub != null) {
    459                 result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIdx);
    460             }
    461         } catch (RemoteException ex) {
    462             // ignore it
    463         }
    464 
    465         return result;
    466     }
    467 
    468     /**
    469      * @return List of all SubscriptionInfo records in database,
    470      * include those that were inserted before, maybe empty but not null.
    471      * @hide
    472      */
    473     public List<SubscriptionInfo> getAllSubscriptionInfoList() {
    474         if (VDBG) logd("[getAllSubscriptionInfoList]+");
    475 
    476         List<SubscriptionInfo> result = null;
    477 
    478         try {
    479             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    480             if (iSub != null) {
    481                 result = iSub.getAllSubInfoList();
    482             }
    483         } catch (RemoteException ex) {
    484             // ignore it
    485         }
    486 
    487         if (result == null) {
    488             result = new ArrayList<SubscriptionInfo>();
    489         }
    490         return result;
    491     }
    492 
    493     /**
    494      * Get the SubscriptionInfo(s) of the currently inserted SIM(s). The records will be sorted
    495      * by {@link SubscriptionInfo#getSimSlotIndex} then by {@link SubscriptionInfo#getSubscriptionId}.
    496      *
    497      * @return Sorted list of the currently {@link SubscriptionInfo} records available on the device.
    498      * <ul>
    499      * <li>
    500      * If null is returned the current state is unknown but if a {@link OnSubscriptionsChangedListener}
    501      * has been registered {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be
    502      * invoked in the future.
    503      * </li>
    504      * <li>
    505      * If the list is empty then there are no {@link SubscriptionInfo} records currently available.
    506      * </li>
    507      * <li>
    508      * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex}
    509      * then by {@link SubscriptionInfo#getSubscriptionId}.
    510      * </li>
    511      * </ul>
    512      */
    513     public List<SubscriptionInfo> getActiveSubscriptionInfoList() {
    514         List<SubscriptionInfo> result = null;
    515 
    516         try {
    517             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    518             if (iSub != null) {
    519                 result = iSub.getActiveSubscriptionInfoList();
    520             }
    521         } catch (RemoteException ex) {
    522             // ignore it
    523         }
    524         return result;
    525     }
    526 
    527     /**
    528      * @return the count of all subscriptions in the database, this includes
    529      * all subscriptions that have been seen.
    530      * @hide
    531      */
    532     public int getAllSubscriptionInfoCount() {
    533         if (VDBG) logd("[getAllSubscriptionInfoCount]+");
    534 
    535         int result = 0;
    536 
    537         try {
    538             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    539             if (iSub != null) {
    540                 result = iSub.getAllSubInfoCount();
    541             }
    542         } catch (RemoteException ex) {
    543             // ignore it
    544         }
    545 
    546         return result;
    547     }
    548 
    549     /**
    550      * @return the current number of active subscriptions. There is no guarantee the value
    551      * returned by this method will be the same as the length of the list returned by
    552      * {@link #getActiveSubscriptionInfoList}.
    553      */
    554     public int getActiveSubscriptionInfoCount() {
    555         int result = 0;
    556 
    557         try {
    558             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    559             if (iSub != null) {
    560                 result = iSub.getActiveSubInfoCount();
    561             }
    562         } catch (RemoteException ex) {
    563             // ignore it
    564         }
    565 
    566         return result;
    567     }
    568 
    569     /**
    570      * @return the maximum number of active subscriptions that will be returned by
    571      * {@link #getActiveSubscriptionInfoList} and the value returned by
    572      * {@link #getActiveSubscriptionInfoCount}.
    573      */
    574     public int getActiveSubscriptionInfoCountMax() {
    575         int result = 0;
    576 
    577         try {
    578             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    579             if (iSub != null) {
    580                 result = iSub.getActiveSubInfoCountMax();
    581             }
    582         } catch (RemoteException ex) {
    583             // ignore it
    584         }
    585 
    586         return result;
    587     }
    588 
    589     /**
    590      * Add a new SubscriptionInfo to SubscriptionInfo database if needed
    591      * @param iccId the IccId of the SIM card
    592      * @param slotId the slot which the SIM is inserted
    593      * @return the URL of the newly created row or the updated row
    594      * @hide
    595      */
    596     public Uri addSubscriptionInfoRecord(String iccId, int slotId) {
    597         if (VDBG) logd("[addSubscriptionInfoRecord]+ iccId:" + iccId + " slotId:" + slotId);
    598         if (iccId == null) {
    599             logd("[addSubscriptionInfoRecord]- null iccId");
    600         }
    601         if (!isValidSlotId(slotId)) {
    602             logd("[addSubscriptionInfoRecord]- invalid slotId");
    603         }
    604 
    605         try {
    606             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    607             if (iSub != null) {
    608                 // FIXME: This returns 1 on success, 0 on error should should we return it?
    609                 iSub.addSubInfoRecord(iccId, slotId);
    610             }
    611         } catch (RemoteException ex) {
    612             // ignore it
    613         }
    614 
    615         // FIXME: Always returns null?
    616         return null;
    617 
    618     }
    619 
    620     /**
    621      * Set SIM icon tint color by simInfo index
    622      * @param tint the RGB value of icon tint color of the SIM
    623      * @param subId the unique SubInfoRecord index in database
    624      * @return the number of records updated
    625      * @hide
    626      */
    627     public int setIconTint(int tint, int subId) {
    628         if (VDBG) logd("[setIconTint]+ tint:" + tint + " subId:" + subId);
    629         if (!isValidSubscriptionId(subId)) {
    630             logd("[setIconTint]- fail");
    631             return -1;
    632         }
    633 
    634         int result = 0;
    635 
    636         try {
    637             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    638             if (iSub != null) {
    639                 result = iSub.setIconTint(tint, subId);
    640             }
    641         } catch (RemoteException ex) {
    642             // ignore it
    643         }
    644 
    645         return result;
    646 
    647     }
    648 
    649     /**
    650      * Set display name by simInfo index
    651      * @param displayName the display name of SIM card
    652      * @param subId the unique SubscriptionInfo index in database
    653      * @return the number of records updated
    654      * @hide
    655      */
    656     public int setDisplayName(String displayName, int subId) {
    657         return setDisplayName(displayName, subId, NAME_SOURCE_UNDEFINDED);
    658     }
    659 
    660     /**
    661      * Set display name by simInfo index with name source
    662      * @param displayName the display name of SIM card
    663      * @param subId the unique SubscriptionInfo index in database
    664      * @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE,
    665      *                   2: NAME_SOURCE_USER_INPUT, -1 NAME_SOURCE_UNDEFINED
    666      * @return the number of records updated or < 0 if invalid subId
    667      * @hide
    668      */
    669     public int setDisplayName(String displayName, int subId, long nameSource) {
    670         if (VDBG) {
    671             logd("[setDisplayName]+  displayName:" + displayName + " subId:" + subId
    672                     + " nameSource:" + nameSource);
    673         }
    674         if (!isValidSubscriptionId(subId)) {
    675             logd("[setDisplayName]- fail");
    676             return -1;
    677         }
    678 
    679         int result = 0;
    680 
    681         try {
    682             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    683             if (iSub != null) {
    684                 result = iSub.setDisplayNameUsingSrc(displayName, subId, nameSource);
    685             }
    686         } catch (RemoteException ex) {
    687             // ignore it
    688         }
    689 
    690         return result;
    691 
    692     }
    693 
    694     /**
    695      * Set phone number by subId
    696      * @param number the phone number of the SIM
    697      * @param subId the unique SubscriptionInfo index in database
    698      * @return the number of records updated
    699      * @hide
    700      */
    701     public int setDisplayNumber(String number, int subId) {
    702         if (number == null || !isValidSubscriptionId(subId)) {
    703             logd("[setDisplayNumber]- fail");
    704             return -1;
    705         }
    706 
    707         int result = 0;
    708 
    709         try {
    710             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    711             if (iSub != null) {
    712                 result = iSub.setDisplayNumber(number, subId);
    713             }
    714         } catch (RemoteException ex) {
    715             // ignore it
    716         }
    717 
    718         return result;
    719 
    720     }
    721 
    722     /**
    723      * Set data roaming by simInfo index
    724      * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming
    725      * @param subId the unique SubscriptionInfo index in database
    726      * @return the number of records updated
    727      * @hide
    728      */
    729     public int setDataRoaming(int roaming, int subId) {
    730         if (VDBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId);
    731         if (roaming < 0 || !isValidSubscriptionId(subId)) {
    732             logd("[setDataRoaming]- fail");
    733             return -1;
    734         }
    735 
    736         int result = 0;
    737 
    738         try {
    739             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    740             if (iSub != null) {
    741                 result = iSub.setDataRoaming(roaming, subId);
    742             }
    743         } catch (RemoteException ex) {
    744             // ignore it
    745         }
    746 
    747         return result;
    748     }
    749 
    750     /**
    751      * Get slotId associated with the subscription.
    752      * @return slotId as a positive integer or a negative value if an error either
    753      * SIM_NOT_INSERTED or < 0 if an invalid slot index
    754      * @hide
    755      */
    756     public static int getSlotId(int subId) {
    757         if (!isValidSubscriptionId(subId)) {
    758             logd("[getSlotId]- fail");
    759         }
    760 
    761         int result = INVALID_SIM_SLOT_INDEX;
    762 
    763         try {
    764             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    765             if (iSub != null) {
    766                 result = iSub.getSlotId(subId);
    767             }
    768         } catch (RemoteException ex) {
    769             // ignore it
    770         }
    771 
    772         return result;
    773 
    774     }
    775 
    776     /** @hide */
    777     public static int[] getSubId(int slotId) {
    778         if (!isValidSlotId(slotId)) {
    779             logd("[getSubId]- fail");
    780             return null;
    781         }
    782 
    783         int[] subId = null;
    784 
    785         try {
    786             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    787             if (iSub != null) {
    788                 subId = iSub.getSubId(slotId);
    789             }
    790         } catch (RemoteException ex) {
    791             // ignore it
    792         }
    793 
    794         return subId;
    795     }
    796 
    797     /** @hide */
    798     public static int getPhoneId(int subId) {
    799         if (!isValidSubscriptionId(subId)) {
    800             logd("[getPhoneId]- fail");
    801             return INVALID_PHONE_INDEX;
    802         }
    803 
    804         int result = INVALID_PHONE_INDEX;
    805 
    806         try {
    807             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    808             if (iSub != null) {
    809                 result = iSub.getPhoneId(subId);
    810             }
    811         } catch (RemoteException ex) {
    812             // ignore it
    813         }
    814 
    815         if (VDBG) logd("[getPhoneId]- phoneId=" + result);
    816         return result;
    817 
    818     }
    819 
    820     private static void logd(String msg) {
    821         Rlog.d(LOG_TAG, msg);
    822     }
    823 
    824     /**
    825      * @return the "system" defaultSubId on a voice capable device this
    826      * will be getDefaultVoiceSubId() and on a data only device it will be
    827      * getDefaultDataSubId().
    828      * @hide
    829      */
    830     public static int getDefaultSubId() {
    831         int subId = INVALID_SUBSCRIPTION_ID;
    832 
    833         try {
    834             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    835             if (iSub != null) {
    836                 subId = iSub.getDefaultSubId();
    837             }
    838         } catch (RemoteException ex) {
    839             // ignore it
    840         }
    841 
    842         if (VDBG) logd("getDefaultSubId=" + subId);
    843         return subId;
    844     }
    845 
    846     /** @hide */
    847     public static int getDefaultVoiceSubId() {
    848         int subId = INVALID_SUBSCRIPTION_ID;
    849 
    850         try {
    851             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    852             if (iSub != null) {
    853                 subId = iSub.getDefaultVoiceSubId();
    854             }
    855         } catch (RemoteException ex) {
    856             // ignore it
    857         }
    858 
    859         if (VDBG) logd("getDefaultVoiceSubId, sub id = " + subId);
    860         return subId;
    861     }
    862 
    863     /** @hide */
    864     public void setDefaultVoiceSubId(int subId) {
    865         if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId);
    866         try {
    867             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    868             if (iSub != null) {
    869                 iSub.setDefaultVoiceSubId(subId);
    870             }
    871         } catch (RemoteException ex) {
    872             // ignore it
    873         }
    874     }
    875 
    876     /** @hide */
    877     public SubscriptionInfo getDefaultVoiceSubscriptionInfo() {
    878         return getActiveSubscriptionInfo(getDefaultVoiceSubId());
    879     }
    880 
    881     /** @hide */
    882     public static int getDefaultVoicePhoneId() {
    883         return getPhoneId(getDefaultVoiceSubId());
    884     }
    885 
    886     /**
    887      * @return subId of the DefaultSms subscription or
    888      * a value < 0 if an error.
    889      *
    890      * @hide
    891      */
    892     public static int getDefaultSmsSubId() {
    893         int subId = INVALID_SUBSCRIPTION_ID;
    894 
    895         try {
    896             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    897             if (iSub != null) {
    898                 subId = iSub.getDefaultSmsSubId();
    899             }
    900         } catch (RemoteException ex) {
    901             // ignore it
    902         }
    903 
    904         if (VDBG) logd("getDefaultSmsSubId, sub id = " + subId);
    905         return subId;
    906     }
    907 
    908     /** @hide */
    909     public void setDefaultSmsSubId(int subId) {
    910         if (VDBG) logd("setDefaultSmsSubId sub id = " + subId);
    911         try {
    912             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    913             if (iSub != null) {
    914                 iSub.setDefaultSmsSubId(subId);
    915             }
    916         } catch (RemoteException ex) {
    917             // ignore it
    918         }
    919     }
    920 
    921     /** @hide */
    922     public SubscriptionInfo getDefaultSmsSubscriptionInfo() {
    923         return getActiveSubscriptionInfo(getDefaultSmsSubId());
    924     }
    925 
    926     /** @hide */
    927     public int getDefaultSmsPhoneId() {
    928         return getPhoneId(getDefaultSmsSubId());
    929     }
    930 
    931     /** @hide */
    932     public static int getDefaultDataSubId() {
    933         int subId = INVALID_SUBSCRIPTION_ID;
    934 
    935         try {
    936             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    937             if (iSub != null) {
    938                 subId = iSub.getDefaultDataSubId();
    939             }
    940         } catch (RemoteException ex) {
    941             // ignore it
    942         }
    943 
    944         if (VDBG) logd("getDefaultDataSubId, sub id = " + subId);
    945         return subId;
    946     }
    947 
    948     /** @hide */
    949     public void setDefaultDataSubId(int subId) {
    950         if (VDBG) logd("setDataSubscription sub id = " + subId);
    951         try {
    952             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    953             if (iSub != null) {
    954                 iSub.setDefaultDataSubId(subId);
    955             }
    956         } catch (RemoteException ex) {
    957             // ignore it
    958         }
    959     }
    960 
    961     /** @hide */
    962     public SubscriptionInfo getDefaultDataSubscriptionInfo() {
    963         return getActiveSubscriptionInfo(getDefaultDataSubId());
    964     }
    965 
    966     /** @hide */
    967     public int getDefaultDataPhoneId() {
    968         return getPhoneId(getDefaultDataSubId());
    969     }
    970 
    971     /** @hide */
    972     public void clearSubscriptionInfo() {
    973         try {
    974             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
    975             if (iSub != null) {
    976                 iSub.clearSubInfo();
    977             }
    978         } catch (RemoteException ex) {
    979             // ignore it
    980         }
    981 
    982         return;
    983     }
    984 
    985     //FIXME this is vulnerable to race conditions
    986     /** @hide */
    987     public boolean allDefaultsSelected() {
    988         if (!isValidSubscriptionId(getDefaultDataSubId())) {
    989             return false;
    990         }
    991         if (!isValidSubscriptionId(getDefaultSmsSubId())) {
    992             return false;
    993         }
    994         if (!isValidSubscriptionId(getDefaultVoiceSubId())) {
    995             return false;
    996         }
    997         return true;
    998     }
    999 
   1000     /**
   1001      * If a default is set to subscription which is not active, this will reset that default back to
   1002      * an invalid subscription id, i.e. < 0.
   1003      * @hide
   1004      */
   1005     public void clearDefaultsForInactiveSubIds() {
   1006         if (VDBG) logd("clearDefaultsForInactiveSubIds");
   1007         try {
   1008             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
   1009             if (iSub != null) {
   1010                 iSub.clearDefaultsForInactiveSubIds();
   1011             }
   1012         } catch (RemoteException ex) {
   1013             // ignore it
   1014         }
   1015     }
   1016 
   1017     /**
   1018      * @return true if a valid subId else false
   1019      * @hide
   1020      */
   1021     public static boolean isValidSubscriptionId(int subId) {
   1022         return subId > INVALID_SUBSCRIPTION_ID ;
   1023     }
   1024 
   1025     /**
   1026      * @return true if subId is an usable subId value else false. A
   1027      * usable subId means its neither a INVALID_SUBSCRIPTION_ID nor a DEFAULT_SUB_ID.
   1028      * @hide
   1029      */
   1030     public static boolean isUsableSubIdValue(int subId) {
   1031         return subId >= MIN_SUBSCRIPTION_ID_VALUE && subId <= MAX_SUBSCRIPTION_ID_VALUE;
   1032     }
   1033 
   1034     /** @hide */
   1035     public static boolean isValidSlotId(int slotId) {
   1036         return slotId >= 0 && slotId < TelephonyManager.getDefault().getSimCount();
   1037     }
   1038 
   1039     /** @hide */
   1040     public static boolean isValidPhoneId(int phoneId) {
   1041         return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount();
   1042     }
   1043 
   1044     /** @hide */
   1045     public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) {
   1046         int[] subIds = SubscriptionManager.getSubId(phoneId);
   1047         if (subIds != null && subIds.length > 0) {
   1048             putPhoneIdAndSubIdExtra(intent, phoneId, subIds[0]);
   1049         } else {
   1050             logd("putPhoneIdAndSubIdExtra: no valid subs");
   1051         }
   1052     }
   1053 
   1054     /** @hide */
   1055     public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId, int subId) {
   1056         if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId);
   1057         intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
   1058         intent.putExtra(PhoneConstants.PHONE_KEY, phoneId);
   1059         //FIXME this is using phoneId and slotId interchangeably
   1060         //Eventually, this should be removed as it is not the slot id
   1061         intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);
   1062     }
   1063 
   1064     /**
   1065      * @return the list of subId's that are active,
   1066      *         is never null but the length maybe 0.
   1067      * @hide
   1068      */
   1069     public @NonNull int[] getActiveSubscriptionIdList() {
   1070         int[] subId = null;
   1071 
   1072         try {
   1073             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
   1074             if (iSub != null) {
   1075                 subId = iSub.getActiveSubIdList();
   1076             }
   1077         } catch (RemoteException ex) {
   1078             // ignore it
   1079         }
   1080 
   1081         if (subId == null) {
   1082             subId = new int[0];
   1083         }
   1084 
   1085         return subId;
   1086 
   1087     }
   1088 
   1089     /**
   1090      * Returns true if the device is considered roaming on the current
   1091      * network for a subscription.
   1092      * <p>
   1093      * Availability: Only when user registered to a network.
   1094      *
   1095      * @param subId The subscription ID
   1096      * @return true if the network for the subscription is roaming, false otherwise
   1097      */
   1098     public boolean isNetworkRoaming(int subId) {
   1099         final int phoneId = getPhoneId(subId);
   1100         if (phoneId < 0) {
   1101             // What else can we do?
   1102             return false;
   1103         }
   1104         return TelephonyManager.getDefault().isNetworkRoaming(subId);
   1105     }
   1106 
   1107     /**
   1108      * Returns a constant indicating the state of sim for the subscription.
   1109      *
   1110      * @param subId
   1111      *
   1112      * {@See TelephonyManager#SIM_STATE_UNKNOWN}
   1113      * {@See TelephonyManager#SIM_STATE_ABSENT}
   1114      * {@See TelephonyManager#SIM_STATE_PIN_REQUIRED}
   1115      * {@See TelephonyManager#SIM_STATE_PUK_REQUIRED}
   1116      * {@See TelephonyManager#SIM_STATE_NETWORK_LOCKED}
   1117      * {@See TelephonyManager#SIM_STATE_READY}
   1118      * {@See TelephonyManager#SIM_STATE_NOT_READY}
   1119      * {@See TelephonyManager#SIM_STATE_PERM_DISABLED}
   1120      * {@See TelephonyManager#SIM_STATE_CARD_IO_ERROR}
   1121      *
   1122      * {@hide}
   1123      */
   1124     public static int getSimStateForSubscriber(int subId) {
   1125         int simState;
   1126 
   1127         try {
   1128             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
   1129             simState = iSub.getSimStateForSubscriber(subId);
   1130         } catch (RemoteException ex) {
   1131             simState = TelephonyManager.SIM_STATE_UNKNOWN;
   1132         }
   1133         logd("getSimStateForSubscriber: simState=" + simState + " subId=" + subId);
   1134         return simState;
   1135     }
   1136 }
   1137 
   1138