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