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