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