Add ANSWERED state to call states
Add an ANSWERED state, indicating that the in-call service has picked up
the call but the connection service hasn't yet marked it active.
Also remove the old audio hack that was used for answered-but-not-active
IMS calls -- it can be gated on the call state now.
Change-Id: Ic91299762354efbf1899a70916d793e4c62ba07e
Fixes: 28349393
Test: manual, unit
diff --git a/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java b/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java
index 804909c..9c70666 100644
--- a/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java
+++ b/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java
@@ -875,6 +875,7 @@
return CALL_STATE_HELD;
case CallState.RINGING:
+ case CallState.ANSWERED:
if (isForegroundCall) {
return CALL_STATE_INCOMING;
} else {
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index d975a4f..6cedc4f 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -943,6 +943,9 @@
case CallState.RINGING:
event = LogUtils.Events.SET_RINGING;
break;
+ case CallState.ANSWERED:
+ event = LogUtils.Events.SET_ANSWERED;
+ break;
}
if (event != null) {
// The string data should be just the tag.
@@ -1980,6 +1983,7 @@
switch (mState) {
case CallState.NEW:
case CallState.RINGING:
+ case CallState.ANSWERED:
case CallState.DISCONNECTED:
case CallState.ABORTED:
return false;
@@ -3049,13 +3053,13 @@
/**
* Sets the video history based on the state and state transitions of the call. Always add the
* current video state to the video state history during a call transition except for the
- * transitions DIALING->ACTIVE and RINGING->ACTIVE. In these cases, clear the history. If a
+ * transitions DIALING->ACTIVE and RINGING->ANSWERED. In these cases, clear the history. If a
* call starts dialing/ringing as a VT call and gets downgraded to audio, we need to record
* the history as an audio call.
*/
private void updateVideoHistoryViaState(int oldState, int newState) {
- if ((oldState == CallState.DIALING || oldState == CallState.RINGING)
- && newState == CallState.ACTIVE) {
+ if ((oldState == CallState.DIALING && newState == CallState.ACTIVE)
+ || (oldState == CallState.RINGING && newState == CallState.ANSWERED)) {
mVideoStateHistory = mVideoState;
}
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index 7bc2519..8eb4756 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -105,11 +105,10 @@
Log.d(LOG_TAG, "Call state changed for TC@%s: %s -> %s", call.getId(),
CallState.toString(oldState), CallState.toString(newState));
- for (int i = 0; i < mCallStateToCalls.size(); i++) {
- mCallStateToCalls.valueAt(i).remove(call);
- }
- if (mCallStateToCalls.get(newState) != null) {
- mCallStateToCalls.get(newState).add(call);
+ removeCallFromAllBins(call);
+ HashSet<Call> newBinForCall = getBinForCall(call);
+ if (newBinForCall != null) {
+ newBinForCall.add(call);
}
updateForegroundCall();
@@ -148,8 +147,9 @@
Log.d(LOG_TAG, "Call added with id TC@%s in state %s", call.getId(),
CallState.toString(call.getState()));
- if (mCallStateToCalls.get(call.getState()) != null) {
- mCallStateToCalls.get(call.getState()).add(call);
+ HashSet<Call> newBinForCall = getBinForCall(call);
+ if (newBinForCall != null) {
+ newBinForCall.add(call);
}
updateForegroundCall();
mCalls.add(call);
@@ -168,9 +168,7 @@
Log.d(LOG_TAG, "Call removed with id TC@%s in state %s", call.getId(),
CallState.toString(call.getState()));
- for (int i = 0; i < mCallStateToCalls.size(); i++) {
- mCallStateToCalls.valueAt(i).remove(call);
- }
+ removeCallFromAllBins(call);
updateForegroundCall();
mCalls.remove(call);
@@ -226,24 +224,6 @@
return;
}
- // This is called after the UI answers the call, but before the connection service
- // sets the call to active. Only thing to handle for mode here is the audio speedup thing.
-
- if (call.can(android.telecom.Call.Details.CAPABILITY_SPEED_UP_MT_AUDIO)) {
- if (mForegroundCall == call) {
- Log.i(LOG_TAG, "Invoking the MT_AUDIO_SPEEDUP mechanism. Transitioning into " +
- "an active in-call audio state before connection service has " +
- "connected the call.");
- if (mCallStateToCalls.get(call.getState()) != null) {
- mCallStateToCalls.get(call.getState()).remove(call);
- }
- mActiveDialingOrConnectingCalls.add(call);
- mCallAudioModeStateMachine.sendMessageWithArgs(
- CallAudioModeStateMachine.MT_AUDIO_SPEEDUP_FOR_RINGING_CALL,
- makeArgsForModeStateMachine());
- }
- }
-
// Turn off mute when a new incoming call is answered iff it's not a handover.
if (!call.isHandoverInProgress()) {
mute(false /* shouldMute */);
@@ -325,10 +305,7 @@
onCallAdded(call);
} else {
// The call joined a conference, so stop tracking it.
- if (mCallStateToCalls.get(call.getState()) != null) {
- mCallStateToCalls.get(call.getState()).remove(call);
- }
-
+ removeCallFromAllBins(call);
updateForegroundCall();
mCalls.remove(call);
}
@@ -590,6 +567,11 @@
onCallEnteringActiveDialingOrConnecting();
playRingbackForCall(call);
break;
+ case CallState.ANSWERED:
+ if (call.can(android.telecom.Call.Details.CAPABILITY_SPEED_UP_MT_AUDIO)) {
+ onCallEnteringActiveDialingOrConnecting();
+ }
+ break;
}
}
@@ -680,6 +662,24 @@
Log.createSubsession());
}
+ private HashSet<Call> getBinForCall(Call call) {
+ if (call.getState() == CallState.ANSWERED) {
+ // If the call has the speed-up-mt-audio capability, treat answered state as active
+ // for audio purposes.
+ if (call.can(android.telecom.Call.Details.CAPABILITY_SPEED_UP_MT_AUDIO)) {
+ return mActiveDialingOrConnectingCalls;
+ }
+ return mRingingCalls;
+ }
+ return mCallStateToCalls.get(call.getState());
+ }
+
+ private void removeCallFromAllBins(Call call) {
+ for (int i = 0; i < mCallStateToCalls.size(); i++) {
+ mCallStateToCalls.valueAt(i).remove(call);
+ }
+ }
+
private void playToneForDisconnectedCall(Call call) {
// If this call is being disconnected as a result of being handed over to another call,
// we will not play a disconnect tone.
diff --git a/src/com/android/server/telecom/CallAudioModeStateMachine.java b/src/com/android/server/telecom/CallAudioModeStateMachine.java
index 990a453..92e2973 100644
--- a/src/com/android/server/telecom/CallAudioModeStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioModeStateMachine.java
@@ -86,7 +86,6 @@
public static final int NEW_ACTIVE_OR_DIALING_CALL = 2001;
public static final int NEW_RINGING_CALL = 2002;
public static final int NEW_HOLDING_CALL = 2003;
- public static final int MT_AUDIO_SPEEDUP_FOR_RINGING_CALL = 2004;
public static final int TONE_STARTED_PLAYING = 3001;
public static final int TONE_STOPPED_PLAYING = 3002;
@@ -109,7 +108,6 @@
put(NEW_ACTIVE_OR_DIALING_CALL, "NEW_ACTIVE_OR_DIALING_CALL");
put(NEW_RINGING_CALL, "NEW_RINGING_CALL");
put(NEW_HOLDING_CALL, "NEW_HOLDING_CALL");
- put(MT_AUDIO_SPEEDUP_FOR_RINGING_CALL, "MT_AUDIO_SPEEDUP_FOR_RINGING_CALL");
put(TONE_STARTED_PLAYING, "TONE_STARTED_PLAYING");
put(TONE_STOPPED_PLAYING, "TONE_STOPPED_PLAYING");
put(FOREGROUND_VOIP_MODE_CHANGE, "FOREGROUND_VOIP_MODE_CHANGE");
@@ -279,15 +277,6 @@
" Args are: " + args.toString());
transitionTo(mOtherFocusState);
return HANDLED;
- case MT_AUDIO_SPEEDUP_FOR_RINGING_CALL:
- // This happens when an IMS call is answered by the in-call UI. Special case
- // that we have to deal with for some reason.
-
- // The IMS audio routing may be via modem or via RTP stream. In case via RTP
- // stream, the state machine should transit to mVoipCallFocusState.
- transitionTo(args.foregroundCallIsVoip
- ? mVoipCallFocusState : mSimCallFocusState);
- return HANDLED;
case RINGER_MODE_CHANGE: {
Log.i(LOG_TAG, "RINGING state, received RINGER_MODE_CHANGE");
tryStartRinging();
diff --git a/src/com/android/server/telecom/CallState.java b/src/com/android/server/telecom/CallState.java
index 0aa928f..3f52166 100644
--- a/src/com/android/server/telecom/CallState.java
+++ b/src/com/android/server/telecom/CallState.java
@@ -112,6 +112,12 @@
*/
public static final int PULLING = 10;
+ /**
+ * Indicates that an incoming call has been answered by the in-call UI, but Telephony hasn't yet
+ * set the call to active.
+ */
+ public static final int ANSWERED = 11;
+
public static String toString(int callState) {
switch (callState) {
case NEW:
@@ -136,6 +142,8 @@
return "DISCONNECTING";
case PULLING:
return "PULLING";
+ case ANSWERED:
+ return "ANSWERED";
default:
return "UNKNOWN";
}
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 528c7af..897134a 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -193,12 +193,13 @@
*/
public static final int[] ONGOING_CALL_STATES =
{CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING, CallState.PULLING, CallState.ACTIVE,
- CallState.ON_HOLD, CallState.RINGING};
+ CallState.ON_HOLD, CallState.RINGING, CallState.ANSWERED};
private static final int[] ANY_CALL_STATE =
{CallState.NEW, CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING,
CallState.RINGING, CallState.ACTIVE, CallState.ON_HOLD, CallState.DISCONNECTED,
- CallState.ABORTED, CallState.DISCONNECTING, CallState.PULLING};
+ CallState.ABORTED, CallState.DISCONNECTING, CallState.PULLING,
+ CallState.ANSWERED};
public static final String TELECOM_CALL_ID_PREFIX = "TC@";
@@ -2106,7 +2107,7 @@
}
boolean hasRingingCall() {
- return getFirstCallWithState(CallState.RINGING) != null;
+ return getFirstCallWithState(CallState.RINGING, CallState.ANSWERED) != null;
}
boolean onMediaButton(int type) {
@@ -2191,7 +2192,7 @@
@VisibleForTesting
public Call getRingingCall() {
- return getFirstCallWithState(CallState.RINGING);
+ return getFirstCallWithState(CallState.RINGING, CallState.ANSWERED);
}
public Call getActiveCall() {
@@ -2747,13 +2748,13 @@
private boolean hasMaximumManagedRingingCalls(Call exceptCall) {
return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(false /* isSelfManaged */, exceptCall,
- null /* phoneAccountHandle */, CallState.RINGING);
+ null /* phoneAccountHandle */, CallState.RINGING, CallState.ANSWERED);
}
private boolean hasMaximumSelfManagedRingingCalls(Call exceptCall,
PhoneAccountHandle phoneAccountHandle) {
return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(true /* isSelfManaged */, exceptCall,
- phoneAccountHandle, CallState.RINGING);
+ phoneAccountHandle, CallState.RINGING, CallState.ANSWERED);
}
private boolean hasMaximumOutgoingCalls(Call exceptCall) {
@@ -3893,6 +3894,7 @@
// We do not update the UI until we get confirmation of the answer() through
// {@link #markCallAsActive}.
mCall.answer(mVideoState);
+ setCallState(mCall, CallState.ANSWERED, "answered");
if (isSpeakerphoneAutoEnabledForVideoCalls(mVideoState)) {
mCall.setStartWithSpeakerphoneOn(true);
}
diff --git a/src/com/android/server/telecom/LogUtils.java b/src/com/android/server/telecom/LogUtils.java
index c4ccd8b..388ac95 100644
--- a/src/com/android/server/telecom/LogUtils.java
+++ b/src/com/android/server/telecom/LogUtils.java
@@ -65,6 +65,7 @@
public static final String SET_ACTIVE = "SET_ACTIVE";
public static final String SET_HOLD = "SET_HOLD";
public static final String SET_RINGING = "SET_RINGING";
+ public static final String SET_ANSWERED = "SET_ANSWERED";
public static final String SET_DISCONNECTED = "SET_DISCONNECTED";
public static final String SET_DISCONNECTING = "SET_DISCONNECTING";
public static final String SET_SELECT_PHONE_ACCOUNT = "SET_SELECT_PHONE_ACCOUNT";
diff --git a/src/com/android/server/telecom/ParcelableCallUtils.java b/src/com/android/server/telecom/ParcelableCallUtils.java
index 77598c8..dc43095 100644
--- a/src/com/android/server/telecom/ParcelableCallUtils.java
+++ b/src/com/android/server/telecom/ParcelableCallUtils.java
@@ -226,6 +226,8 @@
state = android.telecom.Call.STATE_HOLDING;
break;
case CallState.RINGING:
+ case CallState.ANSWERED:
+ // TODO: does in-call UI need to see ANSWERED?
state = android.telecom.Call.STATE_RINGING;
break;
case CallState.SELECT_PHONE_ACCOUNT:
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java b/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
index 5e23dcc..e4b22ec 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
@@ -198,13 +198,16 @@
Call call = createIncomingCall();
when(call.can(android.telecom.Call.Details.CAPABILITY_SPEED_UP_MT_AUDIO))
.thenReturn(true);
+ when(call.getState()).thenReturn(CallState.ANSWERED);
ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor =
ArgumentCaptor.forClass(CallAudioModeStateMachine.MessageArgs.class);
// Answer the incoming call
- mCallAudioManager.onIncomingCallAnswered(call);
+ mCallAudioManager.onCallStateChanged(call, CallState.RINGING, CallState.ANSWERED);
verify(mCallAudioModeStateMachine).sendMessageWithArgs(
- eq(CallAudioModeStateMachine.MT_AUDIO_SPEEDUP_FOR_RINGING_CALL), captor.capture());
+ eq(CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL), captor.capture());
+ verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+ eq(CallAudioModeStateMachine.NO_MORE_RINGING_CALLS), captor.capture());
CallAudioModeStateMachine.MessageArgs correctArgs =
new CallAudioModeStateMachine.MessageArgs(
true, // hasActiveOrDialingCalls
@@ -217,7 +220,7 @@
assertMessageArgEquality(correctArgs, captor.getValue());
assertMessageArgEquality(correctArgs, captor.getValue());
when(call.getState()).thenReturn(CallState.ACTIVE);
- mCallAudioManager.onCallStateChanged(call, CallState.RINGING, CallState.ACTIVE);
+ mCallAudioManager.onCallStateChanged(call, CallState.ANSWERED, CallState.ACTIVE);
disconnectCall(call);
stopTone();
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index 5e87b4c..ad00456 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -988,8 +988,9 @@
mInCallServiceFixtureX.mInCallAdapter
.answerCall(ids.mCallId, videoState);
- // Wait on the main looper (due to the CS focus manager)
- waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
+ // Wait on the CS focus manager handler
+ waitForHandlerAction(mTelecomSystem.getCallsManager()
+ .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT);
if (!VideoProfile.isVideo(videoState)) {
verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))