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