Merge "Resolve call supported routes issue" into main
diff --git a/flags/telecom_call_flags.aconfig b/flags/telecom_call_flags.aconfig
index 2c53938..634d7a3 100644
--- a/flags/telecom_call_flags.aconfig
+++ b/flags/telecom_call_flags.aconfig
@@ -54,4 +54,15 @@
   metadata {
       purpose: PURPOSE_BUGFIX
     }
+}
+
+# OWNER=tjstuart TARGET=25Q1
+flag {
+  name: "remap_transactional_capabilities"
+  namespace: "telecom"
+  description: "Transactional call capabilities need to be remapped to Connection capabilities"
+  bug: "366063695"
+  metadata {
+      purpose: PURPOSE_BUGFIX
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index ba371f1..dcd9486 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -2331,6 +2331,25 @@
         setConnectionCapabilities(connectionCapabilities, false /* forceUpdate */);
     }
 
+    public void setTransactionalCapabilities(Bundle extras) {
+        if (!mFlags.remapTransactionalCapabilities()) {
+            setConnectionCapabilities(
+                    extras.getInt(CallAttributes.CALL_CAPABILITIES_KEY,
+                            CallAttributes.SUPPORTS_SET_INACTIVE), true);
+            return;
+        }
+        int connectionCapabilitesBitmap = 0;
+        int transactionalCapabilitiesBitmap = extras.getInt(
+                CallAttributes.CALL_CAPABILITIES_KEY,
+                CallAttributes.SUPPORTS_SET_INACTIVE);
+        if ((transactionalCapabilitiesBitmap & CallAttributes.SUPPORTS_SET_INACTIVE)
+                == CallAttributes.SUPPORTS_SET_INACTIVE) {
+            connectionCapabilitesBitmap = connectionCapabilitesBitmap | Connection.CAPABILITY_HOLD
+                    | Connection.CAPABILITY_SUPPORT_HOLD;
+        }
+        setConnectionCapabilities(connectionCapabilitesBitmap, true);
+    }
+
     void setConnectionCapabilities(int connectionCapabilities, boolean forceUpdate) {
         Log.v(this, "setConnectionCapabilities: %s", Connection.capabilitiesToString(
                 connectionCapabilities));
diff --git a/src/com/android/server/telecom/CallAudioCommunicationDeviceTracker.java b/src/com/android/server/telecom/CallAudioCommunicationDeviceTracker.java
index 8130685..8d5f9fd 100644
--- a/src/com/android/server/telecom/CallAudioCommunicationDeviceTracker.java
+++ b/src/com/android/server/telecom/CallAudioCommunicationDeviceTracker.java
@@ -46,7 +46,7 @@
     private static final int sAUDIO_DEVICE_TYPE_INVALID = -1;
     private AudioManager mAudioManager;
     private BluetoothRouteManager mBluetoothRouteManager;
-    private int mAudioDeviceType = sAUDIO_DEVICE_TYPE_INVALID;
+    private @AudioDeviceInfo.AudioDeviceType int mAudioDeviceType = sAUDIO_DEVICE_TYPE_INVALID;
     // Keep track of the locally requested BT audio device if set
     private String mBtAudioDevice = null;
     private final Lock mLock = new ReentrantLock();
@@ -59,7 +59,7 @@
         mBluetoothRouteManager = bluetoothRouteManager;
     }
 
-    public boolean isAudioDeviceSetForType(int audioDeviceType) {
+    public boolean isAudioDeviceSetForType(@AudioDeviceInfo.AudioDeviceType int audioDeviceType) {
         if (Flags.communicationDeviceProtectedByLock()) {
             mLock.lock();
         }
@@ -86,7 +86,7 @@
     }
 
     @VisibleForTesting
-    public void setTestCommunicationDevice(int audioDeviceType) {
+    public void setTestCommunicationDevice(@AudioDeviceInfo.AudioDeviceType int audioDeviceType) {
         mAudioDeviceType = audioDeviceType;
     }
 
@@ -119,7 +119,7 @@
      * @return {@code true} if the device was set for communication, {@code false} if the device
      * wasn't set.
      */
-    public boolean setCommunicationDevice(int audioDeviceType,
+    public boolean setCommunicationDevice(@AudioDeviceInfo.AudioDeviceType int audioDeviceType,
             BluetoothDevice btDevice) {
         if (Flags.communicationDeviceProtectedByLock()) {
             mLock.lock();
@@ -133,8 +133,8 @@
         }
     }
 
-    private boolean processSetCommunicationDevice(int audioDeviceType,
-            BluetoothDevice btDevice) {
+    private boolean processSetCommunicationDevice(
+        @AudioDeviceInfo.AudioDeviceType int audioDeviceType, BluetoothDevice btDevice) {
         // There is only one audio device type associated with each type of BT device.
         boolean isBtDevice = BT_AUDIO_DEVICE_INFO_TYPES.contains(audioDeviceType);
         Log.i(this, "setCommunicationDevice: type = %s, isBtDevice = %s, btDevice = %s",
@@ -208,7 +208,7 @@
      * has previously been set for communication.
      * @param audioDeviceTypes The supported audio device types for the device.
      */
-    public void clearCommunicationDevice(int audioDeviceType) {
+    public void clearCommunicationDevice(@AudioDeviceInfo.AudioDeviceType int audioDeviceType) {
         if (Flags.communicationDeviceProtectedByLock()) {
             mLock.lock();
         }
@@ -221,7 +221,8 @@
         }
     }
 
-    public void processClearCommunicationDevice(int audioDeviceType) {
+    public void processClearCommunicationDevice(
+        @AudioDeviceInfo.AudioDeviceType int audioDeviceType) {
         if (audioDeviceType == sAUDIO_DEVICE_TYPE_INVALID) {
             Log.i(this, "clearCommunicationDevice: Skip clearing communication device"
                     + "for invalid audio type (-1).");
@@ -260,7 +261,8 @@
         }
     }
 
-    private boolean isUsbHeadsetType(int audioDeviceType, int sourceType) {
+    private boolean isUsbHeadsetType(@AudioDeviceInfo.AudioDeviceType int audioDeviceType,
+        @AudioDeviceInfo.AudioDeviceType int sourceType) {
         return audioDeviceType == AudioDeviceInfo.TYPE_WIRED_HEADSET
                 && sourceType == AudioDeviceInfo.TYPE_USB_HEADSET;
     }
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 04f93fc..a1b8a50 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -1563,9 +1563,7 @@
         if (extras.containsKey(TelecomManager.TRANSACTION_CALL_ID_KEY)) {
             call.setIsTransactionalCall(true);
             call.setCallingPackageIdentity(extras);
-            call.setConnectionCapabilities(
-                    extras.getInt(CallAttributes.CALL_CAPABILITIES_KEY,
-                            CallAttributes.SUPPORTS_SET_INACTIVE), true);
+            call.setTransactionalCapabilities(extras);
             call.setTargetPhoneAccount(phoneAccountHandle);
             if (extras.containsKey(CallAttributes.DISPLAY_NAME_KEY)) {
                 CharSequence displayName = extras.getCharSequence(CallAttributes.DISPLAY_NAME_KEY);
@@ -1917,9 +1915,7 @@
             if (extras.containsKey(TelecomManager.TRANSACTION_CALL_ID_KEY)) {
                 call.setIsTransactionalCall(true);
                 call.setCallingPackageIdentity(extras);
-                call.setConnectionCapabilities(
-                        extras.getInt(CallAttributes.CALL_CAPABILITIES_KEY,
-                                CallAttributes.SUPPORTS_SET_INACTIVE), true);
+                call.setTransactionalCapabilities(extras);
                 if (extras.containsKey(CallAttributes.DISPLAY_NAME_KEY)) {
                     CharSequence displayName = extras.getCharSequence(
                             CallAttributes.DISPLAY_NAME_KEY);
diff --git a/tests/src/com/android/server/telecom/tests/CallTest.java b/tests/src/com/android/server/telecom/tests/CallTest.java
index fa7d21a..3a7a822 100644
--- a/tests/src/com/android/server/telecom/tests/CallTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallTest.java
@@ -152,6 +152,32 @@
     }
 
     /**
+     * Verify that transactional calls remap the [CallAttributes#CallCapability]s to
+     * Connection capabilities.
+     */
+    @Test
+    @SmallTest
+    public void testTransactionalCallCapabilityRemapping() {
+        // ensure when the flag is disabled, the old behavior is unchanged
+        Bundle disabledFlagExtras = new Bundle();
+        Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
+        disabledFlagExtras.putInt(CallAttributes.CALL_CAPABILITIES_KEY,
+                Connection.CAPABILITY_MERGE_CONFERENCE);
+        when(mFeatureFlags.remapTransactionalCapabilities()).thenReturn(false);
+        call.setTransactionalCapabilities(disabledFlagExtras);
+        assertTrue(call.can(Connection.CAPABILITY_MERGE_CONFERENCE));
+        // enable the bug fix flag and ensure the transactional capabilities are remapped
+        Bundle enabledFlagExtras = new Bundle();
+        Call call2 = createCall("2", Call.CALL_DIRECTION_INCOMING);
+        enabledFlagExtras.putInt(CallAttributes.CALL_CAPABILITIES_KEY,
+                CallAttributes.SUPPORTS_SET_INACTIVE);
+        when(mFeatureFlags.remapTransactionalCapabilities()).thenReturn(true);
+        call2.setTransactionalCapabilities(enabledFlagExtras);
+        assertTrue(call2.can(Connection.CAPABILITY_HOLD));
+        assertTrue(call2.can(Connection.CAPABILITY_SUPPORT_HOLD));
+    }
+
+    /**
      * Verify Call#setVideoState will only upgrade to video if the PhoneAccount supports video
      * state capabilities
      */