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
17package com.android.services.telephony;
18
19import static junit.framework.Assert.assertEquals;
20import static junit.framework.Assert.assertTrue;
21import static junit.framework.Assert.fail;
22
23import static org.mockito.ArgumentMatchers.any;
24import static org.mockito.ArgumentMatchers.anyInt;
25import static org.mockito.ArgumentMatchers.anyString;
26import static org.mockito.Matchers.eq;
27import static org.mockito.Mockito.mock;
28import static org.mockito.Mockito.never;
29import static org.mockito.Mockito.verify;
30import static org.mockito.Mockito.when;
31
32import android.net.Uri;
33import android.os.AsyncResult;
34import android.os.Bundle;
35import android.os.Handler;
36import android.support.test.filters.FlakyTest;
37import android.support.test.runner.AndroidJUnit4;
38import android.telecom.DisconnectCause;
39import android.telecom.TelecomManager;
40import android.telephony.RadioAccessFamily;
41import android.telephony.ServiceState;
42import android.telephony.TelephonyManager;
43import android.test.suitebuilder.annotation.SmallTest;
44
45import com.android.TelephonyTestBase;
46import com.android.internal.telephony.CallStateException;
47import com.android.internal.telephony.Connection;
48import com.android.internal.telephony.Phone;
49import com.android.internal.telephony.gsm.SuppServiceNotification;
50
51import org.junit.After;
52import org.junit.Before;
53import org.junit.Test;
54import org.junit.runner.RunWith;
55import org.mockito.ArgumentCaptor;
56import org.mockito.Mock;
57
58import java.util.ArrayList;
59import java.util.List;
60
61/**
62 * Unit tests for TelephonyConnectionService.
63 */
64
65@RunWith(AndroidJUnit4.class)
66public class TelephonyConnectionServiceTest extends TelephonyTestBase {
67
68    private static final long TIMEOUT_MS = 100;
69    private static final int SLOT_0_PHONE_ID = 0;
70    private static final int SLOT_1_PHONE_ID = 1;
71
72    @Mock TelephonyConnectionService.TelephonyManagerProxy mTelephonyManagerProxy;
73    @Mock TelephonyConnectionService.SubscriptionManagerProxy mSubscriptionManagerProxy;
74    @Mock TelephonyConnectionService.PhoneFactoryProxy mPhoneFactoryProxy;
75
76    TelephonyConnectionService mTestConnectionService;
77
78    @Before
79    public void setUp() throws Exception {
80        super.setUp();
81        mTestConnectionService = new TelephonyConnectionService();
82        mTestConnectionService.setPhoneFactoryProxy(mPhoneFactoryProxy);
83        mTestConnectionService.setTelephonyManagerProxy(mTelephonyManagerProxy);
84        mTestConnectionService.setSubscriptionManagerProxy(mSubscriptionManagerProxy);
85    }
86
87    @After
88    public void tearDown() throws Exception {
89        mTestConnectionService = null;
90        super.tearDown();
91    }
92
93    /**
94     * Prerequisites:
95     * - MSIM Device, two slots with SIMs inserted
96     * - Users default Voice SIM choice is IN_SERVICE
97     *
98     * Result: getFirstPhoneForEmergencyCall returns the default Voice SIM choice.
99     */
100    @Test
101    @SmallTest
102    public void testDefaultVoiceSimInService() {
103        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_IN_SERVICE,
104                false /*isEmergencyOnly*/);
105        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
106                true /*isEmergencyOnly*/);
107        setDefaultPhone(slot0Phone);
108        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
109
110        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
111
112        assertEquals(slot0Phone, resultPhone);
113    }
114
115    /**
116     * Prerequisites:
117     * - MSIM Device, two slots with SIMs inserted
118     * - Slot 0 is OUT_OF_SERVICE, Slot 1 is OUT_OF_SERVICE (emergency calls only)
119     *
120     * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone
121     */
122    @Test
123    @SmallTest
124    public void testSlot1EmergencyOnly() {
125        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
126                false /*isEmergencyOnly*/);
127        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
128                true /*isEmergencyOnly*/);
129        setDefaultPhone(slot0Phone);
130        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
131
132        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
133
134        assertEquals(slot1Phone, resultPhone);
135    }
136
137    /**
138     * Prerequisites:
139     * - MSIM Device, two slots with SIMs inserted
140     * - Slot 0 is OUT_OF_SERVICE, Slot 1 is IN_SERVICE
141     *
142     * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone
143     */
144    @Test
145    @SmallTest
146    public void testSlot1InService() {
147        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
148                false /*isEmergencyOnly*/);
149        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_IN_SERVICE,
150                false /*isEmergencyOnly*/);
151        setDefaultPhone(slot0Phone);
152        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
153
154        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
155
156        assertEquals(slot1Phone, resultPhone);
157    }
158
159    /**
160     * Prerequisites:
161     * - MSIM Device, two slots with SIMs inserted
162     * - Slot 0 is PUK locked, Slot 1 is ready
163     * - Slot 0 is LTE capable, Slot 1 is GSM capable
164     *
165     * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone. Although Slot 0 is more
166     * capable, it is locked, so use the other slot.
167     */
168    @Test
169    @SmallTest
170    public void testSlot0PukLocked() {
171        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
172                false /*isEmergencyOnly*/);
173        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
174                false /*isEmergencyOnly*/);
175        setDefaultPhone(slot0Phone);
176        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
177        // Set Slot 0 to be PUK locked
178        setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_PUK_REQUIRED);
179        setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
180        // Make Slot 0 higher capability
181        setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
182        setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_GSM);
183
184        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
185
186        assertEquals(slot1Phone, resultPhone);
187    }
188
189    /**
190     * Prerequisites:
191     * - MSIM Device, two slots with SIMs inserted
192     * - Slot 0 is PIN locked, Slot 1 is ready
193     * - Slot 0 is LTE capable, Slot 1 is GSM capable
194     *
195     * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone. Although Slot 0 is more
196     * capable, it is locked, so use the other slot.
197     */
198    @Test
199    @SmallTest
200    public void testSlot0PinLocked() {
201        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
202                false /*isEmergencyOnly*/);
203        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
204                false /*isEmergencyOnly*/);
205        setDefaultPhone(slot0Phone);
206        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
207        // Set Slot 0 to be PUK locked
208        setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_PIN_REQUIRED);
209        setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
210        // Make Slot 0 higher capability
211        setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
212        setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_GSM);
213
214        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
215
216        assertEquals(slot1Phone, resultPhone);
217    }
218
219    /**
220     * Prerequisites:
221     * - MSIM Device, two slots with SIMs inserted
222     * - Slot 1 is PUK locked, Slot 0 is ready
223     * - Slot 1 is LTE capable, Slot 0 is GSM capable
224     *
225     * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone. Although Slot 1 is more
226     * capable, it is locked, so use the other slot.
227     */
228    @Test
229    @SmallTest
230    public void testSlot1PukLocked() {
231        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
232                false /*isEmergencyOnly*/);
233        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
234                false /*isEmergencyOnly*/);
235        setDefaultPhone(slot0Phone);
236        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
237        // Set Slot 1 to be PUK locked
238        setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
239        setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_PUK_REQUIRED);
240        // Make Slot 1 higher capability
241        setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
242        setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
243
244        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
245
246        assertEquals(slot0Phone, resultPhone);
247    }
248
249    /**
250     * Prerequisites:
251     * - MSIM Device, two slots with SIMs inserted
252     * - Slot 1 is PIN locked, Slot 0 is ready
253     * - Slot 1 is LTE capable, Slot 0 is GSM capable
254     *
255     * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone. Although Slot 1 is more
256     * capable, it is locked, so use the other slot.
257     */
258    @Test
259    @SmallTest
260    public void testSlot1PinLocked() {
261        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
262                false /*isEmergencyOnly*/);
263        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
264                false /*isEmergencyOnly*/);
265        setDefaultPhone(slot0Phone);
266        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
267        // Set Slot 1 to be PUK locked
268        setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
269        setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_PIN_REQUIRED);
270        // Make Slot 1 higher capability
271        setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
272        setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
273
274        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
275
276        assertEquals(slot0Phone, resultPhone);
277    }
278
279    /**
280     * Prerequisites:
281     * - MSIM Device, two slots with SIMs inserted
282     * - Slot 1 is LTE capable, Slot 0 is GSM capable
283     *
284     * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone because it is more capable
285     */
286    @Test
287    @SmallTest
288    public void testSlot1HigherCapablity() {
289        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
290                false /*isEmergencyOnly*/);
291        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
292                false /*isEmergencyOnly*/);
293        setDefaultPhone(slot0Phone);
294        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
295        setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
296        setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
297        // Make Slot 1 higher capability
298        setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
299        setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
300
301        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
302
303        assertEquals(slot1Phone, resultPhone);
304    }
305
306    /**
307     * Prerequisites:
308     * - MSIM Device, two slots with SIMs inserted
309     * - Slot 1 is GSM/LTE capable, Slot 0 is GSM capable
310     *
311     * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone because it has more
312     * capabilities.
313     */
314    @Test
315    @SmallTest
316    public void testSlot1MoreCapabilities() {
317        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
318                false /*isEmergencyOnly*/);
319        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
320                false /*isEmergencyOnly*/);
321        setDefaultPhone(slot0Phone);
322        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
323        setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
324        setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
325        // Make Slot 1 more capable
326        setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
327        setPhoneRadioAccessFamily(slot1Phone,
328                RadioAccessFamily.RAF_GSM | RadioAccessFamily.RAF_LTE);
329
330        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
331
332        assertEquals(slot1Phone, resultPhone);
333    }
334
335    /**
336     * Prerequisites:
337     * - MSIM Device, two slots with SIMs inserted
338     * - Both SIMs PUK Locked
339     * - Slot 0 is LTE capable, Slot 1 is GSM capable
340     *
341     * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone because it is more capable,
342     * ignoring that both SIMs are PUK locked.
343     */
344    @Test
345    @SmallTest
346    public void testSlot0MoreCapableBothPukLocked() {
347        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
348                false /*isEmergencyOnly*/);
349        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
350                false /*isEmergencyOnly*/);
351        setDefaultPhone(slot0Phone);
352        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
353        setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_PUK_REQUIRED);
354        setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_PUK_REQUIRED);
355        // Make Slot 0 higher capability
356        setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
357        setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_GSM);
358
359        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
360
361        assertEquals(slot0Phone, resultPhone);
362    }
363
364    /**
365     * Prerequisites:
366     * - MSIM Device, two slots with SIMs inserted
367     * - Both SIMs have the same capability
368     *
369     * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone because it is the first slot.
370     */
371    @Test
372    @SmallTest
373    public void testEqualCapabilityTwoSimsInserted() {
374        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
375                false /*isEmergencyOnly*/);
376        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
377                false /*isEmergencyOnly*/);
378        setDefaultPhone(slot0Phone);
379        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
380        setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
381        setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
382        // Make Capability the same
383        setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
384        setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
385        // Two SIMs inserted
386        setSlotHasIccCard(SLOT_0_PHONE_ID, true /*isInserted*/);
387        setSlotHasIccCard(SLOT_1_PHONE_ID, true /*isInserted*/);
388
389        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
390
391        assertEquals(slot0Phone, resultPhone);
392    }
393
394    /**
395     * Prerequisites:
396     * - MSIM Device, only slot 0 inserted
397     * - Both SIMs have the same capability
398     *
399     * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone because it is the only one
400     * with a SIM inserted
401     */
402    @Test
403    @SmallTest
404    public void testEqualCapabilitySim0Inserted() {
405        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
406                false /*isEmergencyOnly*/);
407        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
408                false /*isEmergencyOnly*/);
409        setDefaultPhone(slot0Phone);
410        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
411        setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
412        setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
413        // Make Capability the same
414        setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
415        setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
416        // Slot 0 has SIM inserted.
417        setSlotHasIccCard(SLOT_0_PHONE_ID, true /*isInserted*/);
418        setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
419
420        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
421
422        assertEquals(slot0Phone, resultPhone);
423    }
424
425    /**
426     * Prerequisites:
427     * - MSIM Device, only slot 1 inserted
428     * - Both SIMs have the same capability
429     *
430     * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone because it is the only one
431     * with a SIM inserted
432     */
433    @Test
434    @SmallTest
435    public void testEqualCapabilitySim1Inserted() {
436        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
437                false /*isEmergencyOnly*/);
438        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
439                false /*isEmergencyOnly*/);
440        setDefaultPhone(slot0Phone);
441        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
442        setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
443        setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
444        // Make Capability the same
445        setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
446        setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
447        // Slot 1 has SIM inserted.
448        setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
449        setSlotHasIccCard(SLOT_1_PHONE_ID, true /*isInserted*/);
450
451        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
452
453        assertEquals(slot1Phone, resultPhone);
454    }
455
456    /**
457     * Prerequisites:
458     * - MSIM Device, no SIMs inserted
459     * - SIM 1 has the higher capability
460     *
461     * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone, since it is a higher
462     * capability
463     */
464    @Test
465    @SmallTest
466    public void testSim1HigherCapabilityNoSimsInserted() {
467        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
468                false /*isEmergencyOnly*/);
469        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
470                false /*isEmergencyOnly*/);
471        setDefaultPhone(slot0Phone);
472        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
473        setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
474        setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
475        // Make Capability the same
476        setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
477        setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
478        // No SIMs inserted
479        setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
480        setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
481
482        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
483
484        assertEquals(slot1Phone, resultPhone);
485    }
486
487    /**
488     * Prerequisites:
489     * - MSIM Device, no SIMs inserted
490     * - Both SIMs have the same capability (Unknown)
491     *
492     * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone, since it is the first slot.
493     */
494    @Test
495    @SmallTest
496    public void testEqualCapabilityNoSimsInserted() {
497        Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
498                false /*isEmergencyOnly*/);
499        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
500                false /*isEmergencyOnly*/);
501        setDefaultPhone(slot0Phone);
502        setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
503        setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
504        setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
505        // Make Capability the same
506        setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_UNKNOWN);
507        setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_UNKNOWN);
508        // No SIMs inserted
509        setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
510        setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
511
512        Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
513
514        assertEquals(slot0Phone, resultPhone);
515    }
516
517    /**
518     * The modem has returned a temporary error when placing an emergency call on a phone with one
519     * SIM slot.
520     *
521     * Verify that dial is called on the same phone again when retryOutgoingOriginalConnection is
522     * called.
523     */
524    @Test
525    @FlakyTest
526    @SmallTest
527    public void testRetryOutgoingOriginalConnection_redialTempFailOneSlot() {
528        TestTelephonyConnection c = new TestTelephonyConnection();
529        Phone slot0Phone = c.getPhone();
530        when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
531        List<Phone> phones = new ArrayList<>(1);
532        phones.add(slot0Phone);
533        setPhones(phones);
534        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
535
536        mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
537
538        // We never need to be notified in telecom that the PhoneAccount has changed, because it
539        // was redialed on the same slot
540        assertEquals(0, c.getNotifyPhoneAccountChangedCount());
541        try {
542            verify(slot0Phone).dial(anyString(), any());
543        } catch (CallStateException e) {
544            // This shouldn't happen
545            fail();
546        }
547    }
548
549    /**
550     * The modem has returned a permanent failure when placing an emergency call on a phone with one
551     * SIM slot.
552     *
553     * Verify that the connection is set to disconnected with an error disconnect cause and dial is
554     * not called.
555     */
556    @Test
557    @FlakyTest
558    @SmallTest
559    public void testRetryOutgoingOriginalConnection_redialPermFailOneSlot() {
560        TestTelephonyConnection c = new TestTelephonyConnection();
561        Phone slot0Phone = c.getPhone();
562        when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
563        List<Phone> phones = new ArrayList<>(1);
564        phones.add(slot0Phone);
565        setPhones(phones);
566        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
567
568        mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
569
570        // We never need to be notified in telecom that the PhoneAccount has changed, because it
571        // was never redialed
572        assertEquals(0, c.getNotifyPhoneAccountChangedCount());
573        try {
574            verify(slot0Phone, never()).dial(anyString(), any());
575        } catch (CallStateException e) {
576            // This shouldn't happen
577            fail();
578        }
579        assertEquals(c.getState(), android.telecom.Connection.STATE_DISCONNECTED);
580        assertEquals(c.getDisconnectCause().getCode(), DisconnectCause.ERROR);
581    }
582
583    /**
584     * The modem has returned a temporary failure when placing an emergency call on a phone with two
585     * SIM slots.
586     *
587     * Verify that the emergency call is dialed on the other slot and telecom is notified of the new
588     * PhoneAccount.
589     */
590    @Test
591    @FlakyTest
592    @SmallTest
593    public void testRetryOutgoingOriginalConnection_redialTempFailTwoSlot() {
594        TestTelephonyConnection c = new TestTelephonyConnection();
595        Phone slot0Phone = c.getPhone();
596        when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
597        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
598                false /*isEmergencyOnly*/);
599        setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
600        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
601        List<Phone> phones = new ArrayList<>(2);
602        phones.add(slot0Phone);
603        phones.add(slot1Phone);
604        setPhones(phones);
605
606        mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
607
608        // The cache should still contain all of the Phones, since it was a temporary failure.
609        assertEquals(2, mTestConnectionService.mEmergencyRetryCache.second.size());
610        // We need to be notified in Telecom that the PhoneAccount has changed, because it was
611        // redialed on another slot
612        assertEquals(1, c.getNotifyPhoneAccountChangedCount());
613        try {
614            verify(slot1Phone).dial(anyString(), any());
615        } catch (CallStateException e) {
616            // This shouldn't happen
617            fail();
618        }
619    }
620
621    /**
622     * The modem has returned a temporary failure when placing an emergency call on a phone with two
623     * SIM slots.
624     *
625     * Verify that the emergency call is dialed on the other slot and telecom is notified of the new
626     * PhoneAccount.
627     */
628    @Test
629    @FlakyTest
630    @SmallTest
631    public void testRetryOutgoingOriginalConnection_redialPermFailTwoSlot() {
632        TestTelephonyConnection c = new TestTelephonyConnection();
633        Phone slot0Phone = c.getPhone();
634        when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
635        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
636                false /*isEmergencyOnly*/);
637        setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
638        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
639        List<Phone> phones = new ArrayList<>(2);
640        phones.add(slot0Phone);
641        phones.add(slot1Phone);
642        setPhones(phones);
643
644        mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
645
646        // The cache should only contain the slot1Phone.
647        assertEquals(1, mTestConnectionService.mEmergencyRetryCache.second.size());
648        // We need to be notified in Telecom that the PhoneAccount has changed, because it was
649        // redialed on another slot
650        assertEquals(1, c.getNotifyPhoneAccountChangedCount());
651        try {
652            verify(slot1Phone).dial(anyString(), any());
653        } catch (CallStateException e) {
654            // This shouldn't happen
655            fail();
656        }
657    }
658
659    /**
660     * The modem has returned a temporary failure twice while placing an emergency call on a phone
661     * with two SIM slots.
662     *
663     * Verify that the emergency call is dialed on slot 1 and then on slot 0 and telecom is
664     * notified of this twice.
665     */
666    @Test
667    @FlakyTest
668    @SmallTest
669    public void testRetryOutgoingOriginalConnection_redialTempFailTwoSlot_twoFailure() {
670        TestTelephonyConnection c = new TestTelephonyConnection();
671        Phone slot0Phone = c.getPhone();
672        when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
673        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
674                false /*isEmergencyOnly*/);
675        setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
676        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
677        List<Phone> phones = new ArrayList<>(2);
678        phones.add(slot0Phone);
679        phones.add(slot1Phone);
680        setPhones(phones);
681
682        // First Temporary failure
683        mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
684        // Set the Phone to the new phone that was just used to dial.
685        c.setMockPhone(slot1Phone);
686        // The cache should still contain all of the Phones, since it was a temporary failure.
687        assertEquals(2, mTestConnectionService.mEmergencyRetryCache.second.size());
688        // Make sure slot 1 is next in the queue.
689        assertEquals(slot1Phone, mTestConnectionService.mEmergencyRetryCache.second.peek());
690        // Second Temporary failure
691        mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
692        // Set the Phone to the new phone that was just used to dial.
693        c.setMockPhone(slot0Phone);
694        // The cache should still contain all of the Phones, since it was a temporary failure.
695        assertEquals(2, mTestConnectionService.mEmergencyRetryCache.second.size());
696        // Make sure slot 0 is next in the queue.
697        assertEquals(slot0Phone, mTestConnectionService.mEmergencyRetryCache.second.peek());
698
699        // We need to be notified in Telecom that the PhoneAccount has changed, because it was
700        // redialed on another slot
701        assertEquals(2, c.getNotifyPhoneAccountChangedCount());
702        try {
703            verify(slot0Phone).dial(anyString(), any());
704            verify(slot1Phone).dial(anyString(), any());
705        } catch (CallStateException e) {
706            // This shouldn't happen
707            fail();
708        }
709    }
710
711    /**
712     * The modem has returned a permanent failure twice while placing an emergency call on a phone
713     * with two SIM slots.
714     *
715     * Verify that the emergency call is dialed on slot 1 and then disconnected and telecom is
716     * notified of the change to slot 1.
717     */
718    @Test
719    @FlakyTest
720    @SmallTest
721    public void testRetryOutgoingOriginalConnection_redialPermFailTwoSlot_twoFailure() {
722        TestTelephonyConnection c = new TestTelephonyConnection();
723        Phone slot0Phone = c.getPhone();
724        when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
725        Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
726                false /*isEmergencyOnly*/);
727        setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
728        c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
729        List<Phone> phones = new ArrayList<>(2);
730        phones.add(slot0Phone);
731        phones.add(slot1Phone);
732        setPhones(phones);
733
734        // First Permanent failure
735        mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
736        // Set the Phone to the new phone that was just used to dial.
737        c.setMockPhone(slot1Phone);
738        // The cache should only contain one phone
739        assertEquals(1, mTestConnectionService.mEmergencyRetryCache.second.size());
740        // Make sure slot 1 is next in the queue.
741        assertEquals(slot1Phone, mTestConnectionService.mEmergencyRetryCache.second.peek());
742        // Second Permanent failure
743        mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
744        // The cache should be empty
745        assertEquals(true, mTestConnectionService.mEmergencyRetryCache.second.isEmpty());
746
747        assertEquals(c.getState(), android.telecom.Connection.STATE_DISCONNECTED);
748        assertEquals(c.getDisconnectCause().getCode(), DisconnectCause.ERROR);
749        // We need to be notified in Telecom that the PhoneAccount has changed, because it was
750        // redialed on another slot
751        assertEquals(1, c.getNotifyPhoneAccountChangedCount());
752        try {
753            verify(slot1Phone).dial(anyString(), any());
754            verify(slot0Phone, never()).dial(anyString(), any());
755        } catch (CallStateException e) {
756            // This shouldn't happen
757            fail();
758        }
759    }
760
761    @Test
762    @SmallTest
763    public void testSuppServiceNotification() {
764        TestTelephonyConnection c = new TestTelephonyConnection();
765
766        // We need to set the original connection to cause the supp service notification
767        // registration to occur.
768        Phone phone = c.getPhone();
769        c.setOriginalConnection(c.getOriginalConnection());
770
771        // When the registration occurs, we'll capture the handler and message so we can post our
772        // own messages to it.
773        ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
774        ArgumentCaptor<Integer> messageCaptor = ArgumentCaptor.forClass(Integer.class);
775        verify(phone).registerForSuppServiceNotification(handlerCaptor.capture(),
776                messageCaptor.capture(), any());
777        Handler handler = handlerCaptor.getValue();
778        int message = messageCaptor.getValue();
779
780        // With the handler and message now known, we'll post a supp service notification.
781        AsyncResult result = getSuppServiceNotification(
782                SuppServiceNotification.NOTIFICATION_TYPE_CODE_1,
783                SuppServiceNotification.CODE_1_CALL_FORWARDED);
784        handler.obtainMessage(message, result).sendToTarget();
785        waitForHandlerAction(handler, TIMEOUT_MS);
786
787        assertTrue(c.getLastConnectionEvents().contains(TelephonyManager.EVENT_CALL_FORWARDED));
788
789        // With the handler and message now known, we'll post a supp service notification.
790        result = getSuppServiceNotification(
791                SuppServiceNotification.NOTIFICATION_TYPE_CODE_1,
792                SuppServiceNotification.CODE_1_CALL_IS_WAITING);
793        handler.obtainMessage(message, result).sendToTarget();
794        waitForHandlerAction(handler, TIMEOUT_MS);
795
796        // We we want the 3rd event since the forwarding one above sends 2.
797        assertEquals(c.getLastConnectionEvents().get(2),
798                TelephonyManager.EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION);
799        Bundle extras = c.getLastConnectionEventExtras().get(2);
800        assertEquals(SuppServiceNotification.NOTIFICATION_TYPE_CODE_1,
801                extras.getInt(TelephonyManager.EXTRA_NOTIFICATION_TYPE));
802        assertEquals(SuppServiceNotification.CODE_1_CALL_IS_WAITING,
803                extras.getInt(TelephonyManager.EXTRA_NOTIFICATION_CODE));
804    }
805
806    private AsyncResult getSuppServiceNotification(int notificationType, int code) {
807        SuppServiceNotification notification = new SuppServiceNotification();
808        notification.notificationType = notificationType;
809        notification.code = code;
810        return new AsyncResult(null, notification, null);
811    }
812
813    private Phone makeTestPhone(int phoneId, int serviceState, boolean isEmergencyOnly) {
814        Phone phone = mock(Phone.class);
815        ServiceState testServiceState = new ServiceState();
816        testServiceState.setState(serviceState);
817        testServiceState.setEmergencyOnly(isEmergencyOnly);
818        when(phone.getServiceState()).thenReturn(testServiceState);
819        when(phone.getPhoneId()).thenReturn(phoneId);
820        return phone;
821    }
822
823    // Setup 2 SIM device
824    private void setupDeviceConfig(Phone slot0Phone, Phone slot1Phone, int defaultVoicePhoneId) {
825        when(mTelephonyManagerProxy.getPhoneCount()).thenReturn(2);
826        when(mSubscriptionManagerProxy.getDefaultVoicePhoneId()).thenReturn(defaultVoicePhoneId);
827        when(mPhoneFactoryProxy.getPhone(eq(SLOT_0_PHONE_ID))).thenReturn(slot0Phone);
828        when(mPhoneFactoryProxy.getPhone(eq(SLOT_1_PHONE_ID))).thenReturn(slot1Phone);
829    }
830
831    private void setPhoneRadioAccessFamily(Phone phone, int radioAccessFamily) {
832        when(phone.getRadioAccessFamily()).thenReturn(radioAccessFamily);
833    }
834
835    private void setPhoneSlotState(int slotId, int slotState) {
836        when(mSubscriptionManagerProxy.getSimStateForSlotIdx(slotId)).thenReturn(slotState);
837    }
838
839    private void setSlotHasIccCard(int slotId, boolean isInserted) {
840        when(mTelephonyManagerProxy.hasIccCard(slotId)).thenReturn(isInserted);
841    }
842
843    private void setDefaultPhone(Phone phone) {
844        when(mPhoneFactoryProxy.getDefaultPhone()).thenReturn(phone);
845    }
846
847    private void setPhones(List<Phone> phones) {
848        when(mPhoneFactoryProxy.getPhones()).thenReturn(phones.toArray(new Phone[phones.size()]));
849    }
850
851    private void setPhonesDialConnection(Phone phone, Connection c) {
852        try {
853            when(phone.dial(anyString(), any())).thenReturn(c);
854        } catch (CallStateException e) {
855            // this shouldn't happen
856            fail();
857        }
858    }
859}
860