• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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          */
onSubscriptionsChanged()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 
log(String s)443         private void log(String s) {
444             Rlog.d(LOG_TAG, s);
445         }
446     }
447 
448     /** @hide */
SubscriptionManager(Context context)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      */
from(Context context)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      */
addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener)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      */
removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener)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      */
getActiveSubscriptionInfo(int subId)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      */
getActiveSubscriptionInfoForIccIndex(String iccId)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      */
getActiveSubscriptionInfoForSimSlotIndex(int slotIndex)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      */
getAllSubscriptionInfoList()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      */
getActiveSubscriptionInfoList()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      */
getAvailableSubscriptionInfoList()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      */
getAccessibleSubscriptionInfoList()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      */
requestEmbeddedSubscriptionInfoListRefresh()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      */
getAllSubscriptionInfoCount()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      */
getActiveSubscriptionInfoCount()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      */
getActiveSubscriptionInfoCountMax()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      */
addSubscriptionInfoRecord(String iccId, int slotIndex)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      */
setIconTint(int tint, int subId)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      */
setDisplayName(String displayName, int subId)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      */
setDisplayName(String displayName, int subId, long nameSource)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      */
setDisplayNumber(String number, int subId)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      */
setDataRoaming(int roaming, int subId)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      */
getSlotIndex(int subId)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 */
getSubId(int slotIndex)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 */
getPhoneId(int subId)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 
logd(String msg)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      */
getDefaultSubscriptionId()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      */
getDefaultVoiceSubscriptionId()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 */
setDefaultVoiceSubId(int subId)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      */
getDefaultVoiceSubscriptionInfo()1139     public SubscriptionInfo getDefaultVoiceSubscriptionInfo() {
1140         return getActiveSubscriptionInfo(getDefaultVoiceSubscriptionId());
1141     }
1142 
1143     /** @hide */
getDefaultVoicePhoneId()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      */
getDefaultSmsSubscriptionId()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 */
setDefaultSmsSubId(int subId)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      */
getDefaultSmsSubscriptionInfo()1192     public SubscriptionInfo getDefaultSmsSubscriptionInfo() {
1193         return getActiveSubscriptionInfo(getDefaultSmsSubscriptionId());
1194     }
1195 
1196     /** @hide */
getDefaultSmsPhoneId()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      */
getDefaultDataSubscriptionId()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 */
setDefaultDataSubId(int subId)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      */
getDefaultDataSubscriptionInfo()1245     public SubscriptionInfo getDefaultDataSubscriptionInfo() {
1246         return getActiveSubscriptionInfo(getDefaultDataSubscriptionId());
1247     }
1248 
1249     /** @hide */
getDefaultDataPhoneId()1250     public int getDefaultDataPhoneId() {
1251         return getPhoneId(getDefaultDataSubscriptionId());
1252     }
1253 
1254     /** @hide */
clearSubscriptionInfo()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 */
allDefaultsSelected()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      */
clearDefaultsForInactiveSubIds()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      */
isValidSubscriptionId(int subId)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      */
isUsableSubIdValue(int subId)1313     public static boolean isUsableSubIdValue(int subId) {
1314         return subId >= MIN_SUBSCRIPTION_ID_VALUE && subId <= MAX_SUBSCRIPTION_ID_VALUE;
1315     }
1316 
1317     /** @hide */
isValidSlotIndex(int slotIndex)1318     public static boolean isValidSlotIndex(int slotIndex) {
1319         return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getSimCount();
1320     }
1321 
1322     /** @hide */
isValidPhoneId(int phoneId)1323     public static boolean isValidPhoneId(int phoneId) {
1324         return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount();
1325     }
1326 
1327     /** @hide */
putPhoneIdAndSubIdExtra(Intent intent, int phoneId)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 */
putPhoneIdAndSubIdExtra(Intent intent, int phoneId, int subId)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      */
getActiveSubscriptionIdList()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      */
isNetworkRoaming(int subId)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      */
getSimStateForSlotIndex(int slotIndex)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      */
setSubscriptionProperty(int subId, String propKey, String propValue)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      */
getSubscriptionProperty(int subId, String propKey, Context context)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      */
getBooleanSubscriptionProperty(int subId, String propKey, boolean defValue, Context context)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      */
getIntegerSubscriptionProperty(int subId, String propKey, int defValue, Context context)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      */
getResourcesForSubId(Context context, int subId)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      */
isActiveSubId(int subId)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
getSubscriptionPlans(int subId)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
setSubscriptionPlans(int subId, @NonNull List<SubscriptionPlan> plans)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