Ensure external calls are ended on the headset.

Tag: #compatibility
Bug: 272320459
Test: atest BluetoothInCallServiceTest
(cherry picked from https://android-review.googlesource.com/q/commit:85bfc16c707bfadc552e01e34d5e53383a9addd2)
Merged-In: Ibfa9706281d6054c7ffd6fcc41d75729733035ed
Change-Id: Ibfa9706281d6054c7ffd6fcc41d75729733035ed
Bug: 263323082
diff --git a/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java b/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java
index 7cc5bac..5dc4321 100644
--- a/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java
+++ b/android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java
@@ -267,7 +267,7 @@
                 return;
             }
             if (call.isExternalCall()) {
-                onCallRemoved(call);
+                onCallRemoved(call, false /* forceRemoveCallback */);
             } else {
                 onCallAdded(call);
             }
@@ -605,13 +605,19 @@
         onCallAdded(new BluetoothCall(call));
     }
 
-    public void onCallRemoved(BluetoothCall call) {
-        if (call.isExternalCall()) {
-            return;
-        }
+    /**
+     * Called when a {@code BluetoothCall} has been removed from this in-call session.
+     *
+     * @param call the {@code BluetoothCall} to remove
+     * @param forceRemoveCallback if true, this will always unregister this {@code InCallService} as
+     *                            a callback for the given {@code BluetoothCall}, when false, this
+     *                            will not remove the callback when the {@code BluetoothCall} is
+     *                            external so that the call can be added back if no longer external.
+     */
+    public void onCallRemoved(BluetoothCall call, boolean forceRemoveCallback) {
         Log.d(TAG, "onCallRemoved");
         CallStateCallback callback = getCallback(call);
-        if (callback != null) {
+        if (callback != null && (forceRemoveCallback || !call.isExternalCall())) {
             call.unregisterCallback(callback);
         }
 
@@ -635,7 +641,7 @@
             Log.w(TAG, "onCallRemoved, BluetoothCall is removed before registered");
             return;
         }
-        onCallRemoved(bluetoothCall);
+        onCallRemoved(bluetoothCall, true /* forceRemoveCallback */);
     }
 
     @Override
diff --git a/android/app/tests/unit/src/com/android/bluetooth/telephony/BluetoothInCallServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/telephony/BluetoothInCallServiceTest.java
index 9332eea..4abe619 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/telephony/BluetoothInCallServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/telephony/BluetoothInCallServiceTest.java
@@ -987,13 +987,46 @@
         mBluetoothInCallService.onCallAdded(activeCall);
         doReturn(null).when(mMockCallInfo).getActiveCall();
         when(activeCall.getHandle()).thenReturn(Uri.parse("tel:555-0001"));
-        mBluetoothInCallService.onCallRemoved(activeCall);
+
+        mBluetoothInCallService.onCallRemoved(activeCall, true /* forceRemoveCallback */);
 
         verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_IDLE),
                 eq(""), eq(128), nullable(String.class));
     }
 
     @Test
+    public void testOnDetailsChangeExternalRemovesCall() throws Exception {
+        BluetoothCall activeCall = createActiveCall();
+        mBluetoothInCallService.onCallAdded(activeCall);
+        doReturn(null).when(mMockCallInfo).getActiveCall();
+        when(activeCall.getHandle()).thenReturn(Uri.parse("tel:555-0001"));
+
+        when(activeCall.isExternalCall()).thenReturn(true);
+        mBluetoothInCallService.getCallback(activeCall).onDetailsChanged(activeCall, null);
+
+        verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_IDLE),
+                eq(""), eq(128), nullable(String.class));
+    }
+
+    @Test
+    public void testOnDetailsChangeExternalAddsCall() throws Exception {
+        BluetoothCall activeCall = createActiveCall();
+        mBluetoothInCallService.onCallAdded(activeCall);
+        when(activeCall.getHandle()).thenReturn(Uri.parse("tel:555-0001"));
+        BluetoothInCallService.CallStateCallback callBack = mBluetoothInCallService.getCallback(
+                activeCall);
+
+        when(activeCall.isExternalCall()).thenReturn(true);
+        callBack.onDetailsChanged(activeCall, null);
+
+        when(activeCall.isExternalCall()).thenReturn(false);
+        callBack.onDetailsChanged(activeCall, null);
+
+        verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(0), eq(CALL_STATE_IDLE),
+                eq(""), eq(128), nullable(String.class));
+    }
+
+    @Test
     public void testOnCallStateChangedConnectingCall() throws Exception {
         BluetoothCall activeCall = getMockCall();
         BluetoothCall connectingCall = getMockCall();