Fix answering waiting call simultaneously with active call disconnect
When the user answers a call-waiting call at the same time as the remote
end disconnects the formerly-active call, an error may occur where the
in-call ui is left in an inconsistent state and the waiting call is
never answered.
Normally, when a call-waiting call is answered, the active call will
first be held. Then, after the modem reports that as successful,
onCallHeld will issue the EVENT_RESUME_BACKGROUND message to answer the
call-waiting call. However, if the remote end disconnects while the user
is answering, onCallTerminated will be called instead.
This change alters onCallTerminated to issue the EVENT_RESUME_BACKGROUND
message if it occurs in the middle of a call-switch.
Change-Id: Icb757274ad63af46ebff5028dc484f8497777987
Fix: 31684640
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index 6f5fa3e..062743c 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -776,8 +776,16 @@
// Swap the ImsCalls pointed to by the foreground and background ImsPhoneCalls.
// If hold or resume later fails, we will swap them back.
+ boolean switchingWithWaitingCall = mBackgroundCall.getImsCall() == null &&
+ mRingingCall != null &&
+ mRingingCall.getState() == ImsPhoneCall.State.WAITING;
+
mSwitchingFgAndBgCalls = true;
- mCallExpectedToResume = mBackgroundCall.getImsCall();
+ if (switchingWithWaitingCall) {
+ mCallExpectedToResume = mRingingCall.getImsCall();
+ } else {
+ mCallExpectedToResume = mBackgroundCall.getImsCall();
+ }
mForegroundCall.switchWith(mBackgroundCall);
// Hold the foreground call; once the foreground call is held, the background call will
@@ -788,6 +796,7 @@
// If there is no background call to resume, then don't expect there to be a switch.
if (mCallExpectedToResume == null) {
+ log("mCallExpectedToResume is null");
mSwitchingFgAndBgCalls = false;
}
} catch (ImsException e) {
@@ -1446,6 +1455,16 @@
public void onCallStarted(ImsCall imsCall) {
if (DBG) log("onCallStarted");
+ if (mSwitchingFgAndBgCalls) {
+ // If we put a call on hold to answer an incoming call, we should reset the
+ // variables that keep track of the switch here.
+ if (mCallExpectedToResume != null && mCallExpectedToResume == imsCall) {
+ if (DBG) log("onCallStarted: starting a call as a result of a switch.");
+ mSwitchingFgAndBgCalls = false;
+ mCallExpectedToResume = null;
+ }
+ }
+
mPendingMO = null;
processCallStateChange(imsCall, ImsPhoneCall.State.ACTIVE,
DisconnectCause.NOT_DISCONNECTED);
@@ -1483,6 +1502,16 @@
public void onCallStartFailed(ImsCall imsCall, ImsReasonInfo reasonInfo) {
if (DBG) log("onCallStartFailed reasonCode=" + reasonInfo.getCode());
+ if (mSwitchingFgAndBgCalls) {
+ // If we put a call on hold to answer an incoming call, we should reset the
+ // variables that keep track of the switch here.
+ if (mCallExpectedToResume != null && mCallExpectedToResume == imsCall) {
+ if (DBG) log("onCallStarted: starting a call as a result of a switch.");
+ mSwitchingFgAndBgCalls = false;
+ mCallExpectedToResume = null;
+ }
+ }
+
if (mPendingMO != null) {
// To initiate dialing circuit-switched call
if (reasonInfo.getCode() == ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED
@@ -1591,7 +1620,12 @@
}
// This call terminated in the midst of a switch after the other call was held, so
// resume it back to ACTIVE state since the switch failed.
- if (mForegroundCall.getState() == ImsPhoneCall.State.HOLDING) {
+ log("onCallTerminated: foreground call in state " + mForegroundCall.getState() +
+ " and ringing call in state " + (mRingingCall == null ? "null" :
+ mRingingCall.getState().toString()));
+
+ if (mForegroundCall.getState() == ImsPhoneCall.State.HOLDING ||
+ mRingingCall.getState() == ImsPhoneCall.State.WAITING) {
sendEmptyMessage(EVENT_RESUME_BACKGROUND);
mSwitchingFgAndBgCalls = false;
mCallExpectedToResume = null;