Merge cherrypicks of ['googleplex-android-review.googlesource.com/32808568'] into 25Q2-release.

Change-Id: I070a745173c8fda054999ee07a5c210b6c9162c2
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 4d59fc8..f959c52 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -42,6 +42,7 @@
 import static android.telecom.TelecomManager.VERY_SHORT_CALL_TIME_MS;
 
 import android.Manifest;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -155,6 +156,8 @@
 import com.android.server.telecom.callsequencing.TransactionManager;
 import com.android.server.telecom.callsequencing.voip.VoipCallMonitorLegacy;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -189,6 +192,23 @@
  */
 public class CallsManager extends Call.ListenerBase
         implements VideoProviderProxy.Listener, CallFilterResultCallback, CurrentUserProxy {
+    /**
+     * The origin of the request is not known.
+     */
+    public static final int REQUEST_ORIGIN_UNKNOWN = -1;
+
+    /**
+     * The request originated from a Telecom-provided disambiguation.
+     */
+    public static final int REQUEST_ORIGIN_TELECOM_DISAMBIGUATION = 1;
+
+    /**
+     * @hide
+     */
+    @IntDef(prefix = { "REQUEST_ORIGIN_" },
+            value = {REQUEST_ORIGIN_UNKNOWN, REQUEST_ORIGIN_TELECOM_DISAMBIGUATION})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RequestOrigin {}
 
     // TODO: Consider renaming this CallsManagerPlugin.
     @VisibleForTesting
@@ -3268,19 +3288,32 @@
     }
 
     /**
+     * Similar to {@link #answerCall(Call, int, int)}, instructs Telecom to answer the specified
+     * call.  This prototype assumes that the origin of the request is
+     * {@link #REQUEST_ORIGIN_UNKNOWN} for the time being.  In most cases this is likely a user
+     * request to answer a call, but could be internal to Telecom.
+     * @param call The call to answer.
+     * @param videoState The video state in which to answer the call.
+     */
+    public void answerCall(Call call, int videoState) {
+        answerCall(call, videoState, REQUEST_ORIGIN_UNKNOWN);
+    }
+
+    /**
      * Instructs Telecom to answer the specified call. Intended to be invoked by the in-call
      * app through {@link InCallAdapter} after Telecom notifies it of an incoming call followed by
      * the user opting to answer said call.
      *
      * @param call The call to answer.
      * @param videoState The video state in which to answer the call.
+     * @param requestOrigin The origin of the request being made.
      */
     @VisibleForTesting
-    public void answerCall(Call call, int videoState) {
+    public void answerCall(Call call, int videoState, @RequestOrigin int requestOrigin) {
         if (!mCalls.contains(call)) {
             Log.i(this, "Request to answer a non-existent call %s", call);
         }
-        mCallSequencingAdapter.answerCall(call, videoState);
+        mCallSequencingAdapter.answerCall(call, videoState, requestOrigin);
     }
 
     /**
@@ -3293,7 +3326,7 @@
      * <p>
      * Note: This is only used when {@link FeatureFlags#enableCallSequencing()} is false.
      */
-    public void answerCallOld(Call call, int videoState) {
+    public void answerCallOld(Call call, int videoState, @RequestOrigin int requestOrigin) {
         if (call.isTransactionalCall()) {
             // InCallAdapter is requesting to answer the given transactioanl call. Must get an ack
             // from the client via a transaction before answering.
diff --git a/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java b/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
index 523b841..2efc79c 100644
--- a/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
+++ b/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
@@ -184,7 +184,8 @@
                 // Answer the current ringing call.
                 Call incomingCall = mCallsManager.getIncomingCallNotifier().getIncomingCall();
                 if (incomingCall != null) {
-                    mCallsManager.answerCall(incomingCall, incomingCall.getVideoState());
+                    mCallsManager.answerCall(incomingCall, incomingCall.getVideoState(),
+                            CallsManager.REQUEST_ORIGIN_TELECOM_DISAMBIGUATION);
                 }
             } finally {
                 Log.endSession();
diff --git a/src/com/android/server/telecom/callsequencing/CallSequencingController.java b/src/com/android/server/telecom/callsequencing/CallSequencingController.java
index d418cff..f396257 100644
--- a/src/com/android/server/telecom/callsequencing/CallSequencingController.java
+++ b/src/com/android/server/telecom/callsequencing/CallSequencingController.java
@@ -169,11 +169,16 @@
      * sequencing provided that the calls that are being manipulated are across phone accounts.
      * @param incomingCall The incoming call to be answered.
      * @param videoState The video state configuration for the provided call.
+     * @param requestOrigin The origin of the request to answer the call; this can impact sequencing
+     *                      decisions as requests that Telecom makes can override rules we have set
+     *                      for actions which originate from outside.
      */
-    public void answerCall(Call incomingCall, int videoState) {
+    public void answerCall(Call incomingCall, int videoState,
+            @CallsManager.RequestOrigin int requestOrigin) {
         Log.i(this, "answerCall: Beginning call sequencing transaction for answering "
                 + "incoming call.");
-        holdActiveCallForNewCallWithSequencing(incomingCall).thenComposeAsync((result) -> {
+        holdActiveCallForNewCallWithSequencing(incomingCall, requestOrigin)
+                .thenComposeAsync((result) -> {
                 if (result) {
                     mCallsManager.requestFocusActionAnswerCall(incomingCall, videoState);
                 } else {
@@ -190,7 +195,8 @@
      * @param call The self-managed call that's waiting to go active.
      */
     public void handleSetSelfManagedCallActive(Call call) {
-        holdActiveCallForNewCallWithSequencing(call).thenComposeAsync((result) -> {
+        holdActiveCallForNewCallWithSequencing(call, CallsManager.REQUEST_ORIGIN_UNKNOWN)
+                .thenComposeAsync((result) -> {
                 if (result) {
                     Log.i(this, "markCallAsActive: requesting focus for self managed call "
                             + "before setting active.");
@@ -218,7 +224,7 @@
      */
     public void transactionHoldPotentialActiveCallForNewCallSequencing(
             Call newCall, OutcomeReceiver<Boolean, CallException> callback) {
-        holdActiveCallForNewCallWithSequencing(newCall)
+        holdActiveCallForNewCallWithSequencing(newCall, CallsManager.REQUEST_ORIGIN_UNKNOWN)
                 .thenComposeAsync((result) -> {
                     if (result) {
                         // Either we were able to hold the active call or the active call was
@@ -245,13 +251,14 @@
      * Attempts to hold the active call so that the provided call can go active. This is done via
      * call sequencing and the resulting future is an indication of whether that request
      * has succeeded.
+     *
      * @param call The call that's waiting to go active.
      * @return The {@link CompletableFuture} indicating the result of whether the
-     *         active call was able to be held (if applicable).
+     * active call was able to be held (if applicable).
      */
     @VisibleForTesting
     public CompletableFuture<Boolean> holdActiveCallForNewCallWithSequencing(
-            Call call) {
+            Call call, int requestOrigin) {
         Call activeCall = (Call) mCallsManager.getConnectionServiceFocusManager()
                 .getCurrentFocusCall();
         Log.i(this, "holdActiveCallForNewCallWithSequencing, newCall: %s, "
@@ -292,8 +299,14 @@
                     // and the held call is a carrier call, then disconnect the held call. The
                     // idea is that if we have a held carrier call and the incoming call is a
                     // VOIP call, we don't want to force the carrier call to auto-disconnect).
-                    if (isManagedCall(heldCall) && isVoipCall(call)) {
+                    // Note: If the origin of this request was from the Telecom call incoming call
+                    // disambiguation notification, we will allow the request to continue.
+                    if (isManagedCall(heldCall) && isVoipCall(call) && requestOrigin
+                            != CallsManager.REQUEST_ORIGIN_TELECOM_DISAMBIGUATION) {
                         // Otherwise, fail the transaction.
+                        Log.w(this, "holdActiveCallForNewCallWithSequencing: ignoring request to "
+                                + "disconnect carrier call %s for voip call %s.", activeCall,
+                                heldCall);
                         return CompletableFuture.completedFuture(false);
                     } else {
                         isSequencingRequiredHeldAndActive = !arePhoneAccountsSame(
diff --git a/src/com/android/server/telecom/callsequencing/CallsManagerCallSequencingAdapter.java b/src/com/android/server/telecom/callsequencing/CallsManagerCallSequencingAdapter.java
index 611bb9e..b2cfcab 100644
--- a/src/com/android/server/telecom/callsequencing/CallsManagerCallSequencingAdapter.java
+++ b/src/com/android/server/telecom/callsequencing/CallsManagerCallSequencingAdapter.java
@@ -70,12 +70,14 @@
      * (mIsCallSequencingEnabled) is enabled.
      * @param incomingCall The incoming call that should be answered.
      * @param videoState The video state configuration associated with the call.
+     * @param requestOrigin The origin of the request.
      */
-    public void answerCall(Call incomingCall, int videoState) {
+    public void answerCall(Call incomingCall, int videoState,
+            @CallsManager.RequestOrigin int requestOrigin) {
         if (mIsCallSequencingEnabled && !incomingCall.isTransactionalCall()) {
-            mSequencingController.answerCall(incomingCall, videoState);
+            mSequencingController.answerCall(incomingCall, videoState, requestOrigin);
         } else {
-            mCallsManager.answerCallOld(incomingCall, videoState);
+            mCallsManager.answerCallOld(incomingCall, videoState, requestOrigin);
         }
     }
 
diff --git a/tests/src/com/android/server/telecom/tests/CallSequencingTests.java b/tests/src/com/android/server/telecom/tests/CallSequencingTests.java
index 66dc879..fc476f8 100644
--- a/tests/src/com/android/server/telecom/tests/CallSequencingTests.java
+++ b/tests/src/com/android/server/telecom/tests/CallSequencingTests.java
@@ -194,7 +194,7 @@
     public void testAnswerCall() {
         // This will allow holdActiveCallForNewCallWithSequencing to immediately return true
         setActiveCallFocus(null);
-        mController.answerCall(mNewCall, 0);
+        mController.answerCall(mNewCall, 0, CallsManager.REQUEST_ORIGIN_UNKNOWN);
         verify(mCallsManager, timeout(SEQUENCING_TIMEOUT_MS))
                 .requestFocusActionAnswerCall(eq(mNewCall), eq(0));
     }
@@ -203,13 +203,28 @@
     @Test
     public void testAnswerCallFail() {
         setupHoldActiveCallForNewCallFailMocks();
-        mController.answerCall(mNewCall, 0);
+        mController.answerCall(mNewCall, 0, CallsManager.REQUEST_ORIGIN_UNKNOWN);
         verify(mCallsManager, timeout(SEQUENCING_TIMEOUT_MS).times(0))
                 .requestFocusActionAnswerCall(eq(mNewCall), eq(0));
     }
 
     @SmallTest
     @Test
+    public void testAnswerCallAcceptedFromTelecom() {
+        setPhoneAccounts(mNewCall, mActiveCall, false);
+        setActiveCallFocus(mActiveCall);
+        when(mCallsManager.canHold(mActiveCall)).thenReturn(true);
+        when(mActiveCall.hold(anyString())).thenReturn(CompletableFuture.completedFuture(true));
+
+        when(mHeldCall.isSelfManaged()).thenReturn(false);
+        when(mNewCall.isSelfManaged()).thenReturn(true);
+        mController.answerCall(mNewCall, 0, CallsManager.REQUEST_ORIGIN_TELECOM_DISAMBIGUATION);
+        verify(mCallsManager, timeout(SEQUENCING_TIMEOUT_MS).times(1))
+                .requestFocusActionAnswerCall(eq(mNewCall), eq(0));
+    }
+
+    @SmallTest
+    @Test
     public void testSetSelfManagedCallActive() {
         // This will allow holdActiveCallForNewCallWithSequencing to immediately return true
         setActiveCallFocus(null);
@@ -270,7 +285,8 @@
     public void testHoldCallForNewCall_NoActiveCall() {
         setActiveCallFocus(null);
         CompletableFuture<Boolean> resultFuture = mController
-                .holdActiveCallForNewCallWithSequencing(mNewCall);
+                .holdActiveCallForNewCallWithSequencing(mNewCall,
+                        CallsManager.REQUEST_ORIGIN_UNKNOWN);
         assertTrue(waitForFutureResult(resultFuture, false));
     }
 
@@ -285,13 +301,15 @@
         // Cross phone account case (sequencing enabled)
         assertFalse(mController.arePhoneAccountsSame(mNewCall, mActiveCall));
         CompletableFuture<Boolean> resultFuture = mController
-                .holdActiveCallForNewCallWithSequencing(mNewCall);
+                .holdActiveCallForNewCallWithSequencing(mNewCall,
+                        CallsManager.REQUEST_ORIGIN_UNKNOWN);
         assertTrue(waitForFutureResult(resultFuture, false));
 
         // Same phone account case
         setPhoneAccounts(mNewCall, mActiveCall, true);
         assertTrue(mController.arePhoneAccountsSame(mNewCall, mActiveCall));
-        resultFuture = mController.holdActiveCallForNewCallWithSequencing(mNewCall);
+        resultFuture = mController.holdActiveCallForNewCallWithSequencing(mNewCall,
+                CallsManager.REQUEST_ORIGIN_UNKNOWN);
         assertTrue(waitForFutureResult(resultFuture, false));
     }
 
@@ -312,7 +330,8 @@
         // disconnect the active (carrier) call.
         assertFalse(mController.arePhoneAccountsSame(mNewCall, mActiveCall));
         CompletableFuture<Boolean> resultFuture = mController
-                .holdActiveCallForNewCallWithSequencing(mNewCall);
+                .holdActiveCallForNewCallWithSequencing(mNewCall,
+                        CallsManager.REQUEST_ORIGIN_UNKNOWN);
         verify(mHeldCall, timeout(SEQUENCING_TIMEOUT_MS)).disconnect();
         verify(mActiveCall, timeout(SEQUENCING_TIMEOUT_MS)).hold();
         verify(mNewCall).increaseHeldByThisCallCount();
@@ -332,7 +351,8 @@
         // Cross phone account case (sequencing enabled)
         assertFalse(mController.arePhoneAccountsSame(mNewCall, mActiveCall));
         CompletableFuture<Boolean> resultFuture = mController
-                .holdActiveCallForNewCallWithSequencing(mNewCall);
+                .holdActiveCallForNewCallWithSequencing(mNewCall,
+                        CallsManager.REQUEST_ORIGIN_UNKNOWN);
         verify(mActiveCall, timeout(SEQUENCING_TIMEOUT_MS)).hold();
         verify(mNewCall).increaseHeldByThisCallCount();
         assertTrue(waitForFutureResult(resultFuture, false));
@@ -352,7 +372,8 @@
 
         assertFalse(mController.arePhoneAccountsSame(mNewCall, mActiveCall));
         CompletableFuture<Boolean> resultFuture = mController
-                .holdActiveCallForNewCallWithSequencing(mNewCall);
+                .holdActiveCallForNewCallWithSequencing(mNewCall,
+                        CallsManager.REQUEST_ORIGIN_UNKNOWN);
         verify(mActiveCall, timeout(SEQUENCING_TIMEOUT_MS)).disconnect(anyString());
         assertTrue(waitForFutureResult(resultFuture, false));
     }
@@ -372,7 +393,8 @@
         // disconnect the active (carrier) call.
         assertFalse(mController.arePhoneAccountsSame(mNewCall, mActiveCall));
         CompletableFuture<Boolean> resultFuture = mController
-                .holdActiveCallForNewCallWithSequencing(mNewCall);
+                .holdActiveCallForNewCallWithSequencing(mNewCall,
+                        CallsManager.REQUEST_ORIGIN_UNKNOWN);
         assertFalse(waitForFutureResult(resultFuture, true));
     }
 
@@ -387,7 +409,8 @@
 
         assertTrue(mController.arePhoneAccountsSame(mNewCall, mActiveCall));
         CompletableFuture<Boolean> resultFuture = mController
-                .holdActiveCallForNewCallWithSequencing(mNewCall);
+                .holdActiveCallForNewCallWithSequencing(mNewCall,
+                        CallsManager.REQUEST_ORIGIN_UNKNOWN);
         assertTrue(waitForFutureResult(resultFuture, true));
     }
 
@@ -404,7 +427,8 @@
 
         assertFalse(mController.arePhoneAccountsSame(mNewCall, mActiveCall));
         CompletableFuture<Boolean> resultFuture = mController
-                .holdActiveCallForNewCallWithSequencing(mNewCall);
+                .holdActiveCallForNewCallWithSequencing(mNewCall,
+                        CallsManager.REQUEST_ORIGIN_UNKNOWN);
         verify(mNewCall, timeout(SEQUENCING_TIMEOUT_MS)).reject(
                 anyBoolean(), anyString(), anyString());
         assertFalse(waitForFutureResult(resultFuture, true));
@@ -423,7 +447,8 @@
 
         assertFalse(mController.arePhoneAccountsSame(mNewCall, mActiveCall));
         CompletableFuture<Boolean> resultFuture = mController
-                .holdActiveCallForNewCallWithSequencing(mNewCall);
+                .holdActiveCallForNewCallWithSequencing(mNewCall,
+                        CallsManager.REQUEST_ORIGIN_UNKNOWN);
         assertFalse(waitForFutureResult(resultFuture, true));
     }