Implement parts of the audio call screening API
Add code to enable the APIs that let a call screening service enter the
background audio processing audio state, as well as the APIs that handle
simulated ringing and answering.
Test: CTS
Bug: 140317205
Change-Id: I05a51fcaf7c69bda6dd13f358e1d8667d8f463d4
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index e5b9de9..98eceb9 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -365,6 +365,12 @@
*/
private DisconnectCause mDisconnectCause = new DisconnectCause(DisconnectCause.UNKNOWN);
+ /**
+ * Override the disconnect cause set by the connection service. Used for audio processing and
+ * simulated ringing calls.
+ */
+ private int mOverrideDisconnectCauseCode = DisconnectCause.UNKNOWN;
+
private Bundle mIntentExtras = new Bundle();
/**
@@ -1144,6 +1150,11 @@
public void setDisconnectCause(DisconnectCause disconnectCause) {
// TODO: Consider combining this method with a setDisconnected() method that is totally
// separate from setState.
+ if (mOverrideDisconnectCauseCode != DisconnectCause.UNKNOWN) {
+ disconnectCause = new DisconnectCause(mOverrideDisconnectCauseCode,
+ disconnectCause.getLabel(), disconnectCause.getDescription(),
+ disconnectCause.getReason(), disconnectCause.getTone());
+ }
mAnalytics.setCallDisconnectCause(disconnectCause);
mDisconnectCause = disconnectCause;
}
@@ -1922,6 +1933,13 @@
Log.v(this, "Aborting call %s", this);
abort(disconnectionTimeout);
} else if (mState != CallState.ABORTED && mState != CallState.DISCONNECTED) {
+ if (mState == CallState.AUDIO_PROCESSING) {
+ mOverrideDisconnectCauseCode = DisconnectCause.REJECTED;
+ } else if (mState == CallState.SIMULATED_RINGING) {
+ // This is the case where the dialer calls disconnect() because the call timed out
+ // Override the disconnect cause to MISSED
+ mOverrideDisconnectCauseCode = DisconnectCause.MISSED;
+ }
if (mConnectionService == null) {
Log.e(this, new Exception(), "disconnect() request on a call without a"
+ " connection service.");
@@ -2000,6 +2018,30 @@
}
/**
+ * Answers the call on the connectionservice side in order to start audio processing.
+ *
+ * This pathway keeps the call in the ANSWERED state until the connection service confirms the
+ * answer, at which point we'll set it to AUDIO_PROCESSING. However, to prevent any other
+ * components from seeing the churn between RINGING -> ANSWERED -> AUDIO_PROCESSING, we'll
+ * refrain from tracking this call in CallsManager until we've stabilized in AUDIO_PROCESSING
+ */
+ public void answerForAudioProcessing() {
+ if (mState != CallState.RINGING) {
+ Log.w(this, "Trying to audio-process a non-ringing call: id=%s", mId);
+ return;
+ }
+
+ if (mConnectionService != null) {
+ mConnectionService.answer(this, VideoProfile.STATE_AUDIO_ONLY);
+ } else {
+ Log.e(this, new NullPointerException(),
+ "answer call (audio processing) failed due to null CS callId=%s", getId());
+ }
+
+ Log.addEvent(this, LogUtils.Events.REQUEST_PICKUP_FOR_AUDIO_PROCESSING);
+ }
+
+ /**
* Deflects the call if it is ringing.
*
* @param address address to be deflected to.
@@ -2045,9 +2087,19 @@
*/
@VisibleForTesting
public void reject(boolean rejectWithMessage, String textMessage, String reason) {
- // Check to verify that the call is still in the ringing state. A call can change states
- // between the time the user hits 'reject' and Telecomm receives the command.
- if (isRinging("reject")) {
+ if (mState == CallState.SIMULATED_RINGING) {
+ // This handles the case where the user manually rejects a call that's in simulated
+ // ringing. Since the call is already active on the connectionservice side, we want to
+ // hangup, not reject.
+ mOverrideDisconnectCauseCode = DisconnectCause.REJECTED;
+ if (mConnectionService != null) {
+ mConnectionService.disconnect(this);
+ } else {
+ Log.e(this, new NullPointerException(),
+ "reject call failed due to null CS callId=%s", getId());
+ }
+ Log.addEvent(this, LogUtils.Events.REQUEST_REJECT, reason);
+ } else if (isRinging("reject")) {
// Ensure video state history tracks video state at time of rejection.
mVideoStateHistory |= mVideoState;
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index ca673ad..ce9f877 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -252,6 +252,13 @@
* Used by {@link #onCallRedirectionComplete}.
*/
private Call mPendingRedirectedOutgoingCall;
+
+ /**
+ * Cached call that's been answered but will be added to mCalls pending confirmation of active
+ * status from the connection service.
+ */
+ private Call mPendingAudioProcessingCall;
+
/**
* Cached latest pending redirected call information which require user-intervention in order
* to be placed. Used by {@link #onCallRedirectionComplete}.
@@ -682,6 +689,9 @@
Log.i(this, "onCallFilteringCompleted: setting the call to silent ringing state");
incomingCall.setSilentRingingRequested(true);
addCall(incomingCall);
+ } else if (result.shouldScreenViaAudio) {
+ Log.i(this, "onCallFilteringCompleted: starting background audio processing");
+ answerCallForAudioProcessing(incomingCall);
} else {
addCall(incomingCall);
}
@@ -975,6 +985,10 @@
return mEmergencyCallHelper;
}
+ public DefaultDialerCache getDefaultDialerCache() {
+ return mDefaultDialerCache;
+ }
+
@VisibleForTesting
public PhoneAccountRegistrar.Listener getPhoneAccountListener() {
return mPhoneAccountListener;
@@ -1977,6 +1991,62 @@
}
}
+ private void answerCallForAudioProcessing(Call call) {
+ // We don't check whether the call has been added to the internal lists yet -- it's optional
+ // until the call is actually in the AUDIO_PROCESSING state.
+ Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall();
+ if (activeCall != null && activeCall != call) {
+ Log.w(this, "answerCallForAudioProcessing: another active call already exists. "
+ + "Ignoring request for audio processing and letting the incoming call "
+ + "through.");
+ // The call should already be in the RINGING state, so all we have to do is add the
+ // call to the internal tracker.
+ addCall(call);
+ return;
+ }
+ Log.d(this, "answerCallForAudioProcessing: Incoming call = %s", call);
+ mConnectionSvrFocusMgr.requestFocus(
+ call,
+ new RequestCallback(() -> {
+ synchronized (mLock) {
+ Log.d(this, "answering call %s for audio processing with cs focus", call);
+ call.answerForAudioProcessing();
+ // Skip setting the call state to ANSWERED -- that's only for calls that
+ // were answered by user intervention.
+ mPendingAudioProcessingCall = call;
+ }
+ }));
+
+ }
+
+ /**
+ * Instructs Telecom to bring a call out of the AUDIO_PROCESSING state.
+ *
+ * Used by the background audio call screener (also the default dialer) to signal that it's
+ * finished doing its thing and the user should be made aware of the call.
+ *
+ * @param call The call to manipulate
+ * @param shouldRing if true, puts the call into SIMULATED_RINGING. Otherwise, makes the call
+ * active.
+ */
+ public void exitBackgroundAudioProcessing(Call call, boolean shouldRing) {
+ if (!mCalls.contains(call)) {
+ Log.w(this, "Trying to exit audio processing on an untracked call");
+ return;
+ }
+
+ Call activeCall = getActiveCall();
+ if (activeCall != null) {
+ Log.w(this, "Ignoring exit audio processing because there's already a call active");
+ }
+
+ if (shouldRing) {
+ setCallState(call, CallState.SIMULATED_RINGING, "exitBackgroundAudioProcessing");
+ } else {
+ setCallState(call, CallState.ACTIVE, "exitBackgroundAudioProcessing");
+ }
+ }
+
/**
* Instructs Telecom to deflect 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
@@ -2482,6 +2552,15 @@
CallState.ACTIVE,
"active set explicitly for self-managed")));
} else {
+ if (mPendingAudioProcessingCall == call) {
+ if (mCalls.contains(call)) {
+ setCallState(call, CallState.AUDIO_PROCESSING, "active set explicitly");
+ } else {
+ call.setState(CallState.AUDIO_PROCESSING, "active set explicitly and adding");
+ addCall(call);
+ }
+ return;
+ }
setCallState(call, CallState.ACTIVE, "active set explicitly");
maybeMoveToSpeakerPhone(call);
ensureCallAudible();
@@ -4553,9 +4632,14 @@
// We do not update the UI until we get confirmation of the answer() through
// {@link #markCallAsActive}.
- mCall.answer(mVideoState);
if (mCall.getState() == CallState.RINGING) {
+ mCall.answer(mVideoState);
setCallState(mCall, CallState.ANSWERED, "answered");
+ } else if (mCall.getState() == CallState.SIMULATED_RINGING) {
+ // If the call's in simulated ringing, we don't have to wait for the CS --
+ // we can just declare it active.
+ setCallState(mCall, CallState.ACTIVE, "answering simulated ringing");
+ Log.addEvent(mCall, LogUtils.Events.REQUEST_SIMULATED_ACCEPT);
}
if (isSpeakerphoneAutoEnabledForVideoCalls(mVideoState)) {
mCall.setStartWithSpeakerphoneOn(true);
diff --git a/src/com/android/server/telecom/ConnectionServiceFocusManager.java b/src/com/android/server/telecom/ConnectionServiceFocusManager.java
index 9c0bfa2..fbb23f4 100644
--- a/src/com/android/server/telecom/ConnectionServiceFocusManager.java
+++ b/src/com/android/server/telecom/ConnectionServiceFocusManager.java
@@ -154,7 +154,7 @@
}
private static final int[] PRIORITY_FOCUS_CALL_STATE = new int[] {
- CallState.ACTIVE, CallState.CONNECTING, CallState.DIALING
+ CallState.ACTIVE, CallState.CONNECTING, CallState.DIALING, CallState.AUDIO_PROCESSING
};
private static final int MSG_REQUEST_FOCUS = 1;
diff --git a/src/com/android/server/telecom/InCallAdapter.java b/src/com/android/server/telecom/InCallAdapter.java
index 888010d..81314ea 100644
--- a/src/com/android/server/telecom/InCallAdapter.java
+++ b/src/com/android/server/telecom/InCallAdapter.java
@@ -326,7 +326,22 @@
@Override
public void exitBackgroundAudioProcessing(String callId, boolean shouldRing) {
- // TODO: implement this
+ try {
+ Log.startSession(LogUtils.Sessions.ICA_EXIT_AUDIO_PROCESSING, mOwnerComponentName);
+ Binder.withCleanCallingIdentity(() -> {
+ synchronized (mLock) {
+ Call call = mCallIdMapper.getCall(callId);
+ if (call != null) {
+ mCallsManager.exitBackgroundAudioProcessing(call, shouldRing);
+ } else {
+ Log.w(InCallAdapter.this,
+ "exitBackgroundAudioProcessing, unknown call id: %s", callId);
+ }
+ }
+ });
+ } finally {
+ Log.endSession();
+ }
}
@Override
diff --git a/src/com/android/server/telecom/LogUtils.java b/src/com/android/server/telecom/LogUtils.java
index f55fa2c..9b089a2 100644
--- a/src/com/android/server/telecom/LogUtils.java
+++ b/src/com/android/server/telecom/LogUtils.java
@@ -68,6 +68,8 @@
public static final String ICA_UNHOLD_CALL = "ICA.uC";
public static final String ICA_MUTE = "ICA.m";
public static final String ICA_SET_AUDIO_ROUTE = "ICA.sAR";
+ public static final String ICA_ENTER_AUDIO_PROCESSING = "ICA.enBAP";
+ public static final String ICA_EXIT_AUDIO_PROCESSING = "ICA.exBAP";
public static final String ICA_CONFERENCE = "ICA.c";
public static final String CSW_HANDLE_CREATE_CONNECTION_COMPLETE = "CSW.hCCC";
public static final String CSW_SET_ACTIVE = "CSW.sA";
@@ -101,6 +103,9 @@
public static final String REQUEST_UNHOLD = "REQUEST_UNHOLD";
public static final String REQUEST_DISCONNECT = "REQUEST_DISCONNECT";
public static final String REQUEST_ACCEPT = "REQUEST_ACCEPT";
+ public static final String REQUEST_SIMULATED_ACCEPT = "REQUEST_SIMULATED_ACCEPT";
+ public static final String REQUEST_PICKUP_FOR_AUDIO_PROCESSING =
+ "REQUEST_PICKUP_FOR_AUDIO_PROCESSING";
public static final String REQUEST_DEFLECT = "REQUEST_DEFLECT";
public static final String REQUEST_REJECT = "REQUEST_REJECT";
public static final String START_DTMF = "START_DTMF";
diff --git a/src/com/android/server/telecom/ParcelableCallUtils.java b/src/com/android/server/telecom/ParcelableCallUtils.java
index 6a66ccf..be44131 100644
--- a/src/com/android/server/telecom/ParcelableCallUtils.java
+++ b/src/com/android/server/telecom/ParcelableCallUtils.java
@@ -421,6 +421,12 @@
case CallState.SELECT_PHONE_ACCOUNT:
state = android.telecom.Call.STATE_SELECT_PHONE_ACCOUNT;
break;
+ case CallState.AUDIO_PROCESSING:
+ state = android.telecom.Call.STATE_AUDIO_PROCESSING;
+ break;
+ case CallState.SIMULATED_RINGING:
+ state = android.telecom.Call.STATE_SIMULATED_RINGING;
+ break;
}
// If we are marked as 'locally disconnecting' then mark ourselves as disconnecting instead.
diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java
index 2469c1e..11271b8 100644
--- a/src/com/android/server/telecom/Ringer.java
+++ b/src/com/android/server/telecom/Ringer.java
@@ -211,7 +211,8 @@
return false;
}
- if (foregroundCall.getState() != CallState.RINGING) {
+ if (foregroundCall.getState() != CallState.RINGING
+ && foregroundCall.getState() != CallState.SIMULATED_RINGING) {
// Its possible for bluetooth to connect JUST as a call goes active, which would mean
// the call would start ringing again.
Log.i(this, "startRinging called for non-ringing foreground callid=%s",
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index f82215f..f04c825 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -1616,9 +1616,7 @@
try {
Log.startSession("TSI.aORTCCA");
enforceModifyPermission();
- if (!Build.IS_USERDEBUG) {
- throw new SecurityException("Test-only API.");
- }
+ enforceShellOnly(Binder.getCallingUid(), "addOrRemoveTestCallCompanionApp");
synchronized (mLock) {
long token = Binder.clearCallingIdentity();
try {
diff --git a/src/com/android/server/telecom/callfiltering/CallFilteringResult.java b/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
index 028fbf5..afd145e 100644
--- a/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
+++ b/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
@@ -27,6 +27,7 @@
private boolean mShouldAddToCallLog;
private boolean mShouldShowNotification;
private boolean mShouldSilence = false;
+ private boolean mShouldScreenViaAudio = false;
private int mCallBlockReason = Calls.BLOCK_REASON_NOT_BLOCKED;
private CharSequence mCallScreeningAppName = null;
private String mCallScreeningComponentName = null;
@@ -61,6 +62,11 @@
return this;
}
+ public Builder setShouldScreenViaAudio(boolean shouldScreenViaAudio) {
+ mShouldScreenViaAudio = shouldScreenViaAudio;
+ return this;
+ }
+
public Builder setCallScreeningAppName(CharSequence callScreeningAppName) {
mCallScreeningAppName = callScreeningAppName;
return this;
@@ -73,8 +79,8 @@
public CallFilteringResult build() {
return new CallFilteringResult(mShouldAllowCall, mShouldReject, mShouldSilence,
- mShouldAddToCallLog, mShouldShowNotification, mCallBlockReason,
- mCallScreeningAppName, mCallScreeningComponentName);
+ mShouldAddToCallLog, mShouldShowNotification, mShouldScreenViaAudio,
+ mCallBlockReason, mCallScreeningAppName, mCallScreeningComponentName);
}
}
@@ -82,19 +88,22 @@
public boolean shouldReject;
public boolean shouldSilence;
public boolean shouldAddToCallLog;
+ public boolean shouldScreenViaAudio = false;
public boolean shouldShowNotification;
public int mCallBlockReason;
public CharSequence mCallScreeningAppName;
public String mCallScreeningComponentName;
private CallFilteringResult(boolean shouldAllowCall, boolean shouldReject, boolean
- shouldSilence, boolean shouldAddToCallLog, boolean shouldShowNotification, int
- callBlockReason, CharSequence callScreeningAppName, String callScreeningComponentName) {
+ shouldSilence, boolean shouldAddToCallLog, boolean shouldShowNotification,
+ boolean shouldScreenViaAudio, int callBlockReason, CharSequence callScreeningAppName,
+ String callScreeningComponentName) {
this.shouldAllowCall = shouldAllowCall;
this.shouldReject = shouldReject;
this.shouldSilence = shouldSilence;
this.shouldAddToCallLog = shouldAddToCallLog;
this.shouldShowNotification = shouldShowNotification;
+ this.shouldScreenViaAudio = shouldScreenViaAudio;
this.mCallBlockReason = callBlockReason;
this.mCallScreeningAppName = callScreeningAppName;
this.mCallScreeningComponentName = callScreeningComponentName;
@@ -141,6 +150,7 @@
.setShouldSilence(shouldSilence || other.shouldSilence)
.setShouldAddToCallLog(shouldAddToCallLog && other.shouldAddToCallLog)
.setShouldShowNotification(shouldShowNotification && other.shouldShowNotification)
+ .setShouldScreenViaAudio(shouldScreenViaAudio || other.shouldScreenViaAudio)
.build();
}
@@ -164,6 +174,7 @@
.setShouldSilence(shouldSilence || other.shouldSilence)
.setShouldAddToCallLog(shouldAddToCallLog && other.shouldAddToCallLog)
.setShouldShowNotification(shouldShowNotification && other.shouldShowNotification)
+ .setShouldScreenViaAudio(shouldScreenViaAudio || other.shouldScreenViaAudio)
.setCallBlockReason(callBlockReason)
.setCallScreeningAppName(callScreeningAppName)
.setCallScreeningComponentName(callScreeningComponentName)
@@ -226,6 +237,10 @@
sb.append("Ignore");
}
+ if (shouldScreenViaAudio) {
+ sb.append(", audio processing");
+ }
+
if (shouldAddToCallLog) {
sb.append(", logged");
}
diff --git a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
index 9ea8d70..7e0f6b0 100644
--- a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
+++ b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
@@ -181,7 +181,31 @@
@Override
public void screenCallFurther(String callId) {
- // TODO: implement this
+ Log.startSession("CSCR.sCF");
+ Binder.withCleanCallingIdentity(() -> {
+ synchronized (mTelecomLock) {
+ // This is only allowed if the caller is also the default dialer.
+ if (!mCallsManager.getDefaultDialerCache().isDefaultOrSystemDialer(
+ mPackageName, UserHandle.USER_CURRENT)) {
+ throw new SecurityException("Only the default/system dialer may request"
+ + " screening via background call audio");
+ }
+ // TODO: add permissions check for the additional role-based permission
+
+ Log.d(this, "screenCallFurther: %s", callId);
+ if (mCall != null && mCall.getId().equals(callId)) {
+ mResult = new CallFilteringResult.Builder()
+ .setShouldAllowCall(true)
+ .setShouldReject(false)
+ .setShouldSilence(false)
+ .setShouldScreenViaAudio(true)
+ .build();
+ } else {
+ Log.w(this, "screenCallFurther, unknown call id: %s", callId);
+ }
+ finishCallScreening();
+ }
+ });
}
}
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index fdd1d89..6da4723 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -537,13 +537,13 @@
@Test
public void testUnholdCallWhenOngoingCallCanNotBeHeldAndFromDifferentConnectionService() {
// GIVEN a CallsManager with ongoing call, and this call can not be held
- Call ongoingCall = addSpyCall(SIM_1_HANDLE);
+ Call ongoingCall = addSpyCall(SIM_1_HANDLE, CallState.ACTIVE);
doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
// and a held call which has different ConnectionService
- Call heldCall = addSpyCall(VOIP_1_HANDLE);
+ Call heldCall = addSpyCall(VOIP_1_HANDLE, CallState.ON_HOLD);
// WHEN unhold the held call
mCallsManager.unholdCall(heldCall);
@@ -561,14 +561,14 @@
public void testUnholdCallWhenOngoingEmergCallCanNotBeHeldAndFromDifferentConnectionService() {
// GIVEN a CallsManager with ongoing call, and this call can not be held, but it also an
// emergency call.
- Call ongoingCall = addSpyCall(SIM_1_HANDLE);
+ Call ongoingCall = addSpyCall(SIM_1_HANDLE, CallState.ACTIVE);
doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
doReturn(true).when(ongoingCall).isEmergencyCall();
when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
// and a held call which has different ConnectionService
- Call heldCall = addSpyCall(VOIP_1_HANDLE);
+ Call heldCall = addSpyCall(VOIP_1_HANDLE, CallState.ON_HOLD);
// WHEN unhold the held call
mCallsManager.unholdCall(heldCall);
@@ -584,13 +584,13 @@
@Test
public void testUnholdCallWhenOngoingCallCanNotBeHeldAndHasSameConnectionService() {
// GIVEN a CallsManager with ongoing call, and this call can not be held
- Call ongoingCall = addSpyCall(SIM_1_HANDLE);
+ Call ongoingCall = addSpyCall(SIM_1_HANDLE, CallState.ACTIVE);
doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
// and a held call which has the same ConnectionService
- Call heldCall = addSpyCall(SIM_2_HANDLE);
+ Call heldCall = addSpyCall(SIM_2_HANDLE, CallState.ON_HOLD);
// WHEN unhold the held call
mCallsManager.unholdCall(heldCall);
@@ -613,7 +613,7 @@
when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
// WHEN answer an incoming call
- Call incomingCall = addSpyCall();
+ Call incomingCall = addSpyCall(CallState.RINGING);
mCallsManager.answerCall(incomingCall, VideoProfile.STATE_AUDIO_ONLY);
// THEN the ongoing call is held and the focus request for incoming call is sent
@@ -628,12 +628,12 @@
@Test
public void testAnswerCallWhenOngoingHasSameConnectionService() {
// GIVEN a CallsManager with ongoing call, and this call can not be held
- Call ongoingCall = addSpyCall(SIM_1_HANDLE);
+ Call ongoingCall = addSpyCall(SIM_1_HANDLE, CallState.ACTIVE);
doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
// WHEN answer an incoming call
- Call incomingCall = addSpyCall(VOIP_1_HANDLE);
+ Call incomingCall = addSpyCall(VOIP_1_HANDLE, CallState.RINGING);
mCallsManager.answerCall(incomingCall, VideoProfile.STATE_AUDIO_ONLY);
// THEN nothing happened on the ongoing call and the focus request for incoming call is sent
@@ -647,13 +647,13 @@
@Test
public void testAnswerCallWhenOngoingHasDifferentConnectionService() {
// GIVEN a CallsManager with ongoing call, and this call can not be held
- Call ongoingCall = addSpyCall(SIM_1_HANDLE);
+ Call ongoingCall = addSpyCall(SIM_1_HANDLE, CallState.ACTIVE);
doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
// WHEN answer an incoming call
- Call incomingCall = addSpyCall(VOIP_1_HANDLE);
+ Call incomingCall = addSpyCall(VOIP_1_HANDLE, CallState.RINGING);
mCallsManager.answerCall(incomingCall, VideoProfile.STATE_AUDIO_ONLY);
// THEN the ongoing call is disconnected and the focus request for incoming call is sent
@@ -668,14 +668,14 @@
@Test
public void testAnswerCallWhenOngoingHasDifferentConnectionServiceButIsEmerg() {
// GIVEN a CallsManager with ongoing call, and this call can not be held
- Call ongoingCall = addSpyCall(SIM_1_HANDLE);
+ Call ongoingCall = addSpyCall(SIM_1_HANDLE, CallState.ACTIVE);
doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
doReturn(true).when(ongoingCall).isEmergencyCall();
when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
// WHEN answer an incoming call
- Call incomingCall = addSpyCall(VOIP_1_HANDLE);
+ Call incomingCall = addSpyCall(VOIP_1_HANDLE, CallState.RINGING);
mCallsManager.answerCall(incomingCall, VideoProfile.STATE_AUDIO_ONLY);
// THEN the ongoing call is not disconnected
@@ -691,21 +691,21 @@
public void testAnswerCallWhenMultipleHeldCallsExisted() {
// Given an ongoing call and held call with the ConnectionService connSvr1. The
// ConnectionService connSvr1 can handle one held call
- Call ongoingCall = addSpyCall(SIM_1_HANDLE);
+ Call ongoingCall = addSpyCall(SIM_1_HANDLE, CallState.ACTIVE);
doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
doReturn(CallState.ACTIVE).when(ongoingCall).getState();
when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
- Call heldCall = addSpyCall(SIM_1_HANDLE);
+ Call heldCall = addSpyCall(SIM_1_HANDLE, CallState.ON_HOLD);
doReturn(CallState.ON_HOLD).when(heldCall).getState();
// and other held call has difference ConnectionService
- Call heldCall2 = addSpyCall(VOIP_1_HANDLE);
+ Call heldCall2 = addSpyCall(VOIP_1_HANDLE, CallState.ON_HOLD);
doReturn(CallState.ON_HOLD).when(heldCall2).getState();
// WHEN answer an incoming call which ConnectionService is connSvr1
- Call incomingCall = addSpyCall(SIM_1_HANDLE);
+ Call incomingCall = addSpyCall(SIM_1_HANDLE, CallState.RINGING);
doReturn(true).when(incomingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
mCallsManager.answerCall(incomingCall, VideoProfile.STATE_AUDIO_ONLY);
@@ -731,7 +731,7 @@
// GIVEN a CallsManager with no ongoing call.
// WHEN answer an incoming call
- Call incomingCall = addSpyCall();
+ Call incomingCall = addSpyCall(CallState.RINGING);
mCallsManager.answerCall(incomingCall, VideoProfile.STATE_AUDIO_ONLY);
// THEN the focus request for incoming call is sent
@@ -747,7 +747,7 @@
// GIVEN a CallsManager with no ongoing call.
// WHEN answer an already active call
- Call incomingCall = addSpyCall();
+ Call incomingCall = addSpyCall(CallState.RINGING);
mCallsManager.answerCall(incomingCall, VideoProfile.STATE_AUDIO_ONLY);
// THEN the focus request for incoming call is sent
@@ -756,21 +756,21 @@
// and the incoming call is answered.
verify(incomingCall).answer(VideoProfile.STATE_AUDIO_ONLY);
- // and the incoming call's state is still ACTIVE
- assertEquals(CallState.ACTIVE, incomingCall.getState());
+ // and the incoming call's state is now ANSWERED
+ assertEquals(CallState.ANSWERED, incomingCall.getState());
}
@SmallTest
@Test
public void testSetActiveCallWhenOngoingCallCanNotBeHeldAndFromDifferentConnectionService() {
// GIVEN a CallsManager with ongoing call, and this call can not be held
- Call ongoingCall = addSpyCall(SIM_1_HANDLE);
+ Call ongoingCall = addSpyCall(SIM_1_HANDLE, CallState.ACTIVE);
doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
doReturn(ongoingCall).when(mConnectionSvrFocusMgr).getCurrentFocusCall();
// and a new self-managed call which has different ConnectionService
- Call newCall = addSpyCall(VOIP_1_HANDLE);
+ Call newCall = addSpyCall(VOIP_1_HANDLE, CallState.ACTIVE);
doReturn(true).when(newCall).isSelfManaged();
// WHEN active the new call
@@ -788,13 +788,13 @@
@Test
public void testSetActiveCallWhenOngoingCallCanNotBeHeldAndHasSameConnectionService() {
// GIVEN a CallsManager with ongoing call, and this call can not be held
- Call ongoingCall = addSpyCall(SIM_1_HANDLE);
+ Call ongoingCall = addSpyCall(SIM_1_HANDLE, CallState.ACTIVE);
doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
// and a new self-managed call which has the same ConnectionService
- Call newCall = addSpyCall(SIM_1_HANDLE);
+ Call newCall = addSpyCall(SIM_1_HANDLE, CallState.ACTIVE);
doReturn(true).when(newCall).isSelfManaged();
// WHEN active the new call
@@ -836,7 +836,7 @@
@Test
public void testDisconnectDialingCallOnIncoming() {
// GIVEN a CallsManager with a self-managed call which is dialing, and this call can be held
- Call ongoingCall = addSpyCall(SELF_MANAGED_HANDLE);
+ Call ongoingCall = addSpyCall(SELF_MANAGED_HANDLE, CallState.DIALING);
ongoingCall.setState(CallState.DIALING, "test");
doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
@@ -869,7 +869,7 @@
@Test
public void testNoFilteringOfSelfManagedCalls() {
// GIVEN an incoming call which is self managed.
- Call incomingCall = addSpyCall(SELF_MANAGED_HANDLE);
+ Call incomingCall = addSpyCall(SELF_MANAGED_HANDLE, CallState.NEW);
doReturn(false).when(incomingCall).can(Connection.CAPABILITY_HOLD);
doReturn(false).when(incomingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
doReturn(true).when(incomingCall).isSelfManaged();
@@ -986,7 +986,7 @@
@Test
public void testNoFilteringOfCallsWhenPhoneAccountRequestsSkipped() {
// GIVEN an incoming call which is from a PhoneAccount that requested to skip filtering.
- Call incomingCall = addSpyCall(SIM_1_HANDLE);
+ Call incomingCall = addSpyCall(SIM_1_HANDLE, CallState.NEW);
Bundle extras = new Bundle();
extras.putBoolean(PhoneAccount.EXTRA_SKIP_CALL_FILTERING, true);
PhoneAccount skipRequestedAccount = new PhoneAccount.Builder(SIM_2_HANDLE, "Skipper")
@@ -1098,10 +1098,14 @@
}
private Call addSpyCall() {
- return addSpyCall(SIM_2_HANDLE);
+ return addSpyCall(SIM_2_HANDLE, CallState.ACTIVE);
}
- private Call addSpyCall(PhoneAccountHandle targetPhoneAccount) {
+ private Call addSpyCall(int initialState) {
+ return addSpyCall(SIM_2_HANDLE, initialState);
+ }
+
+ private Call addSpyCall(PhoneAccountHandle targetPhoneAccount, int initialState) {
Call ongoingCall = new Call(String.format("TC@%d", sCallId++), /* callId */
mContext,
mCallsManager,
@@ -1116,7 +1120,7 @@
false /* shouldAttachToExistingConnection*/,
false /* isConference */,
mClockProxy);
- ongoingCall.setState(CallState.ACTIVE, "just cuz");
+ ongoingCall.setState(initialState, "just cuz");
Call callSpy = Mockito.spy(ongoingCall);
// Mocks some methods to not call the real method.