• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 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 com.android.internal.telephony;
18 
19 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
20 import static android.telephony.TelephonyManager.ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED;
21 import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE;
22 import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL;
23 import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA;
24 import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DISMISS;
25 import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE;
26 import static android.telephony.TelephonyManager.EXTRA_SIM_COMBINATION_NAMES;
27 import static android.telephony.TelephonyManager.EXTRA_SIM_COMBINATION_WARNING_TYPE;
28 import static android.telephony.TelephonyManager.EXTRA_SIM_COMBINATION_WARNING_TYPE_DUAL_CDMA;
29 import static android.telephony.TelephonyManager.EXTRA_SIM_COMBINATION_WARNING_TYPE_NONE;
30 import static android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID;
31 
32 import android.annotation.CallbackExecutor;
33 import android.annotation.IntDef;
34 import android.annotation.NonNull;
35 import android.app.PendingIntent;
36 import android.content.Context;
37 import android.content.Intent;
38 import android.os.AsyncResult;
39 import android.os.Handler;
40 import android.os.Looper;
41 import android.os.Message;
42 import android.os.ParcelUuid;
43 import android.provider.Settings;
44 import android.provider.Settings.SettingNotFoundException;
45 import android.telephony.CarrierConfigManager;
46 import android.telephony.SubscriptionInfo;
47 import android.telephony.SubscriptionManager;
48 import android.telephony.TelephonyManager;
49 import android.telephony.euicc.EuiccManager;
50 import android.text.TextUtils;
51 import android.util.Log;
52 
53 import com.android.internal.annotations.VisibleForTesting;
54 import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback;
55 import com.android.internal.telephony.subscription.SubscriptionInfoInternal;
56 import com.android.internal.telephony.subscription.SubscriptionManagerService;
57 import com.android.internal.telephony.util.ArrayUtils;
58 
59 import java.lang.annotation.Retention;
60 import java.lang.annotation.RetentionPolicy;
61 import java.util.ArrayList;
62 import java.util.Arrays;
63 import java.util.List;
64 import java.util.concurrent.Executor;
65 import java.util.stream.Collectors;
66 
67 /**
68  * This class will make sure below setting rules are coordinated across different subscriptions
69  * and phones in multi-SIM case:
70  *
71  * 1) Grouped subscriptions will have same settings for MOBILE_DATA and DATA_ROAMING.
72  * 2) Default settings updated automatically. It may be cleared or inherited within group.
73  *    If default subscription A switches to profile B which is in the same group, B will
74  *    become the new default.
75  * 3) For primary subscriptions, only default data subscription will have MOBILE_DATA on.
76  */
77 public class MultiSimSettingController extends Handler {
78     private static final String LOG_TAG = "MultiSimSettingController";
79     private static final boolean DBG = true;
80     private static final int EVENT_USER_DATA_ENABLED                 = 1;
81     private static final int EVENT_ROAMING_DATA_ENABLED              = 2;
82     private static final int EVENT_ALL_SUBSCRIPTIONS_LOADED          = 3;
83     private static final int EVENT_SUBSCRIPTION_INFO_CHANGED         = 4;
84     private static final int EVENT_SUBSCRIPTION_GROUP_CHANGED        = 5;
85     private static final int EVENT_DEFAULT_DATA_SUBSCRIPTION_CHANGED = 6;
86     @VisibleForTesting
87     public static final int EVENT_MULTI_SIM_CONFIG_CHANGED          = 8;
88     @VisibleForTesting
89     public static final int EVENT_RADIO_STATE_CHANGED                = 9;
90 
91     @Retention(RetentionPolicy.SOURCE)
92     @IntDef(prefix = {"PRIMARY_SUB_"},
93             value = {
94                     PRIMARY_SUB_NO_CHANGE,
95                     PRIMARY_SUB_ADDED,
96                     PRIMARY_SUB_REMOVED,
97                     PRIMARY_SUB_SWAPPED,
98                     PRIMARY_SUB_SWAPPED_IN_GROUP,
99                     PRIMARY_SUB_MARKED_OPPT,
100                     PRIMARY_SUB_INITIALIZED,
101                     PRIMARY_SUB_REMOVED_IN_GROUP
102     })
103     private @interface PrimarySubChangeType {}
104 
105     // Primary subscription not change.
106     private static final int PRIMARY_SUB_NO_CHANGE              = 0;
107     // One or more primary subscriptions are activated.
108     private static final int PRIMARY_SUB_ADDED                  = 1;
109     // One or more primary subscriptions are deactivated.
110     private static final int PRIMARY_SUB_REMOVED                = 2;
111     // One or more primary subscriptions are swapped.
112     private static final int PRIMARY_SUB_SWAPPED                = 3;
113     // One or more primary subscriptions are swapped but within same sub group.
114     private static final int PRIMARY_SUB_SWAPPED_IN_GROUP       = 4;
115     // One or more primary subscriptions are marked as opportunistic.
116     private static final int PRIMARY_SUB_MARKED_OPPT            = 5;
117     // Subscription information is initially loaded.
118     private static final int PRIMARY_SUB_INITIALIZED            = 6;
119     // One or more primary subscriptions are deactivated but within the same group as another active
120     // sub.
121     private static final int PRIMARY_SUB_REMOVED_IN_GROUP       = 7;
122 
123     protected final Context mContext;
124     private final SubscriptionManagerService mSubscriptionManagerService;
125 
126     // Keep a record of active primary (non-opportunistic) subscription list.
127     @NonNull private List<Integer> mPrimarySubList = new ArrayList<>();
128 
129     /** The singleton instance. */
130     protected static MultiSimSettingController sInstance = null;
131 
132     // This will be set true when handling EVENT_ALL_SUBSCRIPTIONS_LOADED.
133     private boolean mSubInfoInitialized = false;
134 
135     // mInitialHandling is to make sure we don't always ask user to re-select data SIM after reboot.
136     // After boot-up when things are firstly initialized (mSubInfoInitialized is changed to true
137     // and carrier configs are all loaded), we do a reEvaluateAll(). In the first reEvaluateAll(),
138     // mInitialHandling will be true and we won't pop up SIM select dialog.
139     private boolean mInitialHandling = true;
140 
141     // Keep a record of which subIds have carrier config loaded. Length of the array is phone count.
142     // The index is phoneId, and value is subId. For example:
143     // If carrier config of subId 2 is loaded on phone 0,mCarrierConfigLoadedSubIds[0] = 2.
144     // Then if subId 2 is deactivated from phone 0, the value becomes INVALID,
145     // mCarrierConfigLoadedSubIds[0] = INVALID_SUBSCRIPTION_ID.
146     private int[] mCarrierConfigLoadedSubIds;
147 
148     // It indicates whether "Ask every time" option for default SMS subscription is supported by the
149     // device.
150     private final boolean mIsAskEverytimeSupportedForSms;
151 
152     // The number of existing DataSettingsControllerCallback
153     private int mCallbacksCount;
154     /** The number of active modem count. */
155     private int mActiveModemCount;
156 
157     private static final String SETTING_USER_PREF_DATA_SUB = "user_preferred_data_sub";
158 
159     private static class DataSettingsControllerCallback extends DataSettingsManagerCallback {
160         private final Phone mPhone;
161 
DataSettingsControllerCallback(@onNull Phone phone, @NonNull @CallbackExecutor Executor executor)162         DataSettingsControllerCallback(@NonNull Phone phone,
163                 @NonNull @CallbackExecutor Executor executor) {
164             super(executor);
165             mPhone = phone;
166         }
167 
168         @Override
onUserDataEnabledChanged(boolean enabled, @NonNull String callingPackage)169         public void onUserDataEnabledChanged(boolean enabled, @NonNull String callingPackage) {
170             int subId = mPhone.getSubId();
171             // only notifyUserDataEnabled if the change is called from external to avoid
172             // setUserDataEnabledForGroup infinite loop
173             if (SubscriptionManager.isValidSubscriptionId(subId)
174                     && !getInstance().mContext.getOpPackageName().equals(callingPackage)) {
175                 getInstance().notifyUserDataEnabled(subId, enabled);
176             }
177         }
178 
179         @Override
onDataRoamingEnabledChanged(boolean enabled)180         public void onDataRoamingEnabledChanged(boolean enabled) {
181             int subId = mPhone.getSubId();
182             if (SubscriptionManager.isValidSubscriptionId(subId)) {
183                 getInstance().notifyRoamingDataEnabled(mPhone.getSubId(), enabled);
184             }
185         }
186     }
187 
188     /**
189      * Return the singleton or create one if not existed.
190      */
getInstance()191     public static MultiSimSettingController getInstance() {
192         synchronized (MultiSimSettingController.class) {
193             if (sInstance == null) {
194                 Log.wtf(LOG_TAG, "getInstance null");
195             }
196 
197             return sInstance;
198         }
199     }
200 
201     /**
202      * Init instance of MultiSimSettingController.
203      */
init(Context context)204     public static MultiSimSettingController init(Context context) {
205         synchronized (MultiSimSettingController.class) {
206             if (sInstance == null) {
207                 sInstance = new MultiSimSettingController(context);
208             } else {
209                 Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);
210             }
211             return sInstance;
212         }
213     }
214 
215     @VisibleForTesting
MultiSimSettingController(Context context)216     public MultiSimSettingController(Context context) {
217         mContext = context;
218         mSubscriptionManagerService = SubscriptionManagerService.getInstance();
219 
220         // Initialize mCarrierConfigLoadedSubIds and register to listen to carrier config change.
221         TelephonyManager telephonyManager = ((TelephonyManager) mContext.getSystemService(
222                 TelephonyManager.class));
223         final int phoneCount = telephonyManager.getSupportedModemCount();
224         mCarrierConfigLoadedSubIds = new int[phoneCount];
225         Arrays.fill(mCarrierConfigLoadedSubIds, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
226 
227         mActiveModemCount = telephonyManager.getActiveModemCount();
228 
229         PhoneConfigurationManager.registerForMultiSimConfigChange(
230                 this, EVENT_MULTI_SIM_CONFIG_CHANGED, null);
231 
232         mIsAskEverytimeSupportedForSms = mContext.getResources()
233                 .getBoolean(com.android.internal.R.bool.config_sms_ask_every_time_support);
234 
235         CarrierConfigManager ccm = mContext.getSystemService(CarrierConfigManager.class);
236         // Listener callback is executed on handler thread to directly handle config change
237         ccm.registerCarrierConfigChangeListener(this::post,
238                 (slotIndex, subId, carrierId, specificCarrierId) ->
239                         onCarrierConfigChanged(slotIndex, subId));
240     }
241 
242     /**
243      * Notify MOBILE_DATA of a subscription is changed.
244      */
notifyUserDataEnabled(int subId, boolean enable)245     public void notifyUserDataEnabled(int subId, boolean enable) {
246         if (SubscriptionManager.isValidSubscriptionId(subId)) {
247             obtainMessage(EVENT_USER_DATA_ENABLED, subId, enable ? 1 : 0).sendToTarget();
248         }
249     }
250 
251     /**
252      * Notify DATA_ROAMING of a subscription is changed.
253      */
notifyRoamingDataEnabled(int subId, boolean enable)254     public void notifyRoamingDataEnabled(int subId, boolean enable) {
255         if (SubscriptionManager.isValidSubscriptionId(subId)) {
256             obtainMessage(EVENT_ROAMING_DATA_ENABLED, subId, enable ? 1 : 0).sendToTarget();
257         }
258     }
259 
260     /**
261      * Notify that, for the first time after boot, SIMs are initialized.
262      * Should only be triggered once.
263      */
notifyAllSubscriptionLoaded()264     public void notifyAllSubscriptionLoaded() {
265         obtainMessage(EVENT_ALL_SUBSCRIPTIONS_LOADED).sendToTarget();
266     }
267 
268     /**
269      * Notify subscription info change.
270      */
notifySubscriptionInfoChanged()271     public void notifySubscriptionInfoChanged() {
272         log("notifySubscriptionInfoChanged");
273         obtainMessage(EVENT_SUBSCRIPTION_INFO_CHANGED).sendToTarget();
274     }
275 
276     /**
277      * Notify subscription group information change.
278      */
notifySubscriptionGroupChanged(ParcelUuid groupUuid)279     public void notifySubscriptionGroupChanged(ParcelUuid groupUuid) {
280         obtainMessage(EVENT_SUBSCRIPTION_GROUP_CHANGED, groupUuid).sendToTarget();
281     }
282 
283     /**
284      * Notify default data subscription change.
285      */
notifyDefaultDataSubChanged()286     public void notifyDefaultDataSubChanged() {
287         obtainMessage(EVENT_DEFAULT_DATA_SUBSCRIPTION_CHANGED).sendToTarget();
288     }
289 
290     @Override
handleMessage(Message msg)291     public void handleMessage(Message msg) {
292         switch (msg.what) {
293             case EVENT_USER_DATA_ENABLED: {
294                 int subId = msg.arg1;
295                 boolean enable = msg.arg2 != 0;
296                 onUserDataEnabled(subId, enable, true);
297                 break;
298             }
299             case EVENT_ROAMING_DATA_ENABLED: {
300                 int subId = msg.arg1;
301                 boolean enable = msg.arg2 != 0;
302                 onRoamingDataEnabled(subId, enable);
303                 break;
304             }
305             case EVENT_ALL_SUBSCRIPTIONS_LOADED:
306                 onAllSubscriptionsLoaded();
307                 break;
308             case EVENT_SUBSCRIPTION_INFO_CHANGED:
309                 onSubscriptionsChanged();
310                 break;
311             case EVENT_SUBSCRIPTION_GROUP_CHANGED:
312                 ParcelUuid groupUuid = (ParcelUuid) msg.obj;
313                 onSubscriptionGroupChanged(groupUuid);
314                 break;
315             case EVENT_DEFAULT_DATA_SUBSCRIPTION_CHANGED:
316                 onDefaultDataSettingChanged();
317                 break;
318             case EVENT_MULTI_SIM_CONFIG_CHANGED:
319                 int activeModems = (int) ((AsyncResult) msg.obj).result;
320                 onMultiSimConfigChanged(activeModems);
321                 break;
322             case EVENT_RADIO_STATE_CHANGED:
323                 for (int phoneId = 0; phoneId < mActiveModemCount; phoneId++) {
324                     Phone phone = PhoneFactory.getPhone(phoneId);
325                     if (phone != null && phone.mCi.getRadioState()
326                             == TelephonyManager.RADIO_POWER_UNAVAILABLE) {
327                         if (DBG) {
328                             log("Radio unavailable on phone " + phoneId
329                                     + ", clearing sub info initialized flag");
330                         }
331                         mSubInfoInitialized = false;
332                         break;
333                     }
334                 }
335                 break;
336         }
337     }
338 
339     /**
340      * Make sure MOBILE_DATA of subscriptions in same group are synced.
341      *
342      * If user is enabling a non-default non-opportunistic subscription, make it default
343      * data subscription.
344      */
onUserDataEnabled(int subId, boolean enable, boolean setDefaultData)345     private void onUserDataEnabled(int subId, boolean enable, boolean setDefaultData) {
346         if (DBG) log("[onUserDataEnabled] subId=" + subId + " enable=" + enable +
347         " setDefaultData=" + setDefaultData);
348         // Make sure MOBILE_DATA of subscriptions in same group are synced.
349         setUserDataEnabledForGroup(subId, enable);
350 
351         SubscriptionInfo subInfo = mSubscriptionManagerService.getSubscriptionInfo(subId);
352         int defaultDataSubId = mSubscriptionManagerService.getDefaultDataSubId();
353 
354         // If user is enabling a non-default non-opportunistic subscription, make it default.
355         if (defaultDataSubId != subId && subInfo != null && !subInfo.isOpportunistic() && enable
356                 && subInfo.isActive() && setDefaultData) {
357             android.provider.Settings.Global.putInt(mContext.getContentResolver(),
358                     SETTING_USER_PREF_DATA_SUB, subId);
359             mSubscriptionManagerService.setDefaultDataSubId(subId);
360         }
361     }
362 
363     /**
364      * Make sure DATA_ROAMING of subscriptions in same group are synced.
365      */
onRoamingDataEnabled(int subId, boolean enable)366     private void onRoamingDataEnabled(int subId, boolean enable) {
367         if (DBG) log("onRoamingDataEnabled");
368         setRoamingDataEnabledForGroup(subId, enable);
369 
370         // Also inform SubscriptionManagerService as it keeps another copy of user setting.
371         mSubscriptionManagerService.setDataRoaming(enable ? 1 : 0, subId);
372     }
373 
374     /**
375      * Upon initialization or radio available, update defaults and mobile data enabling.
376      * Should only be triggered once.
377      */
onAllSubscriptionsLoaded()378     private void onAllSubscriptionsLoaded() {
379         if (DBG) log("onAllSubscriptionsLoaded: mSubInfoInitialized=" + mSubInfoInitialized);
380         if (!mSubInfoInitialized) {
381             mSubInfoInitialized = true;
382             for (Phone phone : PhoneFactory.getPhones()) {
383                 phone.mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
384             }
385             reEvaluateAll();
386         }
387         registerDataSettingsControllerCallbackAsNeeded();
388     }
389 
390     /**
391      * Make sure default values are cleaned or updated.
392      *
393      * Make sure non-default non-opportunistic subscriptions has data off.
394      */
onSubscriptionsChanged()395     private void onSubscriptionsChanged() {
396         if (DBG) log("onSubscriptionsChanged");
397         reEvaluateAll();
398     }
399 
400     /**
401      * This method is called when a phone object is removed (for example when going from multi-sim
402      * to single-sim).
403      * NOTE: This method does not post a message to self, instead it calls reEvaluateAll() directly.
404      * so it should only be called from the main thread. The reason is to update defaults asap
405      * after multi_sim_config property has been updated (see b/163582235).
406      */
onPhoneRemoved()407     public void onPhoneRemoved() {
408         if (DBG) log("onPhoneRemoved");
409         if (Looper.myLooper() != this.getLooper()) {
410             throw new RuntimeException("This method must be called from the same looper as "
411                     + "MultiSimSettingController.");
412         }
413         reEvaluateAll();
414     }
415 
onCarrierConfigChanged(int phoneId, int subId)416     private void onCarrierConfigChanged(int phoneId, int subId) {
417         log("onCarrierConfigChanged phoneId " + phoneId + " subId " + subId);
418         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
419             loge("Carrier config change with invalid phoneId " + phoneId);
420             return;
421         }
422 
423         // b/153860050 Occasionally we receive carrier config change broadcast without subId
424         // being specified in it. So here we do additional check to make sur we don't miss the
425         // subId.
426         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
427             subId = SubscriptionManager.getSubscriptionId(phoneId);
428             if (SubscriptionManager.isValidSubscriptionId(subId)) {
429                 CarrierConfigManager cm = mContext.getSystemService(CarrierConfigManager.class);
430                 if (cm != null && cm.getConfigForSubId(subId) != null) {
431                     loge("onCarrierConfigChanged with invalid subId while subId "
432                             + subId + " is active and its config is loaded");
433                 }
434             }
435         }
436 
437         mCarrierConfigLoadedSubIds[phoneId] = subId;
438         reEvaluateAll();
439     }
440 
441     /**
442      * Check whether carrier config loaded for all subs
443      */
444     @VisibleForTesting
isCarrierConfigLoadedForAllSub()445     public boolean isCarrierConfigLoadedForAllSub() {
446         int[] activeSubIds = mSubscriptionManagerService.getActiveSubIdList(false);
447         for (int activeSubId : activeSubIds) {
448             boolean isLoaded = false;
449             for (int configLoadedSub : mCarrierConfigLoadedSubIds) {
450                 if (configLoadedSub == activeSubId) {
451                     isLoaded = true;
452                     break;
453                 }
454             }
455             if (!isLoaded) {
456                 if (DBG) log("Carrier config subId " + activeSubId + " is not loaded.");
457                 return false;
458             }
459         }
460 
461         return true;
462     }
463 
onMultiSimConfigChanged(int activeModems)464     private void onMultiSimConfigChanged(int activeModems) {
465         mActiveModemCount = activeModems;
466         log("onMultiSimConfigChanged: current ActiveModemCount=" + mActiveModemCount);
467         // Clear mCarrierConfigLoadedSubIds. Other actions will responds to active
468         // subscription change.
469         for (int phoneId = activeModems; phoneId < mCarrierConfigLoadedSubIds.length; phoneId++) {
470             mCarrierConfigLoadedSubIds[phoneId] = INVALID_SUBSCRIPTION_ID;
471         }
472         for (Phone phone : PhoneFactory.getPhones()) {
473             phone.mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
474         }
475         registerDataSettingsControllerCallbackAsNeeded();
476     }
477 
478     /**
479      * Wait for subInfo initialization (after boot up or radio unavailable) and carrier config load
480      * for all active subscriptions before re-evaluate multi SIM settings.
481      */
isReadyToReevaluate()482     private boolean isReadyToReevaluate() {
483         boolean carrierConfigsLoaded = isCarrierConfigLoadedForAllSub();
484         if (DBG) {
485             log("isReadyToReevaluate: subInfoInitialized=" + mSubInfoInitialized
486                     + ", carrierConfigsLoaded=" + carrierConfigsLoaded);
487         }
488         return mSubInfoInitialized && carrierConfigsLoaded;
489     }
490 
reEvaluateAll()491     private void reEvaluateAll() {
492         if (!isReadyToReevaluate()) return;
493         updateDefaults();
494         disableDataForNonDefaultNonOpportunisticSubscriptions();
495         deactivateGroupedOpportunisticSubscriptionIfNeeded();
496     }
497 
498     /**
499      * Make sure non-default non-opportunistic subscriptions has data disabled.
500      */
onDefaultDataSettingChanged()501     private void onDefaultDataSettingChanged() {
502         if (DBG) log("onDefaultDataSettingChanged");
503         disableDataForNonDefaultNonOpportunisticSubscriptions();
504     }
505 
506     /**
507      * When a subscription group is created or new subscriptions are added in the group, make
508      * sure the settings among them are synced.
509      * TODO: b/130258159 have a separate database table for grouped subscriptions so we don't
510      * manually sync each setting.
511      */
onSubscriptionGroupChanged(ParcelUuid groupUuid)512     private void onSubscriptionGroupChanged(ParcelUuid groupUuid) {
513         if (DBG) log("onSubscriptionGroupChanged");
514 
515         List<SubscriptionInfo> infoList = mSubscriptionManagerService.getSubscriptionsInGroup(
516                 groupUuid, mContext.getOpPackageName(), mContext.getAttributionTag());
517         if (infoList == null || infoList.isEmpty()) return;
518 
519         // Get a reference subscription to copy settings from.
520         // TODO: the reference sub should be passed in from external caller.
521         int refSubId = infoList.get(0).getSubscriptionId();
522         for (SubscriptionInfo info : infoList) {
523             int subId = info.getSubscriptionId();
524             if (info.isActive() && !info.isOpportunistic()) {
525                 refSubId = subId;
526                 break;
527             }
528         }
529 
530         if (DBG) log("refSubId is " + refSubId);
531 
532         boolean enable = false;
533         try {
534             enable = GlobalSettingsHelper.getBoolean(
535                     mContext, Settings.Global.MOBILE_DATA, refSubId);
536         } catch (SettingNotFoundException exception) {
537             //pass invalid refSubId to fetch the single-sim setting
538             enable = GlobalSettingsHelper.getBoolean(
539                     mContext, Settings.Global.MOBILE_DATA, INVALID_SUBSCRIPTION_ID, enable);
540         }
541         boolean setDefaultData = true;
542         List<SubscriptionInfo> activeSubList = mSubscriptionManagerService
543                 .getActiveSubscriptionInfoList(mContext.getOpPackageName(),
544                         mContext.getAttributionTag());
545         for (SubscriptionInfo activeInfo : activeSubList) {
546             if (!(groupUuid.equals(activeInfo.getGroupUuid()))) {
547                 // Do not set refSubId as defaultDataSubId if there are other active
548                 // subscriptions which does not belong to this groupUuid
549                 setDefaultData = false;
550                 break;
551             }
552         }
553         onUserDataEnabled(refSubId, enable, setDefaultData);
554 
555         enable = false;
556         try {
557             enable = GlobalSettingsHelper.getBoolean(
558                     mContext, Settings.Global.DATA_ROAMING, refSubId);
559             onRoamingDataEnabled(refSubId, enable);
560         } catch (SettingNotFoundException exception) {
561             //pass invalid refSubId to fetch the single-sim setting
562             enable = GlobalSettingsHelper.getBoolean(
563                     mContext, Settings.Global.DATA_ROAMING, INVALID_SUBSCRIPTION_ID, enable);
564             onRoamingDataEnabled(refSubId, enable);
565         }
566 
567         mSubscriptionManagerService.syncGroupedSetting(refSubId);
568     }
569 
570     /**
571      * Automatically update default settings (data / voice / sms).
572      *
573      * Opportunistic subscriptions can't be default data / voice / sms subscription.
574      *
575      * 1) If the default subscription is still active, keep it unchanged.
576      * 2) Or if there's another active primary subscription that's in the same group,
577      *    make it the new default value.
578      * 3) Or if there's only one active primary subscription, automatically set default
579      *    data subscription on it. Because default data in Android Q is an internal value,
580      *    not a user settable value anymore.
581      * 4) If non above is met, clear the default value to INVALID.
582      *
583      */
updateDefaults()584     protected void updateDefaults() {
585         if (DBG) log("updateDefaults");
586 
587         if (!isReadyToReevaluate()) return;
588 
589         List<SubscriptionInfo> activeSubInfos = mSubscriptionManagerService
590                 .getActiveSubscriptionInfoList(mContext.getOpPackageName(),
591                         mContext.getAttributionTag());
592 
593         if (ArrayUtils.isEmpty(activeSubInfos)) {
594             mPrimarySubList.clear();
595             if (DBG) log("updateDefaults: No active sub. Setting default to INVALID sub.");
596             mSubscriptionManagerService.setDefaultDataSubId(
597                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
598             mSubscriptionManagerService.setDefaultVoiceSubId(
599                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
600             mSubscriptionManagerService.setDefaultSmsSubId(
601                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
602             return;
603         }
604 
605         int change = updatePrimarySubListAndGetChangeType(activeSubInfos);
606         if (DBG) log("updateDefaultValues: change: " + change);
607         if (change == PRIMARY_SUB_NO_CHANGE) return;
608 
609         // If there's only one primary subscription active, we trigger PREFERRED_PICK_DIALOG
610         // dialog if and only if there were multiple primary SIM cards and one is removed.
611         // Otherwise, if user just inserted their first SIM, or there's one primary and one
612         // opportunistic subscription active (activeSubInfos.size() > 1), we automatically
613         // set the primary to be default SIM and return.
614         if (mPrimarySubList.size() == 1 && (change != PRIMARY_SUB_REMOVED
615                 || mActiveModemCount == 1)) {
616             int subId = mPrimarySubList.get(0);
617             if (DBG) log("updateDefaultValues: to only primary sub " + subId);
618             mSubscriptionManagerService.setDefaultDataSubId(subId);
619             mSubscriptionManagerService.setDefaultVoiceSubId(subId);
620             mSubscriptionManagerService.setDefaultSmsSubId(subId);
621             sendDefaultSubConfirmedNotification(subId);
622             return;
623         }
624 
625         if (DBG) log("updateDefaultValues: records: " + mPrimarySubList);
626 
627         boolean dataSelected, voiceSelected, smsSelected;
628 
629         // Update default data subscription.
630         if (DBG) log("updateDefaultValues: Update default data subscription");
631         dataSelected = updateDefaultValue(mPrimarySubList,
632                 mSubscriptionManagerService.getDefaultDataSubId(),
633                 mSubscriptionManagerService::setDefaultDataSubId);
634 
635         // Update default voice subscription.
636         if (DBG) log("updateDefaultValues: Update default voice subscription");
637         voiceSelected = updateDefaultValue(mPrimarySubList,
638                 mSubscriptionManagerService.getDefaultVoiceSubId(),
639                 mSubscriptionManagerService::setDefaultVoiceSubId);
640 
641         // Update default sms subscription.
642         if (DBG) log("updateDefaultValues: Update default sms subscription");
643         smsSelected = updateDefaultValue(mPrimarySubList,
644                 mSubscriptionManagerService.getDefaultSmsSubId(),
645                 mSubscriptionManagerService::setDefaultSmsSubId,
646                 mIsAskEverytimeSupportedForSms);
647 
648         boolean autoFallbackEnabled = mContext.getResources().getBoolean(
649                 com.android.internal.R.bool.config_voice_data_sms_auto_fallback);
650 
651         // Based on config config_voice_data_sms_auto_fallback value choose voice/data/sms
652         // preference auto selection logic or display notification for end used to
653         // select voice/data/SMS preferences.
654         if (!autoFallbackEnabled) {
655             sendSubChangeNotificationIfNeeded(change, dataSelected, voiceSelected, smsSelected);
656         } else {
657             updateUserPreferences(mPrimarySubList, dataSelected, voiceSelected, smsSelected);
658         }
659     }
660 
661     @PrimarySubChangeType
updatePrimarySubListAndGetChangeType(List<SubscriptionInfo> activeSubList)662     private int updatePrimarySubListAndGetChangeType(List<SubscriptionInfo> activeSubList) {
663         // Update mPrimarySubList. Opportunistic subscriptions can't be default
664         // data / voice / sms subscription.
665         List<Integer> prevPrimarySubList = mPrimarySubList;
666         mPrimarySubList = activeSubList.stream().filter(info -> !info.isOpportunistic())
667                 .map(info -> info.getSubscriptionId())
668                 .collect(Collectors.toList());
669 
670         if (mInitialHandling) {
671             mInitialHandling = false;
672             return PRIMARY_SUB_INITIALIZED;
673         }
674         if (mPrimarySubList.equals(prevPrimarySubList)) return PRIMARY_SUB_NO_CHANGE;
675         if (mPrimarySubList.size() > prevPrimarySubList.size()) return PRIMARY_SUB_ADDED;
676 
677         if (mPrimarySubList.size() == prevPrimarySubList.size()) {
678             // We need to differentiate PRIMARY_SUB_SWAPPED and PRIMARY_SUB_SWAPPED_IN_GROUP:
679             // For SWAPPED_IN_GROUP, we never pop up dialog to ask data sub selection again.
680             for (int subId : mPrimarySubList) {
681                 boolean swappedInSameGroup = false;
682                 for (int prevSubId : prevPrimarySubList) {
683                     if (areSubscriptionsInSameGroup(subId, prevSubId)) {
684                         swappedInSameGroup = true;
685                         break;
686                     }
687                 }
688                 if (!swappedInSameGroup) return PRIMARY_SUB_SWAPPED;
689             }
690             return PRIMARY_SUB_SWAPPED_IN_GROUP;
691         } else /* mPrimarySubList.size() < prevPrimarySubList.size() */ {
692             // We need to differentiate whether the missing subscription is removed or marked as
693             // opportunistic. Usually only one subscription may change at a time, But to be safe, if
694             // any previous primary subscription becomes inactive, we consider it
695             for (int subId : prevPrimarySubList) {
696                 if (mPrimarySubList.contains(subId)) continue;
697                 SubscriptionInfo subInfo = mSubscriptionManagerService.getSubscriptionInfo(subId);
698 
699                 if (subInfo == null || !subInfo.isActive()) {
700                     for (int currentSubId : mPrimarySubList) {
701                         if (areSubscriptionsInSameGroup(currentSubId, subId)) {
702                             return PRIMARY_SUB_REMOVED_IN_GROUP;
703                         }
704                     }
705                     return PRIMARY_SUB_REMOVED;
706                 }
707                 if (!subInfo.isOpportunistic()) {
708                     // Should never happen.
709                     loge("[updatePrimarySubListAndGetChangeType]: missing active primary "
710                             + "subId " + subId);
711                 }
712             }
713             return PRIMARY_SUB_MARKED_OPPT;
714         }
715     }
716 
sendDefaultSubConfirmedNotification(int defaultSubId)717     private void sendDefaultSubConfirmedNotification(int defaultSubId) {
718         Intent intent = new Intent();
719         intent.setAction(ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED);
720         intent.setClassName("com.android.settings",
721                 "com.android.settings.sim.SimSelectNotification");
722 
723         intent.putExtra(EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE,
724                 EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DISMISS);
725         intent.putExtra(EXTRA_SUBSCRIPTION_ID, defaultSubId);
726 
727         mContext.sendBroadcast(intent);
728     }
729 
sendSubChangeNotificationIfNeeded(int change, boolean dataSelected, boolean voiceSelected, boolean smsSelected)730     private void sendSubChangeNotificationIfNeeded(int change, boolean dataSelected,
731             boolean voiceSelected, boolean smsSelected) {
732         @TelephonyManager.DefaultSubscriptionSelectType
733         int simSelectDialogType = getSimSelectDialogType(
734                 change, dataSelected, voiceSelected, smsSelected);
735         log("sendSubChangeNotificationIfNeeded: simSelectDialogType=" + simSelectDialogType);
736         SimCombinationWarningParams simCombinationParams = getSimCombinationWarningParams(change);
737 
738         if (simSelectDialogType != EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE
739                 || simCombinationParams.mWarningType != EXTRA_SIM_COMBINATION_WARNING_TYPE_NONE) {
740             log("[sendSubChangeNotificationIfNeeded] showing dialog type "
741                     + simSelectDialogType);
742             log("[sendSubChangeNotificationIfNeeded] showing sim warning "
743                     + simCombinationParams.mWarningType);
744             Intent intent = new Intent();
745             intent.setAction(ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED);
746             intent.setClassName("com.android.settings",
747                     "com.android.settings.sim.SimSelectNotification");
748             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
749 
750             intent.putExtra(EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE, simSelectDialogType);
751             if (simSelectDialogType == EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL) {
752                 intent.putExtra(EXTRA_SUBSCRIPTION_ID, mPrimarySubList.get(0));
753             }
754 
755             intent.putExtra(EXTRA_SIM_COMBINATION_WARNING_TYPE, simCombinationParams.mWarningType);
756             if (simCombinationParams.mWarningType == EXTRA_SIM_COMBINATION_WARNING_TYPE_DUAL_CDMA) {
757                 intent.putExtra(EXTRA_SIM_COMBINATION_NAMES, simCombinationParams.mSimNames);
758             }
759             mContext.sendBroadcast(intent);
760         }
761     }
762 
getSimSelectDialogType(int change, boolean dataSelected, boolean voiceSelected, boolean smsSelected)763     private int getSimSelectDialogType(int change, boolean dataSelected,
764             boolean voiceSelected, boolean smsSelected) {
765         int dialogType = EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE;
766 
767         // Do not show preference selection dialog during SuW as there is fullscreen activity to
768         // choose preference.
769         if (Settings.Global.getInt(mContext.getContentResolver(),
770                 Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
771             return dialogType;
772         }
773         // If a primary subscription is removed and only one is left active, ask user
774         // for preferred sub selection if any default setting is not set.
775         // If another primary subscription is added or default data is not selected, ask
776         // user to select default for data as it's most important.
777         if (mPrimarySubList.size() == 1 && change == PRIMARY_SUB_REMOVED
778                 && (!dataSelected || !smsSelected || !voiceSelected)) {
779             dialogType = EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL;
780         } else if (mPrimarySubList.size() > 1 && (isUserVisibleChange(change)
781                 || (change == PRIMARY_SUB_INITIALIZED && !dataSelected))) {
782             // If change is SWAPPED_IN_GROUP or MARKED_OPPT, don't ask user again.
783             dialogType = EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA;
784         }
785 
786         return dialogType;
787     }
788 
789     private class SimCombinationWarningParams {
790         @TelephonyManager.SimCombinationWarningType
791         int mWarningType = EXTRA_SIM_COMBINATION_WARNING_TYPE_NONE;
792         String mSimNames;
793     }
794 
getSimCombinationWarningParams(int change)795     private SimCombinationWarningParams getSimCombinationWarningParams(int change) {
796         SimCombinationWarningParams params = new SimCombinationWarningParams();
797         // If it's single SIM active, no SIM combination warning is needed.
798         if (mPrimarySubList.size() <= 1) return params;
799         // If it's no primary SIM change or it's not user visible change
800         // (initialized or swapped in a group), no SIM combination warning is needed.
801         if (!isUserVisibleChange(change)) return params;
802 
803         List<String> simNames = new ArrayList<>();
804         int cdmaPhoneCount = 0;
805         for (int subId : mPrimarySubList) {
806             Phone phone = PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId));
807             // If a dual CDMA SIM combination warning is needed.
808             if (phone != null && phone.isCdmaSubscriptionAppPresent()) {
809                 cdmaPhoneCount++;
810                 String simName = null;
811                 SubscriptionInfoInternal subInfo = mSubscriptionManagerService
812                         .getSubscriptionInfoInternal(subId);
813                 if (subInfo != null) {
814                     simName = subInfo.getDisplayName();
815                 }
816                 if (TextUtils.isEmpty(simName)) {
817                     // Fall back to carrier name.
818                     simName = phone.getCarrierName();
819                 }
820                 simNames.add(simName);
821             }
822         }
823 
824         if (cdmaPhoneCount > 1) {
825             params.mWarningType = EXTRA_SIM_COMBINATION_WARNING_TYPE_DUAL_CDMA;
826             params.mSimNames = String.join(" & ", simNames);
827         }
828 
829         return params;
830     }
831 
isUserVisibleChange(int change)832     private boolean isUserVisibleChange(int change) {
833         return (change == PRIMARY_SUB_ADDED || change == PRIMARY_SUB_REMOVED
834                 || change == PRIMARY_SUB_SWAPPED);
835     }
836 
disableDataForNonDefaultNonOpportunisticSubscriptions()837     protected void disableDataForNonDefaultNonOpportunisticSubscriptions() {
838         if (!isReadyToReevaluate()) return;
839 
840         int defaultDataSub = mSubscriptionManagerService.getDefaultDataSubId();
841 
842         for (Phone phone : PhoneFactory.getPhones()) {
843             SubscriptionInfoInternal subInfo = mSubscriptionManagerService
844                     .getSubscriptionInfoInternal(phone.getSubId());
845             boolean isOpportunistic = subInfo != null && subInfo.isOpportunistic();
846             if (phone.getSubId() != defaultDataSub
847                     && SubscriptionManager.isValidSubscriptionId(phone.getSubId())
848                     && !isOpportunistic
849                     && phone.isUserDataEnabled()
850                     && !areSubscriptionsInSameGroup(defaultDataSub, phone.getSubId())) {
851                 log("setting data to false on " + phone.getSubId());
852                 phone.getDataSettingsManager().setDataEnabled(
853                         TelephonyManager.DATA_ENABLED_REASON_USER, false,
854                         mContext.getOpPackageName());
855             }
856         }
857     }
858 
areSubscriptionsInSameGroup(int subId1, int subId2)859     private boolean areSubscriptionsInSameGroup(int subId1, int subId2) {
860         if (!SubscriptionManager.isUsableSubscriptionId(subId1)
861                 || !SubscriptionManager.isUsableSubscriptionId(subId2)) return false;
862         if (subId1 == subId2) return true;
863 
864         SubscriptionInfoInternal subInfo1 =
865                 mSubscriptionManagerService.getSubscriptionInfoInternal(subId1);
866         SubscriptionInfoInternal subInfo2 =
867                 mSubscriptionManagerService.getSubscriptionInfoInternal(subId2);
868         return subInfo1 != null && subInfo2 != null
869                 && !TextUtils.isEmpty(subInfo1.getGroupUuid())
870                 && subInfo1.getGroupUuid().equals(subInfo2.getGroupUuid());
871     }
872 
873     /**
874      * Make sure MOBILE_DATA of subscriptions in the same group with the subId
875      * are synced.
876      */
setUserDataEnabledForGroup(int subId, boolean enable)877     protected void setUserDataEnabledForGroup(int subId, boolean enable) {
878         log("setUserDataEnabledForGroup subId " + subId + " enable " + enable);
879         List<SubscriptionInfo> infoList = null;
880         SubscriptionInfoInternal subInfo = mSubscriptionManagerService
881                 .getSubscriptionInfoInternal(subId);
882         if (subInfo != null && !subInfo.getGroupUuid().isEmpty()) {
883             infoList = mSubscriptionManagerService.getSubscriptionsInGroup(
884                     ParcelUuid.fromString(subInfo.getGroupUuid()), mContext.getOpPackageName(),
885                     mContext.getAttributionTag());
886         }
887 
888         if (infoList == null) return;
889 
890         for (SubscriptionInfo info : infoList) {
891             int currentSubId = info.getSubscriptionId();
892             // TODO: simplify when setUserDataEnabled becomes singleton
893             if (info.isActive()) {
894                 // For active subscription, call setUserDataEnabled through DataSettingsManager.
895                 Phone phone = PhoneFactory.getPhone(mSubscriptionManagerService
896                         .getPhoneId(currentSubId));
897                 // If enable is true and it's not opportunistic subscription, we don't enable it,
898                 // as there can't be two
899                 if (phone != null) {
900                     phone.getDataSettingsManager().setDataEnabled(
901                             TelephonyManager.DATA_ENABLED_REASON_USER, enable,
902                             mContext.getOpPackageName());
903                 }
904             } else {
905                 // For inactive subscription, directly write into global settings.
906                 GlobalSettingsHelper.setBoolean(
907                         mContext, Settings.Global.MOBILE_DATA, currentSubId, enable);
908             }
909         }
910     }
911 
912     /**
913      * Make sure DATA_ROAMING of subscriptions in the same group with the subId
914      * are synced.
915      */
setRoamingDataEnabledForGroup(int subId, boolean enable)916     private void setRoamingDataEnabledForGroup(int subId, boolean enable) {
917         SubscriptionInfoInternal subInfo = mSubscriptionManagerService
918                 .getSubscriptionInfoInternal(subId);
919         if (subInfo == null || subInfo.getGroupUuid().isEmpty()) return;
920         List<SubscriptionInfo> infoList = SubscriptionManagerService.getInstance()
921                 .getSubscriptionsInGroup(ParcelUuid.fromString(subInfo.getGroupUuid()),
922                         mContext.getOpPackageName(), mContext.getAttributionTag());
923         if (infoList == null) return;
924 
925         for (SubscriptionInfo info : infoList) {
926             // For inactive subscription, directly write into global settings.
927             GlobalSettingsHelper.setBoolean(
928                     mContext, Settings.Global.DATA_ROAMING, info.getSubscriptionId(), enable);
929         }
930     }
931 
932     private interface UpdateDefaultAction {
update(int newValue)933         void update(int newValue);
934     }
935 
936     // Returns whether the new default value is valid.
updateDefaultValue(List<Integer> primarySubList, int oldValue, UpdateDefaultAction action)937     private boolean updateDefaultValue(List<Integer> primarySubList, int oldValue,
938             UpdateDefaultAction action) {
939         return updateDefaultValue(primarySubList, oldValue, action, true);
940     }
941 
updateDefaultValue(List<Integer> primarySubList, int oldValue, UpdateDefaultAction action, boolean allowInvalidSubId)942     private boolean updateDefaultValue(List<Integer> primarySubList, int oldValue,
943             UpdateDefaultAction action, boolean allowInvalidSubId) {
944         int newValue = INVALID_SUBSCRIPTION_ID;
945 
946         if (primarySubList.size() > 0) {
947             for (int subId : primarySubList) {
948                 if (DBG) log("[updateDefaultValue] Record.id: " + subId);
949                 // 1) If the old subId is still active, or there's another active primary
950                 // subscription that is in the same group, that should become the new default
951                 // subscription.
952                 // 2) If the old subId is INVALID_SUBSCRIPTION_ID and allowInvalidSubId is false,
953                 // first active subscription is used for new default always.
954                 if (areSubscriptionsInSameGroup(subId, oldValue)
955                         || (!allowInvalidSubId && oldValue == INVALID_SUBSCRIPTION_ID)) {
956                     newValue = subId;
957                     log("[updateDefaultValue] updates to subId=" + newValue);
958                     break;
959                 }
960             }
961         }
962 
963         if (oldValue != newValue) {
964             if (DBG) log("[updateDefaultValue: subId] from " + oldValue + " to " + newValue);
965             action.update(newValue);
966         }
967 
968         return SubscriptionManager.isValidSubscriptionId(newValue);
969     }
970 
971     // When a primary and its grouped opportunistic subscriptions were active, and the primary
972     // subscription gets deactivated or removed, we need to automatically disable the grouped
973     // opportunistic subscription, which will be marked isGroupDisabled as true by SubController.
deactivateGroupedOpportunisticSubscriptionIfNeeded()974     private void deactivateGroupedOpportunisticSubscriptionIfNeeded() {
975         List<SubscriptionInfo> opptSubList = mSubscriptionManagerService.getAllSubInfoList(
976                 mContext.getOpPackageName(), mContext.getAttributionTag()).stream()
977                 .filter(SubscriptionInfo::isOpportunistic)
978                 .collect(Collectors.toList());
979 
980         if (ArrayUtils.isEmpty(opptSubList)) return;
981 
982         for (SubscriptionInfo info : opptSubList) {
983             if (info.isGroupDisabled() && info.isActive()) {
984                 log("deactivateGroupedOpportunisticSubscriptionIfNeeded: "
985                         + "Deactivating grouped opportunistic subscription "
986                         + info.getSubscriptionId());
987                 deactivateSubscription(info);
988             }
989         }
990     }
991 
deactivateSubscription(SubscriptionInfo info)992     private void deactivateSubscription(SubscriptionInfo info) {
993         // TODO: b/133379187 have a way to deactivate pSIM.
994         if (info.isEmbedded()) {
995             log("[deactivateSubscription] eSIM profile " + info.getSubscriptionId());
996             EuiccManager euiccManager = (EuiccManager)
997                     mContext.getSystemService(Context.EUICC_SERVICE);
998             euiccManager.switchToSubscription(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
999                     info.getPortIndex(), PendingIntent.getService(
1000                             mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE));
1001         }
1002     }
1003 
1004     // Voice/Data/SMS preferences would be auto selected without any user
1005     // confirmation in following scenarios,
1006     // 1. When device powered-up with only one SIM Inserted or while two SIM cards
1007     // present if one SIM is removed(or turned OFF) the reaiming SIM would be
1008     // selected as preferred voice/data/sms SIM.
1009     // 2. When device powered-up with two SIM cards or if two SIM cards
1010     // present on device with new SIM insert(or SIM turn ON) the first inserted SIM
1011     // would be selected as preferred voice/data/sms SIM.
updateUserPreferences(List<Integer> primarySubList, boolean dataSelected, boolean voiceSelected, boolean smsSelected)1012     private void updateUserPreferences(List<Integer> primarySubList, boolean dataSelected,
1013             boolean voiceSelected, boolean smsSelected) {
1014         // In Single SIM case or if there are no activated subs available, no need to update.
1015         // EXIT.
1016         if ((primarySubList.isEmpty()) || (mSubscriptionManagerService
1017                 .getActiveSubInfoCountMax() == 1)) {
1018             return;
1019         }
1020 
1021         if (!isRadioAvailableOnAllSubs()) {
1022             log("Radio is in Invalid state, Ignore Updating User Preference!!!");
1023             return;
1024         }
1025         final int defaultDataSubId = mSubscriptionManagerService.getDefaultDataSubId();
1026 
1027         if (DBG) {
1028             log("updateUserPreferences:  dds = " + defaultDataSubId + " voice = "
1029                     + mSubscriptionManagerService.getDefaultVoiceSubId()
1030                     + " sms = " + mSubscriptionManagerService.getDefaultSmsSubId());
1031         }
1032 
1033         int autoDefaultSubId = primarySubList.get(0);
1034 
1035         if ((primarySubList.size() == 1) && !smsSelected) {
1036             mSubscriptionManagerService.setDefaultSmsSubId(autoDefaultSubId);
1037         }
1038 
1039         if ((primarySubList.size() == 1) && !voiceSelected) {
1040             mSubscriptionManagerService.setDefaultVoiceSubId(autoDefaultSubId);
1041         }
1042 
1043         int userPrefDataSubId = getUserPrefDataSubIdFromDB();
1044 
1045         log("User pref subId = " + userPrefDataSubId + " current dds " + defaultDataSubId
1046                 + " next active subId " + autoDefaultSubId);
1047 
1048         // If earlier user selected DDS is now available, set that as DDS subId.
1049         if (primarySubList.contains(userPrefDataSubId)
1050                 && SubscriptionManager.isValidSubscriptionId(userPrefDataSubId)
1051                 && (defaultDataSubId != userPrefDataSubId)) {
1052             mSubscriptionManagerService.setDefaultDataSubId(userPrefDataSubId);
1053         } else if (!dataSelected) {
1054             mSubscriptionManagerService.setDefaultDataSubId(autoDefaultSubId);
1055         }
1056 
1057         if (DBG) {
1058             log("updateUserPreferences: after dds = "
1059                     + mSubscriptionManagerService.getDefaultDataSubId() + " voice = "
1060                     + mSubscriptionManagerService.getDefaultVoiceSubId() + " sms = "
1061                     + mSubscriptionManagerService.getDefaultSmsSubId());
1062         }
1063     }
1064 
getUserPrefDataSubIdFromDB()1065     private int getUserPrefDataSubIdFromDB() {
1066         return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
1067                 SETTING_USER_PREF_DATA_SUB, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
1068     }
1069 
isRadioAvailableOnAllSubs()1070     private boolean isRadioAvailableOnAllSubs() {
1071         for (int phoneId = 0; phoneId < mActiveModemCount; phoneId++) {
1072             Phone phone = PhoneFactory.getPhone(phoneId);
1073             if (phone != null
1074                     && (phone.mCi.getRadioState() == TelephonyManager.RADIO_POWER_UNAVAILABLE
1075                     || phone.isShuttingDown())) {
1076                 return false;
1077             }
1078         }
1079         return true;
1080     }
1081 
registerDataSettingsControllerCallbackAsNeeded()1082     private void registerDataSettingsControllerCallbackAsNeeded() {
1083         // Only register callbacks for new phone instance as PhoneFactory does not remove
1084         // existing phone instance.
1085         Phone[] phones = PhoneFactory.getPhones();
1086         for (int i = mCallbacksCount; i < phones.length; i++) {
1087             phones[i].getDataSettingsManager().registerCallback(
1088                     new DataSettingsControllerCallback(phones[i], this::post));
1089         }
1090         mCallbacksCount = phones.length;
1091     }
1092 
log(String msg)1093     private void log(String msg) {
1094         Log.d(LOG_TAG, msg);
1095     }
1096 
loge(String msg)1097     private void loge(String msg) {
1098         Log.e(LOG_TAG, msg);
1099     }
1100 }
1101