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