blob: c8908890906a243a28599f01752df30d1c9b0a6a [file] [log] [blame]
/*
* Copyright (C) 2017 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 android.telecom.cts;
import android.content.Context;
import android.database.Cursor;
import android.media.AudioManager;
import android.net.Uri;
import android.provider.CallLog;
import android.telecom.Call;
import android.telecom.CallAudioState;
import android.telecom.Connection;
import android.telecom.ConnectionService;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.function.Predicate;
import static android.media.AudioManager.MODE_IN_COMMUNICATION;
import static android.telecom.cts.TestUtils.TEST_SELF_MANAGED_HANDLE_1;
import static android.telecom.cts.TestUtils.TEST_SELF_MANAGED_HANDLE_4;
import static android.telecom.cts.TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS;
import static android.telecom.cts.TestUtils.waitOnAllHandlers;
import static org.junit.Assert.assertNotEquals;
/**
* CTS tests for the self-managed {@link android.telecom.ConnectionService} APIs.
* For more information about these APIs, see {@link android.telecom}, and
* {@link android.telecom.PhoneAccount#CAPABILITY_SELF_MANAGED}.
*/
public class SelfManagedConnectionServiceTest extends BaseTelecomTestWithMockServices {
private Uri TEST_ADDRESS_1 = Uri.fromParts("sip", "call1@test.com", null);
private Uri TEST_ADDRESS_2 = Uri.fromParts("tel", "6505551212", null);
private Uri TEST_ADDRESS_3 = Uri.fromParts("tel", "6505551213", null);
private Uri TEST_ADDRESS_4 = Uri.fromParts(TestUtils.TEST_URI_SCHEME, "fizzle_schmozle", null);
@Override
protected void setUp() throws Exception {
super.setUp();
NewOutgoingCallBroadcastReceiver.reset();
mContext = getInstrumentation().getContext();
if (mShouldTestTelecom) {
// Register and enable the CTS ConnectionService; we want to be able to test a managed
// ConnectionService alongside a self-managed ConnectionService.
setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
mTelecomManager.registerPhoneAccount(TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_1);
mTelecomManager.registerPhoneAccount(TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_2);
mTelecomManager.registerPhoneAccount(TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_3);
mTelecomManager.registerPhoneAccount(TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_4);
}
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
CtsSelfManagedConnectionService connectionService =
CtsSelfManagedConnectionService.getConnectionService();
if (connectionService != null) {
connectionService.tearDown();
mTelecomManager.unregisterPhoneAccount(TestUtils.TEST_SELF_MANAGED_HANDLE_1);
mTelecomManager.unregisterPhoneAccount(TestUtils.TEST_SELF_MANAGED_HANDLE_2);
mTelecomManager.unregisterPhoneAccount(TestUtils.TEST_SELF_MANAGED_HANDLE_3);
}
}
/**
* Tests {@link TelecomManager#getSelfManagedPhoneAccounts()} API to ensure it returns a list of
* the registered self-managed {@link android.telecom.PhoneAccount}s.
*/
public void testTelecomManagerGetSelfManagedPhoneAccounts() {
if (!mShouldTestTelecom) {
return;
}
List<PhoneAccountHandle> phoneAccountHandles =
mTelecomManager.getSelfManagedPhoneAccounts();
assertTrue(phoneAccountHandles.contains(TestUtils.TEST_SELF_MANAGED_HANDLE_1));
assertTrue(phoneAccountHandles.contains(TestUtils.TEST_SELF_MANAGED_HANDLE_2));
assertTrue(phoneAccountHandles.contains(TestUtils.TEST_SELF_MANAGED_HANDLE_3));
assertFalse(phoneAccountHandles.contains(TestUtils.TEST_PHONE_ACCOUNT_HANDLE));
}
/**
* Tests the ability to successfully register a self-managed
* {@link android.telecom.PhoneAccount}.
* <p>
* It should be possible to register self-managed Connection Services which suppor the TEL, SIP,
* or other URI schemes.
*/
public void testRegisterSelfManagedConnectionService() {
if (!mShouldTestTelecom) {
return;
}
verifyAccountRegistration(TestUtils.TEST_SELF_MANAGED_HANDLE_1,
TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_1);
verifyAccountRegistration(TestUtils.TEST_SELF_MANAGED_HANDLE_2,
TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_2);
verifyAccountRegistration(TestUtils.TEST_SELF_MANAGED_HANDLE_3,
TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_3);
}
private void verifyAccountRegistration(PhoneAccountHandle handle, PhoneAccount phoneAccount) {
// The phone account is registered in the setup method.
assertPhoneAccountRegistered(handle);
assertPhoneAccountEnabled(handle);
PhoneAccount registeredAccount = mTelecomManager.getPhoneAccount(handle);
// It should exist and be the same as the previously registered one.
assertNotNull(registeredAccount);
// We cannot just check for equality of the PhoneAccount since the one we registered is not
// enabled, and the one we get back after registration is.
assertPhoneAccountEquals(phoneAccount, registeredAccount);
// An important assumption is that self-managed PhoneAccounts are automatically
// enabled by default.
assertTrue("Self-managed PhoneAccounts must be enabled by default.",
registeredAccount.isEnabled());
}
/**
* This test ensures that a {@link android.telecom.PhoneAccount} declared as self-managed cannot
* but is also registered as a call provider is not permitted.
*
* A self-managed {@link android.telecom.PhoneAccount} cannot also be a call provider.
*/
public void testRegisterCallCapableSelfManagedConnectionService() {
if (!mShouldTestTelecom) {
return;
}
// Attempt to register both a call provider and self-managed account.
PhoneAccount toRegister = TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_1.toBuilder()
.setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED |
PhoneAccount.CAPABILITY_CALL_PROVIDER)
.build();
registerAndExpectFailure(toRegister);
}
/**
* This test ensures that a {@link android.telecom.PhoneAccount} declared as self-managed cannot
* but is also registered as a sim subscription is not permitted.
*
* A self-managed {@link android.telecom.PhoneAccount} cannot also be a SIM subscription.
*/
public void testRegisterSimSelfManagedConnectionService() {
if (!mShouldTestTelecom) {
return;
}
// Attempt to register both a call provider and self-managed account.
PhoneAccount toRegister = TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_1.toBuilder()
.setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED |
PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
.build();
registerAndExpectFailure(toRegister);
}
/**
* This test ensures that a {@link android.telecom.PhoneAccount} declared as self-managed cannot
* but is also registered as a connection manager is not permitted.
*
* A self-managed {@link android.telecom.PhoneAccount} cannot also be a connection manager.
*/
public void testRegisterConnectionManagerSelfManagedConnectionService() {
if (!mShouldTestTelecom) {
return;
}
// Attempt to register both a call provider and self-managed account.
PhoneAccount toRegister = TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_1.toBuilder()
.setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED |
PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
.build();
registerAndExpectFailure(toRegister);
}
/**
* Attempts to register a {@link android.telecom.PhoneAccount}, expecting a security exception
* which indicates that invalid capabilities were specified.
*
* @param toRegister The PhoneAccount to register.
*/
private void registerAndExpectFailure(PhoneAccount toRegister) {
try {
mTelecomManager.registerPhoneAccount(toRegister);
} catch (SecurityException se) {
assertEquals("Self-managed ConnectionServices cannot also be call capable, " +
"connection managers, or SIM accounts.", se.getMessage());
return;
}
fail("Expected SecurityException");
}
/**
* Tests ability to add a new self-managed incoming connection.
*/
public void testAddSelfManagedIncomingConnection() throws Exception {
if (!mShouldTestTelecom) {
return;
}
addAndVerifyIncomingCall(TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
addAndVerifyIncomingCall(TestUtils.TEST_SELF_MANAGED_HANDLE_2, TEST_ADDRESS_3);
addAndVerifyIncomingCall(TestUtils.TEST_SELF_MANAGED_HANDLE_3, TEST_ADDRESS_4);
}
private void addAndVerifyIncomingCall(PhoneAccountHandle handle, Uri address)
throws Exception {
TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager, handle, address);
// Ensure Telecom bound to the self managed CS
if (!CtsSelfManagedConnectionService.waitForBinding()) {
fail("Could not bind to Self-Managed ConnectionService");
}
SelfManagedConnection connection = TestUtils.waitForAndGetConnection(address);
// Setup content observer to notify us when we call log entry is added.
CountDownLatch callLogEntryLatch = getCallLogEntryLatch();
// Expect callback indicating that UI should be shown.
connection.getOnShowIncomingUiInvokeCounter().waitForCount(1);
setActiveAndVerify(connection);
// Ensure that the connection defaulted to voip audio mode.
assertTrue(connection.getAudioModeIsVoip());
// Ensure AudioManager has correct voip mode.
verifyAudioMode();
// Expect there to be no managed calls at the moment.
assertFalse(mTelecomManager.isInManagedCall());
assertTrue(mTelecomManager.isInCall());
setDisconnectedAndVerify(connection, isLoggedCall(handle), callLogEntryLatch);
}
/**
* Tests ensures that Telecom disallow to place outgoing self-managed call when the ongoing
* managed call can not be held.
*/
public void testDisallowOutgoingCallWhileOngoingManagedCallCanNotBeHeld() throws Exception {
if (!mShouldTestTelecom) {
return;
}
// GIVEN an ongoing managed call that can not be held
addAndVerifyNewIncomingCall(createTestNumber(), null);
Connection connection = verifyConnectionForIncomingCall();
int capabilities = connection.getConnectionCapabilities();
capabilities &= ~Connection.CAPABILITY_HOLD;
connection.setConnectionCapabilities(capabilities);
// answer the incoming call
MockInCallService inCallService = mInCallCallbacks.getService();
Call call = inCallService.getLastCall();
call.answer(VideoProfile.STATE_AUDIO_ONLY);
assertConnectionState(connection, Connection.STATE_ACTIVE);
// WHEN place a self-managed outgoing call
TestUtils.placeOutgoingCall(getInstrumentation(), mTelecomManager,
TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
// THEN the new outgoing call is failed.
CtsSelfManagedConnectionService.waitForBinding();
assertTrue(CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
CtsSelfManagedConnectionService.CREATE_OUTGOING_CONNECTION_FAILED_LOCK));
assertIsOutgoingCallPermitted(false, TestUtils.TEST_SELF_MANAGED_HANDLE_1);
}
/**
* Tests ability to add a new self-managed outgoing connection.
* <p>
* A self-managed {@link ConnectionService} shall be able to place an outgoing call to tel or
* sip {@link Uri}s without being interrupted by system UX or other Telephony-related logic.
*/
public void testAddSelfManagedOutgoingConnection() throws Exception {
if (!mShouldTestTelecom) {
return;
}
assertIsOutgoingCallPermitted(true, TestUtils.TEST_SELF_MANAGED_HANDLE_1);
placeAndVerifyOutgoingCall(TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
assertIsOutgoingCallPermitted(true, TestUtils.TEST_SELF_MANAGED_HANDLE_2);
placeAndVerifyOutgoingCall(TestUtils.TEST_SELF_MANAGED_HANDLE_2, TEST_ADDRESS_3);
assertIsOutgoingCallPermitted(true, TestUtils.TEST_SELF_MANAGED_HANDLE_3);
placeAndVerifyOutgoingCall(TestUtils.TEST_SELF_MANAGED_HANDLE_3, TEST_ADDRESS_4);
}
/**
* Ensure that a self-managed call which does not declare
* {@link PhoneAccount#EXTRA_LOG_SELF_MANAGED_CALLS} will NOT be logged in the call log.
* We do this as a separate case because we don't want on the logging latch used in the other
* tests if we don't expect a call to be logged (it would make the CTS mighty slow).
* @throws Exception
*/
public void testSelfManagedCallNotLogged() throws Exception {
if (!mShouldTestTelecom) {
return;
}
// First, complete the call which should not be logged.
Uri unloggedAddress = getTestNumber();
placeAndVerifyOutgoingCall(TestUtils.TEST_SELF_MANAGED_HANDLE_1, unloggedAddress);
// Next, place a call which we DO expect to be logged.
Uri loggedAddress = getTestNumber();
placeAndVerifyOutgoingCall(TestUtils.TEST_SELF_MANAGED_HANDLE_2, loggedAddress);
// The verification code for un-logged numbers doesn't actually wait on the call log latch
// since it would cause the tests to all run slow. However, since we just logged two calls
// and the second one would have triggered the call log latch, we can assume that the last
// two entries in the call log should:
// 1. NOT contain the un-logged call.
// 2. CONTAIN the logged call.
// Lets get the last two entries in the log in descending order by ID. This means that the
// logged call will be first.
Cursor callsCursor = mContext.getContentResolver().query(CallLog.Calls.CONTENT_URI, null,
null, null, CallLog.Calls._ID + " DESC limit 2;");
int numberIndex = callsCursor.getColumnIndex(CallLog.Calls.NUMBER);
// Check that we see the expected log call.
if (callsCursor.moveToNext()) {
String number = callsCursor.getString(numberIndex);
assertEquals(loggedAddress.getSchemeSpecificPart(), number);
} else {
fail("Expected a logged call.");
}
// Now check to ensure the call we DID NOT want to have logged is indeed not logged.
if (callsCursor.moveToNext()) {
// Something else was logged; make sure we did not log the call where the PhoneAccount
// does not indicate calls should be logged.
String number = callsCursor.getString(numberIndex);
assertNotEquals(unloggedAddress.getSchemeSpecificPart(), number);
} else {
// This is great; there was nothing else in the call log!
}
}
private void placeAndVerifyOutgoingCall(PhoneAccountHandle handle, Uri address) throws Exception {
TestUtils.placeOutgoingCall(getInstrumentation(), mTelecomManager, handle, address);
// Ensure Telecom bound to the self managed CS
if (!CtsSelfManagedConnectionService.waitForBinding()) {
fail("Could not bind to Self-Managed ConnectionService");
}
SelfManagedConnection connection = TestUtils.waitForAndGetConnection(address);
assertNotNull("Self-Managed Connection should NOT be null.", connection);
assertTrue("Self-Managed Connection should be outgoing.", !connection.isIncomingCall());
// The self-managed ConnectionService must NOT have been prompted to show its incoming call
// UI for an outgoing call.
assertEquals(connection.getOnShowIncomingUiInvokeCounter().getInvokeCount(), 0);
// Setup content observer to notify us when we call log entry is added.
CountDownLatch callLogEntryLatch = getCallLogEntryLatch();
setActiveAndVerify(connection);
// Ensure that the connection defaulted to voip audio mode.
assertTrue(connection.getAudioModeIsVoip());
// Ensure AudioManager has correct voip mode.
verifyAudioMode();
// Expect there to be no managed calls at the moment.
assertFalse(mTelecomManager.isInManagedCall());
// But there should be a call (including self-managed).
assertTrue(mTelecomManager.isInCall());
// Expect that the new outgoing call broadcast did not fire for the self-managed calls.
assertFalse(NewOutgoingCallBroadcastReceiver.isNewOutgoingCallBroadcastReceived());
setDisconnectedAndVerify(connection, isLoggedCall(handle), callLogEntryLatch);
}
/**
* Tests ability to change the audio route via the
* {@link android.telecom.Connection#setAudioRoute(int)} API.
*/
public void testAudioRoute() throws Exception {
if (!mShouldTestTelecom) {
return;
}
TestUtils.placeOutgoingCall(getInstrumentation(), mTelecomManager,
TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
SelfManagedConnection connection = TestUtils.waitForAndGetConnection(TEST_ADDRESS_1);
setActiveAndVerify(connection);
// Setup content observer to notify us when we call log entry is added.
CountDownLatch callLogEntryLatch = getCallLogEntryLatch();
TestUtils.InvokeCounter counter = connection.getCallAudioStateChangedInvokeCounter();
counter.waitForCount(WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
CallAudioState callAudioState = (CallAudioState) counter.getArgs(0)[0];
int availableRoutes = callAudioState.getSupportedRouteMask();
// Both the speaker and either wired or earpiece are required to test changing the audio
// route. Skip this test if either of these routes is unavailable.
if ((availableRoutes & CallAudioState.ROUTE_SPEAKER) == 0
|| (availableRoutes & CallAudioState.ROUTE_WIRED_OR_EARPIECE) == 0) {
return;
}
// Determine what the second route after SPEAKER should be, depending on what's supported.
int secondRoute = (availableRoutes & CallAudioState.ROUTE_EARPIECE) == 0
? CallAudioState.ROUTE_WIRED_HEADSET
: CallAudioState.ROUTE_EARPIECE;
counter.clearArgs();
connection.setAudioRoute(CallAudioState.ROUTE_SPEAKER);
counter.waitForPredicate(new Predicate<CallAudioState>() {
@Override
public boolean test(CallAudioState cas) {
return cas.getRoute() == CallAudioState.ROUTE_SPEAKER;
}
}, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
counter.clearArgs();
connection.setAudioRoute(secondRoute);
counter.waitForPredicate(new Predicate<CallAudioState>() {
@Override
public boolean test(CallAudioState cas) {
return cas.getRoute() == secondRoute;
}
}, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
if (TestUtils.HAS_BLUETOOTH) {
// Call requestBluetoothAudio on a device. This will be a noop since no devices are
// connected.
connection.requestBluetoothAudio(TestUtils.BLUETOOTH_DEVICE1);
}
setDisconnectedAndVerify(connection, isLoggedCall(TestUtils.TEST_SELF_MANAGED_HANDLE_1),
callLogEntryLatch);
}
/**
* Tests that Telecom will allow the incoming call while the number of self-managed call is not
* exceed the limit.
* @throws Exception
*/
public void testIncomingWhileOngoingWithinLimit() throws Exception {
if (!mShouldTestTelecom) {
return;
}
// Create an ongoing call in the first self-managed PhoneAccount.
TestUtils.placeOutgoingCall(getInstrumentation(), mTelecomManager,
TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
SelfManagedConnection connection = TestUtils.waitForAndGetConnection(TEST_ADDRESS_1);
setActiveAndVerify(connection);
// Setup content observer to notify us when we call log entry is added.
CountDownLatch callLogEntryLatch = getCallLogEntryLatch();
assertIsIncomingCallPermitted(true, TestUtils.TEST_SELF_MANAGED_HANDLE_2);
// Attempt to create a new incoming call for the other PhoneAccount; it should succeed.
TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
TestUtils.TEST_SELF_MANAGED_HANDLE_2, TEST_ADDRESS_2);
SelfManagedConnection connection2 = TestUtils.waitForAndGetConnection(TEST_ADDRESS_2);
connection2.disconnectAndDestroy();
setDisconnectedAndVerify(connection, isLoggedCall(TestUtils.TEST_SELF_MANAGED_HANDLE_1),
callLogEntryLatch);
}
/**
* Tests the self-managed ConnectionService has gained the focus when it become active.
*/
public void testSelfManagedConnectionServiceGainedFocus() throws Exception {
if (!mShouldTestTelecom) {
return;
}
assertIsIncomingCallPermitted(true, TestUtils.TEST_SELF_MANAGED_HANDLE_1);
// Attempt to create a new Incoming self-managed call
TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
SelfManagedConnection connection = TestUtils.waitForAndGetConnection(TEST_ADDRESS_1);
// Setup content observer to notify us when we call log entry is added.
CountDownLatch callLogEntryLatch = getCallLogEntryLatch();
setActiveAndVerify(connection);
// The ConnectionService has gained the focus
assertTrue(CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
CtsSelfManagedConnectionService.FOCUS_GAINED_LOCK));
setDisconnectedAndVerify(connection, isLoggedCall(TestUtils.TEST_SELF_MANAGED_HANDLE_1),
callLogEntryLatch);
}
public void testSelfManagedConnectionServiceLostFocus() throws Exception {
if (!mShouldTestTelecom) {
return;
}
// GIVEN an ongoing self-managed call
TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
SelfManagedConnection connection = TestUtils.waitForAndGetConnection(TEST_ADDRESS_1);
setActiveAndVerify(connection);
assertTrue(CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
CtsSelfManagedConnectionService.FOCUS_GAINED_LOCK));
// WHEN place a managed call
mInCallCallbacks.resetLock();
placeAndVerifyCall();
verifyConnectionForOutgoingCall().setActive();
assertTrue(connectionService.waitForEvent(
MockConnectionService.EVENT_CONNECTION_SERVICE_FOCUS_GAINED));
// THEN the self-managed ConnectionService lost the focus
connection.disconnectAndDestroy();
assertTrue(CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
CtsSelfManagedConnectionService.FOCUS_LOST_LOCK));
}
/**
* Tests that Telecom will disallow the incoming call while the ringing call is existed.
*/
public void testRingCallLimitForOnePhoneAccount() {
if (!mShouldTestTelecom) {
return;
}
// GIVEN a self-managed call which state is ringing
TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
SelfManagedConnection connection = TestUtils.waitForAndGetConnection(TEST_ADDRESS_1);
connection.setRinging();
assertIsIncomingCallPermitted(false, TestUtils.TEST_SELF_MANAGED_HANDLE_1);
// WHEN create a new incoming call for the the same PhoneAccount
TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
// THEN the new incoming call is denied
assertTrue(CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
CtsSelfManagedConnectionService.CREATE_INCOMING_CONNECTION_FAILED_LOCK));
}
/**
* Tests that Telecom enforces a maximum number of calls for a self-managed ConnectionService.
*
* @throws Exception
*/
public void testCallLimit() throws Exception {
if (!mShouldTestTelecom) {
return;
}
List<SelfManagedConnection> connections = new ArrayList<>();
// Create 10 calls; they should succeed.
for (int ix = 0; ix < 10; ix++) {
Uri address = Uri.fromParts("sip", "test" + ix + "@test.com", null);
// Create an ongoing call in the first self-managed PhoneAccount.
assertIsOutgoingCallPermitted(true, TestUtils.TEST_SELF_MANAGED_HANDLE_1);
TestUtils.placeOutgoingCall(getInstrumentation(), mTelecomManager,
TestUtils.TEST_SELF_MANAGED_HANDLE_1, address);
SelfManagedConnection connection = TestUtils.waitForAndGetConnection(address);
setActiveAndVerify(connection);
connections.add(connection);
}
// Try adding an 11th. It should fail to be created.
assertIsIncomingCallPermitted(false, TestUtils.TEST_SELF_MANAGED_HANDLE_1);
TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_2);
assertTrue("Expected onCreateIncomingConnectionFailed callback",
CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
CtsSelfManagedConnectionService.CREATE_INCOMING_CONNECTION_FAILED_LOCK));
connections.forEach((selfManagedConnection) ->
selfManagedConnection.disconnectAndDestroy());
waitOnAllHandlers(getInstrumentation());
}
/**
* Start a self-managed call and then dial an emergency call and make sure the self-managed
* call is successfully disconnected.
*/
public void testDisconnectSelfManagedCallForEmergency() throws Exception {
if (!mShouldTestTelecom) {
return;
}
setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
Uri address = getTestNumber();
TestUtils.placeOutgoingCall(getInstrumentation(), mTelecomManager,
TEST_SELF_MANAGED_HANDLE_1, address);
// Ensure Telecom bound to the self managed CS
if (!CtsSelfManagedConnectionService.waitForBinding()) {
fail("Could not bind to Self-Managed ConnectionService");
}
SelfManagedConnection connection = TestUtils.waitForAndGetConnection(address);
assertNotNull("Self-Managed Connection should NOT be null.", connection);
assertTrue("Self-Managed Connection should be outgoing.", !connection.isIncomingCall());
// The self-managed ConnectionService must NOT have been prompted to show its incoming call
// UI for an outgoing call.
assertEquals(connection.getOnShowIncomingUiInvokeCounter().getInvokeCount(), 0);
setActiveAndVerify(connection);
mInCallCallbacks.resetLock();
placeAndVerifyEmergencyCall(true /*supportsHold*/);
Call eCall = getInCallService().getLastCall();
assertIsInCall(true);
assertIsInManagedCall(true);
try {
TestUtils.waitOnAllHandlers(getInstrumentation());
} catch (Exception e) {
fail("Failed to wait on handlers " + e);
}
assertCallState(eCall, Call.STATE_DIALING);
// The self-managed Connection should be disconnected!
assertConnectionState(connection, Connection.STATE_DISCONNECTED);
}
/**
* Start a managed emergency call and then ensure that a subsequent self-managed call fails to
* be created.
*/
public void testEmergencyCallOngoingNewOutgoingCall() throws Exception {
if (!mShouldTestTelecom) {
return;
}
setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
placeAndVerifyEmergencyCall(true /*supportsHold*/);
assertIsInCall(true);
assertIsInManagedCall(true);
try {
TestUtils.waitOnAllHandlers(getInstrumentation());
} catch (Exception e) {
fail("Failed to wait on handlers " + e);
}
// Try adding a self managed outgoing call. It should fail to be created.
TestUtils.placeOutgoingCall(getInstrumentation(), mTelecomManager,
TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
assertTrue("Expected onCreateOutgoingConnectionFailed callback",
CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
CtsSelfManagedConnectionService.CREATE_OUTGOING_CONNECTION_FAILED_LOCK));
}
/**
* Start a managed emergency call and then ensure that a subsequent self-managed call fails to
* be created.
*/
public void testEmergencyCallOngoingIncomingCall() throws Exception {
if (!mShouldTestTelecom) {
return;
}
setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
placeAndVerifyEmergencyCall(true /*supportsHold*/);
assertIsInCall(true);
assertIsInManagedCall(true);
try {
TestUtils.waitOnAllHandlers(getInstrumentation());
} catch (Exception e) {
fail("Failed to wait on handlers " + e);
}
// Try adding a self managed incoming call. It should fail to be created.
TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
assertTrue("Expected onCreateIncomingConnectionFailed callback",
CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
CtsSelfManagedConnectionService.CREATE_INCOMING_CONNECTION_FAILED_LOCK));
}
/**
* Sets a connection active, and verifies TelecomManager thinks we're in call but not in a
* managed call.
* @param connection The connection.
*/
private void setActiveAndVerify(SelfManagedConnection connection) throws Exception {
// Set the connection active.
connection.setActive();
// Check with Telecom if we're in a call.
assertIsInCall(true);
assertIsInManagedCall(false);
}
/**
* Sets a connection to be disconnected, and then waits until the TelecomManager reports it is
* no longer in a call.
* @param connection The connection to disconnect/destroy.
* @param shouldCallBeLogged When {@code true} verify the call was logged; when {@code false}
* @param callLogLatch
*/
private void setDisconnectedAndVerify(SelfManagedConnection connection,
boolean shouldCallBeLogged, CountDownLatch callLogLatch) {
// Now, disconnect call and clean it up.
connection.disconnectAndDestroy();
assertIsInCall(false);
assertIsInManagedCall(false);
// Verify that an entry was written to the call log for the call if applicable.
verifyCallLogging(callLogLatch, shouldCallBeLogged, connection.getAddress());
}
private void verifyAudioMode() {
AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
waitUntilConditionIsTrueOrTimeout(
new Condition() {
@Override
public Object expected() {
return MODE_IN_COMMUNICATION;
}
@Override
public Object actual() {
return am.getMode();
}
},
WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
"Expected audio mode to be " + MODE_IN_COMMUNICATION
);
}
}