Merge "Handle normal rougint emergency numbers"
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index 27e1606..d2c0e6b 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -1071,7 +1071,8 @@
         mSelectedNetworkOperatorName.remove(subId);
     }
 
-    private static long getTimeStamp() {
+    @VisibleForTesting
+    public long getTimeStamp() {
         return SystemClock.elapsedRealtime();
     }
 }
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 804e074..09b9b6d 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -2051,6 +2051,8 @@
                                         .setVideoState(videoState)
                                         .setIntentExtras(extras)
                                         .setRttTextStream(mNormalCallConnection.getRttTextStream())
+                                        .setIsWpsCall(NormalCallDomainSelectionConnection
+                                                .isWpsCall(number))
                                         .build(),
                                 mNormalCallConnection::registerForCallEvents);
 
@@ -2104,12 +2106,14 @@
         // If the number is both an MMI code and a supplementary service code,
         // it shall be treated as UT. In this case, domain selection is not performed.
         if (isMmiCode && isSuppServiceCode) {
+            Log.v(LOG_TAG, "UT code not handled by call domain selection.");
             return false;
         }
 
         // Check and select same domain as ongoing call on the same subscription (if exists)
         int activeCallDomain = getActiveCallDomain(phone.getSubId());
-        if (activeCallDomain != NetworkRegistrationInfo.DOMAIN_UNKNOWN) {
+        if (activeCallDomain != NetworkRegistrationInfo.DOMAIN_UNKNOWN
+                && !NormalCallDomainSelectionConnection.isWpsCall(number)) {
             Log.d(LOG_TAG, "Selecting same domain as ongoing call on same subId");
             mNormalCallConnection = connection;
             handleOutgoingCallConnectionByCallDomainSelection(
@@ -2126,6 +2130,7 @@
         SelectionAttributes selectionAttributes =
                 new SelectionAttributes.Builder(phone.getPhoneId(), phone.getSubId(),
                         SELECTOR_TYPE_CALLING)
+                        .setNumber(number)
                         .setEmergency(false)
                         .setVideoCall(VideoProfile.isVideo(videoState))
                         .build();
diff --git a/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java b/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
index 146874c..3da0044 100644
--- a/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
@@ -21,7 +21,10 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.os.Looper;
+import android.os.PersistableBundle;
+import android.telecom.TelecomManager;
 import android.telephony.Annotation.DisconnectCauses;
+import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 import android.telephony.DomainSelectionService.SelectionAttributes;
 import android.telephony.NetworkRegistrationInfo;
@@ -30,6 +33,8 @@
 import android.telephony.TransportSelectorCallback;
 import android.telephony.ims.ImsReasonInfo;
 
+import com.android.internal.telephony.domainselection.NormalCallDomainSelectionConnection;
+
 /**
  * Implements domain selector for outgoing non-emergency calls.
  */
@@ -131,14 +136,16 @@
 
     @Override
     public void onImsRegistrationStateChanged() {
-        logd("onImsRegistrationStateChanged");
+        logd("onImsRegistrationStateChanged. IsImsRegistered: "
+                + mImsStateTracker.isImsRegistered());
         mImsRegStateReceived = true;
         selectDomain();
     }
 
     @Override
     public void onImsMmTelCapabilitiesChanged() {
-        logd("onImsMmTelCapabilitiesChanged");
+        logd("onImsMmTelCapabilitiesChanged. ImsVoiceCap: " + mImsStateTracker.isImsVoiceCapable()
+                + " ImsVideoCap: " + mImsStateTracker.isImsVideoCapable());
         mMmTelCapabilitiesReceived = true;
         selectDomain();
     }
@@ -221,6 +228,54 @@
                 || mServiceState.getState() == ServiceState.STATE_EMERGENCY_ONLY);
     }
 
+    private boolean isWpsCallSupportedByIms() {
+        CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class);
+
+        PersistableBundle config = null;
+        if (configManager != null) {
+            config = configManager.getConfigForSubId(mSelectionAttributes.getSubId());
+        }
+
+        return (config != null)
+                ? config.getBoolean(CarrierConfigManager.KEY_SUPPORT_WPS_OVER_IMS_BOOL) : false;
+    }
+
+    private void handleWpsCall() {
+        if (isWpsCallSupportedByIms()) {
+            logd("WPS call placed over PS");
+            notifyPsSelected();
+        } else {
+            if (isOutOfService()) {
+                loge("Cannot place call in current ServiceState: " + mServiceState.getState());
+                notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
+            } else {
+                logd("WPS call placed over CS");
+                notifyCsSelected();
+            }
+        }
+    }
+
+    private boolean isTtySupportedByIms() {
+        CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class);
+
+        PersistableBundle config = null;
+        if (configManager != null) {
+            config = configManager.getConfigForSubId(mSelectionAttributes.getSubId());
+        }
+
+        return (config != null)
+                && config.getBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL);
+    }
+
+    private boolean isTtyModeEnabled() {
+        TelecomManager tm = mContext.getSystemService(TelecomManager.class);
+        if (tm == null) {
+            loge("isTtyModeEnabled: telecom not available");
+            return false;
+        }
+        return tm.getCurrentTtyMode() != TelecomManager.TTY_MODE_OFF;
+    }
+
     private synchronized void selectDomain() {
         if (mStopDomainSelection || mSelectionAttributes == null
                 || mTransportSelectorCallback == null) {
@@ -265,49 +320,71 @@
             return;
         }
 
-        if (mImsStateTracker.isMmTelFeatureAvailable()) {
-
-            if (!mImsRegStateReceived || !mMmTelCapabilitiesReceived) {
-                loge("Waiting for ImsState and MmTelCapabilities callbacks");
-                return;
+        if (!mImsStateTracker.isMmTelFeatureAvailable()) {
+            logd("MmTelFeatureAvailable unavailable");
+            if (isOutOfService()) {
+                loge("Cannot place call in current ServiceState: " + mServiceState.getState());
+                notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
+            } else {
+                notifyCsSelected();
             }
+            return;
+        }
 
-            if (!mImsStateTracker.isImsRegistered()) {
-                logd("IMS is NOT registered");
-                if (isOutOfService()) {
-                    loge("Cannot place call in current ServiceState: " + mServiceState.getState());
-                    notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
-                } else {
-                    notifyCsSelected();
-                }
-                return;
+        if (!mImsRegStateReceived || !mMmTelCapabilitiesReceived) {
+            loge("Waiting for ImsState and MmTelCapabilities callbacks");
+            return;
+        }
+
+        // Check IMS registration state.
+        if (!mImsStateTracker.isImsRegistered()) {
+            logd("IMS is NOT registered");
+            if (isOutOfService()) {
+                loge("Cannot place call in current ServiceState: " + mServiceState.getState());
+                notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
+            } else {
+                notifyCsSelected();
             }
+            return;
+        }
 
-            if (mSelectionAttributes.isVideoCall()) {
-                logd("It's a video call");
-                if (mImsStateTracker.isImsVideoCapable()) {
-                    logd("IMS is video capable");
-                    notifyPsSelected();
-                } else {
-                    logd("IMS is not video capable. Ending the call");
-                    notifySelectionTerminated(DisconnectCause.OUTGOING_FAILURE);
-                }
-            } else if (mImsStateTracker.isImsVoiceCapable()) {
-                logd("IMS is voice capable");
-                // Voice call over PS
+        // Check TTY
+        if (isTtyModeEnabled() && !isTtySupportedByIms()) {
+            if (isOutOfService()) {
+                loge("Cannot place call in current ServiceState: " + mServiceState.getState());
+                notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
+            } else {
+                notifyCsSelected();
+            }
+            return;
+        }
+
+        // Handle video call.
+        if (mSelectionAttributes.isVideoCall()) {
+            logd("It's a video call");
+            if (mImsStateTracker.isImsVideoCapable()) {
+                logd("IMS is video capable");
                 notifyPsSelected();
             } else {
-                logd("IMS is not voice capable");
-                // Voice call CS fallback
-                if (isOutOfService()) {
-                    loge("Cannot place call in current ServiceState: " + mServiceState.getState());
-                    notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
-                } else {
-                    notifyCsSelected();
-                }
+                logd("IMS is not video capable. Ending the call");
+                notifySelectionTerminated(DisconnectCause.OUTGOING_FAILURE);
+            }
+            return;
+        }
+
+        // Handle voice call.
+        if (mImsStateTracker.isImsVoiceCapable()) {
+            logd("IMS is voice capable");
+            // TODO(b/266175810) Remove this dependency.
+            if (NormalCallDomainSelectionConnection
+                    .isWpsCall(mSelectionAttributes.getNumber())) {
+                handleWpsCall();
+            } else {
+                notifyPsSelected();
             }
         } else {
-            logd("IMS is not registered or unavailable");
+            logd("IMS is not voice capable");
+            // Voice call CS fallback
             if (isOutOfService()) {
                 loge("Cannot place call in current ServiceState: " + mServiceState.getState());
                 notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
diff --git a/tests/src/com/android/phone/NotificationMgrTest.java b/tests/src/com/android/phone/NotificationMgrTest.java
index 3e8cf28..e009446 100644
--- a/tests/src/com/android/phone/NotificationMgrTest.java
+++ b/tests/src/com/android/phone/NotificationMgrTest.java
@@ -44,8 +44,10 @@
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -58,6 +60,7 @@
 import android.content.res.Resources;
 import android.os.Build;
 import android.os.PersistableBundle;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.telecom.TelecomManager;
@@ -89,6 +92,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.Collections;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Unit Test for NotificationMgr
@@ -128,6 +132,7 @@
 
     private Phone[] mPhones;
     private NotificationMgr mNotificationMgr;
+    private TestableLooper mTestableLooper;
 
     @Before
     public void setUp() throws Exception {
@@ -182,7 +187,10 @@
         when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
         when(mTelephonyManager.getServiceState()).thenReturn(mServiceState);
 
-        mNotificationMgr = new NotificationMgr(mApp);
+        mTestableLooper = TestableLooper.get(this);
+        // Spy it only to avoid sleep for SystemClock.elapsedRealtime()
+        mNotificationMgr = spy(new NotificationMgr(mApp));
+        mTestableLooper.processAllMessages();
     }
 
     @Test
@@ -278,10 +286,7 @@
         prepareResourcesForNetworkSelection();
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(2000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(2 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
@@ -298,12 +303,11 @@
         config.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true);
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
+        // update to OOS as base state
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        // TODO: use effective TestLooper time eclipse instead of sleeping
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        // 10 seconds later
+        moveTimeForward(10 /* seconds */);
+        // verify the behavior on new request
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verifyNotificationSentWithChannelId(NotificationChannelController.CHANNEL_ID_ALERT);
@@ -322,10 +326,7 @@
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE,
                 INVALID_SUBSCRIPTION_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE,
                 INVALID_SUBSCRIPTION_ID);
 
@@ -339,10 +340,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(null);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
@@ -362,10 +360,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
@@ -386,10 +381,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
@@ -410,10 +402,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
@@ -439,10 +428,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
@@ -469,10 +455,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
@@ -500,10 +483,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verifyNotificationSentWithChannelId(NotificationChannelController.CHANNEL_ID_ALERT);
@@ -524,10 +504,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verifyNotificationSentWithChannelId(NotificationChannelController.CHANNEL_ID_ALERT);
@@ -549,10 +526,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verifyNotificationSentWithChannelId(NotificationChannelController.CHANNEL_ID_ALERT);
@@ -572,10 +546,7 @@
         when(mTelephonyManager.getPhoneType()).thenReturn(TelephonyManager.PHONE_TYPE_CDMA);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
@@ -661,4 +632,11 @@
         when(mApp.getString(R.string.mobile_network_settings_class)).thenReturn(
                 MOBILE_NETWORK_SELECTION_CLASS);
     }
+
+    private void moveTimeForward(long seconds) {
+        final long millis = TimeUnit.SECONDS.toMillis(seconds);
+        mTestableLooper.moveTimeForward(millis);
+        mTestableLooper.processAllMessages();
+        doReturn(SystemClock.elapsedRealtime() + millis).when(mNotificationMgr).getTimeStamp();
+    }
 }
diff --git a/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
index 890ca34..8780f1f 100644
--- a/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
@@ -31,7 +31,10 @@
 import android.os.CancellationSignal;
 import android.os.HandlerThread;
 import android.os.Looper;
+import android.os.PersistableBundle;
+import android.telecom.TelecomManager;
 import android.telephony.AccessNetworkConstants;
+import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 import android.telephony.DomainSelectionService;
 import android.telephony.DomainSelector;
@@ -75,18 +78,32 @@
     private NormalCallDomainSelector mNormalCallDomainSelector;
 
     @Mock private Context mMockContext;
+    @Mock private CarrierConfigManager mMockCarrierConfigMgr;
     @Mock private ImsManager mMockImsManager;
     @Mock private ImsMmTelManager mMockMmTelManager;
     @Mock private ImsStateTracker mMockImsStateTracker;
     @Mock private DomainSelectorBase.DestroyListener mMockDestroyListener;
+    @Mock private TelecomManager mMockTelecomManager;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+
         doReturn(Context.TELEPHONY_IMS_SERVICE).when(mMockContext)
                 .getSystemServiceName(ImsManager.class);
         doReturn(mMockImsManager).when(mMockContext)
                 .getSystemService(Context.TELEPHONY_IMS_SERVICE);
+
+        doReturn(Context.CARRIER_CONFIG_SERVICE).when(mMockContext)
+                .getSystemServiceName(CarrierConfigManager.class);
+        doReturn(mMockCarrierConfigMgr).when(mMockContext)
+                .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+
+        doReturn(Context.TELECOM_SERVICE).when(mMockContext)
+                .getSystemServiceName(TelecomManager.class);
+        doReturn(mMockTelecomManager).when(mMockContext)
+                .getSystemService(Context.TELECOM_SERVICE);
+
         doReturn(mMockMmTelManager).when(mMockImsManager).getImsMmTelManager(SUB_ID_1);
         doReturn(mMockMmTelManager).when(mMockImsManager).getImsMmTelManager(SUB_ID_2);
         doNothing().when(mMockImsStateTracker).removeServiceStateListener(any());
@@ -310,6 +327,90 @@
         assertTrue(transportSelectorCallback.verifyOnWlanSelected());
     }
 
+    @Test
+    public void testWPSCallDomainSelection() {
+        MockTransportSelectorCallback transportSelectorCallback =
+                new MockTransportSelectorCallback();
+        DomainSelectionService.SelectionAttributes attributes =
+                new DomainSelectionService.SelectionAttributes.Builder(
+                        SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
+                        .setNumber("*272121")
+                        .setCallId(TEST_CALLID)
+                        .setEmergency(false)
+                        .setVideoCall(false)
+                        .setExitedFromAirplaneMode(false)
+                        .build();
+
+        //Case 1: WPS not supported by IMS
+        PersistableBundle config = new PersistableBundle();
+        config.putBoolean(CarrierConfigManager.KEY_SUPPORT_WPS_OVER_IMS_BOOL, false);
+        doReturn(config).when(mMockCarrierConfigMgr).getConfigForSubId(SUB_ID_1);
+        ServiceState serviceState = new ServiceState();
+        serviceState.setState(ServiceState.STATE_IN_SERVICE);
+        initialize(serviceState, true, true, true, true);
+        mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
+        assertTrue(transportSelectorCallback.verifyOnWwanSelected());
+        assertTrue(transportSelectorCallback
+                .verifyOnDomainSelected(NetworkRegistrationInfo.DOMAIN_CS));
+
+        //Case 2: WPS supported by IMS and WLAN registered
+        config.putBoolean(CarrierConfigManager.KEY_SUPPORT_WPS_OVER_IMS_BOOL, true);
+        serviceState.setState(ServiceState.STATE_IN_SERVICE);
+        initialize(serviceState, true, true, true, true);
+        mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
+        assertTrue(transportSelectorCallback.verifyOnWlanSelected());
+
+        //Case 2: WPS supported by IMS and LTE registered
+        config.putBoolean(CarrierConfigManager.KEY_SUPPORT_WPS_OVER_IMS_BOOL, true);
+        serviceState.setState(ServiceState.STATE_IN_SERVICE);
+        initialize(serviceState, true, false, true, true);
+        mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
+        assertTrue(transportSelectorCallback.verifyOnWwanSelected());
+        assertTrue(transportSelectorCallback
+                .verifyOnDomainSelected(NetworkRegistrationInfo.DOMAIN_PS));
+    }
+
+    @Test
+    public void testTtyCallDomainSelection() {
+        MockTransportSelectorCallback transportSelectorCallback =
+                new MockTransportSelectorCallback();
+        DomainSelectionService.SelectionAttributes attributes =
+                new DomainSelectionService.SelectionAttributes.Builder(
+                        SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
+                        .setCallId(TEST_CALLID)
+                        .setEmergency(false)
+                        .setVideoCall(false)
+                        .setExitedFromAirplaneMode(false)
+                        .build();
+
+        //Case 1: TTY not supported by IMS and TTY enabled
+        doReturn(TelecomManager.TTY_MODE_FULL).when(mMockTelecomManager).getCurrentTtyMode();
+        PersistableBundle config = new PersistableBundle();
+        config.putBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, false);
+        doReturn(config).when(mMockCarrierConfigMgr).getConfigForSubId(SUB_ID_1);
+        ServiceState serviceState = new ServiceState();
+        serviceState.setState(ServiceState.STATE_IN_SERVICE);
+        initialize(serviceState, true, false, true, true);
+        mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
+        assertTrue(transportSelectorCallback.verifyOnWwanSelected());
+        assertTrue(transportSelectorCallback
+                .verifyOnDomainSelected(NetworkRegistrationInfo.DOMAIN_CS));
+
+        //Case 2: TTY supported by IMS and TTY enabled
+        config.putBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
+        mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
+        assertTrue(transportSelectorCallback.verifyOnWwanSelected());
+        assertTrue(transportSelectorCallback
+                .verifyOnDomainSelected(NetworkRegistrationInfo.DOMAIN_PS));
+
+        //Case 3: TTY supported by IMS and TTY disabled
+        doReturn(TelecomManager.TTY_MODE_OFF).when(mMockTelecomManager).getCurrentTtyMode();
+        mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
+        assertTrue(transportSelectorCallback.verifyOnWwanSelected());
+        assertTrue(transportSelectorCallback
+                .verifyOnDomainSelected(NetworkRegistrationInfo.DOMAIN_PS));
+    }
+
     static class MockTransportSelectorCallback implements TransportSelectorCallback,
             WwanSelectorCallback {
         public boolean mCreated;