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 static android.net.NetworkPolicyManager.OVERRIDE_CONGESTED;
20 import static android.net.NetworkPolicyManager.OVERRIDE_UNMETERED;
21 
22 import android.annotation.DurationMillisLong;
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.annotation.RequiresPermission;
26 import android.annotation.SdkConstant;
27 import android.annotation.SdkConstant.SdkConstantType;
28 import android.annotation.SuppressAutoDoc;
29 import android.annotation.SystemApi;
30 import android.annotation.SystemService;
31 import android.app.BroadcastOptions;
32 import android.content.Context;
33 import android.content.Intent;
34 import android.content.pm.PackageInfo;
35 import android.content.pm.PackageManager;
36 import android.content.res.Configuration;
37 import android.content.res.Resources;
38 import android.net.INetworkPolicyManager;
39 import android.net.NetworkCapabilities;
40 import android.net.Uri;
41 import android.os.Handler;
42 import android.os.Looper;
43 import android.os.Message;
44 import android.os.RemoteException;
45 import android.os.ServiceManager;
46 import android.util.DisplayMetrics;
47 
48 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
49 import com.android.internal.telephony.ISub;
50 import com.android.internal.telephony.ITelephonyRegistry;
51 import com.android.internal.telephony.PhoneConstants;
52 
53 import java.util.ArrayList;
54 import java.util.Arrays;
55 import java.util.Collections;
56 import java.util.List;
57 import java.util.concurrent.TimeUnit;
58 
59 /**
60  * SubscriptionManager is the application interface to SubscriptionController
61  * and provides information about the current Telephony Subscriptions.
62  */
63 @SystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
64 public class SubscriptionManager {
65     private static final String LOG_TAG = "SubscriptionManager";
66     private static final boolean DBG = false;
67     private static final boolean VDBG = false;
68 
69     /** An invalid subscription identifier */
70     public static final int INVALID_SUBSCRIPTION_ID = -1;
71 
72     /** Base value for Dummy SUBSCRIPTION_ID's. */
73     /** FIXME: Remove DummySubId's, but for now have them map just below INVALID_SUBSCRIPTION_ID
74      /** @hide */
75     public static final int DUMMY_SUBSCRIPTION_ID_BASE = INVALID_SUBSCRIPTION_ID - 1;
76 
77     /** An invalid phone identifier */
78     /** @hide */
79     public static final int INVALID_PHONE_INDEX = -1;
80 
81     /** An invalid slot identifier */
82     /** @hide */
83     public static final int INVALID_SIM_SLOT_INDEX = -1;
84 
85     /** Indicates the caller wants the default sub id. */
86     /** @hide */
87     public static final int DEFAULT_SUBSCRIPTION_ID = Integer.MAX_VALUE;
88 
89     /**
90      * Indicates the caller wants the default phone id.
91      * Used in SubscriptionController and Phone but do we really need it???
92      * @hide
93      */
94     public static final int DEFAULT_PHONE_INDEX = Integer.MAX_VALUE;
95 
96     /** Indicates the caller wants the default slot id. NOT used remove? */
97     /** @hide */
98     public static final int DEFAULT_SIM_SLOT_INDEX = Integer.MAX_VALUE;
99 
100     /** Minimum possible subid that represents a subscription */
101     /** @hide */
102     public static final int MIN_SUBSCRIPTION_ID_VALUE = 0;
103 
104     /** Maximum possible subid that represents a subscription */
105     /** @hide */
106     public static final int MAX_SUBSCRIPTION_ID_VALUE = DEFAULT_SUBSCRIPTION_ID - 1;
107 
108     /** @hide */
109     public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
110 
111     /**
112      * TelephonyProvider unique key column name is the subscription id.
113      * <P>Type: TEXT (String)</P>
114      */
115     /** @hide */
116     public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
117 
118     /**
119      * TelephonyProvider column name for SIM ICC Identifier
120      * <P>Type: TEXT (String)</P>
121      */
122     /** @hide */
123     public static final String ICC_ID = "icc_id";
124 
125     /**
126      * TelephonyProvider column name for user SIM_SlOT_INDEX
127      * <P>Type: INTEGER (int)</P>
128      */
129     /** @hide */
130     public static final String SIM_SLOT_INDEX = "sim_id";
131 
132     /** SIM is not inserted */
133     /** @hide */
134     public static final int SIM_NOT_INSERTED = -1;
135 
136     /**
137      * TelephonyProvider column name for user displayed name.
138      * <P>Type: TEXT (String)</P>
139      */
140     /** @hide */
141     public static final String DISPLAY_NAME = "display_name";
142 
143     /**
144      * TelephonyProvider column name for the service provider name for the SIM.
145      * <P>Type: TEXT (String)</P>
146      */
147     /** @hide */
148     public static final String CARRIER_NAME = "carrier_name";
149 
150     /**
151      * Default name resource
152      * @hide
153      */
154     public static final int DEFAULT_NAME_RES = com.android.internal.R.string.unknownName;
155 
156     /**
157      * TelephonyProvider column name for source of the user displayed name.
158      * <P>Type: INT (int)</P> with one of the NAME_SOURCE_XXXX values below
159      *
160      * @hide
161      */
162     public static final String NAME_SOURCE = "name_source";
163 
164     /**
165      * The name_source is undefined
166      * @hide
167      */
168     public static final int NAME_SOURCE_UNDEFINDED = -1;
169 
170     /**
171      * The name_source is the default
172      * @hide
173      */
174     public static final int NAME_SOURCE_DEFAULT_SOURCE = 0;
175 
176     /**
177      * The name_source is from the SIM
178      * @hide
179      */
180     public static final int NAME_SOURCE_SIM_SOURCE = 1;
181 
182     /**
183      * The name_source is from the user
184      * @hide
185      */
186     public static final int NAME_SOURCE_USER_INPUT = 2;
187 
188     /**
189      * TelephonyProvider column name for the color of a SIM.
190      * <P>Type: INTEGER (int)</P>
191      */
192     /** @hide */
193     public static final String COLOR = "color";
194 
195     /** @hide */
196     public static final int COLOR_1 = 0;
197 
198     /** @hide */
199     public static final int COLOR_2 = 1;
200 
201     /** @hide */
202     public static final int COLOR_3 = 2;
203 
204     /** @hide */
205     public static final int COLOR_4 = 3;
206 
207     /** @hide */
208     public static final int COLOR_DEFAULT = COLOR_1;
209 
210     /**
211      * TelephonyProvider column name for the phone number of a SIM.
212      * <P>Type: TEXT (String)</P>
213      */
214     /** @hide */
215     public static final String NUMBER = "number";
216 
217     /**
218      * TelephonyProvider column name for the number display format of a SIM.
219      * <P>Type: INTEGER (int)</P>
220      */
221     /** @hide */
222     public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
223 
224     /** @hide */
225     public static final int DISPLAY_NUMBER_NONE = 0;
226 
227     /** @hide */
228     public static final int DISPLAY_NUMBER_FIRST = 1;
229 
230     /** @hide */
231     public static final int DISPLAY_NUMBER_LAST = 2;
232 
233     /** @hide */
234     public static final int DISPLAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST;
235 
236     /**
237      * TelephonyProvider column name for permission for data roaming of a SIM.
238      * <P>Type: INTEGER (int)</P>
239      */
240     /** @hide */
241     public static final String DATA_ROAMING = "data_roaming";
242 
243     /** Indicates that data roaming is enabled for a subscription */
244     public static final int DATA_ROAMING_ENABLE = 1;
245 
246     /** Indicates that data roaming is disabled for a subscription */
247     public static final int DATA_ROAMING_DISABLE = 0;
248 
249     /** @hide */
250     public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
251 
252     /** @hide */
253     public static final int SIM_PROVISIONED = 0;
254 
255     /**
256      * TelephonyProvider column name for the MCC associated with a SIM.
257      * <P>Type: INTEGER (int)</P>
258      * @hide
259      */
260     public static final String MCC = "mcc";
261 
262     /**
263      * TelephonyProvider column name for the MNC associated with a SIM.
264      * <P>Type: INTEGER (int)</P>
265      * @hide
266      */
267     public static final String MNC = "mnc";
268 
269     /**
270      * TelephonyProvider column name for the sim provisioning status associated with a SIM.
271      * <P>Type: INTEGER (int)</P>
272      * @hide
273      */
274     public static final String SIM_PROVISIONING_STATUS = "sim_provisioning_status";
275 
276     /**
277      * TelephonyProvider column name for whether a subscription is embedded (that is, present on an
278      * eSIM).
279      * <p>Type: INTEGER (int), 1 for embedded or 0 for non-embedded.
280      * @hide
281      */
282     public static final String IS_EMBEDDED = "is_embedded";
283 
284     /**
285      * TelephonyProvider column name for SIM card identifier. For UICC card it is the ICCID of the
286      * current enabled profile on the card, while for eUICC card it is the EID of the card.
287      * <P>Type: TEXT (String)</P>
288      * @hide
289      */
290      public static final String CARD_ID = "card_id";
291 
292     /**
293      * TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
294      * {@link UiccAccessRule#encodeRules}. Only present if {@link #IS_EMBEDDED} is 1.
295      * <p>TYPE: BLOB
296      * @hide
297      */
298     public static final String ACCESS_RULES = "access_rules";
299 
300     /**
301      * TelephonyProvider column name identifying whether an embedded subscription is on a removable
302      * card. Such subscriptions are marked inaccessible as soon as the current card is removed.
303      * Otherwise, they will remain accessible unless explicitly deleted. Only present if
304      * {@link #IS_EMBEDDED} is 1.
305      * <p>TYPE: INTEGER (int), 1 for removable or 0 for non-removable.
306      * @hide
307      */
308     public static final String IS_REMOVABLE = "is_removable";
309 
310     /**
311      *  TelephonyProvider column name for extreme threat in CB settings
312      * @hide
313      */
314     public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
315 
316     /**
317      * TelephonyProvider column name for severe threat in CB settings
318      *@hide
319      */
320     public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
321 
322     /**
323      * TelephonyProvider column name for amber alert in CB settings
324      *@hide
325      */
326     public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
327 
328     /**
329      * TelephonyProvider column name for emergency alert in CB settings
330      *@hide
331      */
332     public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
333 
334     /**
335      * TelephonyProvider column name for alert sound duration in CB settings
336      *@hide
337      */
338     public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
339 
340     /**
341      * TelephonyProvider column name for alert reminder interval in CB settings
342      *@hide
343      */
344     public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
345 
346     /**
347      * TelephonyProvider column name for enabling vibrate in CB settings
348      *@hide
349      */
350     public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
351 
352     /**
353      * TelephonyProvider column name for enabling alert speech in CB settings
354      *@hide
355      */
356     public static final String CB_ALERT_SPEECH = "enable_alert_speech";
357 
358     /**
359      * TelephonyProvider column name for ETWS test alert in CB settings
360      *@hide
361      */
362     public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
363 
364     /**
365      * TelephonyProvider column name for enable channel50 alert in CB settings
366      *@hide
367      */
368     public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
369 
370     /**
371      * TelephonyProvider column name for CMAS test alert in CB settings
372      *@hide
373      */
374     public static final String CB_CMAS_TEST_ALERT= "enable_cmas_test_alerts";
375 
376     /**
377      * TelephonyProvider column name for Opt out dialog in CB settings
378      *@hide
379      */
380     public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
381 
382     /**
383      * TelephonyProvider column name for enable Volte.
384      *
385      * If this setting is not initialized (set to -1)  then we use the Carrier Config value
386      * {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
387      *@hide
388      */
389     public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
390 
391     /**
392      * TelephonyProvider column name for enable VT (Video Telephony over IMS)
393      *@hide
394      */
395     public static final String VT_IMS_ENABLED = "vt_ims_enabled";
396 
397     /**
398      * TelephonyProvider column name for enable Wifi calling
399      *@hide
400      */
401     public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
402 
403     /**
404      * TelephonyProvider column name for Wifi calling mode
405      *@hide
406      */
407     public static final String WFC_IMS_MODE = "wfc_ims_mode";
408 
409     /**
410      * TelephonyProvider column name for Wifi calling mode in roaming
411      *@hide
412      */
413     public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
414 
415     /**
416      * TelephonyProvider column name for enable Wifi calling in roaming
417      *@hide
418      */
419     public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
420 
421     /**
422      * Broadcast Action: The user has changed one of the default subs related to
423      * data, phone calls, or sms</p>
424      *
425      * TODO: Change to a listener
426      * @hide
427      */
428     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
429     public static final String SUB_DEFAULT_CHANGED_ACTION =
430             "android.intent.action.SUB_DEFAULT_CHANGED";
431 
432     /**
433      * Broadcast Action: The default subscription has changed.  This has the following
434      * extra values:</p>
435      * The {@link #EXTRA_SUBSCRIPTION_INDEX} extra indicates the current default subscription index
436      */
437     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
438     public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED
439             = "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED";
440 
441     /**
442      * Broadcast Action: The default sms subscription has changed.  This has the following
443      * extra values:</p>
444      * {@link #EXTRA_SUBSCRIPTION_INDEX} extra indicates the current default sms
445      * subscription index
446      */
447     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
448     public static final String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED
449             = "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED";
450 
451     /**
452      * Activity Action: Display UI for managing the billing relationship plans
453      * between a carrier and a specific subscriber.
454      * <p>
455      * Carrier apps are encouraged to implement this activity, and the OS will
456      * provide an affordance to quickly enter this activity, typically via
457      * Settings. This affordance will only be shown when the carrier app is
458      * actively providing subscription plan information via
459      * {@link #setSubscriptionPlans(int, List)}.
460      * <p>
461      * Contains {@link #EXTRA_SUBSCRIPTION_INDEX} to indicate which subscription
462      * the user is interested in.
463      */
464     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
465     @SystemApi
466     public static final String ACTION_MANAGE_SUBSCRIPTION_PLANS
467             = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS";
468 
469     /**
470      * Broadcast Action: Request a refresh of the billing relationship plans
471      * between a carrier and a specific subscriber.
472      * <p>
473      * Carrier apps are encouraged to implement this receiver, and the OS will
474      * provide an affordance to request a refresh. This affordance will only be
475      * shown when the carrier app is actively providing subscription plan
476      * information via {@link #setSubscriptionPlans(int, List)}.
477      * <p>
478      * Contains {@link #EXTRA_SUBSCRIPTION_INDEX} to indicate which subscription
479      * the user is interested in.
480      * <p>
481      * Receivers should protect themselves by checking that the sender holds the
482      * {@code android.permission.MANAGE_SUBSCRIPTION_PLANS} permission.
483      */
484     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
485     @SystemApi
486     public static final String ACTION_REFRESH_SUBSCRIPTION_PLANS
487             = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS";
488 
489     /**
490      * Broadcast Action: The billing relationship plans between a carrier and a
491      * specific subscriber has changed.
492      * <p>
493      * Contains {@link #EXTRA_SUBSCRIPTION_INDEX} to indicate which subscription
494      * changed.
495      *
496      * @hide
497      */
498     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
499     @RequiresPermission(android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS)
500     public static final String ACTION_SUBSCRIPTION_PLANS_CHANGED
501             = "android.telephony.action.SUBSCRIPTION_PLANS_CHANGED";
502 
503     /**
504      * Integer extra used with {@link #ACTION_DEFAULT_SUBSCRIPTION_CHANGED} and
505      * {@link #ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED} to indicate the subscription
506      * which has changed.
507      */
508     public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
509 
510     private final Context mContext;
511     private volatile INetworkPolicyManager mNetworkPolicy;
512 
513     /**
514      * A listener class for monitoring changes to {@link SubscriptionInfo} records.
515      * <p>
516      * Override the onSubscriptionsChanged method in the object that extends this
517      * class and pass it to {@link #addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener)}
518      * to register your listener and to unregister invoke
519      * {@link #removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener)}
520      * <p>
521      * Permissions android.Manifest.permission.READ_PHONE_STATE is required
522      * for #onSubscriptionsChanged to be invoked.
523      */
524     public static class OnSubscriptionsChangedListener {
525         private class OnSubscriptionsChangedListenerHandler extends Handler {
OnSubscriptionsChangedListenerHandler()526             OnSubscriptionsChangedListenerHandler() {
527                 super();
528             }
529 
OnSubscriptionsChangedListenerHandler(Looper looper)530             OnSubscriptionsChangedListenerHandler(Looper looper) {
531                 super(looper);
532             }
533 
534             @Override
handleMessage(Message msg)535             public void handleMessage(Message msg) {
536                 if (DBG) {
537                     log("handleMessage: invoke the overriden onSubscriptionsChanged()");
538                 }
539                 OnSubscriptionsChangedListener.this.onSubscriptionsChanged();
540             }
541         }
542 
543         private final Handler mHandler;
544 
OnSubscriptionsChangedListener()545         public OnSubscriptionsChangedListener() {
546             mHandler = new OnSubscriptionsChangedListenerHandler();
547         }
548 
549         /**
550          * Allow a listener to be created with a custom looper
551          * @param looper the looper that the underlining handler should run on
552          * @hide
553          */
OnSubscriptionsChangedListener(Looper looper)554         public OnSubscriptionsChangedListener(Looper looper) {
555             mHandler = new OnSubscriptionsChangedListenerHandler(looper);
556         }
557 
558         /**
559          * Callback invoked when there is any change to any SubscriptionInfo. Typically
560          * this method would invoke {@link #getActiveSubscriptionInfoList}
561          */
onSubscriptionsChanged()562         public void onSubscriptionsChanged() {
563             if (DBG) log("onSubscriptionsChanged: NOT OVERRIDDEN");
564         }
565 
566         /**
567          * The callback methods need to be called on the handler thread where
568          * this object was created.  If the binder did that for us it'd be nice.
569          */
570         IOnSubscriptionsChangedListener callback = new IOnSubscriptionsChangedListener.Stub() {
571             @Override
572             public void onSubscriptionsChanged() {
573                 if (DBG) log("callback: received, sendEmptyMessage(0) to handler");
574                 mHandler.sendEmptyMessage(0);
575             }
576         };
577 
log(String s)578         private void log(String s) {
579             Rlog.d(LOG_TAG, s);
580         }
581     }
582 
583     /** @hide */
SubscriptionManager(Context context)584     public SubscriptionManager(Context context) {
585         if (DBG) logd("SubscriptionManager created");
586         mContext = context;
587     }
588 
589     /**
590      * @deprecated developers should always obtain references directly from
591      *             {@link Context#getSystemService(Class)}.
592      */
593     @Deprecated
from(Context context)594     public static SubscriptionManager from(Context context) {
595         return (SubscriptionManager) context
596                 .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
597     }
598 
getNetworkPolicy()599     private final INetworkPolicyManager getNetworkPolicy() {
600         if (mNetworkPolicy == null) {
601             mNetworkPolicy = INetworkPolicyManager.Stub
602                     .asInterface(ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
603         }
604         return mNetworkPolicy;
605     }
606 
607     /**
608      * Register for changes to the list of active {@link SubscriptionInfo} records or to the
609      * individual records themselves. When a change occurs the onSubscriptionsChanged method of
610      * the listener will be invoked immediately if there has been a notification.
611      *
612      * @param listener an instance of {@link OnSubscriptionsChangedListener} with
613      *                 onSubscriptionsChanged overridden.
614      */
addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener)615     public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
616         String pkgName = mContext != null ? mContext.getOpPackageName() : "<unknown>";
617         if (DBG) {
618             logd("register OnSubscriptionsChangedListener pkgName=" + pkgName
619                     + " listener=" + listener);
620         }
621         try {
622             // We use the TelephonyRegistry as it runs in the system and thus is always
623             // available. Where as SubscriptionController could crash and not be available
624             ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
625                     "telephony.registry"));
626             if (tr != null) {
627                 tr.addOnSubscriptionsChangedListener(pkgName, listener.callback);
628             }
629         } catch (RemoteException ex) {
630             // Should not happen
631         }
632     }
633 
634     /**
635      * Unregister the {@link OnSubscriptionsChangedListener}. This is not strictly necessary
636      * as the listener will automatically be unregistered if an attempt to invoke the listener
637      * fails.
638      *
639      * @param listener that is to be unregistered.
640      */
removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener)641     public void removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
642         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
643         if (DBG) {
644             logd("unregister OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug
645                     + " listener=" + listener);
646         }
647         try {
648             // We use the TelephonyRegistry as its runs in the system and thus is always
649             // available where as SubscriptionController could crash and not be available
650             ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
651                     "telephony.registry"));
652             if (tr != null) {
653                 tr.removeOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
654             }
655         } catch (RemoteException ex) {
656             // Should not happen
657         }
658     }
659 
660     /**
661      * Get the active SubscriptionInfo with the input subId.
662      *
663      * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
664      * or that the calling app has carrier privileges (see
665      * {@link TelephonyManager#hasCarrierPrivileges}).
666      *
667      * @param subId The unique SubscriptionInfo key in database.
668      * @return SubscriptionInfo, maybe null if its not active.
669      */
670     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
671     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
getActiveSubscriptionInfo(int subId)672     public SubscriptionInfo getActiveSubscriptionInfo(int subId) {
673         if (VDBG) logd("[getActiveSubscriptionInfo]+ subId=" + subId);
674         if (!isValidSubscriptionId(subId)) {
675             if (DBG) {
676                 logd("[getActiveSubscriptionInfo]- invalid subId");
677             }
678             return null;
679         }
680 
681         SubscriptionInfo subInfo = null;
682 
683         try {
684             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
685             if (iSub != null) {
686                 subInfo = iSub.getActiveSubscriptionInfo(subId, mContext.getOpPackageName());
687             }
688         } catch (RemoteException ex) {
689             // ignore it
690         }
691 
692         return subInfo;
693 
694     }
695 
696     /**
697      * Get the active SubscriptionInfo associated with the iccId
698      * @param iccId the IccId of SIM card
699      * @return SubscriptionInfo, maybe null if its not active
700      * @hide
701      */
getActiveSubscriptionInfoForIccIndex(String iccId)702     public SubscriptionInfo getActiveSubscriptionInfoForIccIndex(String iccId) {
703         if (VDBG) logd("[getActiveSubscriptionInfoForIccIndex]+ iccId=" + iccId);
704         if (iccId == null) {
705             logd("[getActiveSubscriptionInfoForIccIndex]- null iccid");
706             return null;
707         }
708 
709         SubscriptionInfo result = null;
710 
711         try {
712             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
713             if (iSub != null) {
714                 result = iSub.getActiveSubscriptionInfoForIccId(iccId, mContext.getOpPackageName());
715             }
716         } catch (RemoteException ex) {
717             // ignore it
718         }
719 
720         return result;
721     }
722 
723     /**
724      * Get the active SubscriptionInfo associated with the slotIndex
725      *
726      * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
727      * or that the calling app has carrier privileges (see
728      * {@link TelephonyManager#hasCarrierPrivileges}).
729      *
730      * @param slotIndex the slot which the subscription is inserted
731      * @return SubscriptionInfo, maybe null if its not active
732      */
733     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
734     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
getActiveSubscriptionInfoForSimSlotIndex(int slotIndex)735     public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex) {
736         if (VDBG) logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIndex=" + slotIndex);
737         if (!isValidSlotIndex(slotIndex)) {
738             logd("[getActiveSubscriptionInfoForSimSlotIndex]- invalid slotIndex");
739             return null;
740         }
741 
742         SubscriptionInfo result = null;
743 
744         try {
745             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
746             if (iSub != null) {
747                 result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIndex,
748                         mContext.getOpPackageName());
749             }
750         } catch (RemoteException ex) {
751             // ignore it
752         }
753 
754         return result;
755     }
756 
757     /**
758      * @return List of all SubscriptionInfo records in database,
759      * include those that were inserted before, maybe empty but not null.
760      * @hide
761      */
getAllSubscriptionInfoList()762     public List<SubscriptionInfo> getAllSubscriptionInfoList() {
763         if (VDBG) logd("[getAllSubscriptionInfoList]+");
764 
765         List<SubscriptionInfo> result = null;
766 
767         try {
768             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
769             if (iSub != null) {
770                 result = iSub.getAllSubInfoList(mContext.getOpPackageName());
771             }
772         } catch (RemoteException ex) {
773             // ignore it
774         }
775 
776         if (result == null) {
777             result = new ArrayList<>();
778         }
779         return result;
780     }
781 
782     /**
783      * Get the SubscriptionInfo(s) of the currently inserted SIM(s). The records will be sorted
784      * by {@link SubscriptionInfo#getSimSlotIndex} then by {@link SubscriptionInfo#getSubscriptionId}.
785      *
786      * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
787      * or that the calling app has carrier privileges (see
788      * {@link TelephonyManager#hasCarrierPrivileges}). In the latter case, only records accessible
789      * to the calling app are returned.
790      *
791      * @return Sorted list of the currently {@link SubscriptionInfo} records available on the device.
792      * <ul>
793      * <li>
794      * If null is returned the current state is unknown but if a {@link OnSubscriptionsChangedListener}
795      * has been registered {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be
796      * invoked in the future.
797      * </li>
798      * <li>
799      * If the list is empty then there are no {@link SubscriptionInfo} records currently available.
800      * </li>
801      * <li>
802      * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex}
803      * then by {@link SubscriptionInfo#getSubscriptionId}.
804      * </li>
805      * </ul>
806      */
807     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
808     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
getActiveSubscriptionInfoList()809     public List<SubscriptionInfo> getActiveSubscriptionInfoList() {
810         List<SubscriptionInfo> result = null;
811 
812         try {
813             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
814             if (iSub != null) {
815                 result = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName());
816             }
817         } catch (RemoteException ex) {
818             // ignore it
819         }
820         return result;
821     }
822 
823     /**
824      * Gets the SubscriptionInfo(s) of all available subscriptions, if any.
825      *
826      * <p>Available subscriptions include active ones (those with a non-negative
827      * {@link SubscriptionInfo#getSimSlotIndex()}) as well as inactive but installed embedded
828      * subscriptions.
829      *
830      * <p>The records will be sorted by {@link SubscriptionInfo#getSimSlotIndex} then by
831      * {@link SubscriptionInfo#getSubscriptionId}.
832      *
833      * @return Sorted list of the current {@link SubscriptionInfo} records available on the
834      * device.
835      * <ul>
836      * <li>
837      * If null is returned the current state is unknown but if a
838      * {@link OnSubscriptionsChangedListener} has been registered
839      * {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be invoked in the future.
840      * <li>
841      * If the list is empty then there are no {@link SubscriptionInfo} records currently available.
842      * <li>
843      * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex}
844      * then by {@link SubscriptionInfo#getSubscriptionId}.
845      * </ul>
846      *
847      * <p>
848      * Permissions android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE is required
849      * for #getAvailableSubscriptionInfoList to be invoked.
850      * @hide
851      */
852     @SystemApi
getAvailableSubscriptionInfoList()853     public List<SubscriptionInfo> getAvailableSubscriptionInfoList() {
854         List<SubscriptionInfo> result = null;
855 
856         try {
857             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
858             if (iSub != null) {
859                 result = iSub.getAvailableSubscriptionInfoList(mContext.getOpPackageName());
860             }
861         } catch (RemoteException ex) {
862             // ignore it
863         }
864         return result;
865     }
866 
867     /**
868      * Gets the SubscriptionInfo(s) of all embedded subscriptions accessible to the calling app, if
869      * any.
870      *
871      * <p>Only those subscriptions for which the calling app has carrier privileges per the
872      * subscription metadata, if any, will be included in the returned list.
873      *
874      * <p>The records will be sorted by {@link SubscriptionInfo#getSimSlotIndex} then by
875      * {@link SubscriptionInfo#getSubscriptionId}.
876      *
877      * @return Sorted list of the current embedded {@link SubscriptionInfo} records available on the
878      * device which are accessible to the caller.
879      * <ul>
880      * <li>
881      * If null is returned the current state is unknown but if a
882      * {@link OnSubscriptionsChangedListener} has been registered
883      * {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be invoked in the future.
884      * <li>
885      * If the list is empty then there are no {@link SubscriptionInfo} records currently available.
886      * <li>
887      * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex}
888      * then by {@link SubscriptionInfo#getSubscriptionId}.
889      * </ul>
890      */
getAccessibleSubscriptionInfoList()891     public List<SubscriptionInfo> getAccessibleSubscriptionInfoList() {
892         List<SubscriptionInfo> result = null;
893 
894         try {
895             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
896             if (iSub != null) {
897                 result = iSub.getAccessibleSubscriptionInfoList(mContext.getOpPackageName());
898             }
899         } catch (RemoteException ex) {
900             // ignore it
901         }
902         return result;
903     }
904 
905     /**
906      * Request a refresh of the platform cache of profile information.
907      *
908      * <p>Should be called by the EuiccService implementation whenever this information changes due
909      * to an operation done outside the scope of a request initiated by the platform to the
910      * EuiccService. There is no need to refresh for downloads, deletes, or other operations that
911      * were made through the EuiccService.
912      *
913      * <p>Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
914      * @hide
915      */
916     @SystemApi
requestEmbeddedSubscriptionInfoListRefresh()917     public void requestEmbeddedSubscriptionInfoListRefresh() {
918         try {
919             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
920             if (iSub != null) {
921                 iSub.requestEmbeddedSubscriptionInfoListRefresh();
922             }
923         } catch (RemoteException ex) {
924             // ignore it
925         }
926     }
927 
928     /**
929      * @return the count of all subscriptions in the database, this includes
930      * all subscriptions that have been seen.
931      * @hide
932      */
getAllSubscriptionInfoCount()933     public int getAllSubscriptionInfoCount() {
934         if (VDBG) logd("[getAllSubscriptionInfoCount]+");
935 
936         int result = 0;
937 
938         try {
939             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
940             if (iSub != null) {
941                 result = iSub.getAllSubInfoCount(mContext.getOpPackageName());
942             }
943         } catch (RemoteException ex) {
944             // ignore it
945         }
946 
947         return result;
948     }
949 
950     /**
951      *
952      * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
953      * or that the calling app has carrier privileges (see
954      * {@link TelephonyManager#hasCarrierPrivileges}). In the latter case, the count will include
955      * only those subscriptions accessible to the caller.
956      *
957      * @return the current number of active subscriptions. There is no guarantee the value
958      * returned by this method will be the same as the length of the list returned by
959      * {@link #getActiveSubscriptionInfoList}.
960      */
961     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
962     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
getActiveSubscriptionInfoCount()963     public int getActiveSubscriptionInfoCount() {
964         int result = 0;
965 
966         try {
967             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
968             if (iSub != null) {
969                 result = iSub.getActiveSubInfoCount(mContext.getOpPackageName());
970             }
971         } catch (RemoteException ex) {
972             // ignore it
973         }
974 
975         return result;
976     }
977 
978     /**
979      * @return the maximum number of active subscriptions that will be returned by
980      * {@link #getActiveSubscriptionInfoList} and the value returned by
981      * {@link #getActiveSubscriptionInfoCount}.
982      */
getActiveSubscriptionInfoCountMax()983     public int getActiveSubscriptionInfoCountMax() {
984         int result = 0;
985 
986         try {
987             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
988             if (iSub != null) {
989                 result = iSub.getActiveSubInfoCountMax();
990             }
991         } catch (RemoteException ex) {
992             // ignore it
993         }
994 
995         return result;
996     }
997 
998     /**
999      * Add a new SubscriptionInfo to SubscriptionInfo database if needed
1000      * @param iccId the IccId of the SIM card
1001      * @param slotIndex the slot which the SIM is inserted
1002      * @return the URL of the newly created row or the updated row
1003      * @hide
1004      */
addSubscriptionInfoRecord(String iccId, int slotIndex)1005     public Uri addSubscriptionInfoRecord(String iccId, int slotIndex) {
1006         if (VDBG) logd("[addSubscriptionInfoRecord]+ iccId:" + iccId + " slotIndex:" + slotIndex);
1007         if (iccId == null) {
1008             logd("[addSubscriptionInfoRecord]- null iccId");
1009         }
1010         if (!isValidSlotIndex(slotIndex)) {
1011             logd("[addSubscriptionInfoRecord]- invalid slotIndex");
1012         }
1013 
1014         try {
1015             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1016             if (iSub != null) {
1017                 // FIXME: This returns 1 on success, 0 on error should should we return it?
1018                 iSub.addSubInfoRecord(iccId, slotIndex);
1019             } else {
1020                 logd("[addSubscriptionInfoRecord]- ISub service is null");
1021             }
1022         } catch (RemoteException ex) {
1023             // ignore it
1024         }
1025 
1026         // FIXME: Always returns null?
1027         return null;
1028 
1029     }
1030 
1031     /**
1032      * Set SIM icon tint color by simInfo index
1033      * @param tint the RGB value of icon tint color of the SIM
1034      * @param subId the unique SubInfoRecord index in database
1035      * @return the number of records updated
1036      * @hide
1037      */
setIconTint(int tint, int subId)1038     public int setIconTint(int tint, int subId) {
1039         if (VDBG) logd("[setIconTint]+ tint:" + tint + " subId:" + subId);
1040         if (!isValidSubscriptionId(subId)) {
1041             logd("[setIconTint]- fail");
1042             return -1;
1043         }
1044 
1045         int result = 0;
1046 
1047         try {
1048             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1049             if (iSub != null) {
1050                 result = iSub.setIconTint(tint, subId);
1051             }
1052         } catch (RemoteException ex) {
1053             // ignore it
1054         }
1055 
1056         return result;
1057 
1058     }
1059 
1060     /**
1061      * Set display name by simInfo index
1062      * @param displayName the display name of SIM card
1063      * @param subId the unique SubscriptionInfo index in database
1064      * @return the number of records updated
1065      * @hide
1066      */
setDisplayName(String displayName, int subId)1067     public int setDisplayName(String displayName, int subId) {
1068         return setDisplayName(displayName, subId, NAME_SOURCE_UNDEFINDED);
1069     }
1070 
1071     /**
1072      * Set display name by simInfo index with name source
1073      * @param displayName the display name of SIM card
1074      * @param subId the unique SubscriptionInfo index in database
1075      * @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE,
1076      *                   2: NAME_SOURCE_USER_INPUT, -1 NAME_SOURCE_UNDEFINED
1077      * @return the number of records updated or < 0 if invalid subId
1078      * @hide
1079      */
setDisplayName(String displayName, int subId, long nameSource)1080     public int setDisplayName(String displayName, int subId, long nameSource) {
1081         if (VDBG) {
1082             logd("[setDisplayName]+  displayName:" + displayName + " subId:" + subId
1083                     + " nameSource:" + nameSource);
1084         }
1085         if (!isValidSubscriptionId(subId)) {
1086             logd("[setDisplayName]- fail");
1087             return -1;
1088         }
1089 
1090         int result = 0;
1091 
1092         try {
1093             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1094             if (iSub != null) {
1095                 result = iSub.setDisplayNameUsingSrc(displayName, subId, nameSource);
1096             }
1097         } catch (RemoteException ex) {
1098             // ignore it
1099         }
1100 
1101         return result;
1102 
1103     }
1104 
1105     /**
1106      * Set phone number by subId
1107      * @param number the phone number of the SIM
1108      * @param subId the unique SubscriptionInfo index in database
1109      * @return the number of records updated
1110      * @hide
1111      */
setDisplayNumber(String number, int subId)1112     public int setDisplayNumber(String number, int subId) {
1113         if (number == null || !isValidSubscriptionId(subId)) {
1114             logd("[setDisplayNumber]- fail");
1115             return -1;
1116         }
1117 
1118         int result = 0;
1119 
1120         try {
1121             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1122             if (iSub != null) {
1123                 result = iSub.setDisplayNumber(number, subId);
1124             }
1125         } catch (RemoteException ex) {
1126             // ignore it
1127         }
1128 
1129         return result;
1130 
1131     }
1132 
1133     /**
1134      * Set data roaming by simInfo index
1135      * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming
1136      * @param subId the unique SubscriptionInfo index in database
1137      * @return the number of records updated
1138      * @hide
1139      */
setDataRoaming(int roaming, int subId)1140     public int setDataRoaming(int roaming, int subId) {
1141         if (VDBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId);
1142         if (roaming < 0 || !isValidSubscriptionId(subId)) {
1143             logd("[setDataRoaming]- fail");
1144             return -1;
1145         }
1146 
1147         int result = 0;
1148 
1149         try {
1150             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1151             if (iSub != null) {
1152                 result = iSub.setDataRoaming(roaming, subId);
1153             }
1154         } catch (RemoteException ex) {
1155             // ignore it
1156         }
1157 
1158         return result;
1159     }
1160 
1161     /**
1162      * Get slotIndex associated with the subscription.
1163      * @return slotIndex as a positive integer or a negative value if an error either
1164      * SIM_NOT_INSERTED or < 0 if an invalid slot index
1165      * @hide
1166      */
getSlotIndex(int subId)1167     public static int getSlotIndex(int subId) {
1168         if (!isValidSubscriptionId(subId)) {
1169             if (DBG) {
1170                 logd("[getSlotIndex]- fail");
1171             }
1172         }
1173 
1174         int result = INVALID_SIM_SLOT_INDEX;
1175 
1176         try {
1177             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1178             if (iSub != null) {
1179                 result = iSub.getSlotIndex(subId);
1180             }
1181         } catch (RemoteException ex) {
1182             // ignore it
1183         }
1184 
1185         return result;
1186 
1187     }
1188 
1189     /** @hide */
getSubId(int slotIndex)1190     public static int[] getSubId(int slotIndex) {
1191         if (!isValidSlotIndex(slotIndex)) {
1192             logd("[getSubId]- fail");
1193             return null;
1194         }
1195 
1196         int[] subId = null;
1197 
1198         try {
1199             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1200             if (iSub != null) {
1201                 subId = iSub.getSubId(slotIndex);
1202             }
1203         } catch (RemoteException ex) {
1204             // ignore it
1205         }
1206 
1207         return subId;
1208     }
1209 
1210     /** @hide */
getPhoneId(int subId)1211     public static int getPhoneId(int subId) {
1212         if (!isValidSubscriptionId(subId)) {
1213             if (DBG) {
1214                 logd("[getPhoneId]- fail");
1215             }
1216             return INVALID_PHONE_INDEX;
1217         }
1218 
1219         int result = INVALID_PHONE_INDEX;
1220 
1221         try {
1222             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1223             if (iSub != null) {
1224                 result = iSub.getPhoneId(subId);
1225             }
1226         } catch (RemoteException ex) {
1227             // ignore it
1228         }
1229 
1230         if (VDBG) logd("[getPhoneId]- phoneId=" + result);
1231         return result;
1232 
1233     }
1234 
logd(String msg)1235     private static void logd(String msg) {
1236         Rlog.d(LOG_TAG, msg);
1237     }
1238 
1239     /**
1240      * Returns the system's default subscription id.
1241      *
1242      * For a voice capable device, it will return getDefaultVoiceSubscriptionId.
1243      * For a data only device, it will return the getDefaultDataSubscriptionId.
1244      * May return an INVALID_SUBSCRIPTION_ID on error.
1245      *
1246      * @return the "system" default subscription id.
1247      */
getDefaultSubscriptionId()1248     public static int getDefaultSubscriptionId() {
1249         int subId = INVALID_SUBSCRIPTION_ID;
1250 
1251         try {
1252             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1253             if (iSub != null) {
1254                 subId = iSub.getDefaultSubId();
1255             }
1256         } catch (RemoteException ex) {
1257             // ignore it
1258         }
1259 
1260         if (VDBG) logd("getDefaultSubId=" + subId);
1261         return subId;
1262     }
1263 
1264     /**
1265      * Returns the system's default voice subscription id.
1266      *
1267      * On a data only device or on error, will return INVALID_SUBSCRIPTION_ID.
1268      *
1269      * @return the default voice subscription Id.
1270      */
getDefaultVoiceSubscriptionId()1271     public static int getDefaultVoiceSubscriptionId() {
1272         int subId = INVALID_SUBSCRIPTION_ID;
1273 
1274         try {
1275             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1276             if (iSub != null) {
1277                 subId = iSub.getDefaultVoiceSubId();
1278             }
1279         } catch (RemoteException ex) {
1280             // ignore it
1281         }
1282 
1283         if (VDBG) logd("getDefaultVoiceSubscriptionId, sub id = " + subId);
1284         return subId;
1285     }
1286 
1287     /** @hide */
setDefaultVoiceSubId(int subId)1288     public void setDefaultVoiceSubId(int subId) {
1289         if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId);
1290         try {
1291             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1292             if (iSub != null) {
1293                 iSub.setDefaultVoiceSubId(subId);
1294             }
1295         } catch (RemoteException ex) {
1296             // ignore it
1297         }
1298     }
1299 
1300     /**
1301      * Return the SubscriptionInfo for default voice subscription.
1302      *
1303      * Will return null on data only devices, or on error.
1304      *
1305      * @return the SubscriptionInfo for the default voice subscription.
1306      * @hide
1307      */
getDefaultVoiceSubscriptionInfo()1308     public SubscriptionInfo getDefaultVoiceSubscriptionInfo() {
1309         return getActiveSubscriptionInfo(getDefaultVoiceSubscriptionId());
1310     }
1311 
1312     /** @hide */
getDefaultVoicePhoneId()1313     public static int getDefaultVoicePhoneId() {
1314         return getPhoneId(getDefaultVoiceSubscriptionId());
1315     }
1316 
1317     /**
1318      * Returns the system's default SMS subscription id.
1319      *
1320      * On a data only device or on error, will return INVALID_SUBSCRIPTION_ID.
1321      *
1322      * @return the default SMS subscription Id.
1323      */
getDefaultSmsSubscriptionId()1324     public static int getDefaultSmsSubscriptionId() {
1325         int subId = INVALID_SUBSCRIPTION_ID;
1326 
1327         try {
1328             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1329             if (iSub != null) {
1330                 subId = iSub.getDefaultSmsSubId();
1331             }
1332         } catch (RemoteException ex) {
1333             // ignore it
1334         }
1335 
1336         if (VDBG) logd("getDefaultSmsSubscriptionId, sub id = " + subId);
1337         return subId;
1338     }
1339 
1340     /** @hide */
setDefaultSmsSubId(int subId)1341     public void setDefaultSmsSubId(int subId) {
1342         if (VDBG) logd("setDefaultSmsSubId sub id = " + subId);
1343         try {
1344             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1345             if (iSub != null) {
1346                 iSub.setDefaultSmsSubId(subId);
1347             }
1348         } catch (RemoteException ex) {
1349             // ignore it
1350         }
1351     }
1352 
1353     /**
1354      * Return the SubscriptionInfo for default voice subscription.
1355      *
1356      * Will return null on data only devices, or on error.
1357      *
1358      * @return the SubscriptionInfo for the default SMS subscription.
1359      * @hide
1360      */
getDefaultSmsSubscriptionInfo()1361     public SubscriptionInfo getDefaultSmsSubscriptionInfo() {
1362         return getActiveSubscriptionInfo(getDefaultSmsSubscriptionId());
1363     }
1364 
1365     /** @hide */
getDefaultSmsPhoneId()1366     public int getDefaultSmsPhoneId() {
1367         return getPhoneId(getDefaultSmsSubscriptionId());
1368     }
1369 
1370     /**
1371      * Returns the system's default data subscription id.
1372      *
1373      * On a voice only device or on error, will return INVALID_SUBSCRIPTION_ID.
1374      *
1375      * @return the default data subscription Id.
1376      */
getDefaultDataSubscriptionId()1377     public static int getDefaultDataSubscriptionId() {
1378         int subId = INVALID_SUBSCRIPTION_ID;
1379 
1380         try {
1381             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1382             if (iSub != null) {
1383                 subId = iSub.getDefaultDataSubId();
1384             }
1385         } catch (RemoteException ex) {
1386             // ignore it
1387         }
1388 
1389         if (VDBG) logd("getDefaultDataSubscriptionId, sub id = " + subId);
1390         return subId;
1391     }
1392 
1393     /** @hide */
setDefaultDataSubId(int subId)1394     public void setDefaultDataSubId(int subId) {
1395         if (VDBG) logd("setDataSubscription sub id = " + subId);
1396         try {
1397             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1398             if (iSub != null) {
1399                 iSub.setDefaultDataSubId(subId);
1400             }
1401         } catch (RemoteException ex) {
1402             // ignore it
1403         }
1404     }
1405 
1406     /**
1407      * Return the SubscriptionInfo for default data subscription.
1408      *
1409      * Will return null on voice only devices, or on error.
1410      *
1411      * @return the SubscriptionInfo for the default data subscription.
1412      * @hide
1413      */
getDefaultDataSubscriptionInfo()1414     public SubscriptionInfo getDefaultDataSubscriptionInfo() {
1415         return getActiveSubscriptionInfo(getDefaultDataSubscriptionId());
1416     }
1417 
1418     /** @hide */
getDefaultDataPhoneId()1419     public int getDefaultDataPhoneId() {
1420         return getPhoneId(getDefaultDataSubscriptionId());
1421     }
1422 
1423     /** @hide */
clearSubscriptionInfo()1424     public void clearSubscriptionInfo() {
1425         try {
1426             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1427             if (iSub != null) {
1428                 iSub.clearSubInfo();
1429             }
1430         } catch (RemoteException ex) {
1431             // ignore it
1432         }
1433 
1434         return;
1435     }
1436 
1437     //FIXME this is vulnerable to race conditions
1438     /** @hide */
allDefaultsSelected()1439     public boolean allDefaultsSelected() {
1440         if (!isValidSubscriptionId(getDefaultDataSubscriptionId())) {
1441             return false;
1442         }
1443         if (!isValidSubscriptionId(getDefaultSmsSubscriptionId())) {
1444             return false;
1445         }
1446         if (!isValidSubscriptionId(getDefaultVoiceSubscriptionId())) {
1447             return false;
1448         }
1449         return true;
1450     }
1451 
1452     /**
1453      * If a default is set to subscription which is not active, this will reset that default back to
1454      * an invalid subscription id, i.e. < 0.
1455      * @hide
1456      */
clearDefaultsForInactiveSubIds()1457     public void clearDefaultsForInactiveSubIds() {
1458         if (VDBG) logd("clearDefaultsForInactiveSubIds");
1459         try {
1460             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1461             if (iSub != null) {
1462                 iSub.clearDefaultsForInactiveSubIds();
1463             }
1464         } catch (RemoteException ex) {
1465             // ignore it
1466         }
1467     }
1468 
1469     /**
1470      * @return true if a valid subId else false
1471      * @hide
1472      */
isValidSubscriptionId(int subId)1473     public static boolean isValidSubscriptionId(int subId) {
1474         return subId > INVALID_SUBSCRIPTION_ID ;
1475     }
1476 
1477     /**
1478      * @return true if subId is an usable subId value else false. A
1479      * usable subId means its neither a INVALID_SUBSCRIPTION_ID nor a DEFAULT_SUB_ID.
1480      * @hide
1481      */
isUsableSubIdValue(int subId)1482     public static boolean isUsableSubIdValue(int subId) {
1483         return subId >= MIN_SUBSCRIPTION_ID_VALUE && subId <= MAX_SUBSCRIPTION_ID_VALUE;
1484     }
1485 
1486     /** @hide */
isValidSlotIndex(int slotIndex)1487     public static boolean isValidSlotIndex(int slotIndex) {
1488         return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getSimCount();
1489     }
1490 
1491     /** @hide */
isValidPhoneId(int phoneId)1492     public static boolean isValidPhoneId(int phoneId) {
1493         return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount();
1494     }
1495 
1496     /** @hide */
putPhoneIdAndSubIdExtra(Intent intent, int phoneId)1497     public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) {
1498         int[] subIds = SubscriptionManager.getSubId(phoneId);
1499         if (subIds != null && subIds.length > 0) {
1500             putPhoneIdAndSubIdExtra(intent, phoneId, subIds[0]);
1501         } else {
1502             logd("putPhoneIdAndSubIdExtra: no valid subs");
1503         }
1504     }
1505 
1506     /** @hide */
putPhoneIdAndSubIdExtra(Intent intent, int phoneId, int subId)1507     public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId, int subId) {
1508         if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId);
1509         intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
1510         intent.putExtra(EXTRA_SUBSCRIPTION_INDEX, subId);
1511         intent.putExtra(PhoneConstants.PHONE_KEY, phoneId);
1512         //FIXME this is using phoneId and slotIndex interchangeably
1513         //Eventually, this should be removed as it is not the slot id
1514         intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);
1515     }
1516 
1517     /**
1518      * @return the list of subId's that are active,
1519      *         is never null but the length maybe 0.
1520      * @hide
1521      */
getActiveSubscriptionIdList()1522     public @NonNull int[] getActiveSubscriptionIdList() {
1523         int[] subId = null;
1524 
1525         try {
1526             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1527             if (iSub != null) {
1528                 subId = iSub.getActiveSubIdList();
1529             }
1530         } catch (RemoteException ex) {
1531             // ignore it
1532         }
1533 
1534         if (subId == null) {
1535             subId = new int[0];
1536         }
1537 
1538         return subId;
1539 
1540     }
1541 
1542     /**
1543      * Returns true if the device is considered roaming on the current
1544      * network for a subscription.
1545      * <p>
1546      * Availability: Only when user registered to a network.
1547      *
1548      * @param subId The subscription ID
1549      * @return true if the network for the subscription is roaming, false otherwise
1550      */
isNetworkRoaming(int subId)1551     public boolean isNetworkRoaming(int subId) {
1552         final int phoneId = getPhoneId(subId);
1553         if (phoneId < 0) {
1554             // What else can we do?
1555             return false;
1556         }
1557         return TelephonyManager.getDefault().isNetworkRoaming(subId);
1558     }
1559 
1560     /**
1561      * Returns a constant indicating the state of sim for the slot index.
1562      *
1563      * @param slotIndex
1564      *
1565      * {@See TelephonyManager#SIM_STATE_UNKNOWN}
1566      * {@See TelephonyManager#SIM_STATE_ABSENT}
1567      * {@See TelephonyManager#SIM_STATE_PIN_REQUIRED}
1568      * {@See TelephonyManager#SIM_STATE_PUK_REQUIRED}
1569      * {@See TelephonyManager#SIM_STATE_NETWORK_LOCKED}
1570      * {@See TelephonyManager#SIM_STATE_READY}
1571      * {@See TelephonyManager#SIM_STATE_NOT_READY}
1572      * {@See TelephonyManager#SIM_STATE_PERM_DISABLED}
1573      * {@See TelephonyManager#SIM_STATE_CARD_IO_ERROR}
1574      *
1575      * {@hide}
1576      */
getSimStateForSlotIndex(int slotIndex)1577     public static int getSimStateForSlotIndex(int slotIndex) {
1578         int simState = TelephonyManager.SIM_STATE_UNKNOWN;
1579 
1580         try {
1581             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1582             if (iSub != null) {
1583                 simState = iSub.getSimStateForSlotIndex(slotIndex);
1584             }
1585         } catch (RemoteException ex) {
1586         }
1587 
1588         return simState;
1589     }
1590 
1591     /**
1592      * Store properties associated with SubscriptionInfo in database
1593      * @param subId Subscription Id of Subscription
1594      * @param propKey Column name in database associated with SubscriptionInfo
1595      * @param propValue Value to store in DB for particular subId & column name
1596      * @hide
1597      */
setSubscriptionProperty(int subId, String propKey, String propValue)1598     public static void setSubscriptionProperty(int subId, String propKey, String propValue) {
1599         try {
1600             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1601             if (iSub != null) {
1602                 iSub.setSubscriptionProperty(subId, propKey, propValue);
1603             }
1604         } catch (RemoteException ex) {
1605             // ignore it
1606         }
1607     }
1608 
1609     /**
1610      * Store properties associated with SubscriptionInfo in database
1611      * @param subId Subscription Id of Subscription
1612      * @param propKey Column name in SubscriptionInfo database
1613      * @return Value associated with subId and propKey column in database
1614      * @hide
1615      */
getSubscriptionProperty(int subId, String propKey, Context context)1616     private static String getSubscriptionProperty(int subId, String propKey,
1617             Context context) {
1618         String resultValue = null;
1619         try {
1620             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1621             if (iSub != null) {
1622                 resultValue = iSub.getSubscriptionProperty(subId, propKey,
1623                         context.getOpPackageName());
1624             }
1625         } catch (RemoteException ex) {
1626             // ignore it
1627         }
1628         return resultValue;
1629     }
1630 
1631     /**
1632      * Returns boolean value corresponding to query result.
1633      * @param subId Subscription Id of Subscription
1634      * @param propKey Column name in SubscriptionInfo database
1635      * @param defValue Default boolean value to be returned
1636      * @return boolean result value to be returned
1637      * @hide
1638      */
getBooleanSubscriptionProperty(int subId, String propKey, boolean defValue, Context context)1639     public static boolean getBooleanSubscriptionProperty(int subId, String propKey,
1640             boolean defValue, Context context) {
1641         String result = getSubscriptionProperty(subId, propKey, context);
1642         if (result != null) {
1643             try {
1644                 return Integer.parseInt(result) == 1;
1645             } catch (NumberFormatException err) {
1646                 logd("getBooleanSubscriptionProperty NumberFormat exception");
1647             }
1648         }
1649         return defValue;
1650     }
1651 
1652     /**
1653      * Returns integer value corresponding to query result.
1654      * @param subId Subscription Id of Subscription
1655      * @param propKey Column name in SubscriptionInfo database
1656      * @param defValue Default integer value to be returned
1657      * @return integer result value to be returned
1658      * @hide
1659      */
getIntegerSubscriptionProperty(int subId, String propKey, int defValue, Context context)1660     public static int getIntegerSubscriptionProperty(int subId, String propKey, int defValue,
1661             Context context) {
1662         String result = getSubscriptionProperty(subId, propKey, context);
1663         if (result != null) {
1664             try {
1665                 return Integer.parseInt(result);
1666             } catch (NumberFormatException err) {
1667                 logd("getBooleanSubscriptionProperty NumberFormat exception");
1668             }
1669         }
1670         return defValue;
1671     }
1672 
1673     /**
1674      * Returns the resources associated with Subscription.
1675      * @param context Context object
1676      * @param subId Subscription Id of Subscription who's resources are required
1677      * @return Resources associated with Subscription.
1678      * @hide
1679      */
getResourcesForSubId(Context context, int subId)1680     public static Resources getResourcesForSubId(Context context, int subId) {
1681         final SubscriptionInfo subInfo =
1682                 SubscriptionManager.from(context).getActiveSubscriptionInfo(subId);
1683 
1684         Configuration config = context.getResources().getConfiguration();
1685         Configuration newConfig = new Configuration();
1686         newConfig.setTo(config);
1687         if (subInfo != null) {
1688             newConfig.mcc = subInfo.getMcc();
1689             newConfig.mnc = subInfo.getMnc();
1690             if (newConfig.mnc == 0) newConfig.mnc = Configuration.MNC_ZERO;
1691         }
1692         DisplayMetrics metrics = context.getResources().getDisplayMetrics();
1693         DisplayMetrics newMetrics = new DisplayMetrics();
1694         newMetrics.setTo(metrics);
1695         return new Resources(context.getResources().getAssets(), newMetrics, newConfig);
1696     }
1697 
1698     /**
1699      * @return true if the sub ID is active. i.e. The sub ID corresponds to a known subscription
1700      * and the SIM providing the subscription is present in a slot and in "LOADED" state.
1701      * @hide
1702      */
isActiveSubId(int subId)1703     public boolean isActiveSubId(int subId) {
1704         try {
1705             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
1706             if (iSub != null) {
1707                 return iSub.isActiveSubId(subId);
1708             }
1709         } catch (RemoteException ex) {
1710         }
1711         return false;
1712     }
1713 
1714     /**
1715      * Get the description of the billing relationship plan between a carrier
1716      * and a specific subscriber.
1717      * <p>
1718      * This method is only accessible to the following narrow set of apps:
1719      * <ul>
1720      * <li>The carrier app for this subscriberId, as determined by
1721      * {@link TelephonyManager#hasCarrierPrivileges()}.
1722      * <li>The carrier app explicitly delegated access through
1723      * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}.
1724      * </ul>
1725      *
1726      * @param subId the subscriber this relationship applies to
1727      * @throws SecurityException if the caller doesn't meet the requirements
1728      *             outlined above.
1729      */
1730     @SystemApi
getSubscriptionPlans(int subId)1731     public @NonNull List<SubscriptionPlan> getSubscriptionPlans(int subId) {
1732         try {
1733             SubscriptionPlan[] subscriptionPlans =
1734                     getNetworkPolicy().getSubscriptionPlans(subId, mContext.getOpPackageName());
1735             return subscriptionPlans == null
1736                     ? Collections.emptyList() : Arrays.asList(subscriptionPlans);
1737         } catch (RemoteException e) {
1738             throw e.rethrowFromSystemServer();
1739         }
1740     }
1741 
1742     /**
1743      * Set the description of the billing relationship plan between a carrier
1744      * and a specific subscriber.
1745      * <p>
1746      * This method is only accessible to the following narrow set of apps:
1747      * <ul>
1748      * <li>The carrier app for this subscriberId, as determined by
1749      * {@link TelephonyManager#hasCarrierPrivileges()}.
1750      * <li>The carrier app explicitly delegated access through
1751      * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}.
1752      * </ul>
1753      *
1754      * @param subId the subscriber this relationship applies to. An empty list
1755      *            may be sent to clear any existing plans.
1756      * @param plans the list of plans. The first plan is always the primary and
1757      *            most important plan. Any additional plans are secondary and
1758      *            may not be displayed or used by decision making logic.
1759      * @throws SecurityException if the caller doesn't meet the requirements
1760      *             outlined above.
1761      */
1762     @SystemApi
setSubscriptionPlans(int subId, @NonNull List<SubscriptionPlan> plans)1763     public void setSubscriptionPlans(int subId, @NonNull List<SubscriptionPlan> plans) {
1764         try {
1765             getNetworkPolicy().setSubscriptionPlans(subId,
1766                     plans.toArray(new SubscriptionPlan[plans.size()]), mContext.getOpPackageName());
1767         } catch (RemoteException e) {
1768             throw e.rethrowFromSystemServer();
1769         }
1770     }
1771 
1772     /** @hide */
getSubscriptionPlansOwner(int subId)1773     private String getSubscriptionPlansOwner(int subId) {
1774         try {
1775             return getNetworkPolicy().getSubscriptionPlansOwner(subId);
1776         } catch (RemoteException e) {
1777             throw e.rethrowFromSystemServer();
1778         }
1779     }
1780 
1781     /**
1782      * Temporarily override the billing relationship plan between a carrier and
1783      * a specific subscriber to be considered unmetered. This will be reflected
1784      * to apps via {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED}.
1785      * <p>
1786      * This method is only accessible to the following narrow set of apps:
1787      * <ul>
1788      * <li>The carrier app for this subscriberId, as determined by
1789      * {@link TelephonyManager#hasCarrierPrivileges()}.
1790      * <li>The carrier app explicitly delegated access through
1791      * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}.
1792      * </ul>
1793      *
1794      * @param subId the subscriber this override applies to.
1795      * @param overrideUnmetered set if the billing relationship should be
1796      *            considered unmetered.
1797      * @param timeoutMillis the timeout after which the requested override will
1798      *            be automatically cleared, or {@code 0} to leave in the
1799      *            requested state until explicitly cleared, or the next reboot,
1800      *            whichever happens first.
1801      * @throws SecurityException if the caller doesn't meet the requirements
1802      *             outlined above.
1803      */
1804     @SystemApi
setSubscriptionOverrideUnmetered(int subId, boolean overrideUnmetered, @DurationMillisLong long timeoutMillis)1805     public void setSubscriptionOverrideUnmetered(int subId, boolean overrideUnmetered,
1806             @DurationMillisLong long timeoutMillis) {
1807         try {
1808             final int overrideValue = overrideUnmetered ? OVERRIDE_UNMETERED : 0;
1809             getNetworkPolicy().setSubscriptionOverride(subId, OVERRIDE_UNMETERED, overrideValue,
1810                     timeoutMillis, mContext.getOpPackageName());
1811         } catch (RemoteException e) {
1812             throw e.rethrowFromSystemServer();
1813         }
1814     }
1815 
1816     /**
1817      * Temporarily override the billing relationship plan between a carrier and
1818      * a specific subscriber to be considered congested. This will cause the
1819      * device to delay certain network requests when possible, such as developer
1820      * jobs that are willing to run in a flexible time window.
1821      * <p>
1822      * This method is only accessible to the following narrow set of apps:
1823      * <ul>
1824      * <li>The carrier app for this subscriberId, as determined by
1825      * {@link TelephonyManager#hasCarrierPrivileges()}.
1826      * <li>The carrier app explicitly delegated access through
1827      * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}.
1828      * </ul>
1829      *
1830      * @param subId the subscriber this override applies to.
1831      * @param overrideCongested set if the subscription should be considered
1832      *            congested.
1833      * @param timeoutMillis the timeout after which the requested override will
1834      *            be automatically cleared, or {@code 0} to leave in the
1835      *            requested state until explicitly cleared, or the next reboot,
1836      *            whichever happens first.
1837      * @throws SecurityException if the caller doesn't meet the requirements
1838      *             outlined above.
1839      */
1840     @SystemApi
setSubscriptionOverrideCongested(int subId, boolean overrideCongested, @DurationMillisLong long timeoutMillis)1841     public void setSubscriptionOverrideCongested(int subId, boolean overrideCongested,
1842             @DurationMillisLong long timeoutMillis) {
1843         try {
1844             final int overrideValue = overrideCongested ? OVERRIDE_CONGESTED : 0;
1845             getNetworkPolicy().setSubscriptionOverride(subId, OVERRIDE_CONGESTED, overrideValue,
1846                     timeoutMillis, mContext.getOpPackageName());
1847         } catch (RemoteException e) {
1848             throw e.rethrowFromSystemServer();
1849         }
1850     }
1851 
1852     /**
1853      * Create an {@link Intent} that can be launched towards the carrier app
1854      * that is currently defining the billing relationship plan through
1855      * {@link #setSubscriptionPlans(int, List)}.
1856      *
1857      * @return ready to launch Intent targeted towards the carrier app, or
1858      *         {@code null} if no carrier app is defined, or if the defined
1859      *         carrier app provides no management activity.
1860      * @hide
1861      */
createManageSubscriptionIntent(int subId)1862     public @Nullable Intent createManageSubscriptionIntent(int subId) {
1863         // Bail if no owner
1864         final String owner = getSubscriptionPlansOwner(subId);
1865         if (owner == null) return null;
1866 
1867         // Bail if no plans
1868         final List<SubscriptionPlan> plans = getSubscriptionPlans(subId);
1869         if (plans.isEmpty()) return null;
1870 
1871         final Intent intent = new Intent(ACTION_MANAGE_SUBSCRIPTION_PLANS);
1872         intent.setPackage(owner);
1873         intent.putExtra(EXTRA_SUBSCRIPTION_INDEX, subId);
1874 
1875         // Bail if not implemented
1876         if (mContext.getPackageManager().queryIntentActivities(intent,
1877                 PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) {
1878             return null;
1879         }
1880 
1881         return intent;
1882     }
1883 
1884     /** @hide */
createRefreshSubscriptionIntent(int subId)1885     private @Nullable Intent createRefreshSubscriptionIntent(int subId) {
1886         // Bail if no owner
1887         final String owner = getSubscriptionPlansOwner(subId);
1888         if (owner == null) return null;
1889 
1890         // Bail if no plans
1891         final List<SubscriptionPlan> plans = getSubscriptionPlans(subId);
1892         if (plans.isEmpty()) return null;
1893 
1894         final Intent intent = new Intent(ACTION_REFRESH_SUBSCRIPTION_PLANS);
1895         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
1896         intent.setPackage(owner);
1897         intent.putExtra(EXTRA_SUBSCRIPTION_INDEX, subId);
1898 
1899         // Bail if not implemented
1900         if (mContext.getPackageManager().queryBroadcastReceivers(intent, 0).isEmpty()) {
1901             return null;
1902         }
1903 
1904         return intent;
1905     }
1906 
1907     /**
1908      * Check if there is a carrier app that is currently defining the billing
1909      * relationship plan through {@link #setSubscriptionPlans(int, List)} that
1910      * supports refreshing of subscription plans.
1911      *
1912      * @hide
1913      */
isSubscriptionPlansRefreshSupported(int subId)1914     public boolean isSubscriptionPlansRefreshSupported(int subId) {
1915         return createRefreshSubscriptionIntent(subId) != null;
1916     }
1917 
1918     /**
1919      * Request that the carrier app that is currently defining the billing
1920      * relationship plan through {@link #setSubscriptionPlans(int, List)}
1921      * refresh its subscription plans.
1922      * <p>
1923      * If the app is able to successfully update the plans, you'll expect to
1924      * receive the {@link #ACTION_SUBSCRIPTION_PLANS_CHANGED} broadcast.
1925      *
1926      * @hide
1927      */
requestSubscriptionPlansRefresh(int subId)1928     public void requestSubscriptionPlansRefresh(int subId) {
1929         final Intent intent = createRefreshSubscriptionIntent(subId);
1930         final BroadcastOptions options = BroadcastOptions.makeBasic();
1931         options.setTemporaryAppWhitelistDuration(TimeUnit.MINUTES.toMillis(1));
1932         mContext.sendBroadcast(intent, null, options.toBundle());
1933     }
1934 
1935     /**
1936      * Checks whether the app with the given context is authorized to manage the given subscription
1937      * according to its metadata. Only supported for embedded subscriptions (if
1938      * {@code SubscriptionInfo#isEmbedded} returns true).
1939      *
1940      * @param info The subscription to check.
1941      * @return whether the app is authorized to manage this subscription per its metadata.
1942      * @throws IllegalArgumentException if this subscription is not embedded.
1943      */
canManageSubscription(SubscriptionInfo info)1944     public boolean canManageSubscription(SubscriptionInfo info) {
1945         return canManageSubscription(info, mContext.getPackageName());
1946     }
1947 
1948     /**
1949      * Checks whether the given app is authorized to manage the given subscription. An app can only
1950      * be authorized if it is included in the {@link android.telephony.UiccAccessRule} of the
1951      * {@link android.telephony.SubscriptionInfo} with the access status.
1952      * Only supported for embedded subscriptions (if {@link SubscriptionInfo#isEmbedded}
1953      * returns true).
1954      *
1955      * @param info The subscription to check.
1956      * @param packageName Package name of the app to check.
1957      * @return whether the app is authorized to manage this subscription per its access rules.
1958      * @throws IllegalArgumentException if this subscription is not embedded.
1959      * @hide
1960      */
canManageSubscription(SubscriptionInfo info, String packageName)1961     public boolean canManageSubscription(SubscriptionInfo info, String packageName) {
1962         if (!info.isEmbedded()) {
1963             throw new IllegalArgumentException("Not an embedded subscription");
1964         }
1965         if (info.getAccessRules() == null) {
1966             return false;
1967         }
1968         PackageManager packageManager = mContext.getPackageManager();
1969         PackageInfo packageInfo;
1970         try {
1971             packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
1972         } catch (PackageManager.NameNotFoundException e) {
1973             throw new IllegalArgumentException("Unknown package: " + packageName, e);
1974         }
1975         for (UiccAccessRule rule : info.getAccessRules()) {
1976             if (rule.getCarrierPrivilegeStatus(packageInfo)
1977                     == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1978                 return true;
1979             }
1980         }
1981         return false;
1982     }
1983 }
1984