Merge "Fix disableGroup" into main
diff --git a/flags/Android.bp b/flags/Android.bp
index 3c0deee..8f363b6 100644
--- a/flags/Android.bp
+++ b/flags/Android.bp
@@ -22,16 +22,17 @@
     name: "telephony_flags",
     package: "com.android.internal.telephony.flags",
     srcs: [
-      "data.aconfig",
-      "domainselection.aconfig",
-      "ims.aconfig",
-      "messaging.aconfig",
-      "misc.aconfig",
-      "network.aconfig",
-      "subscription.aconfig",
-      "uicc.aconfig",
-      "satellite.aconfig",
-      "iwlan.aconfig",
-      "telephony.aconfig",
+        "calling.aconfig",
+        "data.aconfig",
+        "domainselection.aconfig",
+        "ims.aconfig",
+        "messaging.aconfig",
+        "misc.aconfig",
+        "network.aconfig",
+        "subscription.aconfig",
+        "uicc.aconfig",
+        "satellite.aconfig",
+        "iwlan.aconfig",
+        "telephony.aconfig",
     ],
 }
diff --git a/flags/calling.aconfig b/flags/calling.aconfig
new file mode 100644
index 0000000..82f932b
--- /dev/null
+++ b/flags/calling.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.internal.telephony.flags"
+
+flag {
+  name: "simultaneous_calling_indications"
+  namespace: "telephony"
+  description: "APIs that are used to notify simultaneous calling changes to other applications."
+  bug: "297446980"
+}
\ No newline at end of file
diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index c035329..e81d0f1 100644
--- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -45,6 +45,7 @@
 import com.android.telephony.Rlog;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * broadcast intents
@@ -301,6 +302,11 @@
     }
 
     @Override
+    public void notifySimultaneousCellularCallingSubscriptionsChanged(Set<Integer> subIds) {
+        mTelephonyRegistryMgr.notifySimultaneousCellularCallingSubscriptionsChanged(subIds);
+    }
+
+    @Override
     public void notifyCallbackModeStarted(Phone sender, @EmergencyCallbackModeType int type) {
         mTelephonyRegistryMgr.notifyCallBackModeStarted(sender.getPhoneId(),
                 sender.getSubId(), type);
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 654faaa..28e8ff1 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -5373,7 +5373,11 @@
         }
         boolean prefEnabled = getNullCipherNotificationsPreferenceEnabled();
 
-        // TODO(b/316592273): Enable / disable in NullCipherNotifier once the class is available.
+        if (prefEnabled) {
+            mNullCipherNotifier.enable();
+        } else {
+            mNullCipherNotifier.disable();
+        }
 
         mCi.setSecurityAlgorithmsUpdatedEnabled(prefEnabled,
                 obtainMessage(EVENT_SET_SECURITY_ALGORITHMS_UPDATED_ENABLED_DONE));
diff --git a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
index 26aeaca..1e0aa3a 100644
--- a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
+++ b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
@@ -87,6 +87,7 @@
     /** Feature flags */
     @NonNull
     private final FeatureFlags mFeatureFlags;
+    private final DefaultPhoneNotifier mNotifier;
     /**
      * True if 'Virtual DSDA' i.e., in-call IMS connectivity on both subs with only single logical
      * modem, is enabled.
@@ -128,6 +129,7 @@
         mPhoneStatusMap = new HashMap<>();
         mVirtualDsdaEnabled = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_TELEPHONY, KEY_ENABLE_VIRTUAL_DSDA, false);
+        mNotifier = new DefaultPhoneNotifier(mContext, mFeatureFlags);
         DeviceConfig.addOnPropertiesChangedListener(
                 DeviceConfig.NAMESPACE_TELEPHONY, Runnable::run,
                 properties -> {
@@ -294,6 +296,11 @@
                     } else {
                         log(msg.what + " failure. Not getting logical slots that support "
                                 + "simultaneous calling." + ar.exception);
+                        mSlotsSupportingSimultaneousCellularCalls.clear();
+                    }
+                    if (mFeatureFlags.simultaneousCallingIndications()) {
+                        mNotifier.notifySimultaneousCellularCallingSubscriptionsChanged(
+                                mSlotsSupportingSimultaneousCellularCalls);
                     }
                     break;
                 default:
@@ -449,9 +456,7 @@
     }
 
     private void notifyCapabilityChanged() {
-        PhoneNotifier notifier = new DefaultPhoneNotifier(mContext, mFeatureFlags);
-
-        notifier.notifyPhoneCapabilityChanged(mStaticCapability);
+        mNotifier.notifyPhoneCapabilityChanged(mStaticCapability);
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/PhoneNotifier.java b/src/java/com/android/internal/telephony/PhoneNotifier.java
index 20d6702..cb6b199 100644
--- a/src/java/com/android/internal/telephony/PhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/PhoneNotifier.java
@@ -39,6 +39,7 @@
 import android.telephony.ims.MediaQualityStatus;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * {@hide}
@@ -149,4 +150,7 @@
     /** Notify callback mode stopped. */
     void notifyCallbackModeStopped(Phone sender, @EmergencyCallbackModeType int type,
             @EmergencyCallbackModeStopReason int reason);
+
+    /** Notify that simultaneous cellular calling subscriptions have changed */
+    void notifySimultaneousCellularCallingSubscriptionsChanged(Set<Integer> subIds);
 }
diff --git a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java
index fb9d32f..893509c 100644
--- a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java
+++ b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java
@@ -372,6 +372,7 @@
                                     0) != 0) {
                         mIsAirPlaneModeEnableDuringDataStall = true;
                     }
+                    setRecoveryAction(mLastAction);
                 }
                 break;
             case EVENT_CONTENT_DSRM_ENABLED_ACTIONS_CHANGED:
@@ -527,6 +528,7 @@
         // during data stalled.
         if (mDataStalled && enabled) {
             mMobileDataChangedToEnabledDuringDataStall = true;
+            setRecoveryAction(mLastAction);
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
index 2c84f5e..8dc8098 100644
--- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
+++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
@@ -1521,18 +1521,22 @@
      */
     private void validate(int subId, boolean needValidation, int switchReason,
             @Nullable ISetOpportunisticDataCallback callback) {
-        logl("Validate subId " + subId + " due to " + switchReasonToString(switchReason)
-                + " needValidation=" + needValidation);
         int subIdToValidate = (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)
                 ? mPrimaryDataSubId : subId;
+        logl("Validate subId " + subId + " due to " + switchReasonToString(switchReason)
+                + " needValidation=" + needValidation + " subIdToValidate=" + subIdToValidate
+                + " mAutoSelectedDataSubId=" + mAutoSelectedDataSubId
+                + " mPreferredDataSubId=" + mPreferredDataSubId.get());
         if (!isActiveSubId(subIdToValidate)) {
             logl("Can't switch data to inactive subId " + subIdToValidate);
             if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
                 // the default data sub is not selected yet, store the intent of switching to
                 // default subId once it becomes available.
                 mAutoSelectedDataSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+                sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_SUCCESS);
+            } else {
+                sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION);
             }
-            sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION);
             return;
         }
 
diff --git a/src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java b/src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java
index 26100a8..4d294f4 100644
--- a/src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java
+++ b/src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java
@@ -40,7 +40,7 @@
     public static void resolveNtnCapability(
             @NonNull NetworkRegistrationInfo networkRegistrationInfo, int subId) {
         SatelliteController satelliteController = SatelliteController.getInstance();
-        List<String> satellitePlmnList = satelliteController.getSatellitePlmnList(subId);
+        List<String> satellitePlmnList = satelliteController.getAllSatellitePlmnsForCarrier(subId);
         String registeredPlmn = networkRegistrationInfo.getRegisteredPlmn();
         for (String satellitePlmn : satellitePlmnList) {
             if (TextUtils.equals(satellitePlmn, registeredPlmn)) {
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index c691737..a5a1f82 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -2297,9 +2297,9 @@
      * @return The list of satellite PLMNs used for connecting to satellite networks.
      */
     @NonNull
-    public List<String> getSatellitePlmnList(int subId) {
+    public List<String> getAllSatellitePlmnsForCarrier(int subId) {
         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
-            logd("getSatellitePlmnList: carrierEnabledSatelliteFlag is disabled");
+            logd("getAllSatellitePlmnsForCarrier: carrierEnabledSatelliteFlag is disabled");
             return new ArrayList<>();
         }
         synchronized (mSupportedSatelliteServicesLock) {
diff --git a/src/java/com/android/internal/telephony/security/NullCipherNotifier.java b/src/java/com/android/internal/telephony/security/NullCipherNotifier.java
index cef2bb9..0ab8299 100644
--- a/src/java/com/android/internal/telephony/security/NullCipherNotifier.java
+++ b/src/java/com/android/internal/telephony/security/NullCipherNotifier.java
@@ -34,6 +34,8 @@
     private static final String TAG = "NullCipherNotifier";
     private static NullCipherNotifier sInstance;
 
+    private boolean mEnabled = false;
+
     /**
      * Gets a singleton NullCipherNotifier.
      */
@@ -55,4 +57,28 @@
         // from here.
         Rlog.d(TAG, "Security algorithm update: phoneId = " + phoneId + " " + update);
     }
+
+    /**
+     * Enables null cipher notification; {@code onSecurityAlgorithmUpdate} will start handling
+     * security algorithm updates and send notifications to the user when required.
+     */
+    public void enable() {
+        Rlog.d(TAG, "enabled");
+        mEnabled = true;
+    }
+
+    /**
+     * Clear all internal state and prevent further notifications until re-enabled. This can be
+     * used in response to a user disabling the feature for null cipher notifications. If
+     * {@code onSecurityAlgorithmUpdate} is called while in a disabled state, security algorithm
+     * updates will be dropped.
+     */
+    public void disable() {
+        Rlog.d(TAG, "disabled");
+        mEnabled = false;
+    }
+
+    public boolean isEnabled() {
+        return mEnabled;
+    }
 }
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java
index 0756650..bbe88a8 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java
@@ -2062,7 +2062,7 @@
      */
     public void setGroupDisabled(int subId, boolean isGroupDisabled) {
         // group disabled does not have a corresponding SimInfo column. So we only update the cache.
-
+        boolean isChanged = false;
         // Grab the write lock so no other threads can read or write the cache.
         mReadWriteLock.writeLock().lock();
         try {
@@ -2071,12 +2071,18 @@
                 throw new IllegalArgumentException("setGroupDisabled: Subscription doesn't exist. "
                         + "subId=" + subId);
             }
+            isChanged = subInfoCache.isGroupDisabled() != isGroupDisabled;
             mAllSubscriptionInfoInternalCache.put(subId,
                     new SubscriptionInfoInternal.Builder(subInfoCache)
                             .setGroupDisabled(isGroupDisabled).build());
         } finally {
             mReadWriteLock.writeLock().unlock();
         }
+
+        if (isChanged) {
+            log("setGroupDisabled value changed, firing the callback");
+            mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId));
+        }
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
index dbbd6b0..02d48b1 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
@@ -2139,6 +2139,8 @@
      */
     @Override
     public void requestEmbeddedSubscriptionInfoListRefresh(int cardId) {
+        enforcePermissions("requestEmbeddedSubscriptionInfoListRefresh",
+                Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS);
         updateEmbeddedSubscriptions(List.of(cardId), null);
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
index 5c0cd05..d27ab98 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
@@ -33,6 +33,7 @@
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsCallProfile;
+import android.util.ArraySet;
 
 import androidx.test.filters.SmallTest;
 
@@ -380,4 +381,15 @@
         assertEquals(3, cellLocationCapture.getValue().asCellLocation().getCid());
         assertEquals(-1, cellLocationCapture.getValue().asCellLocation().getPsc());
     }
+
+    @Test
+    @SmallTest
+    public void testSimultaneousCellularCallingSubscriptionsChanged() {
+        ArraySet<Integer> subs = new ArraySet<>(2);
+        subs.add(0);
+        subs.add(1);
+        mDefaultPhoneNotifierUT.notifySimultaneousCellularCallingSubscriptionsChanged(subs);
+        verify(mTelephonyRegistryManager).notifySimultaneousCellularCallingSubscriptionsChanged(
+                eq(subs));
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
index 3962565..a4f4a9c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
@@ -3019,6 +3019,31 @@
         assertTrue(phoneUT.isNullCipherNotificationSupported());
     }
 
+    @Test
+    public void testNullCipherNotification_preferenceEnabled() {
+        when(mFeatureFlags.enableModemCipherTransparency()).thenReturn(true);
+        GsmCdmaPhone phoneUT = makeNewPhoneUT();
+
+        setNullCipherNotificationPreferenceEnabled(true);
+        phoneUT.handleNullCipherNotificationPreferenceChanged();
+
+        verify(mNullCipherNotifier, times(1)).enable();
+        verify(mMockCi, times(1)).setSecurityAlgorithmsUpdatedEnabled(eq(true),
+                any(Message.class));
+    }
+
+    @Test
+    public void testNullCipherNotification_preferenceDisabled() {
+        when(mFeatureFlags.enableModemCipherTransparency()).thenReturn(true);
+        GsmCdmaPhone phoneUT = makeNewPhoneUT();
+
+        setNullCipherNotificationPreferenceEnabled(false);
+        phoneUT.handleNullCipherNotificationPreferenceChanged();
+
+        verify(mNullCipherNotifier, times(1)).disable();
+        verify(mMockCi, times(1)).setSecurityAlgorithmsUpdatedEnabled(eq(false),
+                any(Message.class));
+    }
 
     private void sendRadioAvailableToPhone(GsmCdmaPhone phone) {
         phone.sendMessage(phone.obtainMessage(EVENT_RADIO_AVAILABLE,
@@ -3037,6 +3062,14 @@
         processAllMessages();
     }
 
+    private void setNullCipherNotificationPreferenceEnabled(boolean enabled) {
+        SharedPreferences sharedPreferences =
+                PreferenceManager.getDefaultSharedPreferences(mContext);
+        SharedPreferences.Editor editor = sharedPreferences.edit();
+        editor.putBoolean(Phone.PREF_NULL_CIPHER_NOTIFICATIONS_ENABLED, enabled);
+        editor.apply();
+    }
+
     private GsmCdmaPhone makeNewPhoneUT() {
         return new GsmCdmaPhone(
                 mContext,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java
index c516542..90105e3 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java
@@ -40,6 +40,7 @@
 import android.os.Message;
 import android.telephony.PhoneCapability;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyRegistryManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
@@ -54,6 +55,7 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 
+import java.util.Collections;
 import java.util.HashSet;
 
 @RunWith(AndroidTestingRunner.class)
@@ -69,6 +71,7 @@
     private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 1;
     PhoneConfigurationManager mPcm;
     private FeatureFlags mFeatureFlags;
+    private TelephonyRegistryManager mMockRegistryManager;
 
     @Before
     public void setUp() throws Exception {
@@ -83,6 +86,7 @@
         mCT.mCi = mMockCi0;
         mPhone1.mCi = mMockCi1;
         doReturn(RIL.RADIO_HAL_VERSION_2_1).when(mMockRadioConfigProxy).getVersion();
+        mMockRegistryManager = mContext.getSystemService(TelephonyRegistryManager.class);
     }
 
     @After
@@ -169,6 +173,7 @@
     @Test
     @SmallTest
     public void testUpdateSimultaneousCallingSupport() throws Exception {
+        doReturn(false).when(mFeatureFlags).simultaneousCallingIndications();
         init(2);
         mPcm.updateSimultaneousCallingSupport();
 
@@ -188,6 +193,7 @@
     @Test
     @SmallTest
     public void testUpdateSimultaneousCallingSupport_invalidResponse_shouldFail() throws Exception {
+        doReturn(false).when(mFeatureFlags).simultaneousCallingIndications();
         init(2);
         mPcm.updateSimultaneousCallingSupport();
 
@@ -207,6 +213,46 @@
 
     @Test
     @SmallTest
+    public void testUpdateSimultaneousCallingSupportNotifications() throws Exception {
+        // retry simultaneous calling tests, but with notifications enabled this time
+        doReturn(true).when(mFeatureFlags).simultaneousCallingIndications();
+        init(2);
+
+        // Simultaneous calling enabled
+        mPcm.updateSimultaneousCallingSupport();
+        int[] enabledLogicalSlots = {0, 1};
+        ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
+        verify(mMockRadioConfig).updateSimultaneousCallingSupport(captor.capture());
+        Message msg = captor.getValue();
+        AsyncResult.forMessage(msg, enabledLogicalSlots, null);
+        msg.sendToTarget();
+        processAllMessages();
+
+        HashSet<Integer> expectedSlots = new HashSet<>();
+        for (int i : enabledLogicalSlots) {
+            expectedSlots.add(i);
+        }
+        assertEquals(expectedSlots, mPcm.getSlotsSupportingSimultaneousCellularCalls());
+        verify(mMockRegistryManager).notifySimultaneousCellularCallingSubscriptionsChanged(
+                eq(expectedSlots));
+
+        // Simultaneous Calling Disabled
+        mPcm.updateSimultaneousCallingSupport();
+        int[] disabled = {};
+        captor = ArgumentCaptor.forClass(Message.class);
+        verify(mMockRadioConfig, times(2)).updateSimultaneousCallingSupport(captor.capture());
+        msg = captor.getAllValues().get(1);
+        AsyncResult.forMessage(msg, disabled, null);
+        msg.sendToTarget();
+        processAllMessages();
+
+        assertEquals(Collections.emptySet(), mPcm.getSlotsSupportingSimultaneousCellularCalls());
+        verify(mMockRegistryManager, times(2))
+                .notifySimultaneousCellularCallingSubscriptionsChanged(eq(Collections.emptySet()));
+    }
+
+    @Test
+    @SmallTest
     public void testSwitchMultiSimConfig_notDsdsCapable_shouldFail() throws Exception {
         init(1);
         assertEquals(PhoneCapability.DEFAULT_SSSS_CAPABILITY, mPcm.getStaticPhoneCapability());
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
index d920521..4fa42c9 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
@@ -260,7 +260,8 @@
         mSatelliteController = Mockito.mock(SatelliteController.class);
         replaceInstance(SatelliteController.class, "sInstance", null,
                 mSatelliteController);
-        doReturn(new ArrayList<>()).when(mSatelliteController).getSatellitePlmnList(anyInt());
+        doReturn(new ArrayList<>()).when(mSatelliteController).getAllSatellitePlmnsForCarrier(
+                anyInt());
 
         mContextFixture.putResource(R.string.kg_text_message_separator, " \u2014 ");
 
@@ -3386,7 +3387,8 @@
         CellIdentityGsm cellIdentity =
                 new CellIdentityGsm(0, 1, 900, 5, "101", "23", "test", "tst",
                         Collections.emptyList());
-        doReturn(Arrays.asList("10123")).when(mSatelliteController).getSatellitePlmnList(anyInt());
+        doReturn(Arrays.asList("10123")).when(mSatelliteController).getAllSatellitePlmnsForCarrier(
+                anyInt());
         doReturn(satelliteSupportedServiceList).when(mSatelliteController)
                 .getSupportedSatelliteServices(sst.mSubId, "10123");
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
index 777e851..6050b18 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
@@ -69,6 +69,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.SparseArray;
 
 import androidx.annotation.NonNull;
@@ -115,6 +116,7 @@
     private BarringInfo mBarringInfo = null;
     private CellIdentity mCellIdentityForRegiFail;
     private int mRegistrationFailReason;
+    private Set<Integer> mSimultaneousCallingSubscriptions;
 
     // All events contribute to TelephonyRegistry#isPhoneStatePermissionRequired
     private static final Set<Integer> READ_PHONE_STATE_EVENTS;
@@ -160,6 +162,8 @@
                 TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED);
         READ_PRIVILEGED_PHONE_STATE_EVENTS.add(
                 TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED);
+        READ_PRIVILEGED_PHONE_STATE_EVENTS.add(
+                TelephonyCallback.EVENT_SIMULTANEOUS_CELLULAR_CALLING_SUBSCRIPTIONS_CHANGED);
     }
 
     // All events contribute to TelephonyRegistry#isActiveEmergencySessionPermissionRequired
@@ -187,7 +191,8 @@
             TelephonyCallback.CellInfoListener,
             TelephonyCallback.BarringInfoListener,
             TelephonyCallback.RegistrationFailedListener,
-            TelephonyCallback.DataActivityListener {
+            TelephonyCallback.DataActivityListener,
+            TelephonyCallback.SimultaneousCellularCallingSupportListener {
         // This class isn't mockable to get invocation counts because the IBinder is null and
         // crashes the TelephonyRegistry. Make a cheesy verify(times()) alternative.
         public AtomicInteger invocationCount = new AtomicInteger(0);
@@ -275,6 +280,13 @@
             invocationCount.incrementAndGet();
             mDataActivity = direction;
         }
+
+        @Override
+        public void onSimultaneousCellularCallingSubscriptionsChanged(
+                @NonNull Set<Integer> simultaneousCallingSubscriptionIds) {
+            invocationCount.incrementAndGet();
+            mSimultaneousCallingSubscriptions = simultaneousCallingSubscriptionIds;
+        }
     }
 
     private void addTelephonyRegistryService() {
@@ -1531,4 +1543,23 @@
         processAllMessages();
         assertEquals(TelephonyManager.DATA_ACTIVITY_OUT, mDataActivity);
     }
+
+    @Test
+    public void testSimultaneousCellularCallingSubscriptionsChanged() {
+        final int subId = INVALID_SUBSCRIPTION_ID;
+        int[] events = {TelephonyCallback
+                .EVENT_SIMULTANEOUS_CELLULAR_CALLING_SUBSCRIPTIONS_CHANGED};
+
+        int[] subIds = {0, 1, 2};
+        Set<Integer> subIdSet = new ArraySet<>(3);
+        for (Integer s : subIds) {
+            subIdSet.add(s);
+        }
+        mTelephonyRegistry.listenWithEventList(false, false, subId, mContext.getOpPackageName(),
+                mContext.getAttributionTag(), mTelephonyCallback.callback, events, true);
+
+        mTelephonyRegistry.notifySimultaneousCellularCallingSubscriptionsChanged(subIds);
+        processAllMessages();
+        assertEquals(subIdSet, mSimultaneousCallingSubscriptions);
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java
index 28c6cd6..e508e5b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java
@@ -43,6 +43,7 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback;
+import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback;
 import com.android.internal.telephony.data.DataStallRecoveryManager.DataStallRecoveryManagerCallback;
 
 import org.junit.After;
@@ -145,6 +146,17 @@
         dataNetworkControllerCallback.onInternetDataNetworkValidationStatusChanged(status);
     }
 
+    private void sendDataEabledCallback(boolean isEnabled) {
+        ArgumentCaptor<DataSettingsManagerCallback> dataSettingsManagerCallbackCaptor =
+                ArgumentCaptor.forClass(DataSettingsManagerCallback.class);
+        verify(mDataSettingsManager).registerCallback(dataSettingsManagerCallbackCaptor.capture());
+
+        // Data enabled
+        doReturn(isEnabled).when(mDataSettingsManager).isDataEnabled();
+        dataSettingsManagerCallbackCaptor.getValue().onDataEnabledChanged(isEnabled,
+                TelephonyManager.DATA_ENABLED_REASON_USER, "");
+    }
+
     private void sendOnInternetDataNetworkCallback(boolean isConnected) {
         ArgumentCaptor<DataNetworkControllerCallback> dataNetworkControllerCallbackCaptor =
                 ArgumentCaptor.forClass(DataNetworkControllerCallback.class);
@@ -257,7 +269,8 @@
         moveTimeForward(15000);
         processAllMessages();
 
-        assertThat(mDataStallRecoveryManager.getRecoveryAction()).isEqualTo(3);
+        // should not change the recovery action due to there is an active call.
+        assertThat(mDataStallRecoveryManager.getRecoveryAction()).isEqualTo(1);
     }
 
     @Test
@@ -510,4 +523,59 @@
         // Check if predict waiting millis is 0
         assertThat(field.get(mDataStallRecoveryManager)).isEqualTo(0L);
     }
+
+    @Test
+    public void testRecoveryActionAfterDataEnabled() throws Exception {
+        sendDataEabledCallback(true);
+        sendOnInternetDataNetworkCallback(true);
+        sendValidationStatusCallback(NetworkAgent.VALIDATION_STATUS_VALID);
+        mDataStallRecoveryManager.setRecoveryAction(0);
+        doReturn(PhoneConstants.State.IDLE).when(mPhone).getState();
+        doReturn(3).when(mSignalStrength).getLevel();
+        doReturn(mSignalStrength).when(mPhone).getSignalStrength();
+        logd("Sending validation failed callback");
+
+        assertThat(mDataStallRecoveryManager.getRecoveryAction()).isEqualTo(0);
+        sendValidationStatusCallback(NetworkAgent.VALIDATION_STATUS_NOT_VALID);
+        processAllMessages();
+        moveTimeForward(101);
+        assertThat(mDataStallRecoveryManager.getRecoveryAction()).isEqualTo(1);
+
+        // test mobile data off/on
+        sendDataEabledCallback(false);
+        sendDataEabledCallback(true);
+
+        // recovery action will jump to next action if user doing the mobile data off/on.
+        assertThat(mDataStallRecoveryManager.getRecoveryAction()).isEqualTo(3);
+    }
+
+    @Test
+    public void testJumpToRecoveryActionRadioRestart() throws Exception {
+        sendDataEabledCallback(true);
+        sendOnInternetDataNetworkCallback(true);
+        sendValidationStatusCallback(NetworkAgent.VALIDATION_STATUS_VALID);
+        mDataStallRecoveryManager.setRecoveryAction(0);
+
+        doReturn(PhoneConstants.State.IDLE).when(mPhone).getState();
+        doReturn(3).when(mSignalStrength).getLevel();
+        doReturn(mSignalStrength).when(mPhone).getSignalStrength();
+        doReturn(TelephonyManager.RADIO_POWER_ON).when(mPhone).getRadioPowerState();
+        assertThat(mDataStallRecoveryManager.getRecoveryAction()).isEqualTo(0);
+
+        sendValidationStatusCallback(NetworkAgent.VALIDATION_STATUS_NOT_VALID);
+        moveTimeForward(200);
+        processAllMessages();
+        moveTimeForward(200);
+        mDataStallRecoveryManager.sendMessageDelayed(
+                mDataStallRecoveryManager.obtainMessage(3), 1000);
+        processAllMessages();
+        sendValidationStatusCallback(NetworkAgent.VALIDATION_STATUS_NOT_VALID);
+        moveTimeForward(200);
+        sendValidationStatusCallback(NetworkAgent.VALIDATION_STATUS_NOT_VALID);
+        processAllMessages();
+        moveTimeForward(200);
+
+        // recovery action will jump to modem reset action if user doing the radio restart.
+        assertThat(mDataStallRecoveryManager.getRecoveryAction()).isEqualTo(4);
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java
index 60aac0d..5d5ef64 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java
@@ -1408,13 +1408,22 @@
         // Switch to primary before a primary is selected/inactive.
         setDefaultDataSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
         mPhoneSwitcherUT.trySetOpportunisticDataSubscription(
-                SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false, mSetOpptDataCallback1);
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID, false, mSetOpptDataCallback1);
         processAllMessages();
 
         assertEquals(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                 mPhoneSwitcherUT.getAutoSelectedDataSubId());
         verify(mSetOpptDataCallback1).onComplete(SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION);
 
+        // Verify that the switch to default sub is successful
+        mPhoneSwitcherUT.trySetOpportunisticDataSubscription(
+                SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false, mSetOpptDataCallback1);
+        processAllMessages();
+
+        assertEquals(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                mPhoneSwitcherUT.getAutoSelectedDataSubId());
+        verify(mSetOpptDataCallback1).onComplete(SET_OPPORTUNISTIC_SUB_SUCCESS);
+
         // once the primary is selected, it becomes the active sub.
         setDefaultDataSubId(2);
         assertEquals(2, mPhoneSwitcherUT.getActiveDataSubId());
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/NtnCapabilityResolverTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/NtnCapabilityResolverTest.java
index 0944c6c..5ee7e8f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/NtnCapabilityResolverTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/NtnCapabilityResolverTest.java
@@ -76,7 +76,7 @@
         replaceInstance(SatelliteController.class, "sInstance", null,
                 mMockSatelliteController);
         doReturn(Arrays.asList(SATELLITE_PLMN_ARRAY))
-                .when(mMockSatelliteController).getSatellitePlmnList(anyInt());
+                .when(mMockSatelliteController).getAllSatellitePlmnsForCarrier(anyInt());
         doReturn(mSatelliteSupportedServiceList).when(mMockSatelliteController)
                 .getSupportedSatelliteServices(SUB_ID, SATELLITE_PLMN);
     }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
index 685578c..dedc906 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
@@ -1587,7 +1587,8 @@
     @Test
     public void testSupportedSatelliteServices() {
         when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(false);
-        List<String> satellitePlmnList = mSatelliteControllerUT.getSatellitePlmnList(SUB_ID);
+        List<String> satellitePlmnList = mSatelliteControllerUT.getAllSatellitePlmnsForCarrier(
+                SUB_ID);
         assertEquals(EMPTY_STRING_ARRAY.length, satellitePlmnList.size());
         List<Integer> supportedSatelliteServices =
                 mSatelliteControllerUT.getSupportedSatelliteServices(SUB_ID, "00101");
@@ -1610,7 +1611,7 @@
         TestSatelliteController testSatelliteController =
                 new TestSatelliteController(mContext, Looper.myLooper(), mFeatureFlags);
 
-        satellitePlmnList = testSatelliteController.getSatellitePlmnList(SUB_ID);
+        satellitePlmnList = testSatelliteController.getAllSatellitePlmnsForCarrier(SUB_ID);
         assertTrue(satellitePlmnList.isEmpty());
         supportedSatelliteServices =
                 testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00101");
@@ -1642,7 +1643,7 @@
         }
         processAllMessages();
 
-        satellitePlmnList = testSatelliteController.getSatellitePlmnList(SUB_ID);
+        satellitePlmnList = testSatelliteController.getAllSatellitePlmnsForCarrier(SUB_ID);
         assertTrue(Arrays.equals(
                 expectedSupportedSatellitePlmns, satellitePlmnList.stream().toArray()));
         supportedSatelliteServices =
@@ -1669,7 +1670,7 @@
         }
         processAllMessages();
 
-        satellitePlmnList = testSatelliteController.getSatellitePlmnList(SUB_ID);
+        satellitePlmnList = testSatelliteController.getAllSatellitePlmnsForCarrier(SUB_ID);
         assertTrue(satellitePlmnList.isEmpty());
         supportedSatelliteServices =
                 testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00102");
@@ -1714,7 +1715,8 @@
         TestSatelliteController testSatelliteController =
                 new TestSatelliteController(mContext, Looper.myLooper(), mFeatureFlags);
         processAllMessages();
-        List<String> carrierPlmnList = testSatelliteController.getSatellitePlmnList(SUB_ID);
+        List<String> carrierPlmnList = testSatelliteController.getAllSatellitePlmnsForCarrier(
+                SUB_ID);
         verify(mMockSatelliteModemInterface, never()).setSatellitePlmn(
                 anyInt(), anyList(), anyList(), any(Message.class));
         assertTrue(carrierPlmnList.isEmpty());
@@ -1741,7 +1743,7 @@
             );
         }
         processAllMessages();
-        carrierPlmnList = testSatelliteController.getSatellitePlmnList(SUB_ID);
+        carrierPlmnList = testSatelliteController.getAllSatellitePlmnsForCarrier(SUB_ID);
         verify(mMockSatelliteModemInterface, never()).setSatellitePlmn(
                 anyInt(), anyList(), anyList(), any(Message.class));
         assertTrue(carrierPlmnList.isEmpty());
@@ -1767,7 +1769,7 @@
         }
         processAllMessages();
 
-        carrierPlmnList = testSatelliteController.getSatellitePlmnList(SUB_ID);
+        carrierPlmnList = testSatelliteController.getAllSatellitePlmnsForCarrier(SUB_ID);
         assertTrue(carrierPlmnList.isEmpty());
         List<String> allSatellitePlmnList = SatelliteServiceUtils.mergeStrLists(
                 carrierPlmnList, satellitePlmnListFromOverlayConfig);
@@ -1787,7 +1789,7 @@
             );
         }
         processAllMessages();
-        carrierPlmnList = testSatelliteController.getSatellitePlmnList(SUB_ID);
+        carrierPlmnList = testSatelliteController.getAllSatellitePlmnsForCarrier(SUB_ID);
         allSatellitePlmnList = SatelliteServiceUtils.mergeStrLists(
                 carrierPlmnList, satellitePlmnListFromOverlayConfig);
         assertEquals(expectedCarrierPlmnList, carrierPlmnList);
@@ -1826,7 +1828,7 @@
             );
         }
         processAllMessages();
-        carrierPlmnList = testSatelliteController.getSatellitePlmnList(SUB_ID);
+        carrierPlmnList = testSatelliteController.getAllSatellitePlmnsForCarrier(SUB_ID);
         assertTrue(carrierPlmnList.isEmpty());
         verify(mMockSatelliteModemInterface, times(1)).setSatellitePlmn(anyInt(),
                 eq(EMPTY_STRING_LIST), eq(EMPTY_STRING_LIST), any(Message.class));
diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java
index d75b32a..1a89c15 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java
@@ -2018,6 +2018,36 @@
     }
 
     @Test
+    public void testSetGroupDisabled() throws Exception {
+        assertThrows(IllegalArgumentException.class,
+                () -> mDatabaseManagerUT.setGroupDisabled(
+                        FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), true));
+
+        insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1);
+        mDatabaseManagerUT.setGroupDisabled(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), true);
+        processAllMessages();
+
+        assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(
+            FAKE_SUBSCRIPTION_INFO1.getSubscriptionId()).isGroupDisabled()).isTrue();
+
+        verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1));
+        Mockito.clearInvocations(mSubscriptionDatabaseManagerCallback);
+
+        mDatabaseManagerUT.setGroupDisabled(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), true);
+        processAllMessages();
+        verify(mSubscriptionDatabaseManagerCallback, never()).onSubscriptionChanged(eq(1));
+
+        assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(
+            FAKE_SUBSCRIPTION_INFO1.getSubscriptionId()).isGroupDisabled()).isTrue();
+
+        mDatabaseManagerUT.setGroupDisabled(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), false);
+        processAllMessages();
+        verify(mSubscriptionDatabaseManagerCallback, times(1)).onSubscriptionChanged(eq(1));
+        assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(
+                FAKE_SUBSCRIPTION_INFO1.getSubscriptionId()).isGroupDisabled()).isFalse();
+    }
+
+    @Test
     public void testUpdateSatelliteNtnWithFeatureDisabled() throws Exception {
         assertThrows(IllegalArgumentException.class,
                 () -> mDatabaseManagerUT.setSatelliteAttachEnabledForCarrier(