1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.services.telephony.domainselection;
18 
19 import static android.telephony.DomainSelectionService.SELECTOR_TYPE_CALLING;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
25 import static org.mockito.Mockito.any;
26 import static org.mockito.Mockito.doNothing;
27 import static org.mockito.Mockito.doReturn;
28 
29 import android.annotation.NonNull;
30 import android.content.Context;
31 import android.net.Uri;
32 import android.os.CancellationSignal;
33 import android.os.HandlerThread;
34 import android.os.Looper;
35 import android.os.PersistableBundle;
36 import android.telecom.PhoneAccount;
37 import android.telecom.TelecomManager;
38 import android.telephony.AccessNetworkConstants;
39 import android.telephony.CarrierConfigManager;
40 import android.telephony.DisconnectCause;
41 import android.telephony.DomainSelectionService;
42 import android.telephony.DomainSelector;
43 import android.telephony.EmergencyRegistrationResult;
44 import android.telephony.NetworkRegistrationInfo;
45 import android.telephony.ServiceState;
46 import android.telephony.SubscriptionManager;
47 import android.telephony.TransportSelectorCallback;
48 import android.telephony.WwanSelectorCallback;
49 import android.telephony.ims.ImsManager;
50 import android.telephony.ims.ImsMmTelManager;
51 import android.telephony.ims.ImsReasonInfo;
52 import android.testing.TestableLooper;
53 import android.util.Log;
54 
55 import androidx.test.runner.AndroidJUnit4;
56 
57 import com.android.internal.telephony.CallFailCause;
58 
59 import org.junit.After;
60 import org.junit.Before;
61 import org.junit.Test;
62 import org.junit.runner.RunWith;
63 import org.mockito.Mock;
64 import org.mockito.MockitoAnnotations;
65 
66 import java.util.List;
67 import java.util.function.Consumer;
68 
69 /**
70  * Unit tests for DomainSelectorBase.
71  */
72 @RunWith(AndroidJUnit4.class)
73 public class NormalCallDomainSelectorTest {
74     private static final String TAG = "NormalCallDomainSelectorTest";
75 
76     private static final int SELECTOR_TYPE_UT = 3;
77     private static final int SLOT_ID = 0;
78     private static final int SUB_ID_1 = 1;
79     private static final int SUB_ID_2 = 2;
80     private static final String TEST_CALLID = "01234";
81     private static final Uri TEST_URI = Uri.fromParts(PhoneAccount.SCHEME_TEL, "123456789", null);
82 
83     private HandlerThread mHandlerThread;
84     private NormalCallDomainSelector mNormalCallDomainSelector;
85     private TestableLooper mTestableLooper;
86     @Mock private Context mMockContext;
87     @Mock private CarrierConfigManager mMockCarrierConfigMgr;
88     @Mock private ImsManager mMockImsManager;
89     @Mock private ImsMmTelManager mMockMmTelManager;
90     @Mock private ImsStateTracker mMockImsStateTracker;
91     @Mock private DomainSelectorBase.DestroyListener mMockDestroyListener;
92     @Mock private TelecomManager mMockTelecomManager;
93 
94     @Before
setUp()95     public void setUp() throws Exception {
96         MockitoAnnotations.initMocks(this);
97 
98         doReturn(Context.TELEPHONY_IMS_SERVICE).when(mMockContext)
99                 .getSystemServiceName(ImsManager.class);
100         doReturn(mMockImsManager).when(mMockContext)
101                 .getSystemService(Context.TELEPHONY_IMS_SERVICE);
102 
103         doReturn(Context.CARRIER_CONFIG_SERVICE).when(mMockContext)
104                 .getSystemServiceName(CarrierConfigManager.class);
105         doReturn(mMockCarrierConfigMgr).when(mMockContext)
106                 .getSystemService(Context.CARRIER_CONFIG_SERVICE);
107 
108         doReturn(Context.TELECOM_SERVICE).when(mMockContext)
109                 .getSystemServiceName(TelecomManager.class);
110         doReturn(mMockTelecomManager).when(mMockContext)
111                 .getSystemService(Context.TELECOM_SERVICE);
112 
113         doReturn(mMockMmTelManager).when(mMockImsManager).getImsMmTelManager(SUB_ID_1);
114         doReturn(mMockMmTelManager).when(mMockImsManager).getImsMmTelManager(SUB_ID_2);
115         doNothing().when(mMockImsStateTracker).removeServiceStateListener(any());
116         doNothing().when(mMockImsStateTracker).removeImsStateListener(any());
117         doReturn(true).when(mMockImsStateTracker).isMmTelFeatureAvailable();
118 
119         // Set up the looper if it does not exist on the test thread.
120         if (Looper.myLooper() == null) {
121             Looper.prepare();
122         }
123 
124         mHandlerThread = new HandlerThread(
125                 NormalCallDomainSelectorTest.class.getSimpleName());
126         mHandlerThread.start();
127 
128         mNormalCallDomainSelector = new NormalCallDomainSelector(mMockContext, SLOT_ID, SUB_ID_1,
129                 mHandlerThread.getLooper(), mMockImsStateTracker, mMockDestroyListener);
130 
131         try {
132             setUpTestableLooper();
133         } catch (Exception e) {
134             fail(e.toString());
135         }
136     }
137 
138     @After
tearDown()139     public void tearDown() throws Exception {
140         if (mHandlerThread != null) {
141             mHandlerThread.quit();
142         }
143 
144         if (mTestableLooper != null) {
145             mTestableLooper.destroy();
146             mTestableLooper = null;
147         }
148     }
149 
setUpTestableLooper()150     private void setUpTestableLooper() throws Exception {
151         mTestableLooper = new TestableLooper(mNormalCallDomainSelector.getLooper());
152     }
153 
processAllMessages()154     private void processAllMessages() {
155         Log.d(TAG, "processAllMessages - start");
156         while (!mTestableLooper.getLooper().getQueue().isIdle()) {
157             mTestableLooper.processAllMessages();
158         }
159         Log.d(TAG, "processAllMessages - end");
160     }
161 
initialize(ServiceState serviceState, boolean isImsRegistered, boolean isImsRegisteredOverWlan, boolean isImsVoiceCapable, boolean isImsVideoCapable)162     private void initialize(ServiceState serviceState, boolean isImsRegistered,
163                             boolean isImsRegisteredOverWlan, boolean isImsVoiceCapable,
164                             boolean isImsVideoCapable) {
165         if (serviceState != null) mNormalCallDomainSelector.onServiceStateUpdated(serviceState);
166         doReturn(isImsRegistered).when(mMockImsStateTracker).isImsStateReady();
167         doReturn(isImsRegistered).when(mMockImsStateTracker).isImsRegistered();
168         doReturn(isImsVoiceCapable).when(mMockImsStateTracker).isImsVoiceCapable();
169         doReturn(isImsVideoCapable).when(mMockImsStateTracker).isImsVideoCapable();
170         doReturn(isImsRegisteredOverWlan).when(mMockImsStateTracker).isImsRegisteredOverWlan();
171         mNormalCallDomainSelector.onImsRegistrationStateChanged();
172         mNormalCallDomainSelector.onImsMmTelCapabilitiesChanged();
173     }
174 
175     @Test
testInit()176     public void testInit() {
177         assertEquals(SLOT_ID, mNormalCallDomainSelector.getSlotId());
178         assertEquals(SUB_ID_1, mNormalCallDomainSelector.getSubId());
179     }
180 
181     @Test
testInitialState()182     public void testInitialState() {
183         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
184                 mNormalCallDomainSelector.getSelectorState());
185     }
186 
187     @Test
testDestroyedState()188     public void testDestroyedState() {
189         mNormalCallDomainSelector.destroy();
190 
191         assertEquals(NormalCallDomainSelector.SelectorState.DESTROYED,
192                 mNormalCallDomainSelector.getSelectorState());
193     }
194 
195     @Test
testDestroyedDuringActiveState()196     public void testDestroyedDuringActiveState() {
197         TestTransportSelectorCallback transportSelectorCallback =
198                 new TestTransportSelectorCallback(mNormalCallDomainSelector);
199 
200         DomainSelectionService.SelectionAttributes attributes =
201                 new DomainSelectionService.SelectionAttributes.Builder(
202                         SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
203                         .setAddress(TEST_URI)
204                         .setCallId(TEST_CALLID)
205                         .setEmergency(false)
206                         .setVideoCall(true)
207                         .setExitedFromAirplaneMode(false)
208                         .build();
209 
210         mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
211 
212         assertEquals(NormalCallDomainSelector.SelectorState.ACTIVE,
213                 mNormalCallDomainSelector.getSelectorState());
214 
215         mNormalCallDomainSelector.destroy();
216 
217         assertEquals(NormalCallDomainSelector.SelectorState.DESTROYED,
218                 mNormalCallDomainSelector.getSelectorState());
219     }
220 
221     @Test
testSelectDomainInputParams()222     public void testSelectDomainInputParams() {
223         TestTransportSelectorCallback transportSelectorCallback =
224                 new TestTransportSelectorCallback(mNormalCallDomainSelector);
225 
226         DomainSelectionService.SelectionAttributes attributes =
227                 new DomainSelectionService.SelectionAttributes.Builder(
228                         SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
229                         .setAddress(TEST_URI)
230                         .setCallId(TEST_CALLID)
231                         .setEmergency(false)
232                         .setVideoCall(true)
233                         .setExitedFromAirplaneMode(false)
234                         .build();
235         mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
236 
237         assertEquals(NormalCallDomainSelector.SelectorState.ACTIVE,
238                 mNormalCallDomainSelector.getSelectorState());
239 
240         // Case 1: null inputs
241         try {
242             mNormalCallDomainSelector.selectDomain(null, null);
243         } catch (Exception e) {
244             fail("Invalid input params not handled." + e.getMessage());
245         }
246 
247         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
248                 mNormalCallDomainSelector.getSelectorState());
249 
250         // Case 2: null TransportSelectorCallback
251         try {
252             mNormalCallDomainSelector.selectDomain(attributes, null);
253         } catch (Exception e) {
254             fail("Invalid params (SelectionAttributes) not handled." + e.getMessage());
255         }
256 
257         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
258                 mNormalCallDomainSelector.getSelectorState());
259 
260         // Case 3: null SelectionAttributes
261         transportSelectorCallback.mSelectionTerminated = false;
262         try {
263             mNormalCallDomainSelector.selectDomain(null, transportSelectorCallback);
264         } catch (Exception e) {
265             fail("Invalid params (SelectionAttributes) not handled." + e.getMessage());
266         }
267 
268         assertTrue(transportSelectorCallback.mSelectionTerminated);
269         assertEquals(transportSelectorCallback.mCauseCode, DisconnectCause.OUTGOING_FAILURE);
270         assertEquals(NormalCallDomainSelector.SelectorState.DESTROYED,
271                 mNormalCallDomainSelector.getSelectorState());
272 
273         // Case 4: Invalid Subscription-id
274         attributes = new DomainSelectionService.SelectionAttributes.Builder(
275                 SLOT_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID, SELECTOR_TYPE_CALLING)
276                 .setAddress(TEST_URI)
277                 .setCallId(TEST_CALLID)
278                 .setEmergency(false)
279                 .setVideoCall(true)
280                 .setExitedFromAirplaneMode(false)
281                 .build();
282         try {
283             mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
284         } catch (Exception e) {
285             fail("Invalid params (SelectionAttributes) not handled." + e.getMessage());
286         }
287 
288         assertTrue(transportSelectorCallback.mSelectionTerminated);
289         assertEquals(transportSelectorCallback.mCauseCode, DisconnectCause.OUTGOING_FAILURE);
290         assertEquals(NormalCallDomainSelector.SelectorState.DESTROYED,
291                 mNormalCallDomainSelector.getSelectorState());
292 
293         // Case 5: Invalid SELECTOR_TYPE
294         attributes =
295                 new DomainSelectionService.SelectionAttributes.Builder(
296                         SLOT_ID, SUB_ID_1, SELECTOR_TYPE_UT)
297                         .setAddress(TEST_URI)
298                         .setCallId(TEST_CALLID)
299                         .setEmergency(false)
300                         .setVideoCall(true)
301                         .setExitedFromAirplaneMode(false)
302                         .build();
303         try {
304             mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
305         } catch (Exception e) {
306             fail("Invalid params (SelectionAttributes) not handled." + e.getMessage());
307         }
308 
309         assertTrue(transportSelectorCallback.mSelectionTerminated);
310         assertEquals(transportSelectorCallback.mCauseCode, DisconnectCause.OUTGOING_FAILURE);
311         assertEquals(NormalCallDomainSelector.SelectorState.DESTROYED,
312                 mNormalCallDomainSelector.getSelectorState());
313 
314         // Case 6: Emergency Call
315         attributes = new DomainSelectionService.SelectionAttributes.Builder(
316                 SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
317                 .setAddress(TEST_URI)
318                 .setCallId(TEST_CALLID)
319                 .setEmergency(true)
320                 .setVideoCall(true)
321                 .setExitedFromAirplaneMode(false)
322                 .build();
323         try {
324             mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
325         } catch (Exception e) {
326             fail("Invalid params (SelectionAttributes) not handled." + e.getMessage());
327         }
328 
329         assertTrue(transportSelectorCallback.mSelectionTerminated);
330         assertEquals(transportSelectorCallback.mCauseCode, DisconnectCause.OUTGOING_FAILURE);
331         assertEquals(NormalCallDomainSelector.SelectorState.DESTROYED,
332                 mNormalCallDomainSelector.getSelectorState());
333     }
334 
335     @Test
testOutOfService()336     public void testOutOfService() {
337         final TestTransportSelectorCallback transportSelectorCallback =
338                 new TestTransportSelectorCallback(mNormalCallDomainSelector);
339         mNormalCallDomainSelector.post(() -> {
340 
341             DomainSelectionService.SelectionAttributes attributes =
342                     new DomainSelectionService.SelectionAttributes.Builder(
343                             SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
344                             .setAddress(TEST_URI)
345                             .setCallId(TEST_CALLID)
346                             .setEmergency(false)
347                             .setVideoCall(true)
348                             .setExitedFromAirplaneMode(false)
349                             .build();
350 
351             ServiceState serviceState = new ServiceState();
352             serviceState.setStateOutOfService();
353             initialize(serviceState, false, false, false, false);
354 
355             mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
356         });
357 
358         processAllMessages();
359         assertTrue(transportSelectorCallback.mSelectionTerminated);
360         assertEquals(DisconnectCause.OUT_OF_SERVICE, transportSelectorCallback.mCauseCode);
361 
362         assertEquals(NormalCallDomainSelector.SelectorState.DESTROYED,
363                 mNormalCallDomainSelector.getSelectorState());
364     }
365 
366     @Test
testDomainSelection()367     public void testDomainSelection() {
368         final TestTransportSelectorCallback transportSelectorCallback =
369                 new TestTransportSelectorCallback(mNormalCallDomainSelector);
370 
371         final ServiceState serviceState = new ServiceState();
372         serviceState.setState(ServiceState.STATE_IN_SERVICE);
373         initialize(serviceState, true, true, true, true);
374         transportSelectorCallback.reset();
375         DomainSelectionService.SelectionAttributes attributes =
376                 new DomainSelectionService.SelectionAttributes.Builder(
377                         SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
378                         .setAddress(TEST_URI)
379                         .setCallId(TEST_CALLID)
380                         .setEmergency(false)
381                         .setVideoCall(false)
382                         .setExitedFromAirplaneMode(false)
383                         .build();
384 
385         // Case 1: WLAN
386         mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
387 
388         processAllMessages();
389         assertTrue(transportSelectorCallback.mWlanSelected);
390         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
391                 mNormalCallDomainSelector.getSelectorState());
392 
393         // Case 2: 5G
394         serviceState.setState(ServiceState.STATE_IN_SERVICE);
395         initialize(serviceState, true, false, true, true);
396         transportSelectorCallback.reset();
397         attributes = new DomainSelectionService.SelectionAttributes.Builder(
398                 SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
399                 .setAddress(TEST_URI)
400                 .setCallId(TEST_CALLID)
401                 .setEmergency(false)
402                 .setVideoCall(false)
403                 .setExitedFromAirplaneMode(false)
404                 .build();
405 
406         mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
407 
408         processAllMessages();
409         assertTrue(transportSelectorCallback.mWwanSelected);
410         assertEquals(NetworkRegistrationInfo.DOMAIN_PS, transportSelectorCallback.mSelectedDomain);
411         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
412                 mNormalCallDomainSelector.getSelectorState());
413 
414 
415         // Case 3: PS -> CS redial
416         final ImsReasonInfo imsReasonInfoCsRetry = new ImsReasonInfo(
417                 ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED, 0, null);
418         transportSelectorCallback.reset();
419         attributes = new DomainSelectionService.SelectionAttributes.Builder(
420                 SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
421                 .setAddress(TEST_URI)
422                 .setCallId(TEST_CALLID)
423                 .setEmergency(false)
424                 .setVideoCall(false)
425                 .setExitedFromAirplaneMode(false)
426                 .setPsDisconnectCause(imsReasonInfoCsRetry)
427                 .build();
428 
429         mNormalCallDomainSelector.reselectDomain(attributes);
430 
431         processAllMessages();
432         assertEquals(transportSelectorCallback.mSelectedDomain, NetworkRegistrationInfo.DOMAIN_CS);
433         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
434                 mNormalCallDomainSelector.getSelectorState());
435 
436         // Case 4: CS call
437         transportSelectorCallback.reset();
438         initialize(serviceState, false, false, false, false);
439         NetworkRegistrationInfo nwRegistrationInfo = new NetworkRegistrationInfo(
440                 NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
441                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME,
442                 AccessNetworkConstants.AccessNetworkType.UTRAN, 0, false,
443                 null, null, null, false, 0, 0, 0);
444         serviceState.addNetworkRegistrationInfo(nwRegistrationInfo);
445         attributes = new DomainSelectionService.SelectionAttributes.Builder(
446                 SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
447                 .setAddress(TEST_URI)
448                 .setCallId(TEST_CALLID)
449                 .setEmergency(false)
450                 .setVideoCall(false)
451                 .setExitedFromAirplaneMode(false)
452                 .build();
453 
454         mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
455 
456         processAllMessages();
457         assertEquals(transportSelectorCallback.mSelectedDomain, NetworkRegistrationInfo.DOMAIN_CS);
458         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
459                 mNormalCallDomainSelector.getSelectorState());
460 
461         //Case 5: Backup calling
462         serviceState.setStateOutOfService();
463         transportSelectorCallback.reset();
464         attributes = new DomainSelectionService.SelectionAttributes.Builder(
465                 SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
466                 .setAddress(TEST_URI)
467                 .setCallId(TEST_CALLID)
468                 .setEmergency(false)
469                 .setVideoCall(false)
470                 .setExitedFromAirplaneMode(false)
471                 .setPsDisconnectCause(imsReasonInfoCsRetry)
472                 .build();
473         initialize(serviceState, true, true, true, true);
474         mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
475 
476         processAllMessages();
477         assertTrue(transportSelectorCallback.mWlanSelected);
478         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
479                 mNormalCallDomainSelector.getSelectorState());
480     }
481 
482     @Test
testWPSCallDomainSelection()483     public void testWPSCallDomainSelection() {
484         TestTransportSelectorCallback transportSelectorCallback =
485                 new TestTransportSelectorCallback(mNormalCallDomainSelector);
486         DomainSelectionService.SelectionAttributes attributes =
487                 new DomainSelectionService.SelectionAttributes.Builder(
488                         SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
489                         .setAddress(Uri.fromParts(PhoneAccount.SCHEME_TEL, "*272121", null))
490                         .setCallId(TEST_CALLID)
491                         .setEmergency(false)
492                         .setVideoCall(false)
493                         .setExitedFromAirplaneMode(false)
494                         .build();
495 
496         //Case 1: WPS not supported by IMS
497         PersistableBundle config = new PersistableBundle();
498         config.putBoolean(CarrierConfigManager.KEY_SUPPORT_WPS_OVER_IMS_BOOL, false);
499         doReturn(config).when(mMockCarrierConfigMgr).getConfigForSubId(SUB_ID_1,
500                 new String[]{CarrierConfigManager.KEY_SUPPORT_WPS_OVER_IMS_BOOL});
501 
502         ServiceState serviceState = new ServiceState();
503         serviceState.setState(ServiceState.STATE_IN_SERVICE);
504         initialize(serviceState, true, true, true, true);
505 
506         mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
507 
508         processAllMessages();
509         assertTrue(transportSelectorCallback.mWwanSelected);
510         assertEquals(transportSelectorCallback.mSelectedDomain, NetworkRegistrationInfo.DOMAIN_CS);
511         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
512                 mNormalCallDomainSelector.getSelectorState());
513 
514         //Case 2: WPS supported by IMS and WLAN registered
515         transportSelectorCallback.reset();
516         config.putBoolean(CarrierConfigManager.KEY_SUPPORT_WPS_OVER_IMS_BOOL, true);
517         serviceState.setState(ServiceState.STATE_IN_SERVICE);
518         initialize(serviceState, true, true, true, true);
519 
520         mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
521 
522         processAllMessages();
523         assertTrue(transportSelectorCallback.mWlanSelected);
524         assertEquals(mNormalCallDomainSelector.getSelectorState(),
525                 NormalCallDomainSelector.SelectorState.INACTIVE);
526 
527         //Case 2: WPS supported by IMS and LTE registered
528         transportSelectorCallback.reset();
529         config.putBoolean(CarrierConfigManager.KEY_SUPPORT_WPS_OVER_IMS_BOOL, true);
530         serviceState.setState(ServiceState.STATE_IN_SERVICE);
531         initialize(serviceState, true, false, true, true);
532 
533         mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
534 
535         processAllMessages();
536         assertEquals(transportSelectorCallback.mSelectedDomain, NetworkRegistrationInfo.DOMAIN_PS);
537         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
538                 mNormalCallDomainSelector.getSelectorState());
539     }
540 
541     @Test
testTtyCallDomainSelection()542     public void testTtyCallDomainSelection() {
543         TestTransportSelectorCallback transportSelectorCallback =
544                 new TestTransportSelectorCallback(mNormalCallDomainSelector);
545         DomainSelectionService.SelectionAttributes attributes =
546                 new DomainSelectionService.SelectionAttributes.Builder(
547                         SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
548                         .setAddress(TEST_URI)
549                         .setCallId(TEST_CALLID)
550                         .setEmergency(false)
551                         .setVideoCall(false)
552                         .setExitedFromAirplaneMode(false)
553                         .build();
554 
555         //Case 1: TTY not supported by IMS and TTY enabled
556         doReturn(TelecomManager.TTY_MODE_FULL).when(mMockTelecomManager).getCurrentTtyMode();
557         PersistableBundle config = new PersistableBundle();
558         config.putBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, false);
559         doReturn(config).when(mMockCarrierConfigMgr).getConfigForSubId(SUB_ID_1,
560                 new String[]{CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL});
561 
562         ServiceState serviceState = new ServiceState();
563         serviceState.setState(ServiceState.STATE_IN_SERVICE);
564         initialize(serviceState, true, false, true, true);
565 
566         mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
567 
568         processAllMessages();
569         assertTrue(transportSelectorCallback.mWwanSelected);
570         assertEquals(transportSelectorCallback.mSelectedDomain, NetworkRegistrationInfo.DOMAIN_CS);
571         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
572                 mNormalCallDomainSelector.getSelectorState());
573 
574         //Case 2: TTY supported by IMS and TTY enabled
575         transportSelectorCallback.reset();
576         config.putBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
577         mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
578 
579         processAllMessages();
580         assertEquals(transportSelectorCallback.mSelectedDomain, NetworkRegistrationInfo.DOMAIN_PS);
581         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
582                 mNormalCallDomainSelector.getSelectorState());
583 
584         //Case 3: TTY supported by IMS and TTY disabled
585         transportSelectorCallback.reset();
586         doReturn(TelecomManager.TTY_MODE_OFF).when(mMockTelecomManager).getCurrentTtyMode();
587         mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
588 
589         processAllMessages();
590         assertEquals(transportSelectorCallback.mSelectedDomain, NetworkRegistrationInfo.DOMAIN_PS);
591         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
592                 mNormalCallDomainSelector.getSelectorState());
593     }
594 
595     @Test
testEmcCsFailureAndPsRedial()596     public void testEmcCsFailureAndPsRedial() {
597         final TestTransportSelectorCallback transportSelectorCallback =
598                 new TestTransportSelectorCallback(mNormalCallDomainSelector);
599 
600         final ServiceState serviceState = new ServiceState();
601 
602         // dial CS call
603         serviceState.setState(ServiceState.STATE_IN_SERVICE);
604         initialize(serviceState, false, false, false, false);
605         NetworkRegistrationInfo nwRegistrationInfo = new NetworkRegistrationInfo(
606                 NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
607                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME,
608                 AccessNetworkConstants.AccessNetworkType.UTRAN, 0, false,
609                 null, null, null, false, 0, 0, 0);
610         serviceState.addNetworkRegistrationInfo(nwRegistrationInfo);
611         DomainSelectionService.SelectionAttributes attributes =
612                 new DomainSelectionService.SelectionAttributes.Builder(
613                         SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
614                         .setAddress(TEST_URI)
615                         .setCallId(TEST_CALLID)
616                         .setEmergency(false)
617                         .setVideoCall(false)
618                         .setExitedFromAirplaneMode(false)
619                         .build();
620 
621         mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
622 
623         processAllMessages();
624         assertEquals(transportSelectorCallback.mSelectedDomain, NetworkRegistrationInfo.DOMAIN_CS);
625         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
626                 mNormalCallDomainSelector.getSelectorState());
627 
628         // EMC_REDIAL_ON_IMS
629         transportSelectorCallback.reset();
630         serviceState.setState(ServiceState.STATE_IN_SERVICE);
631         initialize(serviceState, true, false, true, false);
632         attributes = new DomainSelectionService.SelectionAttributes.Builder(
633                 SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
634                 .setAddress(TEST_URI)
635                 .setCallId(TEST_CALLID)
636                 .setEmergency(false)
637                 .setVideoCall(false)
638                 .setExitedFromAirplaneMode(false)
639                 .setCsDisconnectCause(CallFailCause.EMC_REDIAL_ON_IMS)
640                 .build();
641 
642         mNormalCallDomainSelector.reselectDomain(attributes);
643 
644         processAllMessages();
645         assertTrue(transportSelectorCallback.mWwanSelected);
646         assertEquals(NetworkRegistrationInfo.DOMAIN_PS, transportSelectorCallback.mSelectedDomain);
647         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
648                 mNormalCallDomainSelector.getSelectorState());
649 
650         // EMC_REDIAL_ON_VOWIFI
651         transportSelectorCallback.reset();
652         initialize(serviceState, true, true, true, false);
653         attributes = new DomainSelectionService.SelectionAttributes.Builder(
654                 SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
655                 .setAddress(TEST_URI)
656                 .setCallId(TEST_CALLID)
657                 .setEmergency(false)
658                 .setVideoCall(false)
659                 .setExitedFromAirplaneMode(false)
660                 .setCsDisconnectCause(CallFailCause.EMC_REDIAL_ON_VOWIFI)
661                 .build();
662 
663         mNormalCallDomainSelector.reselectDomain(attributes);
664 
665         processAllMessages();
666         assertTrue(transportSelectorCallback.mWlanSelected);
667         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
668                 mNormalCallDomainSelector.getSelectorState());
669     }
670 
671     @Test
testImsRegistrationStateTimeoutMessage()672     public void testImsRegistrationStateTimeoutMessage() {
673         final TestTransportSelectorCallback transportSelectorCallback =
674                 new TestTransportSelectorCallback(mNormalCallDomainSelector);
675 
676         final ServiceState serviceState = new ServiceState();
677         serviceState.setState(ServiceState.STATE_IN_SERVICE);
678         mNormalCallDomainSelector.onServiceStateUpdated(serviceState);
679         doReturn(true).when(mMockImsStateTracker).isImsStateReady();
680         doReturn(true).when(mMockImsStateTracker).isImsRegistered();
681         doReturn(true).when(mMockImsStateTracker).isImsVoiceCapable();
682         doReturn(false).when(mMockImsStateTracker).isImsVideoCapable();
683         doReturn(true).when(mMockImsStateTracker).isImsRegisteredOverWlan();
684 
685         DomainSelectionService.SelectionAttributes attributes =
686                 new DomainSelectionService.SelectionAttributes.Builder(
687                         SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
688                         .setAddress(TEST_URI)
689                         .setCallId(TEST_CALLID)
690                         .setEmergency(false)
691                         .setVideoCall(false)
692                         .setExitedFromAirplaneMode(false)
693                         .build();
694 
695         mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
696         assertTrue(mNormalCallDomainSelector.hasMessages(
697                 NormalCallDomainSelector.MSG_WAIT_FOR_IMS_STATE_TIMEOUT));
698 
699         mNormalCallDomainSelector.onImsRegistrationStateChanged();
700         mNormalCallDomainSelector.onImsMmTelCapabilitiesChanged();
701         processAllMessages();
702 
703         assertFalse(mNormalCallDomainSelector.hasMessages(
704                 NormalCallDomainSelector.MSG_WAIT_FOR_IMS_STATE_TIMEOUT));
705         assertTrue(transportSelectorCallback.mWlanSelected);
706         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
707                 mNormalCallDomainSelector.getSelectorState());
708     }
709 
710     @Test
testImsRegistrationStateTimeoutHandler()711     public void testImsRegistrationStateTimeoutHandler() {
712         final TestTransportSelectorCallback transportSelectorCallback =
713                 new TestTransportSelectorCallback(mNormalCallDomainSelector);
714 
715         final ServiceState serviceState = new ServiceState();
716         serviceState.setState(ServiceState.STATE_IN_SERVICE);
717         mNormalCallDomainSelector.onServiceStateUpdated(serviceState);
718         doReturn(true).when(mMockImsStateTracker).isImsStateReady();
719         doReturn(false).when(mMockImsStateTracker).isImsRegistered();
720         doReturn(true).when(mMockImsStateTracker).isImsVoiceCapable();
721         doReturn(false).when(mMockImsStateTracker).isImsVideoCapable();
722         doReturn(true).when(mMockImsStateTracker).isImsRegisteredOverWlan();
723 
724         DomainSelectionService.SelectionAttributes attributes =
725                 new DomainSelectionService.SelectionAttributes.Builder(
726                         SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
727                         .setAddress(TEST_URI)
728                         .setCallId(TEST_CALLID)
729                         .setEmergency(false)
730                         .setVideoCall(false)
731                         .setExitedFromAirplaneMode(false)
732                         .build();
733 
734         mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
735         assertTrue(mNormalCallDomainSelector.hasMessages(
736                 NormalCallDomainSelector.MSG_WAIT_FOR_IMS_STATE_TIMEOUT));
737 
738         mTestableLooper.moveTimeForward(
739                 NormalCallDomainSelector.WAIT_FOR_IMS_STATE_TIMEOUT_MS + 10);
740         processAllMessages();
741 
742         assertEquals(transportSelectorCallback.mSelectedDomain, NetworkRegistrationInfo.DOMAIN_CS);
743         assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
744                 mNormalCallDomainSelector.getSelectorState());
745     }
746 
747     static class TestTransportSelectorCallback implements TransportSelectorCallback,
748             WwanSelectorCallback {
749         public boolean mCreated;
750         public boolean mWlanSelected;
751         public boolean mWwanSelected;
752         public boolean mSelectionTerminated;
753         public boolean mDomainSelected;
754         int mCauseCode;
755         int mSelectedDomain;
756         NormalCallDomainSelector mNormalCallDomainSelector;
757 
TestTransportSelectorCallback(NormalCallDomainSelector normalCallDomainSelector)758         TestTransportSelectorCallback(NormalCallDomainSelector normalCallDomainSelector) {
759             mNormalCallDomainSelector = normalCallDomainSelector;
760             mCauseCode = DisconnectCause.NOT_VALID;
761         }
762 
763         @Override
onCreated(DomainSelector selector)764         public synchronized void onCreated(DomainSelector selector) {
765             Log.d(TAG, "onCreated");
766             mCreated = true;
767 
768             assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
769                     mNormalCallDomainSelector.getSelectorState());
770         }
771 
772         @Override
onWlanSelected(boolean useEmergencyPdn)773         public synchronized void onWlanSelected(boolean useEmergencyPdn) {
774             Log.d(TAG, "onWlanSelected");
775             mWlanSelected = true;
776         }
777 
778         @Override
onWwanSelected(final Consumer<WwanSelectorCallback> consumer)779         public void onWwanSelected(final Consumer<WwanSelectorCallback> consumer) {
780             Log.d(TAG, "onWwanSelected");
781             mWwanSelected = true;
782             consumer.accept(this);
783         }
784 
785         @Override
onSelectionTerminated(int cause)786         public synchronized void onSelectionTerminated(int cause) {
787             Log.i(TAG, "onSelectionTerminated - called");
788             mCauseCode = cause;
789             mSelectionTerminated = true;
790 
791             assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
792                     mNormalCallDomainSelector.getSelectorState());
793 
794             notifyAll();
795         }
796 
797         @Override
onRequestEmergencyNetworkScan(@onNull List<Integer> preferredNetworks, int scanType, boolean resetScan, @NonNull CancellationSignal signal, @NonNull Consumer<EmergencyRegistrationResult> consumer)798         public void onRequestEmergencyNetworkScan(@NonNull List<Integer> preferredNetworks,
799                 int scanType,
800                 boolean resetScan,
801                 @NonNull CancellationSignal signal,
802                 @NonNull Consumer<EmergencyRegistrationResult> consumer) {
803             Log.i(TAG, "onRequestEmergencyNetworkScan - called");
804 
805         }
806 
onDomainSelected(@etworkRegistrationInfo.Domain int domain, boolean useEmergencyPdn)807         public synchronized void onDomainSelected(@NetworkRegistrationInfo.Domain int domain,
808                 boolean useEmergencyPdn) {
809             Log.i(TAG, "onDomainSelected - called");
810             mSelectedDomain = domain;
811             mDomainSelected = true;
812             mWwanSelected = true;
813 
814             assertEquals(NormalCallDomainSelector.SelectorState.INACTIVE,
815                     mNormalCallDomainSelector.getSelectorState());
816 
817             notifyAll();
818         }
reset()819         public void reset() {
820             mCreated = false;
821             mWlanSelected = false;
822             mWwanSelected = false;
823             mSelectionTerminated = false;
824             mDomainSelected = false;
825             mCauseCode = DisconnectCause.NOT_VALID;
826             mSelectedDomain = NetworkRegistrationInfo.DOMAIN_UNKNOWN;
827         }
828     }
829 }
830