Loading src/java/com/android/internal/telephony/ims/ImsServiceController.java +2 −1 Original line number Diff line number Diff line Loading @@ -184,7 +184,8 @@ public class ImsServiceController { @Override public void notifyImsFeatureStatus(int featureStatus) throws RemoteException { Log.i(LOG_TAG, "notifyImsFeatureStatus"); Log.i(LOG_TAG, "notifyImsFeatureStatus: slot=" + mSlotId + ", feature=" + mFeatureType + ", status=" + featureStatus); sendImsFeatureStatusChanged(mSlotId, mFeatureType, featureStatus); } }; Loading src/java/com/android/internal/telephony/imsphone/ImsPhone.java +2 −2 Original line number Diff line number Diff line Loading @@ -996,8 +996,8 @@ public class ImsPhone extends ImsPhoneBase { } } /* package */ void sendErrorResponse(Message onComplete, Throwable e) { @VisibleForTesting public void sendErrorResponse(Message onComplete, Throwable e) { Rlog.d(LOG_TAG, "sendErrorResponse"); if (onComplete != null) { AsyncResult.forMessage(onComplete, null, getCommandException(e)); Loading src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +68 −18 Original line number Diff line number Diff line Loading @@ -581,10 +581,25 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { */ private boolean mShouldUpdateImsConfigOnDisconnect = false; private ImsServiceProxy.INotifyStatusChanged mNotifyFeatureRemovedCallback = () -> { // Callback fires when ImsManager MMTel Feature changes state private ImsServiceProxy.INotifyStatusChanged mNotifyStatusChangedCallback = () -> { try { if (mImsManager.getImsServiceStatus() != ImsFeature.STATE_READY) { retryGetImsService(); int status = mImsManager.getImsServiceStatus(); log("Status Changed: " + status); switch(status) { case ImsFeature.STATE_READY: { startListeningForCalls(); break; } case ImsFeature.STATE_INITIALIZING: // fall through case ImsFeature.STATE_NOT_AVAILABLE: { stopListeningForCalls(); break; } default: { Log.w(LOG_TAG, "Unexpected State!"); } } } catch (ImsException e) { // Could not get the ImsService, retry! Loading @@ -592,6 +607,24 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } }; @VisibleForTesting public interface IRetryTimeout { int get(); } /** * Default implementation of interface that calculates the ImsService retry timeout. * Override-able for testing. */ @VisibleForTesting public IRetryTimeout mRetryTimeout = () -> { int timeout = (1 << mImsServiceRetryCount) * IMS_RETRY_STARTING_TIMEOUT_MS; if (mImsServiceRetryCount <= CEILING_SERVICE_RETRY_COUNT) { mImsServiceRetryCount++; } return timeout; }; //***** Events Loading Loading @@ -627,13 +660,15 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private void getImsService() throws ImsException { if (DBG) log("getImsService"); mImsManager = ImsManager.getInstance(mPhone.getContext(), mPhone.getPhoneId()); // Adding to set, will be safe adding multiple times. mImsManager.addNotifyStatusChangedCallback(mNotifyFeatureRemovedCallback); if (mImsManager.getImsServiceStatus() != ImsFeature.STATE_READY) { // We can not call "open" until the ims service is ready throw new ImsException("getImsServiceStatus()", ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); // Adding to set, will be safe adding multiple times. If the ImsService is not active yet, // this method will throw an ImsException. mImsManager.addNotifyStatusChangedCallbackIfAvailable(mNotifyStatusChangedCallback); // Wait for ImsService.STATE_READY to start listening for calls. // Call the callback right away for compatibility with older devices that do not use states. mNotifyStatusChangedCallback.notifyStatusChanged(); } private void startListeningForCalls() throws ImsException { mImsServiceRetryCount = 0; mServiceId = mImsManager.open(ImsServiceClass.MMTEL, createIncomingCallPendingIntent(), Loading @@ -660,6 +695,18 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } } private void stopListeningForCalls() { try { // Only close on valid session. if (mImsManager != null && mServiceId > 0) { mImsManager.close(mServiceId); mServiceId = -1; } } catch (ImsException e) { // If the binder is unavailable, then the ImsService doesn't need to close. } } public void dispose() { if (DBG) log("dispose"); mRingingCall.dispose(); Loading Loading @@ -968,6 +1015,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { loge("dialInternal : " + e); conn.setDisconnectCause(DisconnectCause.ERROR_UNSPECIFIED); sendEmptyMessageDelayed(EVENT_HANGUP_PENDINGMO, TIMEOUT_HANGUP_PENDINGMO); retryGetImsService(); } catch (RemoteException e) { } } Loading Loading @@ -1292,6 +1340,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } catch (ImsException e) { loge("setTTYMode : " + e); mPhone.sendErrorResponse(onComplete, e); retryGetImsService(); } } Loading Loading @@ -1491,6 +1540,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } catch (ImsException e) { loge("sendUSSD : " + e); mPhone.sendErrorResponse(response, e); retryGetImsService(); } } Loading Loading @@ -2835,16 +2885,16 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } private void retryGetImsService() { // The binder connection is already up. Do not try to get it again. if (mImsManager.isServiceAvailable()) { return; } //Leave mImsManager as null, then CallStateException will be thrown when dialing mImsManager = null; // Exponential backoff during retry, limited to 32 seconds. loge("getImsService: Retrying getting ImsService..."); removeMessages(EVENT_GET_IMS_SERVICE); sendEmptyMessageDelayed(EVENT_GET_IMS_SERVICE, (1 << mImsServiceRetryCount) * IMS_RETRY_STARTING_TIMEOUT_MS); if (mImsServiceRetryCount <= CEILING_SERVICE_RETRY_COUNT) { mImsServiceRetryCount++; } sendEmptyMessageDelayed(EVENT_GET_IMS_SERVICE, mRetryTimeout.get()); } private void setVideoCallProvider(ImsPhoneConnection conn, ImsCall imsCall) Loading tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +27 −0 Original line number Diff line number Diff line Loading @@ -80,6 +80,8 @@ import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; public abstract class TelephonyTest { protected static String TAG; Loading Loading @@ -482,4 +484,29 @@ public abstract class TelephonyTest { doReturn(mPackageInfo).when(mPackageManager).getPackageInfoAsUser( eq(TAG), anyInt(), anyInt()); } protected final void waitForHandlerAction(Handler h, long timeoutMillis) { final CountDownLatch lock = new CountDownLatch(1); h.post(lock::countDown); while (lock.getCount() > 0) { try { lock.await(timeoutMillis, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { // do nothing } } } protected final void waitForHandlerActionDelayed(Handler h, long timeoutMillis, long delayMs) { final CountDownLatch lock = new CountDownLatch(1); h.postDelayed(lock::countDown, delayMs); while (lock.getCount() > 0) { try { lock.await(timeoutMillis, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { // do nothing } } } } tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +60 −2 Original line number Diff line number Diff line Loading @@ -16,24 +16,29 @@ package com.android.internal.telephony.imsphone; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.support.test.filters.FlakyTest; import android.telephony.PhoneNumberUtils; import android.telephony.ims.feature.ImsFeature; import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.LargeTest; import com.android.ims.ImsCall; import com.android.ims.ImsCallProfile; import com.android.ims.ImsConfig; import com.android.ims.ImsConnectionStateListener; import com.android.ims.ImsException; import com.android.ims.ImsManager; import com.android.ims.ImsReasonInfo; import com.android.ims.ImsServiceClass; import com.android.ims.internal.ImsCallSession; import com.android.internal.telephony.Call; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Connection; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyTest; Loading @@ -50,14 +55,20 @@ import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.isNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; Loading @@ -73,6 +84,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { private int mServiceId; @Mock private ImsCallSession mImsCallSession; private Handler mCTHander; private class ImsCTHandlerThread extends HandlerThread { Loading @@ -87,6 +99,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { ImsReasonInfo.CODE_ANSWERED_ELSEWHERE); mCTUT.addReasonCodeRemapping(510, "Call answered elsewhere.", ImsReasonInfo.CODE_ANSWERED_ELSEWHERE); mCTHander = new Handler(mCTUT.getLooper()); setReady(true); } } Loading Loading @@ -191,8 +204,8 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { waitUntilReady(); logd("ImsPhoneCallTracker initiated"); /* Make sure getImsService is triggered on a separate thread */ waitForMs(100); /* Make sure getImsService is triggered on handler */ waitForHandlerAction(mCTHander, 100); } @After Loading Loading @@ -436,4 +449,49 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { assertEquals(90210, mCTUT.maybeRemapReasonCode(new ImsReasonInfo(90210, 1, "Call answered elsewhere."))); } @Test @SmallTest public void testDialImsServiceUnavailable() throws ImsException { doThrow(new ImsException("Test Exception", ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN)).when( mImsManager).createCallProfile(anyInt(), anyInt(), anyInt()); mCTUT.mRetryTimeout = () -> 0; //ms assertEquals(Call.State.IDLE, mCTUT.mForegroundCall.getState()); assertEquals(PhoneConstants.State.IDLE, mCTUT.getState()); try { mCTUT.dial("+17005554141", ImsCallProfile.CALL_TYPE_VOICE, null); } catch (Exception e) { Assert.fail(); } // wait for handler to process ImsService connection retry waitForHandlerAction(mCTHander, 1000); // 1 second timeout verify(mImsManager, never()).makeCall(anyInt(), nullable(ImsCallProfile.class), eq(new String[]{"+17005554141"}), nullable(ImsCall.Listener.class)); // Make sure that open is called in ImsPhoneCallTracker when it was first connected and // again after retry. verify(mImsManager, times(2)).open(anyInt(), nullable(PendingIntent.class), nullable(ImsConnectionStateListener.class)); } @Test @SmallTest public void testTTYImsServiceUnavailable() throws ImsException { doThrow(new ImsException("Test Exception", ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN)).when( mImsManager).setUiTTYMode(nullable(Context.class), anyInt(), nullable(Message.class)); // Remove retry timeout delay mCTUT.mRetryTimeout = () -> 0; //ms mCTUT.setUiTTYMode(0, new Message()); // wait for handler to process ImsService connection retry waitForHandlerAction(mCTHander, 100); // Make sure that open is called in ImsPhoneCallTracker to re-establish connection to // ImsService verify(mImsManager, times(2)).open(anyInt(), nullable(PendingIntent.class), nullable(ImsConnectionStateListener.class)); } } Loading
src/java/com/android/internal/telephony/ims/ImsServiceController.java +2 −1 Original line number Diff line number Diff line Loading @@ -184,7 +184,8 @@ public class ImsServiceController { @Override public void notifyImsFeatureStatus(int featureStatus) throws RemoteException { Log.i(LOG_TAG, "notifyImsFeatureStatus"); Log.i(LOG_TAG, "notifyImsFeatureStatus: slot=" + mSlotId + ", feature=" + mFeatureType + ", status=" + featureStatus); sendImsFeatureStatusChanged(mSlotId, mFeatureType, featureStatus); } }; Loading
src/java/com/android/internal/telephony/imsphone/ImsPhone.java +2 −2 Original line number Diff line number Diff line Loading @@ -996,8 +996,8 @@ public class ImsPhone extends ImsPhoneBase { } } /* package */ void sendErrorResponse(Message onComplete, Throwable e) { @VisibleForTesting public void sendErrorResponse(Message onComplete, Throwable e) { Rlog.d(LOG_TAG, "sendErrorResponse"); if (onComplete != null) { AsyncResult.forMessage(onComplete, null, getCommandException(e)); Loading
src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +68 −18 Original line number Diff line number Diff line Loading @@ -581,10 +581,25 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { */ private boolean mShouldUpdateImsConfigOnDisconnect = false; private ImsServiceProxy.INotifyStatusChanged mNotifyFeatureRemovedCallback = () -> { // Callback fires when ImsManager MMTel Feature changes state private ImsServiceProxy.INotifyStatusChanged mNotifyStatusChangedCallback = () -> { try { if (mImsManager.getImsServiceStatus() != ImsFeature.STATE_READY) { retryGetImsService(); int status = mImsManager.getImsServiceStatus(); log("Status Changed: " + status); switch(status) { case ImsFeature.STATE_READY: { startListeningForCalls(); break; } case ImsFeature.STATE_INITIALIZING: // fall through case ImsFeature.STATE_NOT_AVAILABLE: { stopListeningForCalls(); break; } default: { Log.w(LOG_TAG, "Unexpected State!"); } } } catch (ImsException e) { // Could not get the ImsService, retry! Loading @@ -592,6 +607,24 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } }; @VisibleForTesting public interface IRetryTimeout { int get(); } /** * Default implementation of interface that calculates the ImsService retry timeout. * Override-able for testing. */ @VisibleForTesting public IRetryTimeout mRetryTimeout = () -> { int timeout = (1 << mImsServiceRetryCount) * IMS_RETRY_STARTING_TIMEOUT_MS; if (mImsServiceRetryCount <= CEILING_SERVICE_RETRY_COUNT) { mImsServiceRetryCount++; } return timeout; }; //***** Events Loading Loading @@ -627,13 +660,15 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private void getImsService() throws ImsException { if (DBG) log("getImsService"); mImsManager = ImsManager.getInstance(mPhone.getContext(), mPhone.getPhoneId()); // Adding to set, will be safe adding multiple times. mImsManager.addNotifyStatusChangedCallback(mNotifyFeatureRemovedCallback); if (mImsManager.getImsServiceStatus() != ImsFeature.STATE_READY) { // We can not call "open" until the ims service is ready throw new ImsException("getImsServiceStatus()", ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); // Adding to set, will be safe adding multiple times. If the ImsService is not active yet, // this method will throw an ImsException. mImsManager.addNotifyStatusChangedCallbackIfAvailable(mNotifyStatusChangedCallback); // Wait for ImsService.STATE_READY to start listening for calls. // Call the callback right away for compatibility with older devices that do not use states. mNotifyStatusChangedCallback.notifyStatusChanged(); } private void startListeningForCalls() throws ImsException { mImsServiceRetryCount = 0; mServiceId = mImsManager.open(ImsServiceClass.MMTEL, createIncomingCallPendingIntent(), Loading @@ -660,6 +695,18 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } } private void stopListeningForCalls() { try { // Only close on valid session. if (mImsManager != null && mServiceId > 0) { mImsManager.close(mServiceId); mServiceId = -1; } } catch (ImsException e) { // If the binder is unavailable, then the ImsService doesn't need to close. } } public void dispose() { if (DBG) log("dispose"); mRingingCall.dispose(); Loading Loading @@ -968,6 +1015,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { loge("dialInternal : " + e); conn.setDisconnectCause(DisconnectCause.ERROR_UNSPECIFIED); sendEmptyMessageDelayed(EVENT_HANGUP_PENDINGMO, TIMEOUT_HANGUP_PENDINGMO); retryGetImsService(); } catch (RemoteException e) { } } Loading Loading @@ -1292,6 +1340,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } catch (ImsException e) { loge("setTTYMode : " + e); mPhone.sendErrorResponse(onComplete, e); retryGetImsService(); } } Loading Loading @@ -1491,6 +1540,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } catch (ImsException e) { loge("sendUSSD : " + e); mPhone.sendErrorResponse(response, e); retryGetImsService(); } } Loading Loading @@ -2835,16 +2885,16 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } private void retryGetImsService() { // The binder connection is already up. Do not try to get it again. if (mImsManager.isServiceAvailable()) { return; } //Leave mImsManager as null, then CallStateException will be thrown when dialing mImsManager = null; // Exponential backoff during retry, limited to 32 seconds. loge("getImsService: Retrying getting ImsService..."); removeMessages(EVENT_GET_IMS_SERVICE); sendEmptyMessageDelayed(EVENT_GET_IMS_SERVICE, (1 << mImsServiceRetryCount) * IMS_RETRY_STARTING_TIMEOUT_MS); if (mImsServiceRetryCount <= CEILING_SERVICE_RETRY_COUNT) { mImsServiceRetryCount++; } sendEmptyMessageDelayed(EVENT_GET_IMS_SERVICE, mRetryTimeout.get()); } private void setVideoCallProvider(ImsPhoneConnection conn, ImsCall imsCall) Loading
tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +27 −0 Original line number Diff line number Diff line Loading @@ -80,6 +80,8 @@ import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; public abstract class TelephonyTest { protected static String TAG; Loading Loading @@ -482,4 +484,29 @@ public abstract class TelephonyTest { doReturn(mPackageInfo).when(mPackageManager).getPackageInfoAsUser( eq(TAG), anyInt(), anyInt()); } protected final void waitForHandlerAction(Handler h, long timeoutMillis) { final CountDownLatch lock = new CountDownLatch(1); h.post(lock::countDown); while (lock.getCount() > 0) { try { lock.await(timeoutMillis, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { // do nothing } } } protected final void waitForHandlerActionDelayed(Handler h, long timeoutMillis, long delayMs) { final CountDownLatch lock = new CountDownLatch(1); h.postDelayed(lock::countDown, delayMs); while (lock.getCount() > 0) { try { lock.await(timeoutMillis, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { // do nothing } } } }
tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +60 −2 Original line number Diff line number Diff line Loading @@ -16,24 +16,29 @@ package com.android.internal.telephony.imsphone; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.support.test.filters.FlakyTest; import android.telephony.PhoneNumberUtils; import android.telephony.ims.feature.ImsFeature; import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.LargeTest; import com.android.ims.ImsCall; import com.android.ims.ImsCallProfile; import com.android.ims.ImsConfig; import com.android.ims.ImsConnectionStateListener; import com.android.ims.ImsException; import com.android.ims.ImsManager; import com.android.ims.ImsReasonInfo; import com.android.ims.ImsServiceClass; import com.android.ims.internal.ImsCallSession; import com.android.internal.telephony.Call; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Connection; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyTest; Loading @@ -50,14 +55,20 @@ import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.isNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; Loading @@ -73,6 +84,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { private int mServiceId; @Mock private ImsCallSession mImsCallSession; private Handler mCTHander; private class ImsCTHandlerThread extends HandlerThread { Loading @@ -87,6 +99,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { ImsReasonInfo.CODE_ANSWERED_ELSEWHERE); mCTUT.addReasonCodeRemapping(510, "Call answered elsewhere.", ImsReasonInfo.CODE_ANSWERED_ELSEWHERE); mCTHander = new Handler(mCTUT.getLooper()); setReady(true); } } Loading Loading @@ -191,8 +204,8 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { waitUntilReady(); logd("ImsPhoneCallTracker initiated"); /* Make sure getImsService is triggered on a separate thread */ waitForMs(100); /* Make sure getImsService is triggered on handler */ waitForHandlerAction(mCTHander, 100); } @After Loading Loading @@ -436,4 +449,49 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { assertEquals(90210, mCTUT.maybeRemapReasonCode(new ImsReasonInfo(90210, 1, "Call answered elsewhere."))); } @Test @SmallTest public void testDialImsServiceUnavailable() throws ImsException { doThrow(new ImsException("Test Exception", ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN)).when( mImsManager).createCallProfile(anyInt(), anyInt(), anyInt()); mCTUT.mRetryTimeout = () -> 0; //ms assertEquals(Call.State.IDLE, mCTUT.mForegroundCall.getState()); assertEquals(PhoneConstants.State.IDLE, mCTUT.getState()); try { mCTUT.dial("+17005554141", ImsCallProfile.CALL_TYPE_VOICE, null); } catch (Exception e) { Assert.fail(); } // wait for handler to process ImsService connection retry waitForHandlerAction(mCTHander, 1000); // 1 second timeout verify(mImsManager, never()).makeCall(anyInt(), nullable(ImsCallProfile.class), eq(new String[]{"+17005554141"}), nullable(ImsCall.Listener.class)); // Make sure that open is called in ImsPhoneCallTracker when it was first connected and // again after retry. verify(mImsManager, times(2)).open(anyInt(), nullable(PendingIntent.class), nullable(ImsConnectionStateListener.class)); } @Test @SmallTest public void testTTYImsServiceUnavailable() throws ImsException { doThrow(new ImsException("Test Exception", ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN)).when( mImsManager).setUiTTYMode(nullable(Context.class), anyInt(), nullable(Message.class)); // Remove retry timeout delay mCTUT.mRetryTimeout = () -> 0; //ms mCTUT.setUiTTYMode(0, new Message()); // wait for handler to process ImsService connection retry waitForHandlerAction(mCTHander, 100); // Make sure that open is called in ImsPhoneCallTracker to re-establish connection to // ImsService verify(mImsManager, times(2)).open(anyInt(), nullable(PendingIntent.class), nullable(ImsConnectionStateListener.class)); } }