Adds implementation for the new TelephonyCallback

Adds the impl to pass the HAL state of cellular
simultaneous calling to TelephonyRegistry to notify
listeners.

Bug: 319904227
Test: atest FrameworksTelephonyTests
Change-Id: Iade7b8249b8e02ad8cff2ce92263ab3a3b420a66
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/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/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/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/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);
+    }
 }