Adds tests for MSIM redial and fixes bug

1) Adds MSIM redial tests.
2) Fixes bug where we were not removing
a phone after making it when initializing
the cache.

Test: Unit tests
Bug: 27059146
Change-Id: Ia6ecc82ddd93ba7ad33ea01a8f5678f02cc09df1
diff --git a/tests/src/com/android/TelephonyTestBase.java b/tests/src/com/android/TelephonyTestBase.java
index 044f26b..a61ffe9 100644
--- a/tests/src/com/android/TelephonyTestBase.java
+++ b/tests/src/com/android/TelephonyTestBase.java
@@ -39,6 +39,14 @@
         // Set up the looper if it does not exist on the test thread.
         if (Looper.myLooper() == null) {
             Looper.prepare();
+            // Wait until the looper is not null anymore
+            for(int i = 0; i < 5; i++) {
+                if (Looper.myLooper() != null) {
+                    break;
+                }
+                Looper.prepare();
+                Thread.sleep(100);
+            }
         }
     }
 
diff --git a/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java b/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java
index 3d88af7..229bdee 100644
--- a/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java
+++ b/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java
@@ -34,7 +34,6 @@
 import org.junit.Test;
 
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
 /**
@@ -48,8 +47,8 @@
 
     private TelecomAccountRegistry mTelecomAccountRegistry;
 
-    private MockTelephonyConnection mMockTelephonyConnectionA;
-    private MockTelephonyConnection mMockTelephonyConnectionB;
+    private TestTelephonyConnection mTestTelephonyConnectionA;
+    private TestTelephonyConnection mTestTelephonyConnectionB;
 
     private ImsConferenceController mControllerTest;
 
@@ -60,8 +59,8 @@
             Looper.prepare();
         }
         mTelecomAccountRegistry = TelecomAccountRegistry.getInstance(null);
-        mMockTelephonyConnectionA = new MockTelephonyConnection();
-        mMockTelephonyConnectionB = new MockTelephonyConnection();
+        mTestTelephonyConnectionA = new TestTelephonyConnection();
+        mTestTelephonyConnectionB = new TestTelephonyConnection();
 
         mControllerTest = new ImsConferenceController(mTelecomAccountRegistry,
                 mMockTelephonyConnectionServiceProxy);
@@ -80,25 +79,25 @@
     @SmallTest
     public void testConferenceable() {
 
-        mControllerTest.add(mMockTelephonyConnectionB);
-        mControllerTest.add(mMockTelephonyConnectionA);
+        mControllerTest.add(mTestTelephonyConnectionB);
+        mControllerTest.add(mTestTelephonyConnectionA);
 
-        mMockTelephonyConnectionA.setActive();
-        mMockTelephonyConnectionB.setOnHold();
+        mTestTelephonyConnectionA.setActive();
+        mTestTelephonyConnectionB.setOnHold();
 
-        assertTrue(mMockTelephonyConnectionA.getConferenceables()
-                .contains(mMockTelephonyConnectionB));
-        assertTrue(mMockTelephonyConnectionB.getConferenceables()
-                .contains(mMockTelephonyConnectionA));
+        assertTrue(mTestTelephonyConnectionA.getConferenceables()
+                .contains(mTestTelephonyConnectionB));
+        assertTrue(mTestTelephonyConnectionB.getConferenceables()
+                .contains(mTestTelephonyConnectionA));
 
         // verify addConference method is never called
         verify(mMockTelephonyConnectionServiceProxy, never())
                 .addConference(any(ImsConference.class));
 
         // call A removed
-        mControllerTest.remove(mMockTelephonyConnectionA);
-        assertFalse(mMockTelephonyConnectionB.getConferenceables()
-                .contains(mMockTelephonyConnectionA));
+        mControllerTest.remove(mTestTelephonyConnectionA);
+        assertFalse(mTestTelephonyConnectionB.getConferenceables()
+                .contains(mTestTelephonyConnectionA));
     }
 
     /**
@@ -114,18 +113,18 @@
     @SmallTest
     public void testMergeMultiPartyCalls() {
 
-        when(mMockTelephonyConnectionA.mMockRadioConnection.getPhoneType())
+        when(mTestTelephonyConnectionA.mMockRadioConnection.getPhoneType())
                 .thenReturn(PhoneConstants.PHONE_TYPE_IMS);
-        when(mMockTelephonyConnectionB.mMockRadioConnection.getPhoneType())
+        when(mTestTelephonyConnectionB.mMockRadioConnection.getPhoneType())
                 .thenReturn(PhoneConstants.PHONE_TYPE_IMS);
-        when(mMockTelephonyConnectionA.mMockRadioConnection.isMultiparty()).thenReturn(true);
-        when(mMockTelephonyConnectionB.mMockRadioConnection.isMultiparty()).thenReturn(true);
+        when(mTestTelephonyConnectionA.mMockRadioConnection.isMultiparty()).thenReturn(true);
+        when(mTestTelephonyConnectionB.mMockRadioConnection.isMultiparty()).thenReturn(true);
 
-        mControllerTest.add(mMockTelephonyConnectionB);
-        mControllerTest.add(mMockTelephonyConnectionA);
+        mControllerTest.add(mTestTelephonyConnectionB);
+        mControllerTest.add(mTestTelephonyConnectionA);
 
-        mMockTelephonyConnectionA.setActive();
-        mMockTelephonyConnectionB.setOnHold();
+        mTestTelephonyConnectionA.setActive();
+        mTestTelephonyConnectionB.setOnHold();
 
         verify(mMockTelephonyConnectionServiceProxy, times(2))
                 .addConference(any(ImsConference.class));
diff --git a/tests/src/com/android/services/telephony/TelephonyConferenceControllerTest.java b/tests/src/com/android/services/telephony/TelephonyConferenceControllerTest.java
index 739359a..275bcc6 100644
--- a/tests/src/com/android/services/telephony/TelephonyConferenceControllerTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConferenceControllerTest.java
@@ -25,7 +25,6 @@
 import org.junit.Test;
 
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.mockito.ArgumentCaptor;
 
@@ -53,8 +52,8 @@
     @Mock
     private Conference.Listener mMockListener;
 
-    private MockTelephonyConnection mMockTelephonyConnectionA;
-    private MockTelephonyConnection mMockTelephonyConnectionB;
+    private TestTelephonyConnection mTestTelephonyConnectionA;
+    private TestTelephonyConnection mTestTelephonyConnectionB;
 
     private TelephonyConferenceController mControllerTest;
 
@@ -64,8 +63,8 @@
         if (Looper.myLooper() == null) {
             Looper.prepare();
         }
-        mMockTelephonyConnectionA = new MockTelephonyConnection();
-        mMockTelephonyConnectionB = new MockTelephonyConnection();
+        mTestTelephonyConnectionA = new TestTelephonyConnection();
+        mTestTelephonyConnectionB = new TestTelephonyConnection();
 
         mControllerTest = new TelephonyConferenceController(mMockTelephonyConnectionServiceProxy);
     }
@@ -84,33 +83,33 @@
     @SmallTest
     public void testConferenceable() {
 
-        when(mMockTelephonyConnectionA.mMockRadioConnection.getCall()
+        when(mTestTelephonyConnectionA.mMockRadioConnection.getCall()
                 .isMultiparty()).thenReturn(false);
-        when(mMockTelephonyConnectionB.mMockRadioConnection.getCall()
+        when(mTestTelephonyConnectionB.mMockRadioConnection.getCall()
                 .isMultiparty()).thenReturn(false);
 
         // add telephony connection B
-        mControllerTest.add(mMockTelephonyConnectionB);
+        mControllerTest.add(mTestTelephonyConnectionB);
 
         // add telephony connection A
-        mControllerTest.add(mMockTelephonyConnectionA);
+        mControllerTest.add(mTestTelephonyConnectionA);
 
-        mMockTelephonyConnectionA.setActive();
-        mMockTelephonyConnectionB.setOnHold();
+        mTestTelephonyConnectionA.setActive();
+        mTestTelephonyConnectionB.setOnHold();
 
-        assertTrue(mMockTelephonyConnectionA.getConferenceables()
-                .contains(mMockTelephonyConnectionB));
-        assertTrue(mMockTelephonyConnectionB.getConferenceables()
-                .contains(mMockTelephonyConnectionA));
+        assertTrue(mTestTelephonyConnectionA.getConferenceables()
+                .contains(mTestTelephonyConnectionB));
+        assertTrue(mTestTelephonyConnectionB.getConferenceables()
+                .contains(mTestTelephonyConnectionA));
 
         // verify addConference method is never called
         verify(mMockTelephonyConnectionServiceProxy, never())
                 .addConference(any(TelephonyConference.class));
 
         // call A removed
-        mControllerTest.remove(mMockTelephonyConnectionA);
-        assertFalse(mMockTelephonyConnectionB.getConferenceables()
-                .contains(mMockTelephonyConnectionA));
+        mControllerTest.remove(mTestTelephonyConnectionA);
+        assertFalse(mTestTelephonyConnectionB.getConferenceables()
+                .contains(mTestTelephonyConnectionA));
     }
 
     /**
@@ -129,31 +128,31 @@
     public void testMergeMultiPartyCalls() {
 
         // set isMultiparty() true to create the same senario of merge behaviour
-        when(mMockTelephonyConnectionA.mMockRadioConnection.getCall()
+        when(mTestTelephonyConnectionA.mMockRadioConnection.getCall()
                 .isMultiparty()).thenReturn(true);
-        when(mMockTelephonyConnectionB.mMockRadioConnection.getCall()
+        when(mTestTelephonyConnectionB.mMockRadioConnection.getCall()
                 .isMultiparty()).thenReturn(true);
 
         // Add connections into connection Service
         Collection<Connection> allConnections = new ArrayList<Connection>();
-        allConnections.add(mMockTelephonyConnectionA);
-        allConnections.add(mMockTelephonyConnectionB);
+        allConnections.add(mTestTelephonyConnectionA);
+        allConnections.add(mTestTelephonyConnectionB);
         when(mMockTelephonyConnectionServiceProxy.getAllConnections())
                 .thenReturn(allConnections);
 
         // add telephony connection B
-        mControllerTest.add(mMockTelephonyConnectionB);
+        mControllerTest.add(mTestTelephonyConnectionB);
 
         // add telephony connection A
-        mControllerTest.add(mMockTelephonyConnectionA);
+        mControllerTest.add(mTestTelephonyConnectionA);
 
-        mMockTelephonyConnectionA.setActive();
-        mMockTelephonyConnectionB.setOnHold();
+        mTestTelephonyConnectionA.setActive();
+        mTestTelephonyConnectionB.setOnHold();
 
-        assertTrue(mMockTelephonyConnectionA.getConferenceables()
-                .contains(mMockTelephonyConnectionB));
-        assertTrue(mMockTelephonyConnectionB.getConferenceables()
-                .contains(mMockTelephonyConnectionA));
+        assertTrue(mTestTelephonyConnectionA.getConferenceables()
+                .contains(mTestTelephonyConnectionB));
+        assertTrue(mTestTelephonyConnectionB.getConferenceables()
+                .contains(mTestTelephonyConnectionA));
 
         // capture the argument in the addConference method, and verify it is called
         ArgumentCaptor<TelephonyConference> argumentCaptor = ArgumentCaptor.
@@ -166,9 +165,9 @@
         verify(mMockListener, never()).onDestroyed(any(Conference.class));
 
         // call A removed
-        mControllerTest.remove(mMockTelephonyConnectionA);
-        assertFalse(mMockTelephonyConnectionB.getConferenceables()
-                .contains(mMockTelephonyConnectionA));
+        mControllerTest.remove(mTestTelephonyConnectionA);
+        assertFalse(mTestTelephonyConnectionB.getConferenceables()
+                .contains(mTestTelephonyConnectionA));
 
         //onDestroy should be called during the destroy
         verify(mMockListener).onDestroyed(any(Conference.class));
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index 45f74df..eb8c48a 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -16,13 +16,19 @@
 
 package com.android.services.telephony;
 
+import android.net.Uri;
+import android.telecom.DisconnectCause;
+import android.telecom.TelecomManager;
 import android.telephony.RadioAccessFamily;
 import android.telephony.ServiceState;
+import android.support.test.filters.FlakyTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.telephony.TelephonyManager;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.TelephonyTestBase;
+import com.android.internal.telephony.CallStateException;
+import com.android.internal.telephony.Connection;
 import com.android.internal.telephony.Phone;
 
 import org.junit.After;
@@ -31,9 +37,20 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 /**
@@ -491,6 +508,250 @@
         assertEquals(slot0Phone, resultPhone);
     }
 
+    /**
+     * The modem has returned a temporary error when placing an emergency call on a phone with one
+     * SIM slot.
+     *
+     * Verify that dial is called on the same phone again when retryOutgoingOriginalConnection is
+     * called.
+     */
+    @Test
+    @FlakyTest
+    @SmallTest
+    public void testRetryOutgoingOriginalConnection_redialTempFailOneSlot() {
+        TestTelephonyConnection c = new TestTelephonyConnection();
+        Phone slot0Phone = c.getPhone();
+        when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
+        List<Phone> phones = new ArrayList<>(1);
+        phones.add(slot0Phone);
+        setPhones(phones);
+        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+
+        mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
+
+        // We never need to be notified in telecom that the PhoneAccount has changed, because it
+        // was redialed on the same slot
+        assertEquals(0, c.getNotifyPhoneAccountChangedCount());
+        try {
+            verify(slot0Phone).dial(anyString(), any(), anyInt(), any());
+        } catch (CallStateException e) {
+            // This shouldn't happen
+            fail();
+        }
+    }
+
+    /**
+     * The modem has returned a permanent failure when placing an emergency call on a phone with one
+     * SIM slot.
+     *
+     * Verify that the connection is set to disconnected with an error disconnect cause and dial is
+     * not called.
+     */
+    @Test
+    @FlakyTest
+    @SmallTest
+    public void testRetryOutgoingOriginalConnection_redialPermFailOneSlot() {
+        TestTelephonyConnection c = new TestTelephonyConnection();
+        Phone slot0Phone = c.getPhone();
+        when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
+        List<Phone> phones = new ArrayList<>(1);
+        phones.add(slot0Phone);
+        setPhones(phones);
+        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+
+        mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
+
+        // We never need to be notified in telecom that the PhoneAccount has changed, because it
+        // was never redialed
+        assertEquals(0, c.getNotifyPhoneAccountChangedCount());
+        try {
+            verify(slot0Phone, never()).dial(anyString(), any(), anyInt(), any());
+        } catch (CallStateException e) {
+            // This shouldn't happen
+            fail();
+        }
+        assertEquals(c.getState(), android.telecom.Connection.STATE_DISCONNECTED);
+        assertEquals(c.getDisconnectCause().getCode(), DisconnectCause.ERROR);
+    }
+
+    /**
+     * The modem has returned a temporary failure when placing an emergency call on a phone with two
+     * SIM slots.
+     *
+     * Verify that the emergency call is dialed on the other slot and telecom is notified of the new
+     * PhoneAccount.
+     */
+    @Test
+    @FlakyTest
+    @SmallTest
+    public void testRetryOutgoingOriginalConnection_redialTempFailTwoSlot() {
+        TestTelephonyConnection c = new TestTelephonyConnection();
+        Phone slot0Phone = c.getPhone();
+        when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
+        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+                false /*isEmergencyOnly*/);
+        setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
+        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+        List<Phone> phones = new ArrayList<>(2);
+        phones.add(slot0Phone);
+        phones.add(slot1Phone);
+        setPhones(phones);
+
+        mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
+
+        // The cache should still contain all of the Phones, since it was a temporary failure.
+        assertEquals(2, mTestConnectionService.mEmergencyRetryCache.second.size());
+        // We need to be notified in Telecom that the PhoneAccount has changed, because it was
+        // redialed on another slot
+        assertEquals(1, c.getNotifyPhoneAccountChangedCount());
+        try {
+            verify(slot1Phone).dial(anyString(), any(), anyInt(), any());
+        } catch (CallStateException e) {
+            // This shouldn't happen
+            fail();
+        }
+    }
+
+    /**
+     * The modem has returned a temporary failure when placing an emergency call on a phone with two
+     * SIM slots.
+     *
+     * Verify that the emergency call is dialed on the other slot and telecom is notified of the new
+     * PhoneAccount.
+     */
+    @Test
+    @FlakyTest
+    @SmallTest
+    public void testRetryOutgoingOriginalConnection_redialPermFailTwoSlot() {
+        TestTelephonyConnection c = new TestTelephonyConnection();
+        Phone slot0Phone = c.getPhone();
+        when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
+        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+                false /*isEmergencyOnly*/);
+        setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
+        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+        List<Phone> phones = new ArrayList<>(2);
+        phones.add(slot0Phone);
+        phones.add(slot1Phone);
+        setPhones(phones);
+
+        mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
+
+        // The cache should only contain the slot1Phone.
+        assertEquals(1, mTestConnectionService.mEmergencyRetryCache.second.size());
+        // We need to be notified in Telecom that the PhoneAccount has changed, because it was
+        // redialed on another slot
+        assertEquals(1, c.getNotifyPhoneAccountChangedCount());
+        try {
+            verify(slot1Phone).dial(anyString(), any(), anyInt(), any());
+        } catch (CallStateException e) {
+            // This shouldn't happen
+            fail();
+        }
+    }
+
+    /**
+     * The modem has returned a temporary failure twice while placing an emergency call on a phone
+     * with two SIM slots.
+     *
+     * Verify that the emergency call is dialed on slot 1 and then on slot 0 and telecom is
+     * notified of this twice.
+     */
+    @Test
+    @FlakyTest
+    @SmallTest
+    public void testRetryOutgoingOriginalConnection_redialTempFailTwoSlot_twoFailure() {
+        TestTelephonyConnection c = new TestTelephonyConnection();
+        Phone slot0Phone = c.getPhone();
+        when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
+        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+                false /*isEmergencyOnly*/);
+        setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
+        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+        List<Phone> phones = new ArrayList<>(2);
+        phones.add(slot0Phone);
+        phones.add(slot1Phone);
+        setPhones(phones);
+
+        // First Temporary failure
+        mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
+        // Set the Phone to the new phone that was just used to dial.
+        c.setMockPhone(slot1Phone);
+        // The cache should still contain all of the Phones, since it was a temporary failure.
+        assertEquals(2, mTestConnectionService.mEmergencyRetryCache.second.size());
+        // Make sure slot 1 is next in the queue.
+        assertEquals(slot1Phone, mTestConnectionService.mEmergencyRetryCache.second.peek());
+        // Second Temporary failure
+        mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
+        // Set the Phone to the new phone that was just used to dial.
+        c.setMockPhone(slot0Phone);
+        // The cache should still contain all of the Phones, since it was a temporary failure.
+        assertEquals(2, mTestConnectionService.mEmergencyRetryCache.second.size());
+        // Make sure slot 0 is next in the queue.
+        assertEquals(slot0Phone, mTestConnectionService.mEmergencyRetryCache.second.peek());
+
+        // We need to be notified in Telecom that the PhoneAccount has changed, because it was
+        // redialed on another slot
+        assertEquals(2, c.getNotifyPhoneAccountChangedCount());
+        try {
+            verify(slot0Phone).dial(anyString(), any(), anyInt(), any());
+            verify(slot1Phone).dial(anyString(), any(), anyInt(), any());
+        } catch (CallStateException e) {
+            // This shouldn't happen
+            fail();
+        }
+    }
+
+    /**
+     * The modem has returned a permanent failure twice while placing an emergency call on a phone
+     * with two SIM slots.
+     *
+     * Verify that the emergency call is dialed on slot 1 and then disconnected and telecom is
+     * notified of the change to slot 1.
+     */
+    @Test
+    @FlakyTest
+    @SmallTest
+    public void testRetryOutgoingOriginalConnection_redialPermFailTwoSlot_twoFailure() {
+        TestTelephonyConnection c = new TestTelephonyConnection();
+        Phone slot0Phone = c.getPhone();
+        when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
+        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+                false /*isEmergencyOnly*/);
+        setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
+        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+        List<Phone> phones = new ArrayList<>(2);
+        phones.add(slot0Phone);
+        phones.add(slot1Phone);
+        setPhones(phones);
+
+        // First Permanent failure
+        mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
+        // Set the Phone to the new phone that was just used to dial.
+        c.setMockPhone(slot1Phone);
+        // The cache should only contain one phone
+        assertEquals(1, mTestConnectionService.mEmergencyRetryCache.second.size());
+        // Make sure slot 1 is next in the queue.
+        assertEquals(slot1Phone, mTestConnectionService.mEmergencyRetryCache.second.peek());
+        // Second Permanent failure
+        mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
+        // The cache should be empty
+        assertEquals(true, mTestConnectionService.mEmergencyRetryCache.second.isEmpty());
+
+        assertEquals(c.getState(), android.telecom.Connection.STATE_DISCONNECTED);
+        assertEquals(c.getDisconnectCause().getCode(), DisconnectCause.ERROR);
+        // We need to be notified in Telecom that the PhoneAccount has changed, because it was
+        // redialed on another slot
+        assertEquals(1, c.getNotifyPhoneAccountChangedCount());
+        try {
+            verify(slot1Phone).dial(anyString(), any(), anyInt(), any());
+            verify(slot0Phone, never()).dial(anyString(), any(), anyInt(), any());
+        } catch (CallStateException e) {
+            // This shouldn't happen
+            fail();
+        }
+    }
+
     private Phone makeTestPhone(int phoneId, int serviceState, boolean isEmergencyOnly) {
         Phone phone = mock(Phone.class);
         ServiceState testServiceState = new ServiceState();
@@ -524,4 +785,17 @@
     private void setDefaultPhone(Phone phone) {
         when(mPhoneFactoryProxy.getDefaultPhone()).thenReturn(phone);
     }
+
+    private void setPhones(List<Phone> phones) {
+        when(mPhoneFactoryProxy.getPhones()).thenReturn(phones.toArray(new Phone[phones.size()]));
+    }
+
+    private void setPhonesDialConnection(Phone phone, Connection c) {
+        try {
+            when(phone.dial(anyString(), anyInt())).thenReturn(c);
+        } catch (CallStateException e) {
+            // this shouldn't happen
+            fail();
+        }
+    }
 }
diff --git a/tests/src/com/android/services/telephony/MockTelephonyConnection.java b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
similarity index 73%
rename from tests/src/com/android/services/telephony/MockTelephonyConnection.java
rename to tests/src/com/android/services/telephony/TestTelephonyConnection.java
index 634cbb5..ea0f965 100644
--- a/tests/src/com/android/services/telephony/MockTelephonyConnection.java
+++ b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
@@ -11,11 +11,14 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
 package com.android.services.telephony;
 
+import android.telecom.PhoneAccountHandle;
+
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import com.android.internal.telephony.Call;
@@ -28,7 +31,7 @@
  * Mock Telephony Connection used in TelephonyConferenceController.java for testing purpose
  */
 
-public class MockTelephonyConnection extends TelephonyConnection {
+public class TestTelephonyConnection extends TelephonyConnection {
 
     @Mock
     com.android.internal.telephony.Connection mMockRadioConnection;
@@ -36,18 +39,19 @@
     @Mock
     Call mMockCall;
 
-    @Mock
-    Phone mMockPhone;
+    private Phone mMockPhone;
+    private int mNotifyPhoneAccountChangedCount = 0;
 
     @Override
     public com.android.internal.telephony.Connection getOriginalConnection() {
         return mMockRadioConnection;
     }
 
-    public MockTelephonyConnection() {
+    public TestTelephonyConnection() {
         super(null, null, false);
         MockitoAnnotations.initMocks(this);
 
+        mMockPhone = mock(Phone.class);
         // Set up mMockRadioConnection and mMockPhone to contain an active call
         when(mMockRadioConnection.getState()).thenReturn(Call.State.ACTIVE);
         when(mMockRadioConnection.getCall()).thenReturn(mMockCall);
@@ -60,6 +64,10 @@
         return true;
     }
 
+    public void setMockPhone(Phone newPhone) {
+        mMockPhone = newPhone;
+    }
+
     @Override
     public Phone getPhone() {
         return mMockPhone;
@@ -69,4 +77,12 @@
         return this;
     }
 
+    @Override
+    public void notifyPhoneAccountChanged(PhoneAccountHandle pHandle) {
+        mNotifyPhoneAccountChangedCount++;
+    }
+
+    public int getNotifyPhoneAccountChangedCount() {
+        return mNotifyPhoneAccountChangedCount;
+    }
 }