| /* |
| * Copyright (C) 2015 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.server.telecom.tests; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.mockito.ArgumentMatchers.nullable; |
| import static org.mockito.Matchers.any; |
| import static org.mockito.Matchers.anyInt; |
| import static org.mockito.Matchers.anyString; |
| import static org.mockito.Matchers.eq; |
| import static org.mockito.Matchers.isNull; |
| import static org.mockito.Mockito.never; |
| import static org.mockito.Mockito.timeout; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.verifyZeroInteractions; |
| import static org.mockito.Mockito.when; |
| |
| import android.content.Context; |
| import android.content.IContentProvider; |
| import android.media.AudioManager; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.os.Process; |
| import android.provider.BlockedNumberContract; |
| import android.telecom.Call; |
| import android.telecom.CallAudioState; |
| import android.telecom.Connection; |
| import android.telecom.ConnectionRequest; |
| import android.telecom.DisconnectCause; |
| import android.telecom.Log; |
| import android.telecom.ParcelableCall; |
| import android.telecom.PhoneAccount; |
| import android.telecom.PhoneAccountHandle; |
| import android.telecom.TelecomManager; |
| import android.telecom.VideoProfile; |
| import android.test.suitebuilder.annotation.LargeTest; |
| import android.test.suitebuilder.annotation.MediumTest; |
| |
| import androidx.test.filters.FlakyTest; |
| |
| import com.android.internal.telecom.IInCallAdapter; |
| import android.telecom.CallerInfo; |
| |
| import com.google.common.base.Predicate; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Ignore; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| import org.mockito.ArgumentCaptor; |
| import org.mockito.invocation.InvocationOnMock; |
| import org.mockito.stubbing.Answer; |
| |
| import java.util.List; |
| import java.util.concurrent.BrokenBarrierException; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.CyclicBarrier; |
| import java.util.concurrent.TimeUnit; |
| |
| /** |
| * Performs various basic call tests in Telecom. |
| */ |
| @RunWith(JUnit4.class) |
| public class BasicCallTests extends TelecomSystemTest { |
| private static final String TEST_BUNDLE_KEY = "android.telecom.extra.TEST"; |
| private static final String TEST_EVENT = "android.telecom.event.TEST"; |
| |
| @Override |
| @Before |
| public void setUp() throws Exception { |
| super.setUp(); |
| } |
| |
| @Override |
| @After |
| public void tearDown() throws Exception { |
| super.tearDown(); |
| } |
| |
| @LargeTest |
| @Test |
| public void testSingleOutgoingCallLocalDisconnect() throws Exception { |
| IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| |
| mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId); |
| assertEquals(Call.STATE_DISCONNECTING, |
| mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| assertEquals(Call.STATE_DISCONNECTING, |
| mInCallServiceFixtureY.getCall(ids.mCallId).getState()); |
| |
| when(mClockProxy.currentTimeMillis()).thenReturn(TEST_DISCONNECT_TIME); |
| when(mClockProxy.elapsedRealtime()).thenReturn(TEST_DISCONNECT_ELAPSED_TIME); |
| mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL); |
| assertEquals(Call.STATE_DISCONNECTED, |
| mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| assertEquals(Call.STATE_DISCONNECTED, |
| mInCallServiceFixtureY.getCall(ids.mCallId).getState()); |
| assertEquals(TEST_CONNECT_TIME, |
| mInCallServiceFixtureX.getCall(ids.mCallId).getConnectTimeMillis()); |
| assertEquals(TEST_CONNECT_TIME, |
| mInCallServiceFixtureY.getCall(ids.mCallId).getConnectTimeMillis()); |
| assertEquals(TEST_CREATE_TIME, |
| mInCallServiceFixtureX.getCall(ids.mCallId).getCreationTimeMillis()); |
| assertEquals(TEST_CREATE_TIME, |
| mInCallServiceFixtureY.getCall(ids.mCallId).getCreationTimeMillis()); |
| |
| verifyNoBlockChecks(); |
| } |
| |
| @LargeTest |
| @Test |
| public void testSingleOutgoingCallRemoteDisconnect() throws Exception { |
| IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| |
| when(mClockProxy.currentTimeMillis()).thenReturn(TEST_DISCONNECT_TIME); |
| when(mClockProxy.elapsedRealtime()).thenReturn(TEST_DISCONNECT_ELAPSED_TIME); |
| mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL); |
| assertEquals(Call.STATE_DISCONNECTED, |
| mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| assertEquals(Call.STATE_DISCONNECTED, |
| mInCallServiceFixtureY.getCall(ids.mCallId).getState()); |
| verifyNoBlockChecks(); |
| } |
| |
| /** |
| * Tests the {@link TelecomManager#acceptRingingCall()} API. Tests simple case of an incoming |
| * audio-only call. |
| * |
| * @throws Exception |
| */ |
| @LargeTest |
| @Test |
| public void testTelecomManagerAcceptRingingCall() throws Exception { |
| IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), |
| mConnectionServiceFixtureA); |
| |
| assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); |
| |
| // Use TelecomManager API to answer the ringing call. |
| TelecomManager telecomManager = (TelecomManager) mComponentContextFixture.getTestDouble() |
| .getApplicationContext().getSystemService(Context.TELECOM_SERVICE); |
| telecomManager.acceptRingingCall(); |
| |
| waitForHandlerAction(mTelecomSystem.getCallsManager() |
| .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT); |
| |
| verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) |
| .answer(eq(ids.mConnectionId), any()); |
| mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId); |
| |
| mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId); |
| } |
| |
| /** |
| * Tests the {@link TelecomManager#acceptRingingCall()} API. Tests simple case of an incoming |
| * video call, which should be answered as video. |
| * |
| * @throws Exception |
| */ |
| @LargeTest |
| @Test |
| public void testTelecomManagerAcceptRingingVideoCall() throws Exception { |
| IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), |
| VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA); |
| |
| assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); |
| |
| // Use TelecomManager API to answer the ringing call; the default expected behavior is to |
| // answer using whatever video state the ringing call requests. |
| TelecomManager telecomManager = (TelecomManager) mComponentContextFixture.getTestDouble() |
| .getApplicationContext().getSystemService(Context.TELECOM_SERVICE); |
| telecomManager.acceptRingingCall(); |
| |
| // Answer video API should be called |
| verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) |
| .answerVideo(eq(ids.mConnectionId), eq(VideoProfile.STATE_BIDIRECTIONAL), any()); |
| mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId); |
| |
| mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId); |
| } |
| |
| /** |
| * Tests the {@link TelecomManager#acceptRingingCall(int)} API. Tests answering a video call |
| * as an audio call. |
| * |
| * @throws Exception |
| */ |
| @LargeTest |
| @Test |
| public void testTelecomManagerAcceptRingingVideoCallAsAudio() throws Exception { |
| IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), |
| VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA); |
| |
| assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); |
| |
| // Use TelecomManager API to answer the ringing call. |
| TelecomManager telecomManager = (TelecomManager) mComponentContextFixture.getTestDouble() |
| .getApplicationContext().getSystemService(Context.TELECOM_SERVICE); |
| telecomManager.acceptRingingCall(VideoProfile.STATE_AUDIO_ONLY); |
| |
| waitForHandlerAction(mTelecomSystem.getCallsManager() |
| .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT); |
| |
| // The generic answer method on the ConnectionService is used to answer audio-only calls. |
| verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) |
| .answer(eq(ids.mConnectionId), any()); |
| mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId); |
| |
| mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId); |
| } |
| |
| /** |
| * Tests the {@link TelecomManager#acceptRingingCall()} API. Tests simple case of an incoming |
| * video call, where an attempt is made to answer with an invalid video state. |
| * |
| * @throws Exception |
| */ |
| @LargeTest |
| @Test |
| public void testTelecomManagerAcceptRingingInvalidVideoState() throws Exception { |
| IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), |
| VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA); |
| |
| assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); |
| |
| // Use TelecomManager API to answer the ringing call; the default expected behavior is to |
| // answer using whatever video state the ringing call requests. |
| TelecomManager telecomManager = (TelecomManager) mComponentContextFixture.getTestDouble() |
| .getApplicationContext().getSystemService(Context.TELECOM_SERVICE); |
| telecomManager.acceptRingingCall(999 /* invalid videostate */); |
| |
| waitForHandlerAction(mTelecomSystem.getCallsManager() |
| .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT); |
| |
| // Answer video API should be called |
| verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) |
| .answerVideo(eq(ids.mConnectionId), eq(VideoProfile.STATE_BIDIRECTIONAL), any()); |
| mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId); |
| mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId); |
| } |
| |
| @LargeTest |
| @Test |
| public void testSingleIncomingCallLocalDisconnect() throws Exception { |
| IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId); |
| assertEquals(Call.STATE_DISCONNECTING, |
| mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| assertEquals(Call.STATE_DISCONNECTING, |
| mInCallServiceFixtureY.getCall(ids.mCallId).getState()); |
| |
| when(mClockProxy.currentTimeMillis()).thenReturn(TEST_DISCONNECT_TIME); |
| when(mClockProxy.elapsedRealtime()).thenReturn(TEST_DISCONNECT_ELAPSED_TIME); |
| mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL); |
| |
| assertEquals(Call.STATE_DISCONNECTED, |
| mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| assertEquals(Call.STATE_DISCONNECTED, |
| mInCallServiceFixtureY.getCall(ids.mCallId).getState()); |
| } |
| |
| @LargeTest |
| @Test |
| public void testSingleIncomingCallRemoteDisconnect() throws Exception { |
| IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| |
| when(mClockProxy.currentTimeMillis()).thenReturn(TEST_DISCONNECT_TIME); |
| when(mClockProxy.elapsedRealtime()).thenReturn(TEST_DISCONNECT_ELAPSED_TIME); |
| mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL); |
| assertEquals(Call.STATE_DISCONNECTED, |
| mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| assertEquals(Call.STATE_DISCONNECTED, |
| mInCallServiceFixtureY.getCall(ids.mCallId).getState()); |
| } |
| |
| @LargeTest |
| @Test |
| public void testIncomingEmergencyCallback() throws Exception { |
| // Make an outgoing emergency call |
| String phoneNumber = "650-555-1212"; |
| IdPair ids = startAndMakeDialingEmergencyCall(phoneNumber, |
| mPhoneAccountE0.getAccountHandle(), mConnectionServiceFixtureA); |
| mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId); |
| mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL); |
| |
| // Incoming call should be marked as a potential emergency callback |
| Bundle extras = new Bundle(); |
| extras.putParcelable( |
| TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, |
| Uri.fromParts(PhoneAccount.SCHEME_TEL, phoneNumber, null)); |
| mTelecomSystem.getTelecomServiceImpl().getBinder() |
| .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras); |
| |
| waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(), |
| TEST_TIMEOUT); |
| ArgumentCaptor<ConnectionRequest> connectionRequestCaptor |
| = ArgumentCaptor.forClass(ConnectionRequest.class); |
| verify(mConnectionServiceFixtureA.getTestDouble()) |
| .createConnection(any(PhoneAccountHandle.class), anyString(), |
| connectionRequestCaptor.capture(), eq(true), eq(false), any()); |
| |
| assertTrue(connectionRequestCaptor.getValue().getExtras().containsKey( |
| android.telecom.Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS)); |
| assertTrue(connectionRequestCaptor.getValue().getExtras().getLong( |
| android.telecom.Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0) > 0); |
| assertTrue(connectionRequestCaptor.getValue().getExtras().containsKey( |
| TelecomManager.EXTRA_INCOMING_CALL_ADDRESS)); |
| } |
| |
| @LargeTest |
| @Test |
| public void testOutgoingCallAndSelectPhoneAccount() throws Exception { |
| // Remove default PhoneAccount so that the Call moves into the correct |
| // SELECT_PHONE_ACCOUNT state. |
| mTelecomSystem.getPhoneAccountRegistrar().setUserSelectedOutgoingPhoneAccount( |
| null, Process.myUserHandle()); |
| int startingNumConnections = mConnectionServiceFixtureA.mConnectionById.size(); |
| int startingNumCalls = mInCallServiceFixtureX.mCallById.size(); |
| String callId = startOutgoingPhoneCallWithNoPhoneAccount("650-555-1212", |
| mConnectionServiceFixtureA); |
| mTelecomSystem.getCallsManager().getLatestPreAccountSelectionFuture().join(); |
| waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(), |
| TEST_TIMEOUT); |
| assertEquals(Call.STATE_SELECT_PHONE_ACCOUNT, |
| mInCallServiceFixtureX.getCall(callId).getState()); |
| assertEquals(Call.STATE_SELECT_PHONE_ACCOUNT, |
| mInCallServiceFixtureY.getCall(callId).getState()); |
| mInCallServiceFixtureX.mInCallAdapter.phoneAccountSelected(callId, |
| mPhoneAccountA0.getAccountHandle(), false); |
| waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(), |
| TEST_TIMEOUT); |
| waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(), |
| TEST_TIMEOUT); |
| verifyAndProcessOutgoingCallBroadcast(mPhoneAccountA0.getAccountHandle()); |
| |
| IdPair ids = outgoingCallPhoneAccountSelected(mPhoneAccountA0.getAccountHandle(), |
| startingNumConnections, startingNumCalls, mConnectionServiceFixtureA); |
| |
| when(mClockProxy.currentTimeMillis()).thenReturn(TEST_DISCONNECT_TIME); |
| when(mClockProxy.elapsedRealtime()).thenReturn(TEST_DISCONNECT_ELAPSED_TIME); |
| mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL); |
| assertEquals(Call.STATE_DISCONNECTED, |
| mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| assertEquals(Call.STATE_DISCONNECTED, |
| mInCallServiceFixtureY.getCall(ids.mCallId).getState()); |
| } |
| |
| @FlakyTest |
| @LargeTest |
| @Test |
| public void testIncomingCallFromContactWithSendToVoicemailIsRejected() throws Exception { |
| Bundle extras = new Bundle(); |
| extras.putParcelable( |
| TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, |
| Uri.fromParts(PhoneAccount.SCHEME_TEL, "650-555-1212", null)); |
| mTelecomSystem.getTelecomServiceImpl().getBinder() |
| .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras); |
| |
| waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(), |
| TEST_TIMEOUT); |
| verify(mConnectionServiceFixtureA.getTestDouble()) |
| .createConnection(any(PhoneAccountHandle.class), anyString(), |
| any(ConnectionRequest.class), eq(true), eq(false), any()); |
| |
| waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(), |
| TEST_TIMEOUT); |
| assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size()); |
| |
| CallerInfo sendToVoicemailCallerInfo = new CallerInfo(); |
| sendToVoicemailCallerInfo.shouldSendToVoicemail = true; |
| sendToVoicemailCallerInfo.contactExists = true; |
| mCallerInfoAsyncQueryFactoryFixture.setResponse(sendToVoicemailCallerInfo); |
| for (CallerInfoAsyncQueryFactoryFixture.Request request : |
| mCallerInfoAsyncQueryFactoryFixture.mRequests) { |
| request.replyWithCallerInfo(sendToVoicemailCallerInfo); |
| } |
| |
| assertTrueWithTimeout(new Predicate<Void>() { |
| @Override |
| public boolean apply(Void aVoid) { |
| return mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size() == 1; |
| } |
| }); |
| assertTrueWithTimeout(new Predicate<Void>() { |
| @Override |
| public boolean apply(Void aVoid) { |
| return mMissedCallNotifier.missedCallsNotified.size() == 1; |
| } |
| }); |
| |
| verify(mInCallServiceFixtureX.getTestDouble(), never()) |
| .setInCallAdapter(any(IInCallAdapter.class)); |
| verify(mInCallServiceFixtureY.getTestDouble(), never()) |
| .setInCallAdapter(any(IInCallAdapter.class)); |
| } |
| |
| @LargeTest |
| @Test |
| public void testIncomingCallCallerInfoLookupTimesOutIsAllowed() throws Exception { |
| when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CREATE_TIME); |
| when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CREATE_ELAPSED_TIME); |
| Bundle extras = new Bundle(); |
| extras.putParcelable( |
| TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, |
| Uri.fromParts(PhoneAccount.SCHEME_TEL, "650-555-1212", null)); |
| mTelecomSystem.getTelecomServiceImpl().getBinder() |
| .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras); |
| |
| waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(), |
| TEST_TIMEOUT); |
| verify(mConnectionServiceFixtureA.getTestDouble()) |
| .createConnection(any(PhoneAccountHandle.class), anyString(), |
| any(ConnectionRequest.class), eq(true), eq(false), any()); |
| |
| waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(), |
| TEST_TIMEOUT); |
| // Never reply to the caller info lookup. |
| assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size()); |
| |
| verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) |
| .setInCallAdapter(any(IInCallAdapter.class)); |
| verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT)) |
| .setInCallAdapter(any(IInCallAdapter.class)); |
| |
| assertEquals(0, mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size()); |
| assertEquals(0, mMissedCallNotifier.missedCallsNotified.size()); |
| |
| assertTrueWithTimeout(new Predicate<Void>() { |
| @Override |
| public boolean apply(Void v) { |
| return mInCallServiceFixtureX.mInCallAdapter != null; |
| } |
| }); |
| |
| verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) |
| .addCall(any(ParcelableCall.class)); |
| verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT)) |
| .addCall(any(ParcelableCall.class)); |
| |
| when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CONNECT_TIME); |
| when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CONNECT_ELAPSED_TIME); |
| disconnectCall(mInCallServiceFixtureX.mLatestCallId, |
| mConnectionServiceFixtureA.mLatestConnectionId); |
| } |
| |
| @LargeTest |
| @Test |
| @FlakyTest |
| @Ignore("b/189904580") |
| public void testIncomingCallFromBlockedNumberIsRejected() throws Exception { |
| String phoneNumber = "650-555-1212"; |
| blockNumber(phoneNumber); |
| |
| Bundle extras = new Bundle(); |
| extras.putParcelable( |
| TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, |
| Uri.fromParts(PhoneAccount.SCHEME_TEL, phoneNumber, null)); |
| mTelecomSystem.getTelecomServiceImpl().getBinder() |
| .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras); |
| |
| waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(), |
| TEST_TIMEOUT); |
| verify(mConnectionServiceFixtureA.getTestDouble()) |
| .createConnection(any(PhoneAccountHandle.class), anyString(), |
| any(ConnectionRequest.class), eq(true), eq(false), any()); |
| |
| waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(), |
| TEST_TIMEOUT); |
| |
| assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size()); |
| for (CallerInfoAsyncQueryFactoryFixture.Request request : |
| mCallerInfoAsyncQueryFactoryFixture.mRequests) { |
| request.reply(); |
| } |
| |
| assertTrueWithTimeout(new Predicate<Void>() { |
| @Override |
| public boolean apply(Void aVoid) { |
| return mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size() == 1; |
| } |
| }); |
| assertEquals(0, mMissedCallNotifier.missedCallsNotified.size()); |
| |
| verify(mInCallServiceFixtureX.getTestDouble(), never()) |
| .setInCallAdapter(any(IInCallAdapter.class)); |
| verify(mInCallServiceFixtureY.getTestDouble(), never()) |
| .setInCallAdapter(any(IInCallAdapter.class)); |
| } |
| |
| @LargeTest |
| @Test |
| public void testIncomingCallBlockCheckTimesoutIsAllowed() throws Exception { |
| final CountDownLatch latch = new CountDownLatch(1); |
| String phoneNumber = "650-555-1212"; |
| blockNumberWithAnswer(phoneNumber, new Answer<Bundle>() { |
| @Override |
| public Bundle answer(InvocationOnMock invocation) throws Throwable { |
| latch.await(TEST_TIMEOUT * 2, TimeUnit.MILLISECONDS); |
| Bundle bundle = new Bundle(); |
| bundle.putBoolean(BlockedNumberContract.RES_NUMBER_IS_BLOCKED, true); |
| return bundle; |
| } |
| }); |
| |
| IdPair ids = startAndMakeActiveIncomingCall( |
| phoneNumber, mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| latch.countDown(); |
| |
| assertEquals(0, mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size()); |
| assertEquals(0, mMissedCallNotifier.missedCallsNotified.size()); |
| disconnectCall(ids.mCallId, ids.mConnectionId); |
| } |
| |
| public void do_testDeadlockOnOutgoingCall() throws Exception { |
| final IdPair ids = startOutgoingPhoneCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, |
| Process.myUserHandle()); |
| rapidFire( |
| new Runnable() { |
| @Override |
| public void run() { |
| while (mCallerInfoAsyncQueryFactoryFixture.mRequests.size() > 0) { |
| mCallerInfoAsyncQueryFactoryFixture.mRequests.remove(0).reply(); |
| } |
| } |
| }, |
| new Runnable() { |
| @Override |
| public void run() { |
| try { |
| mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId); |
| } catch (Exception e) { |
| Log.e(this, e, ""); |
| } |
| } |
| }); |
| } |
| |
| @LargeTest |
| @Test |
| public void testIncomingThenOutgoingCalls() throws Exception { |
| // TODO: We have to use the same PhoneAccount for both; see http://b/18461539 |
| IdPair incoming = startAndMakeActiveIncomingCall("650-555-2323", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| |
| mInCallServiceFixtureX.mInCallAdapter.disconnectCall(incoming.mCallId); |
| mInCallServiceFixtureX.mInCallAdapter.disconnectCall(outgoing.mCallId); |
| } |
| |
| @LargeTest |
| @Test |
| public void testOutgoingThenIncomingCalls() throws Exception { |
| // TODO: We have to use the same PhoneAccount for both; see http://b/18461539 |
| IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(), |
| TEST_TIMEOUT); |
| IdPair incoming = startAndMakeActiveIncomingCall("650-555-2323", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(), |
| TEST_TIMEOUT); |
| verify(mConnectionServiceFixtureA.getTestDouble()) |
| .hold(eq(outgoing.mConnectionId), any()); |
| mConnectionServiceFixtureA.mConnectionById.get(outgoing.mConnectionId).state = |
| Connection.STATE_HOLDING; |
| mConnectionServiceFixtureA.sendSetOnHold(outgoing.mConnectionId); |
| assertEquals(Call.STATE_HOLDING, |
| mInCallServiceFixtureX.getCall(outgoing.mCallId).getState()); |
| assertEquals(Call.STATE_HOLDING, |
| mInCallServiceFixtureY.getCall(outgoing.mCallId).getState()); |
| |
| mInCallServiceFixtureX.mInCallAdapter.disconnectCall(incoming.mCallId); |
| mInCallServiceFixtureX.mInCallAdapter.disconnectCall(outgoing.mCallId); |
| } |
| |
| @LargeTest |
| @Test |
| public void testAudioManagerOperations() throws Exception { |
| AudioManager audioManager = (AudioManager) mComponentContextFixture.getTestDouble() |
| .getApplicationContext().getSystemService(Context.AUDIO_SERVICE); |
| |
| IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| |
| verify(audioManager, timeout(TEST_TIMEOUT)).requestAudioFocusForCall(anyInt(), anyInt()); |
| verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce()) |
| .setMode(AudioManager.MODE_IN_CALL); |
| |
| mInCallServiceFixtureX.mInCallAdapter.mute(true); |
| verify(mAudioService, timeout(TEST_TIMEOUT)) |
| .setMicrophoneMute(eq(true), any(String.class), any(Integer.class)); |
| mInCallServiceFixtureX.mInCallAdapter.mute(false); |
| verify(mAudioService, timeout(TEST_TIMEOUT)) |
| .setMicrophoneMute(eq(false), any(String.class), any(Integer.class)); |
| |
| mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_SPEAKER, null); |
| waitForHandlerAction(mTelecomSystem.getCallsManager().getCallAudioManager() |
| .getCallAudioRouteStateMachine().getHandler(), TEST_TIMEOUT); |
| verify(audioManager, timeout(TEST_TIMEOUT)) |
| .setSpeakerphoneOn(true); |
| mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_EARPIECE, null); |
| waitForHandlerAction(mTelecomSystem.getCallsManager().getCallAudioManager() |
| .getCallAudioRouteStateMachine().getHandler(), TEST_TIMEOUT); |
| // setSpeakerPhoneOn(false) gets called once during the call initiation phase |
| verify(audioManager, timeout(TEST_TIMEOUT).atLeast(1)) |
| .setSpeakerphoneOn(false); |
| |
| mConnectionServiceFixtureA. |
| sendSetDisconnected(outgoing.mConnectionId, DisconnectCause.REMOTE); |
| |
| waitForHandlerAction(mTelecomSystem.getCallsManager().getCallAudioManager() |
| .getCallAudioModeStateMachine().getHandler(), TEST_TIMEOUT); |
| waitForHandlerAction(mTelecomSystem.getCallsManager().getCallAudioManager() |
| .getCallAudioRouteStateMachine().getHandler(), TEST_TIMEOUT); |
| verify(audioManager, timeout(TEST_TIMEOUT)) |
| .abandonAudioFocusForCall(); |
| verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce()) |
| .setMode(AudioManager.MODE_NORMAL); |
| } |
| |
| private void rapidFire(Runnable... tasks) { |
| final CyclicBarrier barrier = new CyclicBarrier(tasks.length); |
| final CountDownLatch latch = new CountDownLatch(tasks.length); |
| for (int i = 0; i < tasks.length; i++) { |
| final Runnable task = tasks[i]; |
| new Thread(new Runnable() { |
| @Override |
| public void run() { |
| try { |
| barrier.await(); |
| task.run(); |
| } catch (InterruptedException | BrokenBarrierException e){ |
| Log.e(BasicCallTests.this, e, "Unexpectedly interrupted"); |
| } finally { |
| latch.countDown(); |
| } |
| } |
| }).start(); |
| } |
| try { |
| latch.await(); |
| } catch (InterruptedException e) { |
| Log.e(BasicCallTests.this, e, "Unexpectedly interrupted"); |
| } |
| } |
| |
| @MediumTest |
| @Test |
| public void testBasicConferenceCall() throws Exception { |
| makeConferenceCall(); |
| } |
| |
| @MediumTest |
| @Test |
| public void testAddCallToConference1() throws Exception { |
| ParcelableCall conferenceCall = makeConferenceCall(); |
| IdPair callId3 = startAndMakeActiveOutgoingCall("650-555-1214", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| // testAddCallToConference{1,2} differ in the order of arguments to InCallAdapter#conference |
| mInCallServiceFixtureX.getInCallAdapter().conference( |
| conferenceCall.getId(), callId3.mCallId); |
| Thread.sleep(200); |
| |
| ParcelableCall call3 = mInCallServiceFixtureX.getCall(callId3.mCallId); |
| ParcelableCall updatedConference = mInCallServiceFixtureX.getCall(conferenceCall.getId()); |
| assertEquals(conferenceCall.getId(), call3.getParentCallId()); |
| assertEquals(3, updatedConference.getChildCallIds().size()); |
| assertTrue(updatedConference.getChildCallIds().contains(callId3.mCallId)); |
| } |
| |
| @MediumTest |
| @Test |
| public void testAddCallToConference2() throws Exception { |
| ParcelableCall conferenceCall = makeConferenceCall(); |
| IdPair callId3 = startAndMakeActiveOutgoingCall("650-555-1214", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| mInCallServiceFixtureX.getInCallAdapter() |
| .conference(callId3.mCallId, conferenceCall.getId()); |
| Thread.sleep(200); |
| |
| ParcelableCall call3 = mInCallServiceFixtureX.getCall(callId3.mCallId); |
| ParcelableCall updatedConference = mInCallServiceFixtureX.getCall(conferenceCall.getId()); |
| assertEquals(conferenceCall.getId(), call3.getParentCallId()); |
| assertEquals(3, updatedConference.getChildCallIds().size()); |
| assertTrue(updatedConference.getChildCallIds().contains(callId3.mCallId)); |
| } |
| |
| /** |
| * Tests the {@link Call#pullExternalCall()} API. Verifies that if a call is not an external |
| * call, no pull call request is made to the connection service. |
| * |
| * @throws Exception |
| */ |
| @MediumTest |
| @Test |
| public void testPullNonExternalCall() throws Exception { |
| // TODO: Revisit this unit test once telecom support for filtering external calls from |
| // InCall services is implemented. |
| IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| |
| // Attempt to pull the call and verify the API call makes it through |
| mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId); |
| Thread.sleep(TEST_TIMEOUT); |
| verify(mConnectionServiceFixtureA.getTestDouble(), never()) |
| .pullExternalCall(eq(ids.mCallId), any()); |
| } |
| |
| /** |
| * Tests the {@link Connection#sendConnectionEvent(String, Bundle)} API. |
| * |
| * @throws Exception |
| */ |
| @MediumTest |
| @Test |
| public void testSendConnectionEventNull() throws Exception { |
| IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| mConnectionServiceFixtureA.sendConnectionEvent(ids.mConnectionId, TEST_EVENT, null); |
| verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) |
| .onConnectionEvent(ids.mCallId, TEST_EVENT, null); |
| } |
| |
| /** |
| * Tests the {@link Connection#sendConnectionEvent(String, Bundle)} API. |
| * |
| * @throws Exception |
| */ |
| @MediumTest |
| @Test |
| public void testSendConnectionEventNotNull() throws Exception { |
| IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| |
| Bundle testBundle = new Bundle(); |
| testBundle.putString(TEST_BUNDLE_KEY, "TEST"); |
| |
| ArgumentCaptor<Bundle> bundleArgumentCaptor = ArgumentCaptor.forClass(Bundle.class); |
| mConnectionServiceFixtureA.sendConnectionEvent(ids.mConnectionId, TEST_EVENT, testBundle); |
| verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) |
| .onConnectionEvent(eq(ids.mCallId), eq(TEST_EVENT), bundleArgumentCaptor.capture()); |
| assert (bundleArgumentCaptor.getValue().containsKey(TEST_BUNDLE_KEY)); |
| } |
| |
| /** |
| * Tests the {@link Call#sendCallEvent(String, Bundle)} API. |
| * |
| * @throws Exception |
| */ |
| @MediumTest |
| @Test |
| public void testSendCallEventNull() throws Exception { |
| IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| |
| mInCallServiceFixtureX.mInCallAdapter.sendCallEvent(ids.mCallId, TEST_EVENT, 26, null); |
| verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) |
| .sendCallEvent(eq(ids.mConnectionId), eq(TEST_EVENT), isNull(Bundle.class), any()); |
| } |
| |
| /** |
| * Tests the {@link Call#sendCallEvent(String, Bundle)} API. |
| * |
| * @throws Exception |
| */ |
| @MediumTest |
| @Test |
| public void testSendCallEventNonNull() throws Exception { |
| IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| |
| Bundle testBundle = new Bundle(); |
| testBundle.putString(TEST_BUNDLE_KEY, "TEST"); |
| |
| ArgumentCaptor<Bundle> bundleArgumentCaptor = ArgumentCaptor.forClass(Bundle.class); |
| mInCallServiceFixtureX.mInCallAdapter.sendCallEvent(ids.mCallId, TEST_EVENT, 26, |
| testBundle); |
| verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) |
| .sendCallEvent(eq(ids.mConnectionId), eq(TEST_EVENT), |
| bundleArgumentCaptor.capture(), any()); |
| assert (bundleArgumentCaptor.getValue().containsKey(TEST_BUNDLE_KEY)); |
| } |
| |
| private void blockNumber(String phoneNumber) throws Exception { |
| blockNumberWithAnswer(phoneNumber, new Answer<Bundle>() { |
| @Override |
| public Bundle answer(InvocationOnMock invocation) throws Throwable { |
| Bundle bundle = new Bundle(); |
| bundle.putInt(BlockedNumberContract.RES_BLOCK_STATUS, |
| BlockedNumberContract.STATUS_BLOCKED_IN_LIST); |
| return bundle; |
| } |
| }); |
| } |
| |
| private void blockNumberWithAnswer(String phoneNumber, Answer answer) throws Exception { |
| when(getBlockedNumberProvider().call( |
| any(), |
| anyString(), |
| eq(BlockedNumberContract.SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER), |
| eq(phoneNumber), |
| nullable(Bundle.class))).thenAnswer(answer); |
| } |
| |
| private void verifyNoBlockChecks() { |
| verifyZeroInteractions(getBlockedNumberProvider()); |
| } |
| |
| private IContentProvider getBlockedNumberProvider() { |
| return mSpyContext.getContentResolver().acquireProvider(BlockedNumberContract.AUTHORITY); |
| } |
| |
| private void disconnectCall(String callId, String connectionId) throws Exception { |
| when(mClockProxy.currentTimeMillis()).thenReturn(TEST_DISCONNECT_TIME); |
| when(mClockProxy.elapsedRealtime()).thenReturn(TEST_DISCONNECT_ELAPSED_TIME); |
| mConnectionServiceFixtureA.sendSetDisconnected(connectionId, DisconnectCause.LOCAL); |
| assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureX.getCall(callId).getState()); |
| assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureY.getCall(callId).getState()); |
| assertEquals(TEST_CREATE_TIME, |
| mInCallServiceFixtureX.getCall(callId).getCreationTimeMillis()); |
| assertEquals(TEST_CREATE_TIME, |
| mInCallServiceFixtureY.getCall(callId).getCreationTimeMillis()); |
| } |
| |
| /** |
| * Tests to make sure that the Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY property is set on a |
| * Call that is based on a Connection with the Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY |
| * property set. |
| */ |
| @MediumTest |
| @Test |
| public void testCdmaEnhancedPrivacyVoiceCall() throws Exception { |
| mConnectionServiceFixtureA.mConnectionServiceDelegate.mProperties = |
| Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY; |
| |
| IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| |
| assertTrue(Call.Details.hasProperty( |
| mInCallServiceFixtureX.getCall(ids.mCallId).getProperties(), |
| Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY)); |
| } |
| |
| /** |
| * Tests to make sure that Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY is dropped |
| * when the Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY property is removed from the Connection. |
| */ |
| @MediumTest |
| @Test |
| public void testDropCdmaEnhancedPrivacyVoiceCall() throws Exception { |
| mConnectionServiceFixtureA.mConnectionServiceDelegate.mProperties = |
| Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY; |
| |
| IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| mConnectionServiceFixtureA.mLatestConnection.setConnectionProperties(0); |
| |
| assertFalse(Call.Details.hasProperty( |
| mInCallServiceFixtureX.getCall(ids.mCallId).getProperties(), |
| Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY)); |
| } |
| |
| /** |
| * Tests the {@link Call#pullExternalCall()} API. Ensures that an external call which is |
| * pullable can be pulled. |
| * |
| * @throws Exception |
| */ |
| @LargeTest |
| @Test |
| public void testPullExternalCall() throws Exception { |
| // TODO: Revisit this unit test once telecom support for filtering external calls from |
| // InCall services is implemented. |
| mConnectionServiceFixtureA.mConnectionServiceDelegate.mCapabilities = |
| Connection.CAPABILITY_CAN_PULL_CALL; |
| mConnectionServiceFixtureA.mConnectionServiceDelegate.mProperties = |
| Connection.PROPERTY_IS_EXTERNAL_CALL; |
| |
| IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| |
| // Attempt to pull the call and verify the API call makes it through |
| mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId); |
| verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) |
| .pullExternalCall(eq(ids.mConnectionId), any()); |
| } |
| |
| /** |
| * Tests the {@link Call#pullExternalCall()} API. Verifies that if an external call is not |
| * marked as pullable that the connection service does not get an API call to pull the external |
| * call. |
| * |
| * @throws Exception |
| */ |
| @LargeTest |
| @Test |
| public void testPullNonPullableExternalCall() throws Exception { |
| // TODO: Revisit this unit test once telecom support for filtering external calls from |
| // InCall services is implemented. |
| mConnectionServiceFixtureA.mConnectionServiceDelegate.mProperties = |
| Connection.PROPERTY_IS_EXTERNAL_CALL; |
| |
| IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| |
| // Attempt to pull the call and verify the API call makes it through |
| mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId); |
| Thread.sleep(TEST_TIMEOUT); |
| verify(mConnectionServiceFixtureA.getTestDouble(), never()) |
| .pullExternalCall(eq(ids.mConnectionId), any()); |
| } |
| |
| /** |
| * Test scenario where the user starts an outgoing video call with no selected PhoneAccount, and |
| * then subsequently selects a PhoneAccount which supports video calling. |
| * @throws Exception |
| */ |
| @LargeTest |
| @Test |
| public void testOutgoingCallSelectPhoneAccountVideo() throws Exception { |
| startOutgoingPhoneCallPendingCreateConnection("650-555-1212", |
| null, mConnectionServiceFixtureA, |
| Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL); |
| com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() |
| .iterator().next(); |
| assert(call.isVideoCallingSupportedByPhoneAccount()); |
| assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState()); |
| |
| // Change the phone account to one which supports video calling. |
| call.setTargetPhoneAccount(mPhoneAccountA1.getAccountHandle()); |
| assert(call.isVideoCallingSupportedByPhoneAccount()); |
| assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState()); |
| } |
| |
| /** |
| * Test scenario where the user starts an outgoing video call with no selected PhoneAccount, and |
| * then subsequently selects a PhoneAccount which does not support video calling. |
| * @throws Exception |
| */ |
| @FlakyTest |
| @LargeTest |
| @Test |
| public void testOutgoingCallSelectPhoneAccountNoVideo() throws Exception { |
| startOutgoingPhoneCallPendingCreateConnection("650-555-1212", |
| null, mConnectionServiceFixtureA, |
| Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL); |
| com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() |
| .iterator().next(); |
| assert(call.isVideoCallingSupportedByPhoneAccount()); |
| assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState()); |
| |
| // Change the phone account to one which does not support video calling. |
| call.setTargetPhoneAccount(mPhoneAccountA2.getAccountHandle()); |
| assert(!call.isVideoCallingSupportedByPhoneAccount()); |
| assertEquals(VideoProfile.STATE_AUDIO_ONLY, call.getVideoState()); |
| } |
| |
| /** |
| * Basic test to ensure that a self-managed ConnectionService can place a call. |
| * @throws Exception |
| */ |
| @LargeTest |
| @Test |
| public void testSelfManagedOutgoing() throws Exception { |
| PhoneAccountHandle phoneAccountHandle = mPhoneAccountSelfManaged.getAccountHandle(); |
| IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212", phoneAccountHandle, |
| mConnectionServiceFixtureA); |
| |
| // The InCallService should not know about the call since its self-managed. |
| assertNull(mInCallServiceFixtureX.getCall(ids.mCallId)); |
| } |
| |
| /** |
| * Basic test to ensure that a self-managed ConnectionService can add an incoming call. |
| * @throws Exception |
| */ |
| @LargeTest |
| @Test |
| public void testSelfManagedIncoming() throws Exception { |
| PhoneAccountHandle phoneAccountHandle = mPhoneAccountSelfManaged.getAccountHandle(); |
| IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", phoneAccountHandle, |
| mConnectionServiceFixtureA); |
| |
| // The InCallService should not know about the call since its self-managed. |
| assertNull(mInCallServiceFixtureX.getCall(ids.mCallId)); |
| } |
| |
| /** |
| * Basic test to ensure that when there are no calls, we permit outgoing calls by a self managed |
| * CS. |
| * @throws Exception |
| */ |
| @LargeTest |
| @Test |
| public void testIsOutgoingCallPermitted() throws Exception { |
| assertTrue(mTelecomSystem.getTelecomServiceImpl().getBinder() |
| .isOutgoingCallPermitted(mPhoneAccountSelfManaged.getAccountHandle())); |
| } |
| |
| /** |
| * Ensure if there is a holdable call ongoing we'll be able to place another call. |
| * @throws Exception |
| */ |
| @LargeTest |
| @Test |
| public void testIsOutgoingCallPermittedOngoingHoldable() throws Exception { |
| // Start a regular call; the self-managed CS can make a call now since ongoing call can be |
| // held |
| IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| |
| assertTrue(mTelecomSystem.getTelecomServiceImpl().getBinder() |
| .isOutgoingCallPermitted(mPhoneAccountSelfManaged.getAccountHandle())); |
| } |
| |
| /** |
| * Ensure if there is an unholdable call we can't place another call. |
| * @throws Exception |
| */ |
| @LargeTest |
| @Test |
| public void testIsOutgoingCallPermittedOngoingUnHoldable() throws Exception { |
| // Start a regular call; the self-managed CS can't make a call now because the ongoing call |
| // can't be held. |
| mConnectionServiceFixtureA.mConnectionServiceDelegate.mCapabilities = 0; |
| IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| |
| assertTrue(mTelecomSystem.getTelecomServiceImpl().getBinder() |
| .isOutgoingCallPermitted(mPhoneAccountSelfManaged.getAccountHandle())); |
| } |
| |
| /** |
| * Basic to verify audio route gets reset to baseline when emergency call placed while a |
| * self-managed call is underway. |
| * @throws Exception |
| */ |
| @LargeTest |
| @Test |
| @FlakyTest |
| public void testDisconnectSelfManaged() throws Exception { |
| // Add a self-managed call. |
| PhoneAccountHandle phoneAccountHandle = mPhoneAccountSelfManaged.getAccountHandle(); |
| startAndMakeActiveIncomingCall("650-555-1212", phoneAccountHandle, |
| mConnectionServiceFixtureA); |
| Connection connection = mConnectionServiceFixtureA.mLatestConnection; |
| |
| // Route self-managed call to speaker. |
| connection.setAudioRoute(CallAudioState.ROUTE_SPEAKER); |
| waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(), |
| TEST_TIMEOUT); |
| |
| // Place an emergency call. |
| startAndMakeDialingEmergencyCall("650-555-1212", mPhoneAccountE0.getAccountHandle(), |
| mConnectionServiceFixtureA); |
| |
| // Should have reverted back to earpiece. |
| assertTrueWithTimeout(new Predicate<Void>() { |
| @Override |
| public boolean apply(Void aVoid) { |
| return mInCallServiceFixtureX.mCallAudioState.getRoute() |
| == CallAudioState.ROUTE_EARPIECE; |
| } |
| }); |
| } |
| |
| /** |
| * Tests the {@link Call#deflect} API. Verifies that if a call is incoming, |
| * and deflect API is called, then request is made to the connection service. |
| * |
| * @throws Exception |
| */ |
| @LargeTest |
| @Test |
| public void testDeflectCallWhenIncoming() throws Exception { |
| Uri deflectAddress = Uri.parse("tel:650-555-1214"); |
| IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), |
| mConnectionServiceFixtureA); |
| |
| assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); |
| assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); |
| // Attempt to deflect the call and verify the API call makes it through |
| mInCallServiceFixtureX.mInCallAdapter.deflectCall(ids.mCallId, deflectAddress); |
| verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) |
| .deflect(eq(ids.mConnectionId), eq(deflectAddress), any()); |
| mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId); |
| } |
| |
| /** |
| * Tests the {@link Call#deflect} API. Verifies that if a call is outgoing, |
| * and deflect API is called, then request is not made to the connection service. |
| * Ideally, deflect option should be displayed only if call is incoming/waiting. |
| * |
| * @throws Exception |
| */ |
| @LargeTest |
| @Test |
| public void testDeflectCallWhenOutgoing() throws Exception { |
| Uri deflectAddress = Uri.parse("tel:650-555-1214"); |
| IdPair ids = startOutgoingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), |
| mConnectionServiceFixtureA, Process.myUserHandle()); |
| // Attempt to deflect the call and verify the API call does not make it through |
| mInCallServiceFixtureX.mInCallAdapter.deflectCall(ids.mCallId, deflectAddress); |
| verify(mConnectionServiceFixtureA.getTestDouble(), never()) |
| .deflect(eq(ids.mConnectionId), eq(deflectAddress), any()); |
| mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId); |
| } |
| |
| /** |
| * Test to make sure to unmute automatically when making an emergency call and keep unmute |
| * during the emergency call. |
| * @throws Exception |
| */ |
| @LargeTest |
| @Test |
| @FlakyTest |
| public void testUnmuteDuringEmergencyCall() throws Exception { |
| // Make an outgoing call and turn ON mute. |
| IdPair outgoingCall = startAndMakeActiveOutgoingCall("650-555-1212", |
| mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); |
| assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(outgoingCall.mCallId) |
| .getState()); |
| mInCallServiceFixtureX.mInCallAdapter.mute(true); |
| waitForHandlerAction(mTelecomSystem.getCallsManager().getCallAudioManager() |
| .getCallAudioRouteStateMachine().getHandler(), TEST_TIMEOUT); |
| assertTrue(mTelecomSystem.getCallsManager().getAudioState().isMuted()); |
| |
| // Make an emergency call. |
| IdPair emergencyCall = startAndMakeDialingEmergencyCall("650-555-1213", |
| mPhoneAccountE0.getAccountHandle(), mConnectionServiceFixtureA); |
| assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(emergencyCall.mCallId) |
| .getState()); |
| waitForHandlerAction(mTelecomSystem.getCallsManager().getCallAudioManager() |
| .getCallAudioRouteStateMachine().getHandler(), TEST_TIMEOUT); |
| // Should be unmute automatically. |
| assertFalse(mTelecomSystem.getCallsManager().getAudioState().isMuted()); |
| |
| // Toggle mute during an emergency call. |
| mTelecomSystem.getCallsManager().getCallAudioManager().toggleMute(); |
| waitForHandlerAction(mTelecomSystem.getCallsManager().getCallAudioManager() |
| .getCallAudioRouteStateMachine().getHandler(), TEST_TIMEOUT); |
| // Should keep unmute. |
| assertFalse(mTelecomSystem.getCallsManager().getAudioState().isMuted()); |
| |
| ArgumentCaptor<Boolean> muteValueCaptor = ArgumentCaptor.forClass(Boolean.class); |
| verify(mAudioService, times(2)).setMicrophoneMute(muteValueCaptor.capture(), |
| any(String.class), any(Integer.class)); |
| List<Boolean> muteValues = muteValueCaptor.getAllValues(); |
| // Check mute status was changed twice with true and false. |
| assertTrue(muteValues.get(0)); |
| assertFalse(muteValues.get(1)); |
| } |
| } |