blob: 1329a77e1c2dcbbdccdc35daf8ffa837b9d3df93 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.services.telephony;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.net.Uri;
import android.os.AsyncResult;
import android.os.Bundle;
import android.os.Handler;
import android.telecom.DisconnectCause;
import android.telecom.TelecomManager;
import android.telephony.RadioAccessFamily;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
import androidx.test.filters.FlakyTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.TelephonyTestBase;
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.Connection;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.gsm.SuppServiceNotification;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import java.util.ArrayList;
import java.util.List;
/**
* Unit tests for TelephonyConnectionService.
*/
@RunWith(AndroidJUnit4.class)
public class TelephonyConnectionServiceTest extends TelephonyTestBase {
private static final long TIMEOUT_MS = 100;
private static final int SLOT_0_PHONE_ID = 0;
private static final int SLOT_1_PHONE_ID = 1;
@Mock TelephonyConnectionService.TelephonyManagerProxy mTelephonyManagerProxy;
@Mock TelephonyConnectionService.SubscriptionManagerProxy mSubscriptionManagerProxy;
@Mock TelephonyConnectionService.PhoneFactoryProxy mPhoneFactoryProxy;
TelephonyConnectionService mTestConnectionService;
@Before
public void setUp() throws Exception {
super.setUp();
mTestConnectionService = new TelephonyConnectionService();
mTestConnectionService.setPhoneFactoryProxy(mPhoneFactoryProxy);
mTestConnectionService.setTelephonyManagerProxy(mTelephonyManagerProxy);
mTestConnectionService.setSubscriptionManagerProxy(mSubscriptionManagerProxy);
}
@After
public void tearDown() throws Exception {
mTestConnectionService = null;
super.tearDown();
}
/**
* Prerequisites:
* - MSIM Device, two slots with SIMs inserted
* - Users default Voice SIM choice is IN_SERVICE
*
* Result: getFirstPhoneForEmergencyCall returns the default Voice SIM choice.
*/
@Test
@SmallTest
public void testDefaultVoiceSimInService() {
Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_IN_SERVICE,
false /*isEmergencyOnly*/);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
true /*isEmergencyOnly*/);
setDefaultPhone(slot0Phone);
setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
assertEquals(slot0Phone, resultPhone);
}
/**
* Prerequisites:
* - MSIM Device, two slots with SIMs inserted
* - Slot 0 is OUT_OF_SERVICE, Slot 1 is OUT_OF_SERVICE (emergency calls only)
*
* Result: getFirstPhoneForEmergencyCall returns the slot 1 phone
*/
@Test
@SmallTest
public void testSlot1EmergencyOnly() {
Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
true /*isEmergencyOnly*/);
setDefaultPhone(slot0Phone);
setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
assertEquals(slot1Phone, resultPhone);
}
/**
* Prerequisites:
* - MSIM Device, two slots with SIMs inserted
* - Slot 0 is OUT_OF_SERVICE, Slot 1 is IN_SERVICE
*
* Result: getFirstPhoneForEmergencyCall returns the slot 1 phone
*/
@Test
@SmallTest
public void testSlot1InService() {
Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_IN_SERVICE,
false /*isEmergencyOnly*/);
setDefaultPhone(slot0Phone);
setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
assertEquals(slot1Phone, resultPhone);
}
/**
* Prerequisites:
* - MSIM Device, two slots with SIMs inserted
* - Slot 0 is PUK locked, Slot 1 is ready
* - Slot 0 is LTE capable, Slot 1 is GSM capable
*
* Result: getFirstPhoneForEmergencyCall returns the slot 1 phone. Although Slot 0 is more
* capable, it is locked, so use the other slot.
*/
@Test
@SmallTest
public void testSlot0PukLocked() {
Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setDefaultPhone(slot0Phone);
setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
// Set Slot 0 to be PUK locked
setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_PUK_REQUIRED);
setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
// Make Slot 0 higher capability
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_GSM);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
assertEquals(slot1Phone, resultPhone);
}
/**
* Prerequisites:
* - MSIM Device, two slots with SIMs inserted
* - Slot 0 is PIN locked, Slot 1 is ready
* - Slot 0 is LTE capable, Slot 1 is GSM capable
*
* Result: getFirstPhoneForEmergencyCall returns the slot 1 phone. Although Slot 0 is more
* capable, it is locked, so use the other slot.
*/
@Test
@SmallTest
public void testSlot0PinLocked() {
Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setDefaultPhone(slot0Phone);
setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
// Set Slot 0 to be PUK locked
setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_PIN_REQUIRED);
setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
// Make Slot 0 higher capability
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_GSM);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
assertEquals(slot1Phone, resultPhone);
}
/**
* Prerequisites:
* - MSIM Device, two slots with SIMs inserted
* - Slot 1 is PUK locked, Slot 0 is ready
* - Slot 1 is LTE capable, Slot 0 is GSM capable
*
* Result: getFirstPhoneForEmergencyCall returns the slot 0 phone. Although Slot 1 is more
* capable, it is locked, so use the other slot.
*/
@Test
@SmallTest
public void testSlot1PukLocked() {
Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setDefaultPhone(slot0Phone);
setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
// Set Slot 1 to be PUK locked
setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_PUK_REQUIRED);
// Make Slot 1 higher capability
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
assertEquals(slot0Phone, resultPhone);
}
/**
* Prerequisites:
* - MSIM Device, two slots with SIMs inserted
* - Slot 1 is PIN locked, Slot 0 is ready
* - Slot 1 is LTE capable, Slot 0 is GSM capable
*
* Result: getFirstPhoneForEmergencyCall returns the slot 0 phone. Although Slot 1 is more
* capable, it is locked, so use the other slot.
*/
@Test
@SmallTest
public void testSlot1PinLocked() {
Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setDefaultPhone(slot0Phone);
setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
// Set Slot 1 to be PUK locked
setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_PIN_REQUIRED);
// Make Slot 1 higher capability
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
assertEquals(slot0Phone, resultPhone);
}
/**
* Prerequisites:
* - MSIM Device, two slots with SIMs inserted
* - Slot 1 is LTE capable, Slot 0 is GSM capable
*
* Result: getFirstPhoneForEmergencyCall returns the slot 1 phone because it is more capable
*/
@Test
@SmallTest
public void testSlot1HigherCapablity() {
Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setDefaultPhone(slot0Phone);
setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
// Make Slot 1 higher capability
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
assertEquals(slot1Phone, resultPhone);
}
/**
* Prerequisites:
* - MSIM Device, two slots with SIMs inserted
* - Slot 1 is GSM/LTE capable, Slot 0 is GSM capable
*
* Result: getFirstPhoneForEmergencyCall returns the slot 1 phone because it has more
* capabilities.
*/
@Test
@SmallTest
public void testSlot1MoreCapabilities() {
Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setDefaultPhone(slot0Phone);
setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
// Make Slot 1 more capable
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
setPhoneRadioAccessFamily(slot1Phone,
RadioAccessFamily.RAF_GSM | RadioAccessFamily.RAF_LTE);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
assertEquals(slot1Phone, resultPhone);
}
/**
* Prerequisites:
* - MSIM Device, two slots with SIMs inserted
* - Both SIMs PUK Locked
* - Slot 0 is LTE capable, Slot 1 is GSM capable
*
* Result: getFirstPhoneForEmergencyCall returns the slot 0 phone because it is more capable,
* ignoring that both SIMs are PUK locked.
*/
@Test
@SmallTest
public void testSlot0MoreCapableBothPukLocked() {
Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setDefaultPhone(slot0Phone);
setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_PUK_REQUIRED);
setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_PUK_REQUIRED);
// Make Slot 0 higher capability
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_GSM);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
assertEquals(slot0Phone, resultPhone);
}
/**
* Prerequisites:
* - MSIM Device, two slots with SIMs inserted
* - Both SIMs have the same capability
*
* Result: getFirstPhoneForEmergencyCall returns the slot 0 phone because it is the first slot.
*/
@Test
@SmallTest
public void testEqualCapabilityTwoSimsInserted() {
Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setDefaultPhone(slot0Phone);
setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
// Make Capability the same
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
// Two SIMs inserted
setSlotHasIccCard(SLOT_0_PHONE_ID, true /*isInserted*/);
setSlotHasIccCard(SLOT_1_PHONE_ID, true /*isInserted*/);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
assertEquals(slot0Phone, resultPhone);
}
/**
* Prerequisites:
* - MSIM Device, only slot 0 inserted
* - Both SIMs have the same capability
*
* Result: getFirstPhoneForEmergencyCall returns the slot 0 phone because it is the only one
* with a SIM inserted
*/
@Test
@SmallTest
public void testEqualCapabilitySim0Inserted() {
Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setDefaultPhone(slot0Phone);
setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
// Make Capability the same
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
// Slot 0 has SIM inserted.
setSlotHasIccCard(SLOT_0_PHONE_ID, true /*isInserted*/);
setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
assertEquals(slot0Phone, resultPhone);
}
/**
* Prerequisites:
* - MSIM Device, only slot 1 inserted
* - Both SIMs have the same capability
*
* Result: getFirstPhoneForEmergencyCall returns the slot 1 phone because it is the only one
* with a SIM inserted
*/
@Test
@SmallTest
public void testEqualCapabilitySim1Inserted() {
Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setDefaultPhone(slot0Phone);
setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
// Make Capability the same
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
// Slot 1 has SIM inserted.
setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
setSlotHasIccCard(SLOT_1_PHONE_ID, true /*isInserted*/);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
assertEquals(slot1Phone, resultPhone);
}
/**
* Prerequisites:
* - MSIM Device, no SIMs inserted
* - SIM 1 has the higher capability
*
* Result: getFirstPhoneForEmergencyCall returns the slot 1 phone, since it is a higher
* capability
*/
@Test
@SmallTest
public void testSim1HigherCapabilityNoSimsInserted() {
Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setDefaultPhone(slot0Phone);
setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
// Make Capability the same
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
// No SIMs inserted
setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
assertEquals(slot1Phone, resultPhone);
}
/**
* Prerequisites:
* - MSIM Device, no SIMs inserted
* - Both SIMs have the same capability (Unknown)
*
* Result: getFirstPhoneForEmergencyCall returns the slot 0 phone, since it is the first slot.
*/
@Test
@SmallTest
public void testEqualCapabilityNoSimsInserted() {
Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setDefaultPhone(slot0Phone);
setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
// Make Capability the same
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_UNKNOWN);
setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_UNKNOWN);
// No SIMs inserted
setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
assertEquals(slot0Phone, resultPhone);
}
/**
* The modem has returned a temporary error when placing an emergency call on a phone with one
* SIM slot.
*
* Verify that dial is called on the same phone again when retryOutgoingOriginalConnection is
* called.
*/
@Test
@FlakyTest
@SmallTest
public void testRetryOutgoingOriginalConnection_redialTempFailOneSlot() {
TestTelephonyConnection c = new TestTelephonyConnection();
Phone slot0Phone = c.getPhone();
when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
List<Phone> phones = new ArrayList<>(1);
phones.add(slot0Phone);
setPhones(phones);
c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
// We never need to be notified in telecom that the PhoneAccount has changed, because it
// was redialed on the same slot
assertEquals(0, c.getNotifyPhoneAccountChangedCount());
try {
verify(slot0Phone).dial(anyString(), any());
} catch (CallStateException e) {
// This shouldn't happen
fail();
}
}
/**
* The modem has returned a permanent failure when placing an emergency call on a phone with one
* SIM slot.
*
* Verify that the connection is set to disconnected with an error disconnect cause and dial is
* not called.
*/
@Test
@FlakyTest
@SmallTest
public void testRetryOutgoingOriginalConnection_redialPermFailOneSlot() {
TestTelephonyConnection c = new TestTelephonyConnection();
Phone slot0Phone = c.getPhone();
when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
List<Phone> phones = new ArrayList<>(1);
phones.add(slot0Phone);
setPhones(phones);
c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
// We never need to be notified in telecom that the PhoneAccount has changed, because it
// was never redialed
assertEquals(0, c.getNotifyPhoneAccountChangedCount());
try {
verify(slot0Phone, never()).dial(anyString(), any());
} catch (CallStateException e) {
// This shouldn't happen
fail();
}
assertEquals(c.getState(), android.telecom.Connection.STATE_DISCONNECTED);
assertEquals(c.getDisconnectCause().getCode(), DisconnectCause.ERROR);
}
/**
* The modem has returned a temporary failure when placing an emergency call on a phone with two
* SIM slots.
*
* Verify that the emergency call is dialed on the other slot and telecom is notified of the new
* PhoneAccount.
*/
@Test
@FlakyTest
@SmallTest
public void testRetryOutgoingOriginalConnection_redialTempFailTwoSlot() {
TestTelephonyConnection c = new TestTelephonyConnection();
Phone slot0Phone = c.getPhone();
when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
List<Phone> phones = new ArrayList<>(2);
phones.add(slot0Phone);
phones.add(slot1Phone);
setPhones(phones);
mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
// The cache should still contain all of the Phones, since it was a temporary failure.
assertEquals(2, mTestConnectionService.mEmergencyRetryCache.second.size());
// We need to be notified in Telecom that the PhoneAccount has changed, because it was
// redialed on another slot
assertEquals(1, c.getNotifyPhoneAccountChangedCount());
try {
verify(slot1Phone).dial(anyString(), any());
} catch (CallStateException e) {
// This shouldn't happen
fail();
}
}
/**
* The modem has returned a temporary failure when placing an emergency call on a phone with two
* SIM slots.
*
* Verify that the emergency call is dialed on the other slot and telecom is notified of the new
* PhoneAccount.
*/
@Test
@FlakyTest
@SmallTest
public void testRetryOutgoingOriginalConnection_redialPermFailTwoSlot() {
TestTelephonyConnection c = new TestTelephonyConnection();
Phone slot0Phone = c.getPhone();
when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
List<Phone> phones = new ArrayList<>(2);
phones.add(slot0Phone);
phones.add(slot1Phone);
setPhones(phones);
mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
// The cache should only contain the slot1Phone.
assertEquals(1, mTestConnectionService.mEmergencyRetryCache.second.size());
// We need to be notified in Telecom that the PhoneAccount has changed, because it was
// redialed on another slot
assertEquals(1, c.getNotifyPhoneAccountChangedCount());
try {
verify(slot1Phone).dial(anyString(), any());
} catch (CallStateException e) {
// This shouldn't happen
fail();
}
}
/**
* The modem has returned a temporary failure twice while placing an emergency call on a phone
* with two SIM slots.
*
* Verify that the emergency call is dialed on slot 1 and then on slot 0 and telecom is
* notified of this twice.
*/
@Test
@FlakyTest
@SmallTest
public void testRetryOutgoingOriginalConnection_redialTempFailTwoSlot_twoFailure() {
TestTelephonyConnection c = new TestTelephonyConnection();
Phone slot0Phone = c.getPhone();
when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
List<Phone> phones = new ArrayList<>(2);
phones.add(slot0Phone);
phones.add(slot1Phone);
setPhones(phones);
// First Temporary failure
mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
// Set the Phone to the new phone that was just used to dial.
c.setMockPhone(slot1Phone);
// The cache should still contain all of the Phones, since it was a temporary failure.
assertEquals(2, mTestConnectionService.mEmergencyRetryCache.second.size());
// Make sure slot 1 is next in the queue.
assertEquals(slot1Phone, mTestConnectionService.mEmergencyRetryCache.second.peek());
// Second Temporary failure
mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
// Set the Phone to the new phone that was just used to dial.
c.setMockPhone(slot0Phone);
// The cache should still contain all of the Phones, since it was a temporary failure.
assertEquals(2, mTestConnectionService.mEmergencyRetryCache.second.size());
// Make sure slot 0 is next in the queue.
assertEquals(slot0Phone, mTestConnectionService.mEmergencyRetryCache.second.peek());
// We need to be notified in Telecom that the PhoneAccount has changed, because it was
// redialed on another slot
assertEquals(2, c.getNotifyPhoneAccountChangedCount());
try {
verify(slot0Phone).dial(anyString(), any());
verify(slot1Phone).dial(anyString(), any());
} catch (CallStateException e) {
// This shouldn't happen
fail();
}
}
/**
* The modem has returned a permanent failure twice while placing an emergency call on a phone
* with two SIM slots.
*
* Verify that the emergency call is dialed on slot 1 and then disconnected and telecom is
* notified of the change to slot 1.
*/
@Test
@FlakyTest
@SmallTest
public void testRetryOutgoingOriginalConnection_redialPermFailTwoSlot_twoFailure() {
TestTelephonyConnection c = new TestTelephonyConnection();
Phone slot0Phone = c.getPhone();
when(slot0Phone.getPhoneId()).thenReturn(SLOT_0_PHONE_ID);
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
List<Phone> phones = new ArrayList<>(2);
phones.add(slot0Phone);
phones.add(slot1Phone);
setPhones(phones);
// First Permanent failure
mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
// Set the Phone to the new phone that was just used to dial.
c.setMockPhone(slot1Phone);
// The cache should only contain one phone
assertEquals(1, mTestConnectionService.mEmergencyRetryCache.second.size());
// Make sure slot 1 is next in the queue.
assertEquals(slot1Phone, mTestConnectionService.mEmergencyRetryCache.second.peek());
// Second Permanent failure
mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
// The cache should be empty
assertEquals(true, mTestConnectionService.mEmergencyRetryCache.second.isEmpty());
assertEquals(c.getState(), android.telecom.Connection.STATE_DISCONNECTED);
assertEquals(c.getDisconnectCause().getCode(), DisconnectCause.ERROR);
// We need to be notified in Telecom that the PhoneAccount has changed, because it was
// redialed on another slot
assertEquals(1, c.getNotifyPhoneAccountChangedCount());
try {
verify(slot1Phone).dial(anyString(), any());
verify(slot0Phone, never()).dial(anyString(), any());
} catch (CallStateException e) {
// This shouldn't happen
fail();
}
}
@Test
@SmallTest
public void testSuppServiceNotification() {
TestTelephonyConnection c = new TestTelephonyConnection();
// We need to set the original connection to cause the supp service notification
// registration to occur.
Phone phone = c.getPhone();
c.setOriginalConnection(c.getOriginalConnection());
// When the registration occurs, we'll capture the handler and message so we can post our
// own messages to it.
ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
ArgumentCaptor<Integer> messageCaptor = ArgumentCaptor.forClass(Integer.class);
verify(phone).registerForSuppServiceNotification(handlerCaptor.capture(),
messageCaptor.capture(), any());
Handler handler = handlerCaptor.getValue();
int message = messageCaptor.getValue();
// With the handler and message now known, we'll post a supp service notification.
AsyncResult result = getSuppServiceNotification(
SuppServiceNotification.NOTIFICATION_TYPE_CODE_1,
SuppServiceNotification.CODE_1_CALL_FORWARDED);
handler.obtainMessage(message, result).sendToTarget();
waitForHandlerAction(handler, TIMEOUT_MS);
assertTrue(c.getLastConnectionEvents().contains(TelephonyManager.EVENT_CALL_FORWARDED));
// With the handler and message now known, we'll post a supp service notification.
result = getSuppServiceNotification(
SuppServiceNotification.NOTIFICATION_TYPE_CODE_1,
SuppServiceNotification.CODE_1_CALL_IS_WAITING);
handler.obtainMessage(message, result).sendToTarget();
waitForHandlerAction(handler, TIMEOUT_MS);
// We we want the 3rd event since the forwarding one above sends 2.
assertEquals(c.getLastConnectionEvents().get(2),
TelephonyManager.EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION);
Bundle extras = c.getLastConnectionEventExtras().get(2);
assertEquals(SuppServiceNotification.NOTIFICATION_TYPE_CODE_1,
extras.getInt(TelephonyManager.EXTRA_NOTIFICATION_TYPE));
assertEquals(SuppServiceNotification.CODE_1_CALL_IS_WAITING,
extras.getInt(TelephonyManager.EXTRA_NOTIFICATION_CODE));
}
private AsyncResult getSuppServiceNotification(int notificationType, int code) {
SuppServiceNotification notification = new SuppServiceNotification();
notification.notificationType = notificationType;
notification.code = code;
return new AsyncResult(null, notification, null);
}
private Phone makeTestPhone(int phoneId, int serviceState, boolean isEmergencyOnly) {
Phone phone = mock(Phone.class);
ServiceState testServiceState = new ServiceState();
testServiceState.setState(serviceState);
testServiceState.setEmergencyOnly(isEmergencyOnly);
when(phone.getServiceState()).thenReturn(testServiceState);
when(phone.getPhoneId()).thenReturn(phoneId);
when(phone.getDefaultPhone()).thenReturn(phone);
return phone;
}
// Setup 2 SIM device
private void setupDeviceConfig(Phone slot0Phone, Phone slot1Phone, int defaultVoicePhoneId) {
when(mTelephonyManagerProxy.getPhoneCount()).thenReturn(2);
when(mSubscriptionManagerProxy.getDefaultVoicePhoneId()).thenReturn(defaultVoicePhoneId);
when(mPhoneFactoryProxy.getPhone(eq(SLOT_0_PHONE_ID))).thenReturn(slot0Phone);
when(mPhoneFactoryProxy.getPhone(eq(SLOT_1_PHONE_ID))).thenReturn(slot1Phone);
}
private void setPhoneRadioAccessFamily(Phone phone, int radioAccessFamily) {
when(phone.getRadioAccessFamily()).thenReturn(radioAccessFamily);
}
private void setPhoneSlotState(int slotId, int slotState) {
when(mSubscriptionManagerProxy.getSimStateForSlotIdx(slotId)).thenReturn(slotState);
}
private void setSlotHasIccCard(int slotId, boolean isInserted) {
when(mTelephonyManagerProxy.hasIccCard(slotId)).thenReturn(isInserted);
}
private void setDefaultPhone(Phone phone) {
when(mPhoneFactoryProxy.getDefaultPhone()).thenReturn(phone);
}
private void setPhones(List<Phone> phones) {
when(mPhoneFactoryProxy.getPhones()).thenReturn(phones.toArray(new Phone[phones.size()]));
}
private void setPhonesDialConnection(Phone phone, Connection c) {
try {
when(phone.dial(anyString(), any())).thenReturn(c);
} catch (CallStateException e) {
// this shouldn't happen
fail();
}
}
}