2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package android.telephony;
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.content.res.Configuration;
25 import android.content.res.Resources;
26 import android.net.Uri;
27 import android.telephony.Rlog;
28 import android.os.Handler;
29 import android.os.Message;
30 import android.os.ServiceManager;
31 import android.os.RemoteException;
32 import android.util.DisplayMetrics;
34 import com.android.internal.telephony.ISub;
35 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
36 import com.android.internal.telephony.ITelephonyRegistry;
37 import com.android.internal.telephony.PhoneConstants;
38 import java.util.ArrayList;
39 import java.util.List;
42 * SubscriptionManager is the application interface to SubscriptionController
43 * and provides information about the current Telephony Subscriptions.
45 * You do not instantiate this class directly; instead, you retrieve
46 * a reference to an instance through {@link #from}.
48 * All SDK public methods require android.Manifest.permission.READ_PHONE_STATE.
50 public class SubscriptionManager {
51 private static final String LOG_TAG = "SubscriptionManager";
52 private static final boolean DBG = false;
53 private static final boolean VDBG = false;
55 /** An invalid subscription identifier */
56 public static final int INVALID_SUBSCRIPTION_ID = -1;
58 /** Base value for Dummy SUBSCRIPTION_ID's. */
59 /** FIXME: Remove DummySubId's, but for now have them map just below INVALID_SUBSCRIPTION_ID
61 public static final int DUMMY_SUBSCRIPTION_ID_BASE = INVALID_SUBSCRIPTION_ID - 1;
63 /** An invalid phone identifier */
65 public static final int INVALID_PHONE_INDEX = -1;
67 /** An invalid slot identifier */
69 public static final int INVALID_SIM_SLOT_INDEX = -1;
71 /** Indicates the caller wants the default sub id. */
73 public static final int DEFAULT_SUBSCRIPTION_ID = Integer.MAX_VALUE;
76 * Indicates the caller wants the default phone id.
77 * Used in SubscriptionController and Phone but do we really need it???
80 public static final int DEFAULT_PHONE_INDEX = Integer.MAX_VALUE;
82 /** Indicates the caller wants the default slot id. NOT used remove? */
84 public static final int DEFAULT_SIM_SLOT_INDEX = Integer.MAX_VALUE;
86 /** Minimum possible subid that represents a subscription */
88 public static final int MIN_SUBSCRIPTION_ID_VALUE = 0;
90 /** Maximum possible subid that represents a subscription */
92 public static final int MAX_SUBSCRIPTION_ID_VALUE = DEFAULT_SUBSCRIPTION_ID - 1;
95 public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
98 * TelephonyProvider unique key column name is the subscription id.
99 * <P>Type: TEXT (String)</P>
102 public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
105 * TelephonyProvider column name for SIM ICC Identifier
106 * <P>Type: TEXT (String)</P>
109 public static final String ICC_ID = "icc_id";
112 * TelephonyProvider column name for user SIM_SlOT_INDEX
113 * <P>Type: INTEGER (int)</P>
116 public static final String SIM_SLOT_INDEX = "sim_id";
118 /** SIM is not inserted */
120 public static final int SIM_NOT_INSERTED = -1;
123 * TelephonyProvider column name for user displayed name.
124 * <P>Type: TEXT (String)</P>
127 public static final String DISPLAY_NAME = "display_name";
130 * TelephonyProvider column name for the service provider name for the SIM.
131 * <P>Type: TEXT (String)</P>
134 public static final String CARRIER_NAME = "carrier_name";
137 * Default name resource
140 public static final int DEFAULT_NAME_RES = com.android.internal.R.string.unknownName;
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
148 public static final String NAME_SOURCE = "name_source";
151 * The name_source is undefined
154 public static final int NAME_SOURCE_UNDEFINDED = -1;
157 * The name_source is the default
160 public static final int NAME_SOURCE_DEFAULT_SOURCE = 0;
163 * The name_source is from the SIM
166 public static final int NAME_SOURCE_SIM_SOURCE = 1;
169 * The name_source is from the user
172 public static final int NAME_SOURCE_USER_INPUT = 2;
175 * TelephonyProvider column name for the color of a SIM.
176 * <P>Type: INTEGER (int)</P>
179 public static final String COLOR = "color";
182 public static final int COLOR_1 = 0;
185 public static final int COLOR_2 = 1;
188 public static final int COLOR_3 = 2;
191 public static final int COLOR_4 = 3;
194 public static final int COLOR_DEFAULT = COLOR_1;
197 * TelephonyProvider column name for the phone number of a SIM.
198 * <P>Type: TEXT (String)</P>
201 public static final String NUMBER = "number";
204 * TelephonyProvider column name for the number display format of a SIM.
205 * <P>Type: INTEGER (int)</P>
208 public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
211 public static final int DISPLAY_NUMBER_NONE = 0;
214 public static final int DISPLAY_NUMBER_FIRST = 1;
217 public static final int DISPLAY_NUMBER_LAST = 2;
220 public static final int DISPLAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST;
223 * TelephonyProvider column name for permission for data roaming of a SIM.
224 * <P>Type: INTEGER (int)</P>
227 public static final String DATA_ROAMING = "data_roaming";
229 /** Indicates that data roaming is enabled for a subscription */
230 public static final int DATA_ROAMING_ENABLE = 1;
232 /** Indicates that data roaming is disabled for a subscription */
233 public static final int DATA_ROAMING_DISABLE = 0;
236 public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
239 public static final int SIM_PROVISIONED = 0;
242 * TelephonyProvider column name for the MCC associated with a SIM.
243 * <P>Type: INTEGER (int)</P>
246 public static final String MCC = "mcc";
249 * TelephonyProvider column name for the MNC associated with a SIM.
250 * <P>Type: INTEGER (int)</P>
253 public static final String MNC = "mnc";
256 * TelephonyProvider column name for the sim provisioning status associated with a SIM.
257 * <P>Type: INTEGER (int)</P>
260 public static final String SIM_PROVISIONING_STATUS = "sim_provisioning_status";
263 * TelephonyProvider column name for extreme threat in CB settings
266 public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
269 * TelephonyProvider column name for severe threat in CB settings
272 public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
275 * TelephonyProvider column name for amber alert in CB settings
278 public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
281 * TelephonyProvider column name for emergency alert in CB settings
284 public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
287 * TelephonyProvider column name for alert sound duration in CB settings
290 public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
293 * TelephonyProvider column name for alert reminder interval in CB settings
296 public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
299 * TelephonyProvider column name for enabling vibrate in CB settings
302 public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
305 * TelephonyProvider column name for enabling alert speech in CB settings
308 public static final String CB_ALERT_SPEECH = "enable_alert_speech";
311 * TelephonyProvider column name for ETWS test alert in CB settings
314 public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
317 * TelephonyProvider column name for enable channel50 alert in CB settings
320 public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
323 * TelephonyProvider column name for CMAS test alert in CB settings
326 public static final String CB_CMAS_TEST_ALERT= "enable_cmas_test_alerts";
329 * TelephonyProvider column name for Opt out dialog in CB settings
332 public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
335 * Broadcast Action: The user has changed one of the default subs related to
336 * data, phone calls, or sms</p>
338 * TODO: Change to a listener
341 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
342 public static final String SUB_DEFAULT_CHANGED_ACTION =
343 "android.intent.action.SUB_DEFAULT_CHANGED";
345 private final Context mContext;
348 * A listener class for monitoring changes to {@link SubscriptionInfo} records.
350 * Override the onSubscriptionsChanged method in the object that extends this
351 * class and pass it to {@link #addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener)}
352 * to register your listener and to unregister invoke
353 * {@link #removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener)}
355 * Permissions android.Manifest.permission.READ_PHONE_STATE is required
356 * for #onSubscriptionsChanged to be invoked.
358 public static class OnSubscriptionsChangedListener {
359 private final Handler mHandler = new Handler() {
361 public void handleMessage(Message msg) {
363 log("handleMessage: invoke the overriden onSubscriptionsChanged()");
365 OnSubscriptionsChangedListener.this.onSubscriptionsChanged();
370 * Callback invoked when there is any change to any SubscriptionInfo. Typically
371 * this method would invoke {@link #getActiveSubscriptionInfoList}
373 public void onSubscriptionsChanged() {
374 if (DBG) log("onSubscriptionsChanged: NOT OVERRIDDEN");
378 * The callback methods need to be called on the handler thread where
379 * this object was created. If the binder did that for us it'd be nice.
381 IOnSubscriptionsChangedListener callback = new IOnSubscriptionsChangedListener.Stub() {
383 public void onSubscriptionsChanged() {
384 if (DBG) log("callback: received, sendEmptyMessage(0) to handler");
385 mHandler.sendEmptyMessage(0);
389 private void log(String s) {
395 public SubscriptionManager(Context context) {
396 if (DBG) logd("SubscriptionManager created");
401 * Get an instance of the SubscriptionManager from the Context.
402 * This invokes {@link android.content.Context#getSystemService
403 * Context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)}.
405 * @param context to use.
406 * @return SubscriptionManager instance
408 public static SubscriptionManager from(Context context) {
409 return (SubscriptionManager) context.getSystemService(
410 Context.TELEPHONY_SUBSCRIPTION_SERVICE);
414 * Register for changes to the list of active {@link SubscriptionInfo} records or to the
415 * individual records themselves. When a change occurs the onSubscriptionsChanged method of
416 * the listener will be invoked immediately if there has been a notification.
418 * @param listener an instance of {@link OnSubscriptionsChangedListener} with
419 * onSubscriptionsChanged overridden.
421 public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
422 String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
424 logd("register OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug
425 + " listener=" + listener);
428 // We use the TelephonyRegistry as it runs in the system and thus is always
429 // available. Where as SubscriptionController could crash and not be available
430 ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
431 "telephony.registry"));
433 tr.addOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
435 } catch (RemoteException ex) {
441 * Unregister the {@link OnSubscriptionsChangedListener}. This is not strictly necessary
442 * as the listener will automatically be unregistered if an attempt to invoke the listener
445 * @param listener that is to be unregistered.
447 public void removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
448 String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
450 logd("unregister OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug
451 + " listener=" + listener);
454 // We use the TelephonyRegistry as its runs in the system and thus is always
455 // available where as SubscriptionController could crash and not be available
456 ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
457 "telephony.registry"));
459 tr.removeOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
461 } catch (RemoteException ex) {
467 * Get the active SubscriptionInfo with the input subId.
469 * @param subId The unique SubscriptionInfo key in database.
470 * @return SubscriptionInfo, maybe null if its not active.
472 public SubscriptionInfo getActiveSubscriptionInfo(int subId) {
473 if (VDBG) logd("[getActiveSubscriptionInfo]+ subId=" + subId);
474 if (!isValidSubscriptionId(subId)) {
476 logd("[getActiveSubscriptionInfo]- invalid subId");
481 SubscriptionInfo subInfo = null;
484 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
486 subInfo = iSub.getActiveSubscriptionInfo(subId, mContext.getOpPackageName());
488 } catch (RemoteException ex) {
497 * Get the active SubscriptionInfo associated with the iccId
498 * @param iccId the IccId of SIM card
499 * @return SubscriptionInfo, maybe null if its not active
502 public SubscriptionInfo getActiveSubscriptionInfoForIccIndex(String iccId) {
503 if (VDBG) logd("[getActiveSubscriptionInfoForIccIndex]+ iccId=" + iccId);
505 logd("[getActiveSubscriptionInfoForIccIndex]- null iccid");
509 SubscriptionInfo result = null;
512 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
514 result = iSub.getActiveSubscriptionInfoForIccId(iccId, mContext.getOpPackageName());
516 } catch (RemoteException ex) {
524 * Get the active SubscriptionInfo associated with the slotIdx
525 * @param slotIdx the slot which the subscription is inserted
526 * @return SubscriptionInfo, maybe null if its not active
528 public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIdx) {
529 if (VDBG) logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIdx=" + slotIdx);
530 if (!isValidSlotId(slotIdx)) {
531 logd("[getActiveSubscriptionInfoForSimSlotIndex]- invalid slotIdx");
535 SubscriptionInfo result = null;
538 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
540 result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIdx,
541 mContext.getOpPackageName());
543 } catch (RemoteException ex) {
551 * @return List of all SubscriptionInfo records in database,
552 * include those that were inserted before, maybe empty but not null.
555 public List<SubscriptionInfo> getAllSubscriptionInfoList() {
556 if (VDBG) logd("[getAllSubscriptionInfoList]+");
558 List<SubscriptionInfo> result = null;
561 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
563 result = iSub.getAllSubInfoList(mContext.getOpPackageName());
565 } catch (RemoteException ex) {
569 if (result == null) {
570 result = new ArrayList<SubscriptionInfo>();
576 * Get the SubscriptionInfo(s) of the currently inserted SIM(s). The records will be sorted
577 * by {@link SubscriptionInfo#getSimSlotIndex} then by {@link SubscriptionInfo#getSubscriptionId}.
579 * @return Sorted list of the currently {@link SubscriptionInfo} records available on the device.
582 * If null is returned the current state is unknown but if a {@link OnSubscriptionsChangedListener}
583 * has been registered {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be
584 * invoked in the future.
587 * If the list is empty then there are no {@link SubscriptionInfo} records currently available.
590 * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex}
591 * then by {@link SubscriptionInfo#getSubscriptionId}.
595 public List<SubscriptionInfo> getActiveSubscriptionInfoList() {
596 List<SubscriptionInfo> result = null;
599 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
601 result = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName());
603 } catch (RemoteException ex) {
610 * @return the count of all subscriptions in the database, this includes
611 * all subscriptions that have been seen.
614 public int getAllSubscriptionInfoCount() {
615 if (VDBG) logd("[getAllSubscriptionInfoCount]+");
620 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
622 result = iSub.getAllSubInfoCount(mContext.getOpPackageName());
624 } catch (RemoteException ex) {
632 * @return the current number of active subscriptions. There is no guarantee the value
633 * returned by this method will be the same as the length of the list returned by
634 * {@link #getActiveSubscriptionInfoList}.
636 public int getActiveSubscriptionInfoCount() {
640 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
642 result = iSub.getActiveSubInfoCount(mContext.getOpPackageName());
644 } catch (RemoteException ex) {
652 * @return the maximum number of active subscriptions that will be returned by
653 * {@link #getActiveSubscriptionInfoList} and the value returned by
654 * {@link #getActiveSubscriptionInfoCount}.
656 public int getActiveSubscriptionInfoCountMax() {
660 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
662 result = iSub.getActiveSubInfoCountMax();
664 } catch (RemoteException ex) {
672 * Add a new SubscriptionInfo to SubscriptionInfo database if needed
673 * @param iccId the IccId of the SIM card
674 * @param slotId the slot which the SIM is inserted
675 * @return the URL of the newly created row or the updated row
678 public Uri addSubscriptionInfoRecord(String iccId, int slotId) {
679 if (VDBG) logd("[addSubscriptionInfoRecord]+ iccId:" + iccId + " slotId:" + slotId);
681 logd("[addSubscriptionInfoRecord]- null iccId");
683 if (!isValidSlotId(slotId)) {
684 logd("[addSubscriptionInfoRecord]- invalid slotId");
688 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
690 // FIXME: This returns 1 on success, 0 on error should should we return it?
691 iSub.addSubInfoRecord(iccId, slotId);
693 } catch (RemoteException ex) {
697 // FIXME: Always returns null?
703 * Set SIM icon tint color by simInfo index
704 * @param tint the RGB value of icon tint color of the SIM
705 * @param subId the unique SubInfoRecord index in database
706 * @return the number of records updated
709 public int setIconTint(int tint, int subId) {
710 if (VDBG) logd("[setIconTint]+ tint:" + tint + " subId:" + subId);
711 if (!isValidSubscriptionId(subId)) {
712 logd("[setIconTint]- fail");
719 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
721 result = iSub.setIconTint(tint, subId);
723 } catch (RemoteException ex) {
732 * Set display name by simInfo index
733 * @param displayName the display name of SIM card
734 * @param subId the unique SubscriptionInfo index in database
735 * @return the number of records updated
738 public int setDisplayName(String displayName, int subId) {
739 return setDisplayName(displayName, subId, NAME_SOURCE_UNDEFINDED);
743 * Set display name by simInfo index with name source
744 * @param displayName the display name of SIM card
745 * @param subId the unique SubscriptionInfo index in database
746 * @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE,
747 * 2: NAME_SOURCE_USER_INPUT, -1 NAME_SOURCE_UNDEFINED
748 * @return the number of records updated or < 0 if invalid subId
751 public int setDisplayName(String displayName, int subId, long nameSource) {
753 logd("[setDisplayName]+ displayName:" + displayName + " subId:" + subId
754 + " nameSource:" + nameSource);
756 if (!isValidSubscriptionId(subId)) {
757 logd("[setDisplayName]- fail");
764 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
766 result = iSub.setDisplayNameUsingSrc(displayName, subId, nameSource);
768 } catch (RemoteException ex) {
777 * Set phone number by subId
778 * @param number the phone number of the SIM
779 * @param subId the unique SubscriptionInfo index in database
780 * @return the number of records updated
783 public int setDisplayNumber(String number, int subId) {
784 if (number == null || !isValidSubscriptionId(subId)) {
785 logd("[setDisplayNumber]- fail");
792 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
794 result = iSub.setDisplayNumber(number, subId);
796 } catch (RemoteException ex) {
805 * Set data roaming by simInfo index
806 * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming
807 * @param subId the unique SubscriptionInfo index in database
808 * @return the number of records updated
811 public int setDataRoaming(int roaming, int subId) {
812 if (VDBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId);
813 if (roaming < 0 || !isValidSubscriptionId(subId)) {
814 logd("[setDataRoaming]- fail");
821 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
823 result = iSub.setDataRoaming(roaming, subId);
825 } catch (RemoteException ex) {
833 * Get slotId associated with the subscription.
834 * @return slotId as a positive integer or a negative value if an error either
835 * SIM_NOT_INSERTED or < 0 if an invalid slot index
838 public static int getSlotId(int subId) {
839 if (!isValidSubscriptionId(subId)) {
841 logd("[getSlotId]- fail");
845 int result = INVALID_SIM_SLOT_INDEX;
848 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
850 result = iSub.getSlotId(subId);
852 } catch (RemoteException ex) {
861 public static int[] getSubId(int slotId) {
862 if (!isValidSlotId(slotId)) {
863 logd("[getSubId]- fail");
870 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
872 subId = iSub.getSubId(slotId);
874 } catch (RemoteException ex) {
882 public static int getPhoneId(int subId) {
883 if (!isValidSubscriptionId(subId)) {
885 logd("[getPhoneId]- fail");
887 return INVALID_PHONE_INDEX;
890 int result = INVALID_PHONE_INDEX;
893 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
895 result = iSub.getPhoneId(subId);
897 } catch (RemoteException ex) {
901 if (VDBG) logd("[getPhoneId]- phoneId=" + result);
906 private static void logd(String msg) {
907 Rlog.d(LOG_TAG, msg);
911 * Returns the system's default subscription id.
913 * For a voice capable device, it will return getDefaultVoiceSubscriptionId.
914 * For a data only device, it will return the getDefaultDataSubscriptionId.
915 * May return an INVALID_SUBSCRIPTION_ID on error.
917 * @return the "system" default subscription id.
919 public static int getDefaultSubscriptionId() {
920 int subId = INVALID_SUBSCRIPTION_ID;
923 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
925 subId = iSub.getDefaultSubId();
927 } catch (RemoteException ex) {
931 if (VDBG) logd("getDefaultSubId=" + subId);
936 * Returns the system's default voice subscription id.
938 * On a data only device or on error, will return INVALID_SUBSCRIPTION_ID.
940 * @return the default voice subscription Id.
942 public static int getDefaultVoiceSubscriptionId() {
943 int subId = INVALID_SUBSCRIPTION_ID;
946 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
948 subId = iSub.getDefaultVoiceSubId();
950 } catch (RemoteException ex) {
954 if (VDBG) logd("getDefaultVoiceSubscriptionId, sub id = " + subId);
959 public void setDefaultVoiceSubId(int subId) {
960 if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId);
962 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
964 iSub.setDefaultVoiceSubId(subId);
966 } catch (RemoteException ex) {
972 * Return the SubscriptionInfo for default voice subscription.
974 * Will return null on data only devices, or on error.
976 * @return the SubscriptionInfo for the default voice subscription.
979 public SubscriptionInfo getDefaultVoiceSubscriptionInfo() {
980 return getActiveSubscriptionInfo(getDefaultVoiceSubscriptionId());
984 public static int getDefaultVoicePhoneId() {
985 return getPhoneId(getDefaultVoiceSubscriptionId());
989 * Returns the system's default SMS subscription id.
991 * On a data only device or on error, will return INVALID_SUBSCRIPTION_ID.
993 * @return the default SMS subscription Id.
995 public static int getDefaultSmsSubscriptionId() {
996 int subId = INVALID_SUBSCRIPTION_ID;
999 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1001 subId = iSub.getDefaultSmsSubId();
1003 } catch (RemoteException ex) {
1007 if (VDBG) logd("getDefaultSmsSubscriptionId, sub id = " + subId);
1012 public void setDefaultSmsSubId(int subId) {
1013 if (VDBG) logd("setDefaultSmsSubId sub id = " + subId);
1015 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1017 iSub.setDefaultSmsSubId(subId);
1019 } catch (RemoteException ex) {
1025 * Return the SubscriptionInfo for default voice subscription.
1027 * Will return null on data only devices, or on error.
1029 * @return the SubscriptionInfo for the default SMS subscription.
1032 public SubscriptionInfo getDefaultSmsSubscriptionInfo() {
1033 return getActiveSubscriptionInfo(getDefaultSmsSubscriptionId());
1037 public int getDefaultSmsPhoneId() {
1038 return getPhoneId(getDefaultSmsSubscriptionId());
1042 * Returns the system's default data subscription id.
1044 * On a voice only device or on error, will return INVALID_SUBSCRIPTION_ID.
1046 * @return the default data subscription Id.
1048 public static int getDefaultDataSubscriptionId() {
1049 int subId = INVALID_SUBSCRIPTION_ID;
1052 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1054 subId = iSub.getDefaultDataSubId();
1056 } catch (RemoteException ex) {
1060 if (VDBG) logd("getDefaultDataSubscriptionId, sub id = " + subId);
1065 public void setDefaultDataSubId(int subId) {
1066 if (VDBG) logd("setDataSubscription sub id = " + subId);
1068 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1070 iSub.setDefaultDataSubId(subId);
1072 } catch (RemoteException ex) {
1078 * Return the SubscriptionInfo for default data subscription.
1080 * Will return null on voice only devices, or on error.
1082 * @return the SubscriptionInfo for the default data subscription.
1085 public SubscriptionInfo getDefaultDataSubscriptionInfo() {
1086 return getActiveSubscriptionInfo(getDefaultDataSubscriptionId());
1090 public int getDefaultDataPhoneId() {
1091 return getPhoneId(getDefaultDataSubscriptionId());
1095 public void clearSubscriptionInfo() {
1097 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1099 iSub.clearSubInfo();
1101 } catch (RemoteException ex) {
1108 //FIXME this is vulnerable to race conditions
1110 public boolean allDefaultsSelected() {
1111 if (!isValidSubscriptionId(getDefaultDataSubscriptionId())) {
1114 if (!isValidSubscriptionId(getDefaultSmsSubscriptionId())) {
1117 if (!isValidSubscriptionId(getDefaultVoiceSubscriptionId())) {
1124 * If a default is set to subscription which is not active, this will reset that default back to
1125 * an invalid subscription id, i.e. < 0.
1128 public void clearDefaultsForInactiveSubIds() {
1129 if (VDBG) logd("clearDefaultsForInactiveSubIds");
1131 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1133 iSub.clearDefaultsForInactiveSubIds();
1135 } catch (RemoteException ex) {
1141 * @return true if a valid subId else false
1144 public static boolean isValidSubscriptionId(int subId) {
1145 return subId > INVALID_SUBSCRIPTION_ID ;
1149 * @return true if subId is an usable subId value else false. A
1150 * usable subId means its neither a INVALID_SUBSCRIPTION_ID nor a DEFAULT_SUB_ID.
1153 public static boolean isUsableSubIdValue(int subId) {
1154 return subId >= MIN_SUBSCRIPTION_ID_VALUE && subId <= MAX_SUBSCRIPTION_ID_VALUE;
1158 public static boolean isValidSlotId(int slotId) {
1159 return slotId >= 0 && slotId < TelephonyManager.getDefault().getSimCount();
1163 public static boolean isValidPhoneId(int phoneId) {
1164 return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount();
1168 public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) {
1169 int[] subIds = SubscriptionManager.getSubId(phoneId);
1170 if (subIds != null && subIds.length > 0) {
1171 putPhoneIdAndSubIdExtra(intent, phoneId, subIds[0]);
1173 logd("putPhoneIdAndSubIdExtra: no valid subs");
1178 public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId, int subId) {
1179 if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId);
1180 intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
1181 intent.putExtra(PhoneConstants.PHONE_KEY, phoneId);
1182 //FIXME this is using phoneId and slotId interchangeably
1183 //Eventually, this should be removed as it is not the slot id
1184 intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);
1188 * @return the list of subId's that are active,
1189 * is never null but the length maybe 0.
1192 public @NonNull int[] getActiveSubscriptionIdList() {
1196 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1198 subId = iSub.getActiveSubIdList();
1200 } catch (RemoteException ex) {
1204 if (subId == null) {
1213 * Returns true if the device is considered roaming on the current
1214 * network for a subscription.
1216 * Availability: Only when user registered to a network.
1218 * @param subId The subscription ID
1219 * @return true if the network for the subscription is roaming, false otherwise
1221 public boolean isNetworkRoaming(int subId) {
1222 final int phoneId = getPhoneId(subId);
1224 // What else can we do?
1227 return TelephonyManager.getDefault().isNetworkRoaming(subId);
1231 * Returns a constant indicating the state of sim for the slot idx.
1235 * {@See TelephonyManager#SIM_STATE_UNKNOWN}
1236 * {@See TelephonyManager#SIM_STATE_ABSENT}
1237 * {@See TelephonyManager#SIM_STATE_PIN_REQUIRED}
1238 * {@See TelephonyManager#SIM_STATE_PUK_REQUIRED}
1239 * {@See TelephonyManager#SIM_STATE_NETWORK_LOCKED}
1240 * {@See TelephonyManager#SIM_STATE_READY}
1241 * {@See TelephonyManager#SIM_STATE_NOT_READY}
1242 * {@See TelephonyManager#SIM_STATE_PERM_DISABLED}
1243 * {@See TelephonyManager#SIM_STATE_CARD_IO_ERROR}
1247 public static int getSimStateForSlotIdx(int slotIdx) {
1248 int simState = TelephonyManager.SIM_STATE_UNKNOWN;
1251 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1253 simState = iSub.getSimStateForSlotIdx(slotIdx);
1255 } catch (RemoteException ex) {
1262 * Store properties associated with SubscriptionInfo in database
1263 * @param subId Subscription Id of Subscription
1264 * @param propKey Column name in database associated with SubscriptionInfo
1265 * @param propValue Value to store in DB for particular subId & column name
1268 public static void setSubscriptionProperty(int subId, String propKey, String propValue) {
1270 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1272 iSub.setSubscriptionProperty(subId, propKey, propValue);
1274 } catch (RemoteException ex) {
1280 * Store properties associated with SubscriptionInfo in database
1281 * @param subId Subscription Id of Subscription
1282 * @param propKey Column name in SubscriptionInfo database
1283 * @return Value associated with subId and propKey column in database
1286 private static String getSubscriptionProperty(int subId, String propKey,
1288 String resultValue = null;
1290 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1292 resultValue = iSub.getSubscriptionProperty(subId, propKey,
1293 context.getOpPackageName());
1295 } catch (RemoteException ex) {
1302 * Returns boolean value corresponding to query result.
1303 * @param subId Subscription Id of Subscription
1304 * @param propKey Column name in SubscriptionInfo database
1305 * @param defValue Default boolean value to be returned
1306 * @return boolean result value to be returned
1309 public static boolean getBooleanSubscriptionProperty(int subId, String propKey,
1310 boolean defValue, Context context) {
1311 String result = getSubscriptionProperty(subId, propKey, context);
1312 if (result != null) {
1314 return Integer.parseInt(result) == 1;
1315 } catch (NumberFormatException err) {
1316 logd("getBooleanSubscriptionProperty NumberFormat exception");
1323 * Returns integer value corresponding to query result.
1324 * @param subId Subscription Id of Subscription
1325 * @param propKey Column name in SubscriptionInfo database
1326 * @param defValue Default integer value to be returned
1327 * @return integer result value to be returned
1330 public static int getIntegerSubscriptionProperty(int subId, String propKey, int defValue,
1332 String result = getSubscriptionProperty(subId, propKey, context);
1333 if (result != null) {
1335 return Integer.parseInt(result);
1336 } catch (NumberFormatException err) {
1337 logd("getBooleanSubscriptionProperty NumberFormat exception");
1344 * Returns the resources associated with Subscription.
1345 * @param context Context object
1346 * @param subId Subscription Id of Subscription who's resources are required
1347 * @return Resources associated with Subscription.
1350 public static Resources getResourcesForSubId(Context context, int subId) {
1351 final SubscriptionInfo subInfo =
1352 SubscriptionManager.from(context).getActiveSubscriptionInfo(subId);
1354 Configuration config = context.getResources().getConfiguration();
1355 Configuration newConfig = new Configuration();
1356 newConfig.setTo(config);
1357 if (subInfo != null) {
1358 newConfig.mcc = subInfo.getMcc();
1359 newConfig.mnc = subInfo.getMnc();
1360 if (newConfig.mnc == 0) newConfig.mnc = Configuration.MNC_ZERO;
1362 DisplayMetrics metrics = context.getResources().getDisplayMetrics();
1363 DisplayMetrics newMetrics = new DisplayMetrics();
1364 newMetrics.setTo(metrics);
1365 return new Resources(context.getResources().getAssets(), newMetrics, newConfig);
1369 * @return true if the sub ID is active. i.e. The sub ID corresponds to a known subscription
1370 * and the SIM providing the subscription is present in a slot and in "LOADED" state.
1373 public boolean isActiveSubId(int subId) {
1375 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1377 return iSub.isActiveSubId(subId);
1379 } catch (RemoteException ex) {