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));
}