Merge "Retry sending hangup command on new connection after redial completes" into sc-dev
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index abc9613..53e923e 100755
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -165,32 +165,7 @@
                     AsyncResult ar = (AsyncResult) msg.obj;
                     com.android.internal.telephony.Connection connection =
                          (com.android.internal.telephony.Connection) ar.result;
-                    if (connection == null) {
-                        setDisconnected(DisconnectCauseUtil
-                                .toTelecomDisconnectCause(DisconnectCause.OUT_OF_NETWORK,
-                                        "handover failure, no connection"));
-                        close();
-                        break;
-                    }
-                    if (mOriginalConnection != null) {
-                        if (connection != null &&
-                            ((connection.getAddress() != null &&
-                            mOriginalConnection.getAddress() != null &&
-                            mOriginalConnection.getAddress().equals(connection.getAddress())) ||
-                            connection.getState() == mOriginalConnection.getStateBeforeHandover())) {
-                            Log.i(TelephonyConnection.this, "Setting original connection after"
-                                    + " handover or redial, current original connection="
-                                    + mOriginalConnection.toString()
-                                    + ", new original connection="
-                                    + connection.toString());
-                            setOriginalConnection(connection);
-                            mWasImsConnection = false;
-                        }
-                    } else {
-                        Log.w(TelephonyConnection.this,
-                                what + ": mOriginalConnection==null --"
-                                        + " invalid state (not cleaned up)");
-                    }
+                    onOriginalConnectionRedialed(connection);
                     break;
                 case MSG_RINGBACK_TONE:
                     Log.v(TelephonyConnection.this, "MSG_RINGBACK_TONE");
@@ -360,6 +335,54 @@
     private final Messenger mHandlerMessenger = new Messenger(mHandler);
 
     /**
+     * The underlying telephony Connection has been redialed on a different domain (CS or IMS).
+     * Track the new telephony Connection and set back up appropriate callbacks.
+     * @param connection The new telephony Connection associated with this TelephonyConnection.
+     */
+    @VisibleForTesting
+    public void onOriginalConnectionRedialed(
+            com.android.internal.telephony.Connection connection) {
+        if (connection == null) {
+            setDisconnected(DisconnectCauseUtil
+                    .toTelecomDisconnectCause(DisconnectCause.OUT_OF_NETWORK,
+                            "handover failure, no connection"));
+            close();
+            return;
+        }
+        if (mOriginalConnection != null) {
+            if ((connection.getAddress() != null
+                    && mOriginalConnection.getAddress() != null
+                    && mOriginalConnection.getAddress().equals(connection.getAddress()))
+                    || connection.getState() == mOriginalConnection.getStateBeforeHandover()) {
+                Log.i(TelephonyConnection.this, "Setting original connection after"
+                        + " handover or redial, current original connection="
+                        + mOriginalConnection.toString()
+                        + ", new original connection="
+                        + connection.toString());
+                setOriginalConnection(connection);
+                mWasImsConnection = false;
+                if (mHangupDisconnectCause != DisconnectCause.NOT_VALID) {
+                    // A hangup request was initiated during the handover process, so
+                    // go ahead and initiate the hangup on the new connection.
+                    try {
+                        Log.i(TelephonyConnection.this, "user has tried to hangup "
+                                + "during handover, retrying hangup.");
+                        connection.hangup();
+                    } catch (CallStateException e) {
+                        // Call state exception may be thrown if the connection was
+                        // already disconnected, so just log this case.
+                        Log.w(TelephonyConnection.this, "hangup during "
+                                + "handover or redial resulted in an exception:" + e);
+                    }
+                }
+            }
+        } else {
+            Log.w(TelephonyConnection.this, " mOriginalConnection==null --"
+                    + " invalid state (not cleaned up)");
+        }
+    }
+
+    /**
      * Handles {@link SuppServiceNotification}s pertinent to Telephony.
      * @param ssn the notification.
      */
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
index c55dee7..388fd29 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
@@ -8,11 +8,15 @@
 import static junit.framework.TestCase.assertFalse;
 
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.os.Bundle;
 import android.telecom.Connection;
 import android.telephony.CarrierConfigManager;
+import android.telephony.DisconnectCause;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -132,6 +136,23 @@
     }
 
     @Test
+    public void testHangupAfterRedial() throws Exception {
+        TestTelephonyConnection c = new TestTelephonyConnection();
+        c.hangup(DisconnectCause.LOCAL);
+        verify(c.mMockRadioConnection).hangup();
+
+        // hangup failed because redial was in progress... The new original connection has been sent
+        // to the TelephonyConnection
+        com.android.internal.telephony.Connection newMockRadioConnection =
+                mock(com.android.internal.telephony.Connection.class);
+        doReturn("5551212").when(c.mMockRadioConnection).getAddress();
+        doReturn("5551212").when(newMockRadioConnection).getAddress();
+        doReturn(Call.State.DIALING).when(newMockRadioConnection).getState();
+        c.onOriginalConnectionRedialed(newMockRadioConnection);
+        verify(newMockRadioConnection).hangup();
+    }
+
+    @Test
     public void testSetupDtmfOnly() {
         TestTelephonyConnection c = new TestTelephonyConnection();
         c.setIsImsConnection(true);