blob: ceec91b7b3e7ca6df181aaad3d138e2f8ed81f83 [file] [log] [blame]
/*
* 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.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.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.Handler;
import android.os.Looper;
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.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 com.android.internal.telecom.IInCallAdapter;
import com.android.internal.telephony.CallerInfo;
import com.android.server.telecom.Log;
import com.google.common.base.Predicate;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import org.mockito.ArgumentCaptor;
/**
* Performs various basic call tests in Telecom.
*/
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";
@LargeTest
public void testSingleOutgoingCallLocalDisconnect() throws Exception {
IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
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();
}
@LargeTest
public void testSingleOutgoingCallRemoteDisconnect() throws Exception {
IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
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
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();
verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
.answer(ids.mConnectionId);
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
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));
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
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);
// The generic answer method on the ConnectionService is used to answer audio-only calls.
verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
.answer(eq(ids.mConnectionId));
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
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 */);
// Answer video API should be called
verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
.answerVideo(eq(ids.mConnectionId), eq(VideoProfile.STATE_BIDIRECTIONAL));
mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId);
mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
}
@LargeTest
public void testSingleIncomingCallLocalDisconnect() throws Exception {
IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
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
public void testSingleIncomingCallRemoteDisconnect() throws Exception {
IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
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
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);
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);
IdPair ids = outgoingCallPhoneAccountSelected(mPhoneAccountA0.getAccountHandle(),
startingNumConnections, startingNumCalls, mConnectionServiceFixtureA);
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
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(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
verify(mConnectionServiceFixtureA.getTestDouble())
.createConnection(any(PhoneAccountHandle.class), anyString(),
any(ConnectionRequest.class), eq(true), eq(false));
assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size());
for (CallerInfoAsyncQueryFactoryFixture.Request request :
mCallerInfoAsyncQueryFactoryFixture.mRequests) {
CallerInfo sendToVoicemailCallerInfo = new CallerInfo();
sendToVoicemailCallerInfo.shouldSendToVoicemail = true;
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
public void testIncomingCallCallerInfoLookupTimesOutIsAllowed() 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);
verify(mConnectionServiceFixtureA.getTestDouble())
.createConnection(any(PhoneAccountHandle.class), anyString(),
any(ConnectionRequest.class), eq(true), eq(false));
// 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));
disconnectCall(mInCallServiceFixtureX.mLatestCallId,
mConnectionServiceFixtureA.mLatestConnectionId);
}
@LargeTest
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);
verify(mConnectionServiceFixtureA.getTestDouble())
.createConnection(any(PhoneAccountHandle.class), anyString(),
any(ConnectionRequest.class), eq(true), eq(false));
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
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, "");
}
}
});
}
@MediumTest
public void testDeadlockOnOutgoingCall() throws Exception {
for (int i = 0; i < 100; i++) {
BasicCallTests test = new BasicCallTests();
test.setContext(getContext());
test.setTestContext(getTestContext());
test.setName(getName());
test.setUp();
test.do_testDeadlockOnOutgoingCall();
test.tearDown();
}
}
@LargeTest
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
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);
IdPair incoming = startAndMakeActiveIncomingCall("650-555-2323",
mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
verify(mConnectionServiceFixtureA.getTestDouble())
.hold(outgoing.mConnectionId);
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
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);
verify(audioManager, timeout(TEST_TIMEOUT))
.setSpeakerphoneOn(true);
mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_EARPIECE);
verify(audioManager, timeout(TEST_TIMEOUT))
.setSpeakerphoneOn(false);
mConnectionServiceFixtureA.
sendSetDisconnected(outgoing.mConnectionId, DisconnectCause.REMOTE);
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
public void testBasicConferenceCall() throws Exception {
makeConferenceCall();
}
@MediumTest
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
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
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);
verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT).never())
.pullExternalCall(ids.mCallId);
}
/**
* Tests the {@link Connection#sendConnectionEvent(String)} API.
*
* @throws Exception
*/
@MediumTest
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)} API.
*
* @throws Exception
*/
@MediumTest
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
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, null);
verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
.sendCallEvent(ids.mConnectionId, TEST_EVENT, null);
}
/**
* Tests the {@link Call#sendCallEvent(String, Bundle)} API.
*
* @throws Exception
*/
@MediumTest
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,
testBundle);
verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
.sendCallEvent(eq(ids.mConnectionId), eq(TEST_EVENT),
bundleArgumentCaptor.capture());
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.putBoolean(BlockedNumberContract.RES_NUMBER_IS_BLOCKED, true);
return bundle;
}
});
}
private void blockNumberWithAnswer(String phoneNumber, Answer answer) throws Exception {
when(getBlockedNumberProvider().call(
anyString(),
eq(BlockedNumberContract.SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER),
eq(phoneNumber),
isNull(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 {
mConnectionServiceFixtureA.sendSetDisconnected(connectionId, DisconnectCause.LOCAL);
assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureX.getCall(callId).getState());
assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureY.getCall(callId).getState());
}
/**
* 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
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
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
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(ids.mConnectionId);
}
/**
* 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
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);
verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT).never())
.pullExternalCall(ids.mConnectionId);
}
public void testMergeFailedAndNotifyInCallUi() throws Exception {
IdPair testCall1 = startAndMakeActiveOutgoingCall(
"650-555-1212",
mPhoneAccountA0.getAccountHandle(),
mConnectionServiceFixtureA);
IdPair testCall2 = startAndMakeActiveOutgoingCall(
"650-555-1213",
mPhoneAccountA0.getAccountHandle(),
mConnectionServiceFixtureA);
assertEquals(Call.STATE_ACTIVE,
mInCallServiceFixtureX.getCall(testCall1.mCallId).getState());
assertEquals(Call.STATE_ACTIVE,
mInCallServiceFixtureX.getCall(testCall2.mCallId).getState());
assertEquals(Call.STATE_ACTIVE,
mInCallServiceFixtureY.getCall(testCall1.mCallId).getState());
assertEquals(Call.STATE_ACTIVE,
mInCallServiceFixtureY.getCall(testCall2.mCallId).getState());
// Conference will not occur and instead will send setConferenceMergeFailed
((ConnectionServiceFixture.FakeConnection)
mConnectionServiceFixtureA.mLatestConnection).setIsConferenceCreated(false);
mInCallServiceFixtureX.getInCallAdapter().conference(testCall2.mCallId, testCall1.mCallId);
verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)).onConnectionEvent(
eq(testCall2.mCallId), eq(Connection.EVENT_CALL_MERGE_FAILED), any(Bundle.class));
verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT)).onConnectionEvent(
eq(testCall2.mCallId), eq(Connection.EVENT_CALL_MERGE_FAILED), any(Bundle.class));
}
@LargeTest
public void testEmergencyCallFailMoveToSecondSim() throws Exception {
IdPair ids = startAndMakeDialingEmergencyCall("650-555-1212",
mPhoneAccountE0.getAccountHandle(), mConnectionServiceFixtureA);
assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
// The Emergency Call has failed on the default SIM with an ERROR Disconnect Cause. Retry
// with the other SIM PhoneAccount
IdPair newIds = triggerEmergencyRedial(mPhoneAccountE1.getAccountHandle(),
mConnectionServiceFixtureA, ids);
// Call should be active on the E1 PhoneAccount
mConnectionServiceFixtureA.sendSetActive(newIds.mConnectionId);
assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(newIds.mCallId).getState());
assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(newIds.mCallId).getState());
assertEquals(mInCallServiceFixtureX.getCall(ids.mCallId).getAccountHandle(),
mPhoneAccountE1.getAccountHandle());
}
}