1 /*
2  * Copyright (C) 2016 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;
18 
19 import static com.android.internal.telephony.RILConstants.GSM_PHONE;
20 
21 import static junit.framework.Assert.assertEquals;
22 import static junit.framework.Assert.assertFalse;
23 import static junit.framework.Assert.assertNotNull;
24 import static junit.framework.Assert.assertTrue;
25 import static junit.framework.Assert.fail;
26 
27 import static org.mockito.ArgumentMatchers.any;
28 import static org.mockito.ArgumentMatchers.anyInt;
29 import static org.mockito.ArgumentMatchers.anyLong;
30 import static org.mockito.ArgumentMatchers.anyString;
31 import static org.mockito.Matchers.eq;
32 import static org.mockito.Mockito.doAnswer;
33 import static org.mockito.Mockito.doReturn;
34 import static org.mockito.Mockito.mock;
35 import static org.mockito.Mockito.never;
36 import static org.mockito.Mockito.verify;
37 import static org.mockito.Mockito.when;
38 
39 import android.content.ComponentName;
40 import android.content.Context;
41 import android.net.Uri;
42 import android.os.AsyncResult;
43 import android.os.Bundle;
44 import android.os.Handler;
45 import android.os.HandlerThread;
46 import android.os.Message;
47 import android.telecom.ConnectionRequest;
48 import android.telecom.DisconnectCause;
49 import android.telecom.PhoneAccountHandle;
50 import android.telecom.TelecomManager;
51 import android.telephony.CarrierConfigManager;
52 import android.telephony.RadioAccessFamily;
53 import android.telephony.ServiceState;
54 import android.telephony.TelephonyManager;
55 import android.telephony.emergency.EmergencyNumber;
56 import android.test.suitebuilder.annotation.SmallTest;
57 
58 import androidx.test.runner.AndroidJUnit4;
59 
60 import com.android.TelephonyTestBase;
61 import com.android.internal.telephony.CallStateException;
62 import com.android.internal.telephony.Connection;
63 import com.android.internal.telephony.Phone;
64 import com.android.internal.telephony.PhoneSwitcher;
65 import com.android.internal.telephony.ServiceStateTracker;
66 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
67 import com.android.internal.telephony.gsm.SuppServiceNotification;
68 
69 import org.junit.After;
70 import org.junit.Before;
71 import org.junit.Test;
72 import org.junit.runner.RunWith;
73 import org.mockito.ArgumentCaptor;
74 import org.mockito.Mock;
75 
76 import java.util.ArrayList;
77 import java.util.Collections;
78 import java.util.HashMap;
79 import java.util.List;
80 
81 /**
82  * Unit tests for TelephonyConnectionService.
83  */
84 
85 @RunWith(AndroidJUnit4.class)
86 public class TelephonyConnectionServiceTest extends TelephonyTestBase {
87 
88     private static final long TIMEOUT_MS = 100;
89     private static final int SLOT_0_PHONE_ID = 0;
90     private static final int SLOT_1_PHONE_ID = 1;
91 
92     private static final ComponentName TEST_COMPONENT_NAME = new ComponentName(
93             "com.android.phone.tests", TelephonyConnectionServiceTest.class.getName());
94     private static final String TEST_ACCOUNT_ID1 = "id1";
95     private static final String TEST_ACCOUNT_ID2 = "id2";
96     private static final PhoneAccountHandle PHONE_ACCOUNT_HANDLE_1 = new PhoneAccountHandle(
97             TEST_COMPONENT_NAME, TEST_ACCOUNT_ID1);
98     private static final PhoneAccountHandle PHONE_ACCOUNT_HANDLE_2 = new PhoneAccountHandle(
99             TEST_COMPONENT_NAME, TEST_ACCOUNT_ID2);
100     private static final Uri TEST_ADDRESS = Uri.parse("tel:+16505551212");
101     private android.telecom.Connection mConnection;
102 
103     @Mock TelephonyConnectionService.TelephonyManagerProxy mTelephonyManagerProxy;
104     @Mock TelephonyConnectionService.SubscriptionManagerProxy mSubscriptionManagerProxy;
105     @Mock TelephonyConnectionService.PhoneFactoryProxy mPhoneFactoryProxy;
106     @Mock DeviceState mDeviceState;
107     @Mock TelephonyConnectionService.PhoneSwitcherProxy mPhoneSwitcherProxy;
108     @Mock TelephonyConnectionService.PhoneNumberUtilsProxy mPhoneNumberUtilsProxy;
109     @Mock TelephonyConnectionService.PhoneUtilsProxy mPhoneUtilsProxy;
110     @Mock TelephonyConnectionService.HandlerFactory mHandlerFactory;
111     @Mock TelephonyConnectionService.DisconnectCauseFactory mDisconnectCauseFactory;
112     @Mock Handler mMockHandler;
113     @Mock EmergencyNumberTracker mEmergencyNumberTracker;
114     @Mock PhoneSwitcher mPhoneSwitcher;
115     @Mock RadioOnHelper mRadioOnHelper;
116     @Mock ServiceStateTracker mSST;
117 
118     private static class TestTelephonyConnectionService extends TelephonyConnectionService {
119 
120         private final Context mContext;
121 
TestTelephonyConnectionService(Context context)122         TestTelephonyConnectionService(Context context) {
123             mContext = context;
124         }
125 
126         @Override
onCreate()127         public void onCreate() {
128             // attach test context.
129             attachBaseContext(mContext);
130             super.onCreate();
131         }
132     }
133 
134     private TelephonyConnectionService mTestConnectionService;
135 
136     @Before
setUp()137     public void setUp() throws Exception {
138         super.setUp();
139         mTestConnectionService = new TestTelephonyConnectionService(mContext);
140         mTestConnectionService.setPhoneFactoryProxy(mPhoneFactoryProxy);
141         mTestConnectionService.setSubscriptionManagerProxy(mSubscriptionManagerProxy);
142         // Set configurations statically
143         doReturn(false).when(mDeviceState).shouldCheckSimStateBeforeOutgoingCall(any());
144         mTestConnectionService.setPhoneSwitcherProxy(mPhoneSwitcherProxy);
145         doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher();
146         when(mPhoneNumberUtilsProxy.convertToEmergencyNumber(any(), anyString()))
147                 .thenAnswer(invocation -> invocation.getArgument(1));
148         mTestConnectionService.setPhoneNumberUtilsProxy(mPhoneNumberUtilsProxy);
149         mTestConnectionService.setPhoneUtilsProxy(mPhoneUtilsProxy);
150         HandlerThread mockHandlerThread = mock(HandlerThread.class);
151         doReturn(mockHandlerThread).when(mHandlerFactory).createHandlerThread(anyString());
152         doReturn(null).when(mockHandlerThread).getLooper();
153         doReturn(mMockHandler).when(mHandlerFactory).createHandler(any());
154         mTestConnectionService.setHandlerFactory(mHandlerFactory);
155         mTestConnectionService.setDeviceState(mDeviceState);
156         mTestConnectionService.setRadioOnHelper(mRadioOnHelper);
157         doReturn(new DisconnectCause(DisconnectCause.UNKNOWN)).when(mDisconnectCauseFactory)
158                 .toTelecomDisconnectCause(anyInt(), any());
159         doReturn(new DisconnectCause(DisconnectCause.UNKNOWN)).when(mDisconnectCauseFactory)
160                 .toTelecomDisconnectCause(anyInt(), any(), anyInt());
161         mTestConnectionService.setDisconnectCauseFactory(mDisconnectCauseFactory);
162         mTestConnectionService.onCreate();
163         mTestConnectionService.setTelephonyManagerProxy(mTelephonyManagerProxy);
164     }
165 
166     @After
tearDown()167     public void tearDown() throws Exception {
168         mTestConnectionService = null;
169         super.tearDown();
170     }
171 
172     /**
173      * Prerequisites:
174      * - MSIM Device, two slots with SIMs inserted
175      * - Users default Voice SIM choice is IN_SERVICE
176      *
177      * Result: getFirstPhoneForEmergencyCall returns the default Voice SIM choice.
178      */
179     @Test
180     @SmallTest
testDefaultVoiceSimInService()181     public void testDefaultVoiceSimInService() {
182         Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_IN_SERVICE,
183                 false /*isEmergencyOnly*/);
184         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
185                 true /*isEmergencyOnly*/);
186         setDefaultPhone(slot0Phone);
187         setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
188 
189         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
190 
191         assertEquals(slot0Phone, resultPhone);
192     }
193 
194     /**
195      * Prerequisites:
196      * - MSIM Device, two slots with SIMs inserted
197      * - Slot 0 is OUT_OF_SERVICE, Slot 1 is OUT_OF_SERVICE (emergency calls only)
198      *
199      * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone
200      */
201     @Test
202     @SmallTest
testSlot1EmergencyOnly()203     public void testSlot1EmergencyOnly() {
204         Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
205                 false /*isEmergencyOnly*/);
206         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
207                 true /*isEmergencyOnly*/);
208         setDefaultPhone(slot0Phone);
209         setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
210 
211         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
212 
213         assertEquals(slot1Phone, resultPhone);
214     }
215 
216     /**
217      * Prerequisites:
218      * - MSIM Device, two slots with SIMs inserted
219      * - Slot 0 is OUT_OF_SERVICE, Slot 1 is IN_SERVICE
220      *
221      * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone
222      */
223     @Test
224     @SmallTest
testSlot1InService()225     public void testSlot1InService() {
226         Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
227                 false /*isEmergencyOnly*/);
228         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_IN_SERVICE,
229                 false /*isEmergencyOnly*/);
230         setDefaultPhone(slot0Phone);
231         setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
232 
233         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
234 
235         assertEquals(slot1Phone, resultPhone);
236     }
237 
238     /**
239      * Prerequisites:
240      * - MSIM Device, two slots with SIMs inserted
241      * - Slot 0 is PUK locked, Slot 1 is ready
242      * - Slot 0 is LTE capable, Slot 1 is GSM capable
243      *
244      * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone. Although Slot 0 is more
245      * capable, it is locked, so use the other slot.
246      */
247     @Test
248     @SmallTest
testSlot0PukLocked()249     public void testSlot0PukLocked() {
250         Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
251                 false /*isEmergencyOnly*/);
252         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
253                 false /*isEmergencyOnly*/);
254         setDefaultPhone(slot0Phone);
255         setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
256         // Set Slot 0 to be PUK locked
257         setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_PUK_REQUIRED);
258         setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
259         // Make Slot 0 higher capability
260         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
261         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_GSM);
262 
263         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
264 
265         assertEquals(slot1Phone, resultPhone);
266     }
267 
268     /**
269      * Prerequisites:
270      * - MSIM Device, two slots with SIMs inserted
271      * - Slot 0 is PIN locked, Slot 1 is ready
272      * - Slot 0 is LTE capable, Slot 1 is GSM capable
273      *
274      * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone. Although Slot 0 is more
275      * capable, it is locked, so use the other slot.
276      */
277     @Test
278     @SmallTest
testSlot0PinLocked()279     public void testSlot0PinLocked() {
280         Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
281                 false /*isEmergencyOnly*/);
282         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
283                 false /*isEmergencyOnly*/);
284         setDefaultPhone(slot0Phone);
285         setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
286         // Set Slot 0 to be PUK locked
287         setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_PIN_REQUIRED);
288         setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
289         // Make Slot 0 higher capability
290         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
291         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_GSM);
292 
293         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
294 
295         assertEquals(slot1Phone, resultPhone);
296     }
297 
298     /**
299      * Prerequisites:
300      * - MSIM Device, two slots with SIMs inserted
301      * - Slot 1 is PUK locked, Slot 0 is ready
302      * - Slot 1 is LTE capable, Slot 0 is GSM capable
303      *
304      * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone. Although Slot 1 is more
305      * capable, it is locked, so use the other slot.
306      */
307     @Test
308     @SmallTest
testSlot1PukLocked()309     public void testSlot1PukLocked() {
310         Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
311                 false /*isEmergencyOnly*/);
312         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
313                 false /*isEmergencyOnly*/);
314         setDefaultPhone(slot0Phone);
315         setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
316         // Set Slot 1 to be PUK locked
317         setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
318         setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_PUK_REQUIRED);
319         // Make Slot 1 higher capability
320         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
321         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
322 
323         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
324 
325         assertEquals(slot0Phone, resultPhone);
326     }
327 
328     /**
329      * Prerequisites:
330      * - MSIM Device, two slots with SIMs inserted
331      * - Slot 1 is PIN locked, Slot 0 is ready
332      * - Slot 1 is LTE capable, Slot 0 is GSM capable
333      *
334      * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone. Although Slot 1 is more
335      * capable, it is locked, so use the other slot.
336      */
337     @Test
338     @SmallTest
testSlot1PinLocked()339     public void testSlot1PinLocked() {
340         Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
341                 false /*isEmergencyOnly*/);
342         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
343                 false /*isEmergencyOnly*/);
344         setDefaultPhone(slot0Phone);
345         setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
346         // Set Slot 1 to be PUK locked
347         setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
348         setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_PIN_REQUIRED);
349         // Make Slot 1 higher capability
350         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
351         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
352 
353         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
354 
355         assertEquals(slot0Phone, resultPhone);
356     }
357 
358     /**
359      * Prerequisites:
360      * - MSIM Device, only slot 1 inserted and PUK locked
361      * - slot 1 has higher capabilities
362      *
363      * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone because it is the only one
364      * with a SIM inserted (even if it is PUK locked)
365      */
366     @Test
367     @SmallTest
testSlot1PinLockedAndSlot0Absent()368     public void testSlot1PinLockedAndSlot0Absent() {
369         Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
370                 false /*isEmergencyOnly*/);
371         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
372                 false /*isEmergencyOnly*/);
373         setDefaultPhone(slot0Phone);
374         setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
375         setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
376         setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_PIN_REQUIRED);
377         // Slot 1 has more capabilities
378         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
379         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
380         // Slot 1 has SIM inserted.
381         setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
382         setSlotHasIccCard(SLOT_1_PHONE_ID, true /*isInserted*/);
383 
384         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
385 
386         assertEquals(slot1Phone, resultPhone);
387     }
388 
389     /**
390      * Prerequisites:
391      * - MSIM Device, two slots with SIMs inserted
392      * - Slot 1 is LTE capable, Slot 0 is GSM capable
393      *
394      * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone because it is more capable
395      */
396     @Test
397     @SmallTest
testSlot1HigherCapablity()398     public void testSlot1HigherCapablity() {
399         Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
400                 false /*isEmergencyOnly*/);
401         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
402                 false /*isEmergencyOnly*/);
403         setDefaultPhone(slot0Phone);
404         setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
405         setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
406         setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
407         // Make Slot 1 higher capability
408         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
409         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
410 
411         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
412 
413         assertEquals(slot1Phone, resultPhone);
414     }
415 
416     /**
417      * Prerequisites:
418      * - MSIM Device, two slots with SIMs inserted
419      * - Slot 1 is GSM/LTE capable, Slot 0 is GSM capable
420      *
421      * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone because it has more
422      * capabilities.
423      */
424     @Test
425     @SmallTest
testSlot1MoreCapabilities()426     public void testSlot1MoreCapabilities() {
427         Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
428                 false /*isEmergencyOnly*/);
429         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
430                 false /*isEmergencyOnly*/);
431         setDefaultPhone(slot0Phone);
432         setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
433         setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
434         setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
435         // Make Slot 1 more capable
436         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
437         setPhoneRadioAccessFamily(slot1Phone,
438                 RadioAccessFamily.RAF_GSM | RadioAccessFamily.RAF_LTE);
439 
440         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
441 
442         assertEquals(slot1Phone, resultPhone);
443     }
444 
445     /**
446      * Prerequisites:
447      * - MSIM Device, two slots with SIMs inserted
448      * - Both SIMs PUK Locked
449      * - Slot 0 is LTE capable, Slot 1 is GSM capable
450      *
451      * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone because it is more capable,
452      * ignoring that both SIMs are PUK locked.
453      */
454     @Test
455     @SmallTest
testSlot0MoreCapableBothPukLocked()456     public void testSlot0MoreCapableBothPukLocked() {
457         Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
458                 false /*isEmergencyOnly*/);
459         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
460                 false /*isEmergencyOnly*/);
461         setDefaultPhone(slot0Phone);
462         setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
463         setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_PUK_REQUIRED);
464         setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_PUK_REQUIRED);
465         // Make Slot 0 higher capability
466         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
467         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_GSM);
468 
469         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
470 
471         assertEquals(slot0Phone, resultPhone);
472     }
473 
474     /**
475      * Prerequisites:
476      * - MSIM Device, two slots with SIMs inserted
477      * - Both SIMs have the same capability
478      *
479      * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone because it is the first slot.
480      */
481     @Test
482     @SmallTest
testEqualCapabilityTwoSimsInserted()483     public void testEqualCapabilityTwoSimsInserted() {
484         Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
485                 false /*isEmergencyOnly*/);
486         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
487                 false /*isEmergencyOnly*/);
488         setDefaultPhone(slot0Phone);
489         setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
490         setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
491         setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
492         // Make Capability the same
493         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
494         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
495         // Two SIMs inserted
496         setSlotHasIccCard(SLOT_0_PHONE_ID, true /*isInserted*/);
497         setSlotHasIccCard(SLOT_1_PHONE_ID, true /*isInserted*/);
498 
499         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
500 
501         assertEquals(slot0Phone, resultPhone);
502     }
503 
504     /**
505      * Prerequisites:
506      * - MSIM Device, only slot 0 inserted
507      * - Both SIMs have the same capability
508      *
509      * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone because it is the only one
510      * with a SIM inserted
511      */
512     @Test
513     @SmallTest
testEqualCapabilitySim0Inserted()514     public void testEqualCapabilitySim0Inserted() {
515         Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
516                 false /*isEmergencyOnly*/);
517         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
518                 false /*isEmergencyOnly*/);
519         setDefaultPhone(slot0Phone);
520         setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
521         setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
522         setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
523         // Make Capability the same
524         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
525         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
526         // Slot 0 has SIM inserted.
527         setSlotHasIccCard(SLOT_0_PHONE_ID, true /*isInserted*/);
528         setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
529 
530         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
531 
532         assertEquals(slot0Phone, resultPhone);
533     }
534 
535     /**
536      * Prerequisites:
537      * - MSIM Device, only slot 1 inserted
538      * - Both SIMs have the same capability
539      *
540      * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone because it is the only one
541      * with a SIM inserted
542      */
543     @Test
544     @SmallTest
testEqualCapabilitySim1Inserted()545     public void testEqualCapabilitySim1Inserted() {
546         Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
547                 false /*isEmergencyOnly*/);
548         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
549                 false /*isEmergencyOnly*/);
550         setDefaultPhone(slot0Phone);
551         setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
552         setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
553         setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
554         // Make Capability the same
555         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
556         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
557         // Slot 1 has SIM inserted.
558         setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
559         setSlotHasIccCard(SLOT_1_PHONE_ID, true /*isInserted*/);
560 
561         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
562 
563         assertEquals(slot1Phone, resultPhone);
564     }
565 
566     /**
567      * Prerequisites:
568      * - MSIM Device, no SIMs inserted
569      * - SIM 1 has the higher capability
570      *
571      * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone, since it is a higher
572      * capability
573      */
574     @Test
575     @SmallTest
testSim1HigherCapabilityNoSimsInserted()576     public void testSim1HigherCapabilityNoSimsInserted() {
577         Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
578                 false /*isEmergencyOnly*/);
579         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
580                 false /*isEmergencyOnly*/);
581         setDefaultPhone(slot0Phone);
582         setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
583         setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
584         setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
585         // Make Capability the same
586         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
587         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
588         // No SIMs inserted
589         setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
590         setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
591 
592         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
593 
594         assertEquals(slot1Phone, resultPhone);
595     }
596 
597     /**
598      * Prerequisites:
599      * - MSIM Device, no SIMs inserted
600      * - Both SIMs have the same capability (Unknown)
601      *
602      * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone, since it is the first slot.
603      */
604     @Test
605     @SmallTest
testEqualCapabilityNoSimsInserted()606     public void testEqualCapabilityNoSimsInserted() {
607         Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
608                 false /*isEmergencyOnly*/);
609         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
610                 false /*isEmergencyOnly*/);
611         setDefaultPhone(slot0Phone);
612         setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
613         setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
614         setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
615         // Make Capability the same
616         setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_UNKNOWN);
617         setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_UNKNOWN);
618         // No SIMs inserted
619         setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
620         setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
621 
622         Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
623 
624         assertEquals(slot0Phone, resultPhone);
625     }
626 
627     /**
628      * The modem has returned a temporary error when placing an emergency call on a phone with one
629      * SIM slot.
630      *
631      * Verify that dial is called on the same phone again when retryOutgoingOriginalConnection is
632      * called.
633      */
634     @Test
635     @SmallTest
testRetryOutgoingOriginalConnection_redialTempFailOneSlot()636     public void testRetryOutgoingOriginalConnection_redialTempFailOneSlot() {
637         TestTelephonyConnection c = new TestTelephonyConnection();
638         Phone slot0Phone = c.getPhone();
639         when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
640         List<Phone> phones = new ArrayList<>(1);
641         phones.add(slot0Phone);
642         setPhones(phones);
643         c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
644 
645         mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
646 
647         // We never need to be notified in telecom that the PhoneAccount has changed, because it
648         // was redialed on the same slot
649         assertEquals(0, c.getNotifyPhoneAccountChangedCount());
650         try {
651             verify(slot0Phone).dial(anyString(), any());
652         } catch (CallStateException e) {
653             // This shouldn't happen
654             fail();
655         }
656     }
657 
658     /**
659      * The modem has returned a permanent failure when placing an emergency call on a phone with one
660      * SIM slot.
661      *
662      * Verify that the connection is set to disconnected with an error disconnect cause and dial is
663      * not called.
664      */
665     @Test
666     @SmallTest
testRetryOutgoingOriginalConnection_redialPermFailOneSlot()667     public void testRetryOutgoingOriginalConnection_redialPermFailOneSlot() {
668         TestTelephonyConnection c = new TestTelephonyConnection();
669         Phone slot0Phone = c.getPhone();
670         when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
671         List<Phone> phones = new ArrayList<>(1);
672         phones.add(slot0Phone);
673         setPhones(phones);
674         c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
675 
676         mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
677 
678         // We never need to be notified in telecom that the PhoneAccount has changed, because it
679         // was never redialed
680         assertEquals(0, c.getNotifyPhoneAccountChangedCount());
681         try {
682             verify(slot0Phone, never()).dial(anyString(), any());
683         } catch (CallStateException e) {
684             // This shouldn't happen
685             fail();
686         }
687         assertEquals(c.getState(), android.telecom.Connection.STATE_DISCONNECTED);
688         assertEquals(c.getDisconnectCause().getCode(), DisconnectCause.ERROR);
689     }
690 
691     /**
692      * The modem has returned a temporary failure when placing an emergency call on a phone with two
693      * SIM slots.
694      *
695      * Verify that the emergency call is dialed on the other slot and telecom is notified of the new
696      * PhoneAccount.
697      */
698     @Test
699     @SmallTest
testRetryOutgoingOriginalConnection_redialTempFailTwoSlot()700     public void testRetryOutgoingOriginalConnection_redialTempFailTwoSlot() {
701         TestTelephonyConnection c = new TestTelephonyConnection();
702         Phone slot0Phone = c.getPhone();
703         when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
704         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
705                 false /*isEmergencyOnly*/);
706         setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
707         c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
708         List<Phone> phones = new ArrayList<>(2);
709         phones.add(slot0Phone);
710         phones.add(slot1Phone);
711         setPhones(phones);
712         doReturn(PHONE_ACCOUNT_HANDLE_1).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
713                 slot0Phone);
714         doReturn(PHONE_ACCOUNT_HANDLE_2).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
715                 slot1Phone);
716 
717         mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
718 
719         // The cache should still contain all of the Phones, since it was a temporary failure.
720         assertEquals(2, mTestConnectionService.mEmergencyRetryCache.second.size());
721         // We need to be notified in Telecom that the PhoneAccount has changed, because it was
722         // redialed on another slot
723         assertEquals(1, c.getNotifyPhoneAccountChangedCount());
724         try {
725             verify(slot1Phone).dial(anyString(), any());
726         } catch (CallStateException e) {
727             // This shouldn't happen
728             fail();
729         }
730     }
731 
732     /**
733      * The modem has returned a temporary failure when placing an emergency call on a phone with two
734      * SIM slots.
735      *
736      * Verify that the emergency call is dialed on the other slot and telecom is notified of the new
737      * PhoneAccount.
738      */
739     @Test
740     @SmallTest
testRetryOutgoingOriginalConnection_redialPermFailTwoSlot()741     public void testRetryOutgoingOriginalConnection_redialPermFailTwoSlot() {
742         TestTelephonyConnection c = new TestTelephonyConnection();
743         Phone slot0Phone = c.getPhone();
744         when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
745         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
746                 false /*isEmergencyOnly*/);
747         setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
748         c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
749         List<Phone> phones = new ArrayList<>(2);
750         phones.add(slot0Phone);
751         phones.add(slot1Phone);
752         setPhones(phones);
753         doReturn(PHONE_ACCOUNT_HANDLE_1).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
754                 slot0Phone);
755         doReturn(PHONE_ACCOUNT_HANDLE_2).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
756                 slot1Phone);
757 
758         mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
759 
760         // The cache should only contain the slot1Phone.
761         assertEquals(1, mTestConnectionService.mEmergencyRetryCache.second.size());
762         // We need to be notified in Telecom that the PhoneAccount has changed, because it was
763         // redialed on another slot
764         assertEquals(1, c.getNotifyPhoneAccountChangedCount());
765         try {
766             verify(slot1Phone).dial(anyString(), any());
767         } catch (CallStateException e) {
768             // This shouldn't happen
769             fail();
770         }
771     }
772 
773     /**
774      * The modem has returned a temporary failure twice while placing an emergency call on a phone
775      * with two SIM slots.
776      *
777      * Verify that the emergency call is dialed on slot 1 and then on slot 0 and telecom is
778      * notified of this twice.
779      */
780     @Test
781     @SmallTest
testRetryOutgoingOriginalConnection_redialTempFailTwoSlot_twoFailure()782     public void testRetryOutgoingOriginalConnection_redialTempFailTwoSlot_twoFailure() {
783         TestTelephonyConnection c = new TestTelephonyConnection();
784         Phone slot0Phone = c.getPhone();
785         when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
786         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
787                 false /*isEmergencyOnly*/);
788         setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
789         c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
790         List<Phone> phones = new ArrayList<>(2);
791         phones.add(slot0Phone);
792         phones.add(slot1Phone);
793         setPhones(phones);
794         doReturn(PHONE_ACCOUNT_HANDLE_1).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
795                 slot0Phone);
796         doReturn(PHONE_ACCOUNT_HANDLE_2).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
797                 slot1Phone);
798 
799         // First Temporary failure
800         mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
801         // Set the Phone to the new phone that was just used to dial.
802         c.setMockPhone(slot1Phone);
803         // The cache should still contain all of the Phones, since it was a temporary failure.
804         assertEquals(2, mTestConnectionService.mEmergencyRetryCache.second.size());
805         // Make sure slot 1 is next in the queue.
806         assertEquals(slot1Phone, mTestConnectionService.mEmergencyRetryCache.second.peek());
807         // Second Temporary failure
808         mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
809         // Set the Phone to the new phone that was just used to dial.
810         c.setMockPhone(slot0Phone);
811         // The cache should still contain all of the Phones, since it was a temporary failure.
812         assertEquals(2, mTestConnectionService.mEmergencyRetryCache.second.size());
813         // Make sure slot 0 is next in the queue.
814         assertEquals(slot0Phone, mTestConnectionService.mEmergencyRetryCache.second.peek());
815 
816         // We need to be notified in Telecom that the PhoneAccount has changed, because it was
817         // redialed on another slot
818         assertEquals(2, c.getNotifyPhoneAccountChangedCount());
819         try {
820             verify(slot0Phone).dial(anyString(), any());
821             verify(slot1Phone).dial(anyString(), any());
822         } catch (CallStateException e) {
823             // This shouldn't happen
824             fail();
825         }
826     }
827 
828     /**
829      * The modem has returned a permanent failure twice while placing an emergency call on a phone
830      * with two SIM slots.
831      *
832      * Verify that the emergency call is dialed on slot 1 and then disconnected and telecom is
833      * notified of the change to slot 1.
834      */
835     @Test
836     @SmallTest
testRetryOutgoingOriginalConnection_redialPermFailTwoSlot_twoFailure()837     public void testRetryOutgoingOriginalConnection_redialPermFailTwoSlot_twoFailure() {
838         TestTelephonyConnection c = new TestTelephonyConnection();
839         Phone slot0Phone = c.getPhone();
840         when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
841         Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
842                 false /*isEmergencyOnly*/);
843         setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
844         c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
845         List<Phone> phones = new ArrayList<>(2);
846         phones.add(slot0Phone);
847         phones.add(slot1Phone);
848         setPhones(phones);
849         doReturn(PHONE_ACCOUNT_HANDLE_1).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
850                 slot0Phone);
851         doReturn(PHONE_ACCOUNT_HANDLE_2).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
852                 slot1Phone);
853 
854         // First Permanent failure
855         mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
856         // Set the Phone to the new phone that was just used to dial.
857         c.setMockPhone(slot1Phone);
858         // The cache should only contain one phone
859         assertEquals(1, mTestConnectionService.mEmergencyRetryCache.second.size());
860         // Make sure slot 1 is next in the queue.
861         assertEquals(slot1Phone, mTestConnectionService.mEmergencyRetryCache.second.peek());
862         // Second Permanent failure
863         mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
864         // The cache should be empty
865         assertEquals(true, mTestConnectionService.mEmergencyRetryCache.second.isEmpty());
866 
867         assertEquals(c.getState(), android.telecom.Connection.STATE_DISCONNECTED);
868         assertEquals(c.getDisconnectCause().getCode(), DisconnectCause.ERROR);
869         // We need to be notified in Telecom that the PhoneAccount has changed, because it was
870         // redialed on another slot
871         assertEquals(1, c.getNotifyPhoneAccountChangedCount());
872         try {
873             verify(slot1Phone).dial(anyString(), any());
874             verify(slot0Phone, never()).dial(anyString(), any());
875         } catch (CallStateException e) {
876             // This shouldn't happen
877             fail();
878         }
879     }
880 
881     @Test
882     @SmallTest
testSuppServiceNotification()883     public void testSuppServiceNotification() {
884         TestTelephonyConnection c = new TestTelephonyConnection();
885 
886         // We need to set the original connection to cause the supp service notification
887         // registration to occur.
888         Phone phone = c.getPhone();
889         c.setOriginalConnection(c.getOriginalConnection());
890         doReturn(mContext).when(phone).getContext();
891 
892         // When the registration occurs, we'll capture the handler and message so we can post our
893         // own messages to it.
894         ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
895         ArgumentCaptor<Integer> messageCaptor = ArgumentCaptor.forClass(Integer.class);
896         verify(phone).registerForSuppServiceNotification(handlerCaptor.capture(),
897                 messageCaptor.capture(), any());
898         Handler handler = handlerCaptor.getValue();
899         int message = messageCaptor.getValue();
900 
901         // With the handler and message now known, we'll post a supp service notification.
902         AsyncResult result = getSuppServiceNotification(
903                 SuppServiceNotification.NOTIFICATION_TYPE_CODE_1,
904                 SuppServiceNotification.CODE_1_CALL_FORWARDED);
905         handler.obtainMessage(message, result).sendToTarget();
906         waitForHandlerAction(handler, TIMEOUT_MS);
907 
908         assertTrue(c.getLastConnectionEvents().contains(TelephonyManager.EVENT_CALL_FORWARDED));
909 
910         // With the handler and message now known, we'll post a supp service notification.
911         result = getSuppServiceNotification(
912                 SuppServiceNotification.NOTIFICATION_TYPE_CODE_1,
913                 SuppServiceNotification.CODE_1_CALL_IS_WAITING);
914         handler.obtainMessage(message, result).sendToTarget();
915         waitForHandlerAction(handler, TIMEOUT_MS);
916 
917         // We we want the 3rd event since the forwarding one above sends 2.
918         assertEquals(c.getLastConnectionEvents().get(2),
919                 TelephonyManager.EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION);
920         Bundle extras = c.getLastConnectionEventExtras().get(2);
921         assertEquals(SuppServiceNotification.NOTIFICATION_TYPE_CODE_1,
922                 extras.getInt(TelephonyManager.EXTRA_NOTIFICATION_TYPE));
923         assertEquals(SuppServiceNotification.CODE_1_CALL_IS_WAITING,
924                 extras.getInt(TelephonyManager.EXTRA_NOTIFICATION_CODE));
925     }
926 
927     /**
928      * Test that the TelephonyConnectionService successfully performs a DDS switch before a call
929      * when we are not roaming and the carrier only supports SUPL over the data plane.
930      */
931     @Test
932     @SmallTest
testCreateOutgoingEmergencyConnection_delayDial_carrierconfig_dds()933     public void testCreateOutgoingEmergencyConnection_delayDial_carrierconfig_dds() {
934         Phone testPhone = setupConnectionServiceForDelayDial();
935         Runnable delayDialRunnable = verifyRunnablePosted();
936 
937         // Setup test to not support SUPL on the non-DDS subscription
938         doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
939         getTestContext().getCarrierConfig().putStringArray(
940                 CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
941                 null);
942         testPhone.getServiceState().setRoaming(false);
943         getTestContext().getCarrierConfig().putInt(
944                 CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
945                 CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY);
946         getTestContext().getCarrierConfig().putString(
947                 CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "150");
948         delayDialRunnable.run();
949 
950         verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /*phoneId*/ ,
951                 eq(150) /*extensionTime*/, any());
952     }
953 
954     /**
955      * Test that the TelephonyConnectionService successfully turns radio on before placing the
956      * emergency call.
957      */
958     @Test
959     @SmallTest
testCreateOutgoingEmerge_exitingApm_disconnected()960     public void testCreateOutgoingEmerge_exitingApm_disconnected() {
961         when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
962         Phone testPhone = setupConnectionServiceInApm();
963 
964         ArgumentCaptor<RadioOnStateListener.Callback> callback =
965                 ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
966         verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
967                 eq(testPhone));
968 
969         assertFalse(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
970         when(mSST.isRadioOn()).thenReturn(true);
971         assertTrue(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
972 
973         mConnection.setDisconnected(null);
974         callback.getValue().onComplete(null, true);
975         for (Phone phone : mPhoneFactoryProxy.getPhones()) {
976             verify(phone).setRadioPower(true, false, false, true);
977         }
978     }
979 
980     /**
981      * Test that the TelephonyConnectionService successfully turns radio on before placing the
982      * emergency call.
983      */
984     @Test
985     @SmallTest
testCreateOutgoingEmergencyConnection_exitingApm_placeCall()986     public void testCreateOutgoingEmergencyConnection_exitingApm_placeCall() {
987         when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
988         Phone testPhone = setupConnectionServiceInApm();
989 
990         ArgumentCaptor<RadioOnStateListener.Callback> callback =
991                 ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
992         verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
993                 eq(testPhone));
994 
995         assertFalse(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
996         when(mSST.isRadioOn()).thenReturn(true);
997         assertTrue(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
998 
999         callback.getValue().onComplete(null, true);
1000         Runnable delayDialRunnable = verifyRunnablePosted();
1001 
1002         try {
1003             doAnswer(invocation -> null).when(mContext).startActivity(any());
1004             delayDialRunnable.run();
1005             verify(testPhone).dial(anyString(), any());
1006         } catch (CallStateException e) {
1007             // This shouldn't happen
1008             fail();
1009         }
1010     }
1011 
1012     /**
1013      * Test that the TelephonyConnectionService does not perform a DDS switch when the carrier
1014      * supports control-plane fallback.
1015      */
1016     @Test
1017     @SmallTest
testCreateOutgoingEmergencyConnection_delayDial_nocarrierconfig()1018     public void testCreateOutgoingEmergencyConnection_delayDial_nocarrierconfig() {
1019         Phone testPhone = setupConnectionServiceForDelayDial();
1020         Runnable delayDialRunnable = verifyRunnablePosted();
1021 
1022         // Setup test to not support SUPL on the non-DDS subscription
1023         doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
1024         getTestContext().getCarrierConfig().putStringArray(
1025                 CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
1026                 null);
1027         testPhone.getServiceState().setRoaming(false);
1028         getTestContext().getCarrierConfig().putInt(
1029                 CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
1030                 CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK);
1031         getTestContext().getCarrierConfig().putString(
1032                 CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
1033         delayDialRunnable.run();
1034 
1035         verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any());
1036     }
1037 
1038     /**
1039      * Test that the TelephonyConnectionService does not perform a DDS switch when the carrier
1040      * supports control-plane fallback.
1041      */
1042     @Test
1043     @SmallTest
testCreateOutgoingEmergencyConnection_delayDial_supportsuplondds()1044     public void testCreateOutgoingEmergencyConnection_delayDial_supportsuplondds() {
1045         Phone testPhone = setupConnectionServiceForDelayDial();
1046         Runnable delayDialRunnable = verifyRunnablePosted();
1047 
1048         // If the non-DDS supports SUPL, dont switch data
1049         doReturn(false).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
1050         getTestContext().getCarrierConfig().putStringArray(
1051                 CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
1052                 null);
1053         testPhone.getServiceState().setRoaming(false);
1054         getTestContext().getCarrierConfig().putInt(
1055                 CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
1056                 CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY);
1057         getTestContext().getCarrierConfig().putString(
1058                 CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
1059         delayDialRunnable.run();
1060 
1061         verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any());
1062     }
1063 
1064     /**
1065      * Test that the TelephonyConnectionService does not perform a DDS switch when the carrier does
1066      * not support control-plane fallback CarrierConfig while roaming.
1067      */
1068     @Test
1069     @SmallTest
testCreateOutgoingEmergencyConnection_delayDial_roaming_nocarrierconfig()1070     public void testCreateOutgoingEmergencyConnection_delayDial_roaming_nocarrierconfig() {
1071         Phone testPhone = setupConnectionServiceForDelayDial();
1072         Runnable delayDialRunnable = verifyRunnablePosted();
1073 
1074         // Setup test to not support SUPL on the non-DDS subscription
1075         doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
1076         getTestContext().getCarrierConfig().putStringArray(
1077                 CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
1078                 null);
1079         testPhone.getServiceState().setRoaming(true);
1080         getTestContext().getCarrierConfig().putInt(
1081                 CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
1082                 CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY);
1083         getTestContext().getCarrierConfig().putString(
1084                 CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
1085         delayDialRunnable.run();
1086 
1087         verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any());
1088     }
1089 
1090     /**
1091      * Test that the TelephonyConnectionService does perform a DDS switch even though the carrier
1092      * supports control-plane fallback CarrierConfig and the roaming partner is configured to look
1093      * like a home network.
1094      */
1095     @Test
1096     @SmallTest
testCreateOutgoingEmergencyConnection_delayDial_roamingcarrierconfig()1097     public void testCreateOutgoingEmergencyConnection_delayDial_roamingcarrierconfig() {
1098         Phone testPhone = setupConnectionServiceForDelayDial();
1099         Runnable delayDialRunnable = verifyRunnablePosted();
1100 
1101         // Setup voice roaming scenario
1102         String testRoamingOperator = "001001";
1103         // In some roaming conditions, we are not technically "roaming"
1104         testPhone.getServiceState().setRoaming(false);
1105         testPhone.getServiceState().setOperatorName("TestTel", "TestTel", testRoamingOperator);
1106         // Setup test to not support SUPL on the non-DDS subscription
1107         doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
1108         String[] roamingPlmns = new String[1];
1109         roamingPlmns[0] = testRoamingOperator;
1110         getTestContext().getCarrierConfig().putStringArray(
1111                 CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
1112                 roamingPlmns);
1113         getTestContext().getCarrierConfig().putInt(
1114                 CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
1115                 CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK);
1116         getTestContext().getCarrierConfig().putString(
1117                 CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
1118         delayDialRunnable.run();
1119 
1120         verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /*phoneId*/ ,
1121                 eq(0) /*extensionTime*/, any());
1122     }
1123 
1124     /**
1125      * Test that the TelephonyConnectionService does perform a DDS switch even though the carrier
1126      * supports control-plane fallback CarrierConfig if we are roaming and the roaming partner is
1127      * configured to use data plane only SUPL.
1128      */
1129     @Test
1130     @SmallTest
testCreateOutgoingEmergencyConnection_delayDial__roaming_roamingcarrierconfig()1131     public void testCreateOutgoingEmergencyConnection_delayDial__roaming_roamingcarrierconfig() {
1132         Phone testPhone = setupConnectionServiceForDelayDial();
1133         Runnable delayDialRunnable = verifyRunnablePosted();
1134 
1135         // Setup voice roaming scenario
1136         String testRoamingOperator = "001001";
1137         testPhone.getServiceState().setRoaming(true);
1138         testPhone.getServiceState().setOperatorName("TestTel", "TestTel", testRoamingOperator);
1139         // Setup test to not support SUPL on the non-DDS subscription
1140         doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
1141         String[] roamingPlmns = new String[1];
1142         roamingPlmns[0] = testRoamingOperator;
1143         getTestContext().getCarrierConfig().putStringArray(
1144                 CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
1145                 roamingPlmns);
1146         getTestContext().getCarrierConfig().putInt(
1147                 CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
1148                 CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK);
1149         getTestContext().getCarrierConfig().putString(
1150                 CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
1151         delayDialRunnable.run();
1152 
1153         verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /*phoneId*/ ,
1154                 eq(0) /*extensionTime*/, any());
1155     }
1156 
1157     /**
1158      * Set up a mock MSIM device with TEST_ADDRESS set as an emergency number.
1159      * @return the Phone associated with slot 0.
1160      */
setupConnectionServiceForDelayDial()1161     private Phone setupConnectionServiceForDelayDial() {
1162         ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
1163                 .setAccountHandle(PHONE_ACCOUNT_HANDLE_1)
1164                 .setAddress(TEST_ADDRESS)
1165                 .build();
1166         Phone testPhone0 = makeTestPhone(0 /*phoneId*/, ServiceState.STATE_IN_SERVICE,
1167                 false /*isEmergencyOnly*/);
1168         Phone testPhone1 = makeTestPhone(1 /*phoneId*/, ServiceState.STATE_OUT_OF_SERVICE,
1169                 false /*isEmergencyOnly*/);
1170         List<Phone> phones = new ArrayList<>(2);
1171         doReturn(true).when(testPhone0).isRadioOn();
1172         doReturn(true).when(testPhone1).isRadioOn();
1173         phones.add(testPhone0);
1174         phones.add(testPhone1);
1175         setPhones(phones);
1176         setupHandleToPhoneMap(PHONE_ACCOUNT_HANDLE_1, testPhone0);
1177         setupDeviceConfig(testPhone0, testPhone1, 1);
1178         doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(
1179                 TEST_ADDRESS.getSchemeSpecificPart());
1180         HashMap<Integer, List<EmergencyNumber>> emergencyNumbers = new HashMap<>(1);
1181         List<EmergencyNumber> numbers = new ArrayList<>();
1182         numbers.add(setupEmergencyNumber(TEST_ADDRESS));
1183         emergencyNumbers.put(0 /*subId*/, numbers);
1184         doReturn(emergencyNumbers).when(mTelephonyManagerProxy).getCurrentEmergencyNumberList();
1185         doReturn(2).when(mTelephonyManagerProxy).getPhoneCount();
1186 
1187         mConnection = mTestConnectionService.onCreateOutgoingConnection(
1188                 PHONE_ACCOUNT_HANDLE_1, connectionRequest);
1189         assertNotNull("test connection was not set up correctly.", mConnection);
1190 
1191         return testPhone0;
1192     }
1193 
1194 
1195     /**
1196      * Set up a mock MSIM device with TEST_ADDRESS set as an emergency number in airplane mode.
1197      * @return the Phone associated with slot 0.
1198      */
setupConnectionServiceInApm()1199     private Phone setupConnectionServiceInApm() {
1200         ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
1201                 .setAccountHandle(PHONE_ACCOUNT_HANDLE_1)
1202                 .setAddress(TEST_ADDRESS)
1203                 .build();
1204         Phone testPhone0 = makeTestPhone(0 /*phoneId*/, ServiceState.STATE_POWER_OFF,
1205                 false /*isEmergencyOnly*/);
1206         Phone testPhone1 = makeTestPhone(1 /*phoneId*/, ServiceState.STATE_POWER_OFF,
1207                 false /*isEmergencyOnly*/);
1208         doReturn(GSM_PHONE).when(testPhone0).getPhoneType();
1209         doReturn(GSM_PHONE).when(testPhone1).getPhoneType();
1210         List<Phone> phones = new ArrayList<>(2);
1211         doReturn(false).when(testPhone0).isRadioOn();
1212         doReturn(false).when(testPhone1).isRadioOn();
1213         phones.add(testPhone0);
1214         phones.add(testPhone1);
1215         setPhones(phones);
1216         setupHandleToPhoneMap(PHONE_ACCOUNT_HANDLE_1, testPhone0);
1217         setupDeviceConfig(testPhone0, testPhone1, 0);
1218         doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(
1219                 TEST_ADDRESS.getSchemeSpecificPart());
1220         HashMap<Integer, List<EmergencyNumber>> emergencyNumbers = new HashMap<>(1);
1221         List<EmergencyNumber> numbers = new ArrayList<>();
1222         numbers.add(setupEmergencyNumber(TEST_ADDRESS));
1223         emergencyNumbers.put(0 /*subId*/, numbers);
1224         doReturn(emergencyNumbers).when(mTelephonyManagerProxy).getCurrentEmergencyNumberList();
1225         doReturn(2).when(mTelephonyManagerProxy).getPhoneCount();
1226 
1227         mConnection = mTestConnectionService.onCreateOutgoingConnection(
1228                 PHONE_ACCOUNT_HANDLE_1, connectionRequest);
1229         assertNotNull("test connection was not set up correctly.", mConnection);
1230 
1231         return testPhone0;
1232     }
1233 
verifyRunnablePosted()1234     private Runnable verifyRunnablePosted() {
1235         ArgumentCaptor<Message> runnableCaptor = ArgumentCaptor.forClass(Message.class);
1236         verify(mMockHandler).sendMessageDelayed(runnableCaptor.capture(), anyLong());
1237         assertNotNull("Invalid Message created", runnableCaptor.getValue());
1238         Runnable runnable = runnableCaptor.getValue().getCallback();
1239         assertNotNull("sendMessageDelayed never occurred.", runnableCaptor);
1240         return runnable;
1241     }
1242 
setupEmergencyNumber(Uri address)1243     private EmergencyNumber setupEmergencyNumber(Uri address) {
1244         return new EmergencyNumber(address.getSchemeSpecificPart(), "", "",
1245         EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
1246         Collections.emptyList(),
1247         EmergencyNumber.EMERGENCY_NUMBER_SOURCE_SIM,
1248         EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY);
1249     }
1250 
setupHandleToPhoneMap(PhoneAccountHandle handle, Phone phone)1251     private void setupHandleToPhoneMap(PhoneAccountHandle handle,  Phone phone) {
1252         // use subId 0
1253         when(mPhoneUtilsProxy.getSubIdForPhoneAccountHandle(handle)).thenReturn(0);
1254         when(mSubscriptionManagerProxy.getPhoneId(0)).thenReturn(0);
1255         when(mPhoneFactoryProxy.getPhone(0)).thenReturn(phone);
1256     }
1257 
getSuppServiceNotification(int notificationType, int code)1258     private AsyncResult getSuppServiceNotification(int notificationType, int code) {
1259         SuppServiceNotification notification = new SuppServiceNotification();
1260         notification.notificationType = notificationType;
1261         notification.code = code;
1262         return new AsyncResult(null, notification, null);
1263     }
1264 
makeTestPhone(int phoneId, int serviceState, boolean isEmergencyOnly)1265     private Phone makeTestPhone(int phoneId, int serviceState, boolean isEmergencyOnly) {
1266         Phone phone = mock(Phone.class);
1267         ServiceState testServiceState = new ServiceState();
1268         testServiceState.setState(serviceState);
1269         testServiceState.setEmergencyOnly(isEmergencyOnly);
1270         when(phone.getContext()).thenReturn(mContext);
1271         when(phone.getServiceState()).thenReturn(testServiceState);
1272         when(phone.getPhoneId()).thenReturn(phoneId);
1273         when(phone.getDefaultPhone()).thenReturn(phone);
1274         when(phone.getEmergencyNumberTracker()).thenReturn(mEmergencyNumberTracker);
1275         when(phone.getServiceStateTracker()).thenReturn(mSST);
1276         when(mEmergencyNumberTracker.getEmergencyNumber(anyString())).thenReturn(null);
1277         return phone;
1278     }
1279 
1280     // Setup 2 SIM device
setupDeviceConfig(Phone slot0Phone, Phone slot1Phone, int defaultVoicePhoneId)1281     private void setupDeviceConfig(Phone slot0Phone, Phone slot1Phone, int defaultVoicePhoneId) {
1282         when(mTelephonyManagerProxy.getPhoneCount()).thenReturn(2);
1283         when(mSubscriptionManagerProxy.getDefaultVoicePhoneId()).thenReturn(defaultVoicePhoneId);
1284         when(mPhoneFactoryProxy.getPhone(eq(SLOT_0_PHONE_ID))).thenReturn(slot0Phone);
1285         when(mPhoneFactoryProxy.getPhone(eq(SLOT_1_PHONE_ID))).thenReturn(slot1Phone);
1286     }
1287 
setPhoneRadioAccessFamily(Phone phone, int radioAccessFamily)1288     private void setPhoneRadioAccessFamily(Phone phone, int radioAccessFamily) {
1289         when(phone.getRadioAccessFamily()).thenReturn(radioAccessFamily);
1290     }
1291 
setPhoneSlotState(int slotId, int slotState)1292     private void setPhoneSlotState(int slotId, int slotState) {
1293         when(mSubscriptionManagerProxy.getSimStateForSlotIdx(slotId)).thenReturn(slotState);
1294     }
1295 
setSlotHasIccCard(int slotId, boolean isInserted)1296     private void setSlotHasIccCard(int slotId, boolean isInserted) {
1297         when(mTelephonyManagerProxy.hasIccCard(slotId)).thenReturn(isInserted);
1298     }
1299 
setDefaultPhone(Phone phone)1300     private void setDefaultPhone(Phone phone) {
1301         when(mPhoneFactoryProxy.getDefaultPhone()).thenReturn(phone);
1302     }
1303 
setPhones(List<Phone> phones)1304     private void setPhones(List<Phone> phones) {
1305         when(mPhoneFactoryProxy.getPhones()).thenReturn(phones.toArray(new Phone[phones.size()]));
1306         when(mPhoneFactoryProxy.getDefaultPhone()).thenReturn(phones.get(0));
1307     }
1308 
setPhonesDialConnection(Phone phone, Connection c)1309     private void setPhonesDialConnection(Phone phone, Connection c) {
1310         try {
1311             when(phone.dial(anyString(), any())).thenReturn(c);
1312         } catch (CallStateException e) {
1313             // this shouldn't happen
1314             fail();
1315         }
1316     }
1317 }
1318