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