BasicCallTests.java revision 805c45364858415de1d43802470c66c95c00ebaf
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17package com.android.server.telecom.tests; 18 19import static org.mockito.Matchers.any; 20import static org.mockito.Matchers.anyInt; 21import static org.mockito.Matchers.anyString; 22import static org.mockito.Matchers.eq; 23import static org.mockito.Matchers.isNull; 24import static org.mockito.Mockito.never; 25import static org.mockito.Mockito.timeout; 26import static org.mockito.Mockito.verify; 27import static org.mockito.Mockito.verifyZeroInteractions; 28import static org.mockito.Mockito.when; 29 30import android.content.Context; 31import android.content.IContentProvider; 32import android.media.AudioManager; 33import android.net.Uri; 34import android.os.Bundle; 35import android.os.Process; 36import android.provider.BlockedNumberContract; 37import android.telecom.Call; 38import android.telecom.CallAudioState; 39import android.telecom.Connection; 40import android.telecom.ConnectionRequest; 41import android.telecom.DisconnectCause; 42import android.telecom.ParcelableCall; 43import android.telecom.ParcelableCallAnalytics; 44import android.telecom.PhoneAccount; 45import android.telecom.PhoneAccountHandle; 46import android.telecom.TelecomManager; 47import android.telecom.VideoProfile; 48import android.test.suitebuilder.annotation.LargeTest; 49import android.test.suitebuilder.annotation.MediumTest; 50import android.test.suitebuilder.annotation.SmallTest; 51 52import com.android.internal.telecom.IInCallAdapter; 53import com.android.internal.telephony.CallerInfo; 54import com.android.internal.util.IndentingPrintWriter; 55import com.android.server.telecom.Analytics; 56import com.android.server.telecom.Log; 57 58import com.google.common.base.Predicate; 59 60import org.mockito.invocation.InvocationOnMock; 61import org.mockito.stubbing.Answer; 62 63import java.io.StringWriter; 64import java.util.List; 65import java.util.Map; 66import java.util.concurrent.BrokenBarrierException; 67import java.util.concurrent.CountDownLatch; 68import java.util.concurrent.CyclicBarrier; 69import java.util.concurrent.TimeUnit; 70 71import org.mockito.ArgumentCaptor; 72 73import static org.mockito.Matchers.any; 74import static org.mockito.Matchers.anyInt; 75import static org.mockito.Matchers.eq; 76import static org.mockito.Mockito.never; 77import static org.mockito.Mockito.timeout; 78import static org.mockito.Mockito.verify; 79 80/** 81 * Performs various basic call tests in Telecom. 82 */ 83public class BasicCallTests extends TelecomSystemTest { 84 private static final String TEST_BUNDLE_KEY = "android.telecom.extra.TEST"; 85 private static final String TEST_EVENT = "android.telecom.event.TEST"; 86 87 @LargeTest 88 public void testSingleOutgoingCallLocalDisconnect() throws Exception { 89 IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212", 90 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 91 92 mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId); 93 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 94 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 95 96 mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL); 97 assertEquals(Call.STATE_DISCONNECTED, 98 mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 99 assertEquals(Call.STATE_DISCONNECTED, 100 mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 101 verifyNoBlockChecks(); 102 } 103 104 @LargeTest 105 public void testSingleOutgoingCallRemoteDisconnect() throws Exception { 106 IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212", 107 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 108 109 mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL); 110 assertEquals(Call.STATE_DISCONNECTED, 111 mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 112 assertEquals(Call.STATE_DISCONNECTED, 113 mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 114 verifyNoBlockChecks(); 115 } 116 117 /** 118 * Tests the {@link TelecomManager#acceptRingingCall()} API. Tests simple case of an incoming 119 * audio-only call. 120 * 121 * @throws Exception 122 */ 123 @LargeTest 124 public void testTelecomManagerAcceptRingingCall() throws Exception { 125 IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), 126 mConnectionServiceFixtureA); 127 128 assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 129 assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 130 131 // Use TelecomManager API to answer the ringing call. 132 TelecomManager telecomManager = (TelecomManager) mComponentContextFixture.getTestDouble() 133 .getApplicationContext().getSystemService(Context.TELECOM_SERVICE); 134 telecomManager.acceptRingingCall(); 135 136 verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) 137 .answer(ids.mCallId); 138 mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId); 139 140 mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId); 141 } 142 143 /** 144 * Tests the {@link TelecomManager#acceptRingingCall()} API. Tests simple case of an incoming 145 * video call, which should be answered as video. 146 * 147 * @throws Exception 148 */ 149 @LargeTest 150 public void testTelecomManagerAcceptRingingVideoCall() throws Exception { 151 IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), 152 VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA); 153 154 assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 155 assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 156 157 // Use TelecomManager API to answer the ringing call; the default expected behavior is to 158 // answer using whatever video state the ringing call requests. 159 TelecomManager telecomManager = (TelecomManager) mComponentContextFixture.getTestDouble() 160 .getApplicationContext().getSystemService(Context.TELECOM_SERVICE); 161 telecomManager.acceptRingingCall(); 162 163 // Answer video API should be called 164 verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) 165 .answerVideo(eq(ids.mCallId), eq(VideoProfile.STATE_BIDIRECTIONAL)); 166 mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId); 167 168 mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId); 169 } 170 171 /** 172 * Tests the {@link TelecomManager#acceptRingingCall(int)} API. Tests answering a video call 173 * as an audio call. 174 * 175 * @throws Exception 176 */ 177 @LargeTest 178 public void testTelecomManagerAcceptRingingVideoCallAsAudio() throws Exception { 179 IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), 180 VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA); 181 182 assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 183 assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 184 185 // Use TelecomManager API to answer the ringing call. 186 TelecomManager telecomManager = (TelecomManager) mComponentContextFixture.getTestDouble() 187 .getApplicationContext().getSystemService(Context.TELECOM_SERVICE); 188 telecomManager.acceptRingingCall(VideoProfile.STATE_AUDIO_ONLY); 189 190 // The generic answer method on the ConnectionService is used to answer audio-only calls. 191 verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) 192 .answer(eq(ids.mCallId)); 193 mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId); 194 195 mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId); 196 } 197 198 /** 199 * Tests the {@link TelecomManager#acceptRingingCall()} API. Tests simple case of an incoming 200 * video call, where an attempt is made to answer with an invalid video state. 201 * 202 * @throws Exception 203 */ 204 @LargeTest 205 public void testTelecomManagerAcceptRingingInvalidVideoState() throws Exception { 206 IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), 207 VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA); 208 209 assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 210 assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 211 212 // Use TelecomManager API to answer the ringing call; the default expected behavior is to 213 // answer using whatever video state the ringing call requests. 214 TelecomManager telecomManager = (TelecomManager) mComponentContextFixture.getTestDouble() 215 .getApplicationContext().getSystemService(Context.TELECOM_SERVICE); 216 telecomManager.acceptRingingCall(999 /* invalid videostate */); 217 218 // Answer video API should be called 219 verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) 220 .answerVideo(eq(ids.mCallId), eq(VideoProfile.STATE_BIDIRECTIONAL)); 221 mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId); 222 mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId); 223 } 224 225 @LargeTest 226 public void testSingleIncomingCallLocalDisconnect() throws Exception { 227 IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", 228 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 229 mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId); 230 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 231 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 232 233 mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL); 234 assertEquals(Call.STATE_DISCONNECTED, 235 mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 236 assertEquals(Call.STATE_DISCONNECTED, 237 mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 238 } 239 240 @LargeTest 241 public void testSingleIncomingCallRemoteDisconnect() throws Exception { 242 IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", 243 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 244 245 mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL); 246 assertEquals(Call.STATE_DISCONNECTED, 247 mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 248 assertEquals(Call.STATE_DISCONNECTED, 249 mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 250 } 251 252 @LargeTest 253 public void testIncomingCallFromContactWithSendToVoicemailIsRejected() throws Exception { 254 Bundle extras = new Bundle(); 255 extras.putParcelable( 256 TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, 257 Uri.fromParts(PhoneAccount.SCHEME_TEL, "650-555-1212", null)); 258 mTelecomSystem.getTelecomServiceImpl().getBinder() 259 .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras); 260 261 verify(mConnectionServiceFixtureA.getTestDouble()) 262 .createConnection(any(PhoneAccountHandle.class), anyString(), 263 any(ConnectionRequest.class), eq(true), eq(false)); 264 265 assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size()); 266 for (CallerInfoAsyncQueryFactoryFixture.Request request : 267 mCallerInfoAsyncQueryFactoryFixture.mRequests) { 268 CallerInfo sendToVoicemailCallerInfo = new CallerInfo(); 269 sendToVoicemailCallerInfo.shouldSendToVoicemail = true; 270 request.replyWithCallerInfo(sendToVoicemailCallerInfo); 271 } 272 273 assertTrueWithTimeout(new Predicate<Void>() { 274 @Override 275 public boolean apply(Void aVoid) { 276 return mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size() == 1; 277 } 278 }); 279 assertTrueWithTimeout(new Predicate<Void>() { 280 @Override 281 public boolean apply(Void aVoid) { 282 return mMissedCallNotifier.missedCallsNotified.size() == 1; 283 } 284 }); 285 286 verify(mInCallServiceFixtureX.getTestDouble(), never()) 287 .setInCallAdapter(any(IInCallAdapter.class)); 288 verify(mInCallServiceFixtureY.getTestDouble(), never()) 289 .setInCallAdapter(any(IInCallAdapter.class)); 290 } 291 292 @LargeTest 293 public void testIncomingCallCallerInfoLookupTimesOutIsAllowed() throws Exception { 294 Bundle extras = new Bundle(); 295 extras.putParcelable( 296 TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, 297 Uri.fromParts(PhoneAccount.SCHEME_TEL, "650-555-1212", null)); 298 mTelecomSystem.getTelecomServiceImpl().getBinder() 299 .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras); 300 301 verify(mConnectionServiceFixtureA.getTestDouble()) 302 .createConnection(any(PhoneAccountHandle.class), anyString(), 303 any(ConnectionRequest.class), eq(true), eq(false)); 304 305 // Never reply to the caller info lookup. 306 assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size()); 307 308 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) 309 .setInCallAdapter(any(IInCallAdapter.class)); 310 verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT)) 311 .setInCallAdapter(any(IInCallAdapter.class)); 312 313 assertEquals(0, mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size()); 314 assertEquals(0, mMissedCallNotifier.missedCallsNotified.size()); 315 316 assertTrueWithTimeout(new Predicate<Void>() { 317 @Override 318 public boolean apply(Void v) { 319 return mInCallServiceFixtureX.mInCallAdapter != null; 320 } 321 }); 322 323 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) 324 .addCall(any(ParcelableCall.class)); 325 verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT)) 326 .addCall(any(ParcelableCall.class)); 327 328 disconnectCall(mInCallServiceFixtureX.mLatestCallId, 329 mConnectionServiceFixtureA.mLatestConnectionId); 330 } 331 332 @LargeTest 333 public void testIncomingCallFromBlockedNumberIsRejected() throws Exception { 334 String phoneNumber = "650-555-1212"; 335 blockNumber(phoneNumber); 336 337 Bundle extras = new Bundle(); 338 extras.putParcelable( 339 TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, 340 Uri.fromParts(PhoneAccount.SCHEME_TEL, phoneNumber, null)); 341 mTelecomSystem.getTelecomServiceImpl().getBinder() 342 .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras); 343 344 verify(mConnectionServiceFixtureA.getTestDouble()) 345 .createConnection(any(PhoneAccountHandle.class), anyString(), 346 any(ConnectionRequest.class), eq(true), eq(false)); 347 348 assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size()); 349 for (CallerInfoAsyncQueryFactoryFixture.Request request : 350 mCallerInfoAsyncQueryFactoryFixture.mRequests) { 351 request.reply(); 352 } 353 354 assertTrueWithTimeout(new Predicate<Void>() { 355 @Override 356 public boolean apply(Void aVoid) { 357 return mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size() == 1; 358 } 359 }); 360 assertEquals(0, mMissedCallNotifier.missedCallsNotified.size()); 361 362 verify(mInCallServiceFixtureX.getTestDouble(), never()) 363 .setInCallAdapter(any(IInCallAdapter.class)); 364 verify(mInCallServiceFixtureY.getTestDouble(), never()) 365 .setInCallAdapter(any(IInCallAdapter.class)); 366 } 367 368 @LargeTest 369 public void testIncomingCallBlockCheckTimesoutIsAllowed() throws Exception { 370 final CountDownLatch latch = new CountDownLatch(1); 371 String phoneNumber = "650-555-1212"; 372 blockNumberWithAnswer(phoneNumber, new Answer<Bundle>() { 373 @Override 374 public Bundle answer(InvocationOnMock invocation) throws Throwable { 375 latch.await(TEST_TIMEOUT * 2, TimeUnit.MILLISECONDS); 376 Bundle bundle = new Bundle(); 377 bundle.putBoolean(BlockedNumberContract.RES_NUMBER_IS_BLOCKED, true); 378 return bundle; 379 } 380 }); 381 382 IdPair ids = startAndMakeActiveIncomingCall( 383 phoneNumber, mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 384 latch.countDown(); 385 386 assertEquals(0, mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size()); 387 assertEquals(0, mMissedCallNotifier.missedCallsNotified.size()); 388 disconnectCall(ids.mCallId, ids.mConnectionId); 389 } 390 391 public void do_testDeadlockOnOutgoingCall() throws Exception { 392 final IdPair ids = startOutgoingPhoneCall("650-555-1212", 393 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, 394 Process.myUserHandle()); 395 rapidFire( 396 new Runnable() { 397 @Override 398 public void run() { 399 while (mCallerInfoAsyncQueryFactoryFixture.mRequests.size() > 0) { 400 mCallerInfoAsyncQueryFactoryFixture.mRequests.remove(0).reply(); 401 } 402 } 403 }, 404 new Runnable() { 405 @Override 406 public void run() { 407 try { 408 mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId); 409 } catch (Exception e) { 410 Log.e(this, e, ""); 411 } 412 } 413 }); 414 } 415 416 @MediumTest 417 public void testDeadlockOnOutgoingCall() throws Exception { 418 for (int i = 0; i < 100; i++) { 419 BasicCallTests test = new BasicCallTests(); 420 test.setContext(getContext()); 421 test.setTestContext(getTestContext()); 422 test.setName(getName()); 423 test.setUp(); 424 test.do_testDeadlockOnOutgoingCall(); 425 test.tearDown(); 426 } 427 } 428 429 @LargeTest 430 public void testIncomingThenOutgoingCalls() throws Exception { 431 // TODO: We have to use the same PhoneAccount for both; see http://b/18461539 432 IdPair incoming = startAndMakeActiveIncomingCall("650-555-2323", 433 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 434 IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1212", 435 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 436 437 mInCallServiceFixtureX.mInCallAdapter.disconnectCall(incoming.mCallId); 438 mInCallServiceFixtureX.mInCallAdapter.disconnectCall(outgoing.mCallId); 439 } 440 441 @LargeTest 442 public void testOutgoingThenIncomingCalls() throws Exception { 443 // TODO: We have to use the same PhoneAccount for both; see http://b/18461539 444 IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1212", 445 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 446 IdPair incoming = startAndMakeActiveIncomingCall("650-555-2323", 447 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 448 verify(mConnectionServiceFixtureA.getTestDouble()) 449 .hold(outgoing.mConnectionId); 450 mConnectionServiceFixtureA.mConnectionById.get(outgoing.mConnectionId).state = 451 Connection.STATE_HOLDING; 452 mConnectionServiceFixtureA.sendSetOnHold(outgoing.mConnectionId); 453 assertEquals(Call.STATE_HOLDING, 454 mInCallServiceFixtureX.getCall(outgoing.mCallId).getState()); 455 assertEquals(Call.STATE_HOLDING, 456 mInCallServiceFixtureY.getCall(outgoing.mCallId).getState()); 457 458 mInCallServiceFixtureX.mInCallAdapter.disconnectCall(incoming.mCallId); 459 mInCallServiceFixtureX.mInCallAdapter.disconnectCall(outgoing.mCallId); 460 } 461 462 public void testAudioManagerOperations() throws Exception { 463 AudioManager audioManager = (AudioManager) mComponentContextFixture.getTestDouble() 464 .getApplicationContext().getSystemService(Context.AUDIO_SERVICE); 465 466 IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1212", 467 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 468 469 verify(audioManager, timeout(TEST_TIMEOUT)).requestAudioFocusForCall(anyInt(), anyInt()); 470 verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce()) 471 .setMode(AudioManager.MODE_IN_CALL); 472 473 mInCallServiceFixtureX.mInCallAdapter.mute(true); 474 verify(mAudioService, timeout(TEST_TIMEOUT)) 475 .setMicrophoneMute(eq(true), any(String.class), any(Integer.class)); 476 mInCallServiceFixtureX.mInCallAdapter.mute(false); 477 verify(mAudioService, timeout(TEST_TIMEOUT)) 478 .setMicrophoneMute(eq(false), any(String.class), any(Integer.class)); 479 480 mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_SPEAKER); 481 verify(audioManager, timeout(TEST_TIMEOUT)) 482 .setSpeakerphoneOn(true); 483 mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_EARPIECE); 484 verify(audioManager, timeout(TEST_TIMEOUT)) 485 .setSpeakerphoneOn(false); 486 487 mConnectionServiceFixtureA. 488 sendSetDisconnected(outgoing.mConnectionId, DisconnectCause.REMOTE); 489 490 verify(audioManager, timeout(TEST_TIMEOUT)) 491 .abandonAudioFocusForCall(); 492 verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce()) 493 .setMode(AudioManager.MODE_NORMAL); 494 } 495 496 private void rapidFire(Runnable... tasks) { 497 final CyclicBarrier barrier = new CyclicBarrier(tasks.length); 498 final CountDownLatch latch = new CountDownLatch(tasks.length); 499 for (int i = 0; i < tasks.length; i++) { 500 final Runnable task = tasks[i]; 501 new Thread(new Runnable() { 502 @Override 503 public void run() { 504 try { 505 barrier.await(); 506 task.run(); 507 } catch (InterruptedException | BrokenBarrierException e){ 508 Log.e(BasicCallTests.this, e, "Unexpectedly interrupted"); 509 } finally { 510 latch.countDown(); 511 } 512 } 513 }).start(); 514 } 515 try { 516 latch.await(); 517 } catch (InterruptedException e) { 518 Log.e(BasicCallTests.this, e, "Unexpectedly interrupted"); 519 } 520 } 521 522 @MediumTest 523 public void testBasicConferenceCall() throws Exception { 524 makeConferenceCall(); 525 } 526 527 @MediumTest 528 public void testAddCallToConference1() throws Exception { 529 ParcelableCall conferenceCall = makeConferenceCall(); 530 IdPair callId3 = startAndMakeActiveOutgoingCall("650-555-1214", 531 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 532 // testAddCallToConference{1,2} differ in the order of arguments to InCallAdapter#conference 533 mInCallServiceFixtureX.getInCallAdapter().conference( 534 conferenceCall.getId(), callId3.mCallId); 535 Thread.sleep(200); 536 537 ParcelableCall call3 = mInCallServiceFixtureX.getCall(callId3.mCallId); 538 ParcelableCall updatedConference = mInCallServiceFixtureX.getCall(conferenceCall.getId()); 539 assertEquals(conferenceCall.getId(), call3.getParentCallId()); 540 assertEquals(3, updatedConference.getChildCallIds().size()); 541 assertTrue(updatedConference.getChildCallIds().contains(callId3.mCallId)); 542 } 543 544 @MediumTest 545 public void testAddCallToConference2() throws Exception { 546 ParcelableCall conferenceCall = makeConferenceCall(); 547 IdPair callId3 = startAndMakeActiveOutgoingCall("650-555-1214", 548 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 549 mInCallServiceFixtureX.getInCallAdapter() 550 .conference(callId3.mCallId, conferenceCall.getId()); 551 Thread.sleep(200); 552 553 ParcelableCall call3 = mInCallServiceFixtureX.getCall(callId3.mCallId); 554 ParcelableCall updatedConference = mInCallServiceFixtureX.getCall(conferenceCall.getId()); 555 assertEquals(conferenceCall.getId(), call3.getParentCallId()); 556 assertEquals(3, updatedConference.getChildCallIds().size()); 557 assertTrue(updatedConference.getChildCallIds().contains(callId3.mCallId)); 558 } 559 560 private ParcelableCall makeConferenceCall() throws Exception { 561 IdPair callId1 = startAndMakeActiveOutgoingCall("650-555-1212", 562 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 563 564 IdPair callId2 = startAndMakeActiveOutgoingCall("650-555-1213", 565 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 566 567 IInCallAdapter inCallAdapter = mInCallServiceFixtureX.getInCallAdapter(); 568 inCallAdapter.conference(callId1.mCallId, callId2.mCallId); 569 // Wait for wacky non-deterministic behavior 570 Thread.sleep(200); 571 ParcelableCall call1 = mInCallServiceFixtureX.getCall(callId1.mCallId); 572 ParcelableCall call2 = mInCallServiceFixtureX.getCall(callId2.mCallId); 573 // Check that the two calls end up with a parent in the end 574 assertNotNull(call1.getParentCallId()); 575 assertNotNull(call2.getParentCallId()); 576 assertEquals(call1.getParentCallId(), call2.getParentCallId()); 577 578 // Check to make sure that the parent call made it to the in-call service 579 String parentCallId = call1.getParentCallId(); 580 ParcelableCall conferenceCall = mInCallServiceFixtureX.getCall(parentCallId); 581 assertEquals(2, conferenceCall.getChildCallIds().size()); 582 assertTrue(conferenceCall.getChildCallIds().contains(callId1.mCallId)); 583 assertTrue(conferenceCall.getChildCallIds().contains(callId2.mCallId)); 584 return conferenceCall; 585 } 586 587 /** 588 * Tests the {@link Call#pullExternalCall()} API. Verifies that if a call is not an external 589 * call, no pull call request is made to the connection service. 590 * 591 * @throws Exception 592 */ 593 @MediumTest 594 public void testPullNonExternalCall() throws Exception { 595 // TODO: Revisit this unit test once telecom support for filtering external calls from 596 // InCall services is implemented. 597 IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", 598 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 599 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 600 601 // Attempt to pull the call and verify the API call makes it through 602 mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId); 603 verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT).never()) 604 .pullExternalCall(ids.mCallId); 605 } 606 607 /** 608 * Tests the {@link Connection#sendConnectionEvent(String)} API. 609 * 610 * @throws Exception 611 */ 612 @MediumTest 613 public void testSendConnectionEventNull() throws Exception { 614 IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", 615 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 616 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 617 mConnectionServiceFixtureA.sendConnectionEvent(ids.mConnectionId, TEST_EVENT, null); 618 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) 619 .onConnectionEvent(ids.mCallId, TEST_EVENT, null); 620 } 621 622 /** 623 * Tests the {@link Connection#sendConnectionEvent(String)} API. 624 * 625 * @throws Exception 626 */ 627 @MediumTest 628 public void testSendConnectionEventNotNull() throws Exception { 629 IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", 630 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 631 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 632 633 Bundle testBundle = new Bundle(); 634 testBundle.putString(TEST_BUNDLE_KEY, "TEST"); 635 636 ArgumentCaptor<Bundle> bundleArgumentCaptor = ArgumentCaptor.forClass(Bundle.class); 637 mConnectionServiceFixtureA.sendConnectionEvent(ids.mConnectionId, TEST_EVENT, testBundle); 638 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) 639 .onConnectionEvent(eq(ids.mCallId), eq(TEST_EVENT), bundleArgumentCaptor.capture()); 640 assert (bundleArgumentCaptor.getValue().containsKey(TEST_BUNDLE_KEY)); 641 } 642 643 /** 644 * Tests the {@link Call#sendCallEvent(String, Bundle)} API. 645 * 646 * @throws Exception 647 */ 648 @MediumTest 649 public void testSendCallEventNull() throws Exception { 650 IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", 651 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 652 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 653 654 mInCallServiceFixtureX.mInCallAdapter.sendCallEvent(ids.mCallId, TEST_EVENT, null); 655 verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) 656 .sendCallEvent(ids.mCallId, TEST_EVENT, null); 657 } 658 659 /** 660 * Tests the {@link Call#sendCallEvent(String, Bundle)} API. 661 * 662 * @throws Exception 663 */ 664 @MediumTest 665 public void testSendCallEventNonNull() throws Exception { 666 IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", 667 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 668 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 669 670 Bundle testBundle = new Bundle(); 671 testBundle.putString(TEST_BUNDLE_KEY, "TEST"); 672 673 ArgumentCaptor<Bundle> bundleArgumentCaptor = ArgumentCaptor.forClass(Bundle.class); 674 mInCallServiceFixtureX.mInCallAdapter.sendCallEvent(ids.mCallId, TEST_EVENT, 675 testBundle); 676 verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) 677 .sendCallEvent(eq(ids.mCallId), eq(TEST_EVENT), 678 bundleArgumentCaptor.capture()); 679 assert (bundleArgumentCaptor.getValue().containsKey(TEST_BUNDLE_KEY)); 680 } 681 682 @MediumTest 683 public void testAnalyticsSingleCall() throws Exception { 684 IdPair testCall = startAndMakeActiveIncomingCall( 685 "650-555-1212", 686 mPhoneAccountA0.getAccountHandle(), 687 mConnectionServiceFixtureA); 688 Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData(); 689 690 assertTrue(analyticsMap.containsKey(testCall.mCallId)); 691 692 Analytics.CallInfoImpl callAnalytics = analyticsMap.get(testCall.mCallId); 693 assertTrue(callAnalytics.startTime > 0); 694 assertEquals(0, callAnalytics.endTime); 695 assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics.callDirection); 696 assertFalse(callAnalytics.isInterrupted); 697 assertNull(callAnalytics.callTerminationReason); 698 assertEquals(mConnectionServiceComponentNameA.flattenToShortString(), 699 callAnalytics.connectionService); 700 701 mConnectionServiceFixtureA. 702 sendSetDisconnected(testCall.mConnectionId, DisconnectCause.ERROR); 703 704 analyticsMap = Analytics.cloneData(); 705 callAnalytics = analyticsMap.get(testCall.mCallId); 706 assertTrue(callAnalytics.endTime > 0); 707 assertNotNull(callAnalytics.callTerminationReason); 708 assertEquals(DisconnectCause.ERROR, callAnalytics.callTerminationReason.getCode()); 709 710 StringWriter sr = new StringWriter(); 711 IndentingPrintWriter ip = new IndentingPrintWriter(sr, " "); 712 Analytics.dump(ip); 713 String dumpResult = sr.toString(); 714 String[] expectedFields = {"startTime", "endTime", "direction", "isAdditionalCall", 715 "isInterrupted", "callTechnologies", "callTerminationReason", "connectionService"}; 716 for (String field : expectedFields) { 717 assertTrue(dumpResult.contains(field)); 718 } 719 } 720 721 @SmallTest 722 public void testAnalyticsDumping() throws Exception { 723 Analytics.reset(); 724 IdPair testCall = startAndMakeActiveIncomingCall( 725 "650-555-1212", 726 mPhoneAccountA0.getAccountHandle(), 727 mConnectionServiceFixtureA); 728 729 mConnectionServiceFixtureA. 730 sendSetDisconnected(testCall.mConnectionId, DisconnectCause.ERROR); 731 Analytics.CallInfoImpl expectedAnalytics = Analytics.cloneData().get(testCall.mCallId); 732 733 TelecomManager tm = (TelecomManager) mSpyContext.getSystemService(Context.TELECOM_SERVICE); 734 List<ParcelableCallAnalytics> analyticsList = tm.dumpAnalytics(); 735 736 assertEquals(1, analyticsList.size()); 737 ParcelableCallAnalytics pCA = analyticsList.get(0); 738 739 assertTrue(Math.abs(expectedAnalytics.startTime - pCA.getStartTimeMillis()) < 740 ParcelableCallAnalytics.MILLIS_IN_5_MINUTES); 741 assertEquals(0, pCA.getStartTimeMillis() % ParcelableCallAnalytics.MILLIS_IN_5_MINUTES); 742 assertTrue(Math.abs((expectedAnalytics.endTime - expectedAnalytics.startTime) - 743 pCA.getCallDurationMillis()) < ParcelableCallAnalytics.MILLIS_IN_1_SECOND); 744 assertEquals(0, pCA.getCallDurationMillis() % ParcelableCallAnalytics.MILLIS_IN_1_SECOND); 745 746 assertEquals(expectedAnalytics.callDirection, pCA.getCallType()); 747 assertEquals(expectedAnalytics.isAdditionalCall, pCA.isAdditionalCall()); 748 assertEquals(expectedAnalytics.isInterrupted, pCA.isInterrupted()); 749 assertEquals(expectedAnalytics.callTechnologies, pCA.getCallTechnologies()); 750 assertEquals(expectedAnalytics.callTerminationReason.getCode(), 751 pCA.getCallTerminationCode()); 752 assertEquals(expectedAnalytics.connectionService, pCA.getConnectionService()); 753 } 754 755 @MediumTest 756 public void testAnalyticsTwoCalls() throws Exception { 757 IdPair testCall1 = startAndMakeActiveIncomingCall( 758 "650-555-1212", 759 mPhoneAccountA0.getAccountHandle(), 760 mConnectionServiceFixtureA); 761 IdPair testCall2 = startAndMakeActiveOutgoingCall( 762 "650-555-1213", 763 mPhoneAccountA0.getAccountHandle(), 764 mConnectionServiceFixtureA); 765 766 Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData(); 767 assertTrue(analyticsMap.containsKey(testCall1.mCallId)); 768 assertTrue(analyticsMap.containsKey(testCall2.mCallId)); 769 770 Analytics.CallInfoImpl callAnalytics1 = analyticsMap.get(testCall1.mCallId); 771 Analytics.CallInfoImpl callAnalytics2 = analyticsMap.get(testCall2.mCallId); 772 assertTrue(callAnalytics1.startTime > 0); 773 assertTrue(callAnalytics2.startTime > 0); 774 assertEquals(0, callAnalytics1.endTime); 775 assertEquals(0, callAnalytics2.endTime); 776 777 assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics1.callDirection); 778 assertEquals(Analytics.OUTGOING_DIRECTION, callAnalytics2.callDirection); 779 780 assertTrue(callAnalytics1.isInterrupted); 781 assertTrue(callAnalytics2.isAdditionalCall); 782 783 assertNull(callAnalytics1.callTerminationReason); 784 assertNull(callAnalytics2.callTerminationReason); 785 786 assertEquals(mConnectionServiceComponentNameA.flattenToShortString(), 787 callAnalytics1.connectionService); 788 assertEquals(mConnectionServiceComponentNameA.flattenToShortString(), 789 callAnalytics1.connectionService); 790 791 mConnectionServiceFixtureA. 792 sendSetDisconnected(testCall2.mConnectionId, DisconnectCause.REMOTE); 793 mConnectionServiceFixtureA. 794 sendSetDisconnected(testCall1.mConnectionId, DisconnectCause.ERROR); 795 796 analyticsMap = Analytics.cloneData(); 797 callAnalytics1 = analyticsMap.get(testCall1.mCallId); 798 callAnalytics2 = analyticsMap.get(testCall2.mCallId); 799 assertTrue(callAnalytics1.endTime > 0); 800 assertTrue(callAnalytics2.endTime > 0); 801 assertNotNull(callAnalytics1.callTerminationReason); 802 assertNotNull(callAnalytics2.callTerminationReason); 803 assertEquals(DisconnectCause.ERROR, callAnalytics1.callTerminationReason.getCode()); 804 assertEquals(DisconnectCause.REMOTE, callAnalytics2.callTerminationReason.getCode()); 805 } 806 807 private void blockNumber(String phoneNumber) throws Exception { 808 blockNumberWithAnswer(phoneNumber, new Answer<Bundle>() { 809 @Override 810 public Bundle answer(InvocationOnMock invocation) throws Throwable { 811 Bundle bundle = new Bundle(); 812 bundle.putBoolean(BlockedNumberContract.RES_NUMBER_IS_BLOCKED, true); 813 return bundle; 814 } 815 }); 816 } 817 818 private void blockNumberWithAnswer(String phoneNumber, Answer answer) throws Exception { 819 when(getBlockedNumberProvider().call( 820 anyString(), 821 eq(BlockedNumberContract.SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER), 822 eq(phoneNumber), 823 isNull(Bundle.class))).thenAnswer(answer); 824 } 825 826 private void verifyNoBlockChecks() { 827 verifyZeroInteractions(getBlockedNumberProvider()); 828 } 829 830 private IContentProvider getBlockedNumberProvider() { 831 return mSpyContext.getContentResolver().acquireProvider(BlockedNumberContract.AUTHORITY); 832 } 833 834 private void disconnectCall(String callId, String connectionId) throws Exception { 835 mConnectionServiceFixtureA.sendSetDisconnected(connectionId, DisconnectCause.LOCAL); 836 assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureX.getCall(callId).getState()); 837 assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureY.getCall(callId).getState()); 838 } 839 840 /** 841 * Tests the {@link Call#pullExternalCall()} API. Ensures that an external call which is 842 * pullable can be pulled. 843 * 844 * @throws Exception 845 */ 846 @LargeTest 847 public void testPullExternalCall() throws Exception { 848 // TODO: Revisit this unit test once telecom support for filtering external calls from 849 // InCall services is implemented. 850 mConnectionServiceFixtureA.mConnectionServiceDelegate.mCapabilities = 851 Connection.CAPABILITY_IS_EXTERNAL_CALL | Connection.CAPABILITY_CAN_PULL_CALL; 852 853 IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", 854 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 855 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 856 857 // Attempt to pull the call and verify the API call makes it through 858 mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId); 859 verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) 860 .pullExternalCall(ids.mCallId); 861 } 862 863 /** 864 * Tests the {@link Call#pullExternalCall()} API. Verifies that if an external call is not 865 * marked as pullable that the connection service does not get an API call to pull the external 866 * call. 867 * 868 * @throws Exception 869 */ 870 @LargeTest 871 public void testPullNonPullableExternalCall() throws Exception { 872 // TODO: Revisit this unit test once telecom support for filtering external calls from 873 // InCall services is implemented. 874 mConnectionServiceFixtureA.mConnectionServiceDelegate.mCapabilities = 875 Connection.CAPABILITY_IS_EXTERNAL_CALL; 876 877 IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", 878 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 879 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 880 881 // Attempt to pull the call and verify the API call makes it through 882 mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId); 883 verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT).never()) 884 .pullExternalCall(ids.mCallId); 885 } 886} 887