BasicCallTests.java revision d7b70ca78c1ba41d5c0a931a6d55f60c19301394
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.Log; 46import android.telecom.ParcelableCall; 47import android.telecom.ParcelableCallAnalytics; 48import android.telecom.PhoneAccount; 49import android.telecom.PhoneAccountHandle; 50import android.telecom.TelecomManager; 51import android.telecom.VideoProfile; 52import android.test.suitebuilder.annotation.LargeTest; 53import android.test.suitebuilder.annotation.MediumTest; 54import android.test.suitebuilder.annotation.SmallTest; 55 56import com.android.internal.telecom.IInCallAdapter; 57import com.android.internal.telephony.CallerInfo; 58import com.android.internal.util.IndentingPrintWriter; 59import com.android.server.telecom.Analytics; 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(eq(ids.mConnectionId), any()); 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.mConnectionId), eq(VideoProfile.STATE_BIDIRECTIONAL), any()); 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.mConnectionId), any()); 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.mConnectionId), eq(VideoProfile.STATE_BIDIRECTIONAL), any()); 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), any()); 295 296 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 297 assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size()); 298 for (CallerInfoAsyncQueryFactoryFixture.Request request : 299 mCallerInfoAsyncQueryFactoryFixture.mRequests) { 300 CallerInfo sendToVoicemailCallerInfo = new CallerInfo(); 301 sendToVoicemailCallerInfo.shouldSendToVoicemail = true; 302 request.replyWithCallerInfo(sendToVoicemailCallerInfo); 303 } 304 305 assertTrueWithTimeout(new Predicate<Void>() { 306 @Override 307 public boolean apply(Void aVoid) { 308 return mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size() == 1; 309 } 310 }); 311 assertTrueWithTimeout(new Predicate<Void>() { 312 @Override 313 public boolean apply(Void aVoid) { 314 return mMissedCallNotifier.missedCallsNotified.size() == 1; 315 } 316 }); 317 318 verify(mInCallServiceFixtureX.getTestDouble(), never()) 319 .setInCallAdapter(any(IInCallAdapter.class)); 320 verify(mInCallServiceFixtureY.getTestDouble(), never()) 321 .setInCallAdapter(any(IInCallAdapter.class)); 322 } 323 324 @LargeTest 325 public void testIncomingCallCallerInfoLookupTimesOutIsAllowed() throws Exception { 326 Bundle extras = new Bundle(); 327 extras.putParcelable( 328 TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, 329 Uri.fromParts(PhoneAccount.SCHEME_TEL, "650-555-1212", null)); 330 mTelecomSystem.getTelecomServiceImpl().getBinder() 331 .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras); 332 333 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 334 verify(mConnectionServiceFixtureA.getTestDouble()) 335 .createConnection(any(PhoneAccountHandle.class), anyString(), 336 any(ConnectionRequest.class), eq(true), eq(false), any()); 337 338 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 339 // Never reply to the caller info lookup. 340 assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size()); 341 342 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) 343 .setInCallAdapter(any(IInCallAdapter.class)); 344 verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT)) 345 .setInCallAdapter(any(IInCallAdapter.class)); 346 347 assertEquals(0, mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size()); 348 assertEquals(0, mMissedCallNotifier.missedCallsNotified.size()); 349 350 assertTrueWithTimeout(new Predicate<Void>() { 351 @Override 352 public boolean apply(Void v) { 353 return mInCallServiceFixtureX.mInCallAdapter != null; 354 } 355 }); 356 357 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) 358 .addCall(any(ParcelableCall.class)); 359 verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT)) 360 .addCall(any(ParcelableCall.class)); 361 362 disconnectCall(mInCallServiceFixtureX.mLatestCallId, 363 mConnectionServiceFixtureA.mLatestConnectionId); 364 } 365 366 @LargeTest 367 public void testIncomingCallFromBlockedNumberIsRejected() throws Exception { 368 String phoneNumber = "650-555-1212"; 369 blockNumber(phoneNumber); 370 371 Bundle extras = new Bundle(); 372 extras.putParcelable( 373 TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, 374 Uri.fromParts(PhoneAccount.SCHEME_TEL, phoneNumber, null)); 375 mTelecomSystem.getTelecomServiceImpl().getBinder() 376 .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras); 377 378 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 379 verify(mConnectionServiceFixtureA.getTestDouble()) 380 .createConnection(any(PhoneAccountHandle.class), anyString(), 381 any(ConnectionRequest.class), eq(true), eq(false), any()); 382 383 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 384 assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size()); 385 for (CallerInfoAsyncQueryFactoryFixture.Request request : 386 mCallerInfoAsyncQueryFactoryFixture.mRequests) { 387 request.reply(); 388 } 389 390 assertTrueWithTimeout(new Predicate<Void>() { 391 @Override 392 public boolean apply(Void aVoid) { 393 return mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size() == 1; 394 } 395 }); 396 assertEquals(0, mMissedCallNotifier.missedCallsNotified.size()); 397 398 verify(mInCallServiceFixtureX.getTestDouble(), never()) 399 .setInCallAdapter(any(IInCallAdapter.class)); 400 verify(mInCallServiceFixtureY.getTestDouble(), never()) 401 .setInCallAdapter(any(IInCallAdapter.class)); 402 } 403 404 @LargeTest 405 public void testIncomingCallBlockCheckTimesoutIsAllowed() throws Exception { 406 final CountDownLatch latch = new CountDownLatch(1); 407 String phoneNumber = "650-555-1212"; 408 blockNumberWithAnswer(phoneNumber, new Answer<Bundle>() { 409 @Override 410 public Bundle answer(InvocationOnMock invocation) throws Throwable { 411 latch.await(TEST_TIMEOUT * 2, TimeUnit.MILLISECONDS); 412 Bundle bundle = new Bundle(); 413 bundle.putBoolean(BlockedNumberContract.RES_NUMBER_IS_BLOCKED, true); 414 return bundle; 415 } 416 }); 417 418 IdPair ids = startAndMakeActiveIncomingCall( 419 phoneNumber, mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 420 latch.countDown(); 421 422 assertEquals(0, mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size()); 423 assertEquals(0, mMissedCallNotifier.missedCallsNotified.size()); 424 disconnectCall(ids.mCallId, ids.mConnectionId); 425 } 426 427 public void do_testDeadlockOnOutgoingCall() throws Exception { 428 final IdPair ids = startOutgoingPhoneCall("650-555-1212", 429 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, 430 Process.myUserHandle()); 431 rapidFire( 432 new Runnable() { 433 @Override 434 public void run() { 435 while (mCallerInfoAsyncQueryFactoryFixture.mRequests.size() > 0) { 436 mCallerInfoAsyncQueryFactoryFixture.mRequests.remove(0).reply(); 437 } 438 } 439 }, 440 new Runnable() { 441 @Override 442 public void run() { 443 try { 444 mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId); 445 } catch (Exception e) { 446 Log.e(this, e, ""); 447 } 448 } 449 }); 450 } 451 452 @MediumTest 453 public void testDeadlockOnOutgoingCall() throws Exception { 454 for (int i = 0; i < 100; i++) { 455 BasicCallTests test = new BasicCallTests(); 456 test.setContext(getContext()); 457 test.setTestContext(getTestContext()); 458 test.setName(getName()); 459 test.setUp(); 460 test.do_testDeadlockOnOutgoingCall(); 461 test.tearDown(); 462 } 463 } 464 465 @LargeTest 466 public void testIncomingThenOutgoingCalls() throws Exception { 467 // TODO: We have to use the same PhoneAccount for both; see http://b/18461539 468 IdPair incoming = startAndMakeActiveIncomingCall("650-555-2323", 469 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 470 IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1212", 471 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 472 473 mInCallServiceFixtureX.mInCallAdapter.disconnectCall(incoming.mCallId); 474 mInCallServiceFixtureX.mInCallAdapter.disconnectCall(outgoing.mCallId); 475 } 476 477 @LargeTest 478 public void testOutgoingThenIncomingCalls() throws Exception { 479 // TODO: We have to use the same PhoneAccount for both; see http://b/18461539 480 IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1212", 481 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 482 IdPair incoming = startAndMakeActiveIncomingCall("650-555-2323", 483 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 484 verify(mConnectionServiceFixtureA.getTestDouble()) 485 .hold(eq(outgoing.mConnectionId), any()); 486 mConnectionServiceFixtureA.mConnectionById.get(outgoing.mConnectionId).state = 487 Connection.STATE_HOLDING; 488 mConnectionServiceFixtureA.sendSetOnHold(outgoing.mConnectionId); 489 assertEquals(Call.STATE_HOLDING, 490 mInCallServiceFixtureX.getCall(outgoing.mCallId).getState()); 491 assertEquals(Call.STATE_HOLDING, 492 mInCallServiceFixtureY.getCall(outgoing.mCallId).getState()); 493 494 mInCallServiceFixtureX.mInCallAdapter.disconnectCall(incoming.mCallId); 495 mInCallServiceFixtureX.mInCallAdapter.disconnectCall(outgoing.mCallId); 496 } 497 498 @LargeTest 499 public void testAudioManagerOperations() throws Exception { 500 AudioManager audioManager = (AudioManager) mComponentContextFixture.getTestDouble() 501 .getApplicationContext().getSystemService(Context.AUDIO_SERVICE); 502 503 IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1212", 504 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 505 506 verify(audioManager, timeout(TEST_TIMEOUT)).requestAudioFocusForCall(anyInt(), anyInt()); 507 verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce()) 508 .setMode(AudioManager.MODE_IN_CALL); 509 510 mInCallServiceFixtureX.mInCallAdapter.mute(true); 511 verify(mAudioService, timeout(TEST_TIMEOUT)) 512 .setMicrophoneMute(eq(true), any(String.class), any(Integer.class)); 513 mInCallServiceFixtureX.mInCallAdapter.mute(false); 514 verify(mAudioService, timeout(TEST_TIMEOUT)) 515 .setMicrophoneMute(eq(false), any(String.class), any(Integer.class)); 516 517 mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_SPEAKER); 518 verify(audioManager, timeout(TEST_TIMEOUT)) 519 .setSpeakerphoneOn(true); 520 mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_EARPIECE); 521 verify(audioManager, timeout(TEST_TIMEOUT)) 522 .setSpeakerphoneOn(false); 523 524 mConnectionServiceFixtureA. 525 sendSetDisconnected(outgoing.mConnectionId, DisconnectCause.REMOTE); 526 527 verify(audioManager, timeout(TEST_TIMEOUT)) 528 .abandonAudioFocusForCall(); 529 verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce()) 530 .setMode(AudioManager.MODE_NORMAL); 531 } 532 533 private void rapidFire(Runnable... tasks) { 534 final CyclicBarrier barrier = new CyclicBarrier(tasks.length); 535 final CountDownLatch latch = new CountDownLatch(tasks.length); 536 for (int i = 0; i < tasks.length; i++) { 537 final Runnable task = tasks[i]; 538 new Thread(new Runnable() { 539 @Override 540 public void run() { 541 try { 542 barrier.await(); 543 task.run(); 544 } catch (InterruptedException | BrokenBarrierException e){ 545 Log.e(BasicCallTests.this, e, "Unexpectedly interrupted"); 546 } finally { 547 latch.countDown(); 548 } 549 } 550 }).start(); 551 } 552 try { 553 latch.await(); 554 } catch (InterruptedException e) { 555 Log.e(BasicCallTests.this, e, "Unexpectedly interrupted"); 556 } 557 } 558 559 @MediumTest 560 public void testBasicConferenceCall() throws Exception { 561 makeConferenceCall(); 562 } 563 564 @MediumTest 565 public void testAddCallToConference1() throws Exception { 566 ParcelableCall conferenceCall = makeConferenceCall(); 567 IdPair callId3 = startAndMakeActiveOutgoingCall("650-555-1214", 568 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 569 // testAddCallToConference{1,2} differ in the order of arguments to InCallAdapter#conference 570 mInCallServiceFixtureX.getInCallAdapter().conference( 571 conferenceCall.getId(), callId3.mCallId); 572 Thread.sleep(200); 573 574 ParcelableCall call3 = mInCallServiceFixtureX.getCall(callId3.mCallId); 575 ParcelableCall updatedConference = mInCallServiceFixtureX.getCall(conferenceCall.getId()); 576 assertEquals(conferenceCall.getId(), call3.getParentCallId()); 577 assertEquals(3, updatedConference.getChildCallIds().size()); 578 assertTrue(updatedConference.getChildCallIds().contains(callId3.mCallId)); 579 } 580 581 @MediumTest 582 public void testAddCallToConference2() throws Exception { 583 ParcelableCall conferenceCall = makeConferenceCall(); 584 IdPair callId3 = startAndMakeActiveOutgoingCall("650-555-1214", 585 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 586 mInCallServiceFixtureX.getInCallAdapter() 587 .conference(callId3.mCallId, conferenceCall.getId()); 588 Thread.sleep(200); 589 590 ParcelableCall call3 = mInCallServiceFixtureX.getCall(callId3.mCallId); 591 ParcelableCall updatedConference = mInCallServiceFixtureX.getCall(conferenceCall.getId()); 592 assertEquals(conferenceCall.getId(), call3.getParentCallId()); 593 assertEquals(3, updatedConference.getChildCallIds().size()); 594 assertTrue(updatedConference.getChildCallIds().contains(callId3.mCallId)); 595 } 596 597 /** 598 * Tests the {@link Call#pullExternalCall()} API. Verifies that if a call is not an external 599 * call, no pull call request is made to the connection service. 600 * 601 * @throws Exception 602 */ 603 @MediumTest 604 public void testPullNonExternalCall() throws Exception { 605 // TODO: Revisit this unit test once telecom support for filtering external calls from 606 // InCall services is implemented. 607 IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", 608 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 609 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 610 611 // Attempt to pull the call and verify the API call makes it through 612 mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId); 613 Thread.sleep(TEST_TIMEOUT); 614 verify(mConnectionServiceFixtureA.getTestDouble(), never()) 615 .pullExternalCall(eq(ids.mCallId), any()); 616 } 617 618 /** 619 * Tests the {@link Connection#sendConnectionEvent(String, Bundle)} API. 620 * 621 * @throws Exception 622 */ 623 @MediumTest 624 public void testSendConnectionEventNull() throws Exception { 625 IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", 626 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 627 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 628 mConnectionServiceFixtureA.sendConnectionEvent(ids.mConnectionId, TEST_EVENT, null); 629 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) 630 .onConnectionEvent(ids.mCallId, TEST_EVENT, null); 631 } 632 633 /** 634 * Tests the {@link Connection#sendConnectionEvent(String, Bundle)} API. 635 * 636 * @throws Exception 637 */ 638 @MediumTest 639 public void testSendConnectionEventNotNull() throws Exception { 640 IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", 641 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 642 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 643 644 Bundle testBundle = new Bundle(); 645 testBundle.putString(TEST_BUNDLE_KEY, "TEST"); 646 647 ArgumentCaptor<Bundle> bundleArgumentCaptor = ArgumentCaptor.forClass(Bundle.class); 648 mConnectionServiceFixtureA.sendConnectionEvent(ids.mConnectionId, TEST_EVENT, testBundle); 649 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) 650 .onConnectionEvent(eq(ids.mCallId), eq(TEST_EVENT), bundleArgumentCaptor.capture()); 651 assert (bundleArgumentCaptor.getValue().containsKey(TEST_BUNDLE_KEY)); 652 } 653 654 /** 655 * Tests the {@link Call#sendCallEvent(String, Bundle)} API. 656 * 657 * @throws Exception 658 */ 659 @MediumTest 660 public void testSendCallEventNull() throws Exception { 661 IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", 662 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 663 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 664 665 mInCallServiceFixtureX.mInCallAdapter.sendCallEvent(ids.mCallId, TEST_EVENT, null); 666 verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) 667 .sendCallEvent(eq(ids.mConnectionId), eq(TEST_EVENT), isNull(Bundle.class), any()); 668 } 669 670 /** 671 * Tests the {@link Call#sendCallEvent(String, Bundle)} API. 672 * 673 * @throws Exception 674 */ 675 @MediumTest 676 public void testSendCallEventNonNull() throws Exception { 677 IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", 678 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 679 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 680 681 Bundle testBundle = new Bundle(); 682 testBundle.putString(TEST_BUNDLE_KEY, "TEST"); 683 684 ArgumentCaptor<Bundle> bundleArgumentCaptor = ArgumentCaptor.forClass(Bundle.class); 685 mInCallServiceFixtureX.mInCallAdapter.sendCallEvent(ids.mCallId, TEST_EVENT, 686 testBundle); 687 verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) 688 .sendCallEvent(eq(ids.mConnectionId), eq(TEST_EVENT), 689 bundleArgumentCaptor.capture(), any()); 690 assert (bundleArgumentCaptor.getValue().containsKey(TEST_BUNDLE_KEY)); 691 } 692 693 @MediumTest 694 public void testAnalyticsSingleCall() throws Exception { 695 IdPair testCall = startAndMakeActiveIncomingCall( 696 "650-555-1212", 697 mPhoneAccountA0.getAccountHandle(), 698 mConnectionServiceFixtureA); 699 Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData(); 700 701 assertTrue(analyticsMap.containsKey(testCall.mCallId)); 702 703 Analytics.CallInfoImpl callAnalytics = analyticsMap.get(testCall.mCallId); 704 assertTrue(callAnalytics.startTime > 0); 705 assertEquals(0, callAnalytics.endTime); 706 assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics.callDirection); 707 assertFalse(callAnalytics.isInterrupted); 708 assertNull(callAnalytics.callTerminationReason); 709 assertEquals(mConnectionServiceComponentNameA.flattenToShortString(), 710 callAnalytics.connectionService); 711 712 mConnectionServiceFixtureA. 713 sendSetDisconnected(testCall.mConnectionId, DisconnectCause.ERROR); 714 715 analyticsMap = Analytics.cloneData(); 716 callAnalytics = analyticsMap.get(testCall.mCallId); 717 assertTrue(callAnalytics.endTime > 0); 718 assertNotNull(callAnalytics.callTerminationReason); 719 assertEquals(DisconnectCause.ERROR, callAnalytics.callTerminationReason.getCode()); 720 721 StringWriter sr = new StringWriter(); 722 IndentingPrintWriter ip = new IndentingPrintWriter(sr, " "); 723 Analytics.dump(ip); 724 String dumpResult = sr.toString(); 725 String[] expectedFields = {"startTime", "endTime", "direction", "isAdditionalCall", 726 "isInterrupted", "callTechnologies", "callTerminationReason", "connectionService"}; 727 for (String field : expectedFields) { 728 assertTrue(dumpResult.contains(field)); 729 } 730 } 731 732 @SmallTest 733 public void testAnalyticsDumping() throws Exception { 734 Analytics.reset(); 735 IdPair testCall = startAndMakeActiveIncomingCall( 736 "650-555-1212", 737 mPhoneAccountA0.getAccountHandle(), 738 mConnectionServiceFixtureA); 739 740 mConnectionServiceFixtureA. 741 sendSetDisconnected(testCall.mConnectionId, DisconnectCause.ERROR); 742 Analytics.CallInfoImpl expectedAnalytics = Analytics.cloneData().get(testCall.mCallId); 743 744 TelecomManager tm = (TelecomManager) mSpyContext.getSystemService(Context.TELECOM_SERVICE); 745 List<ParcelableCallAnalytics> analyticsList = tm.dumpAnalytics(); 746 747 assertEquals(1, analyticsList.size()); 748 ParcelableCallAnalytics pCA = analyticsList.get(0); 749 750 assertTrue(Math.abs(expectedAnalytics.startTime - pCA.getStartTimeMillis()) < 751 ParcelableCallAnalytics.MILLIS_IN_5_MINUTES); 752 assertEquals(0, pCA.getStartTimeMillis() % ParcelableCallAnalytics.MILLIS_IN_5_MINUTES); 753 assertTrue(Math.abs((expectedAnalytics.endTime - expectedAnalytics.startTime) - 754 pCA.getCallDurationMillis()) < ParcelableCallAnalytics.MILLIS_IN_1_SECOND); 755 assertEquals(0, pCA.getCallDurationMillis() % ParcelableCallAnalytics.MILLIS_IN_1_SECOND); 756 757 assertEquals(expectedAnalytics.callDirection, pCA.getCallType()); 758 assertEquals(expectedAnalytics.isAdditionalCall, pCA.isAdditionalCall()); 759 assertEquals(expectedAnalytics.isInterrupted, pCA.isInterrupted()); 760 assertEquals(expectedAnalytics.callTechnologies, pCA.getCallTechnologies()); 761 assertEquals(expectedAnalytics.callTerminationReason.getCode(), 762 pCA.getCallTerminationCode()); 763 assertEquals(expectedAnalytics.connectionService, pCA.getConnectionService()); 764 } 765 766 @MediumTest 767 public void testAnalyticsTwoCalls() throws Exception { 768 IdPair testCall1 = startAndMakeActiveIncomingCall( 769 "650-555-1212", 770 mPhoneAccountA0.getAccountHandle(), 771 mConnectionServiceFixtureA); 772 IdPair testCall2 = startAndMakeActiveOutgoingCall( 773 "650-555-1213", 774 mPhoneAccountA0.getAccountHandle(), 775 mConnectionServiceFixtureA); 776 777 Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData(); 778 assertTrue(analyticsMap.containsKey(testCall1.mCallId)); 779 assertTrue(analyticsMap.containsKey(testCall2.mCallId)); 780 781 Analytics.CallInfoImpl callAnalytics1 = analyticsMap.get(testCall1.mCallId); 782 Analytics.CallInfoImpl callAnalytics2 = analyticsMap.get(testCall2.mCallId); 783 assertTrue(callAnalytics1.startTime > 0); 784 assertTrue(callAnalytics2.startTime > 0); 785 assertEquals(0, callAnalytics1.endTime); 786 assertEquals(0, callAnalytics2.endTime); 787 788 assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics1.callDirection); 789 assertEquals(Analytics.OUTGOING_DIRECTION, callAnalytics2.callDirection); 790 791 assertTrue(callAnalytics1.isInterrupted); 792 assertTrue(callAnalytics2.isAdditionalCall); 793 794 assertNull(callAnalytics1.callTerminationReason); 795 assertNull(callAnalytics2.callTerminationReason); 796 797 assertEquals(mConnectionServiceComponentNameA.flattenToShortString(), 798 callAnalytics1.connectionService); 799 assertEquals(mConnectionServiceComponentNameA.flattenToShortString(), 800 callAnalytics1.connectionService); 801 802 mConnectionServiceFixtureA. 803 sendSetDisconnected(testCall2.mConnectionId, DisconnectCause.REMOTE); 804 mConnectionServiceFixtureA. 805 sendSetDisconnected(testCall1.mConnectionId, DisconnectCause.ERROR); 806 807 analyticsMap = Analytics.cloneData(); 808 callAnalytics1 = analyticsMap.get(testCall1.mCallId); 809 callAnalytics2 = analyticsMap.get(testCall2.mCallId); 810 assertTrue(callAnalytics1.endTime > 0); 811 assertTrue(callAnalytics2.endTime > 0); 812 assertNotNull(callAnalytics1.callTerminationReason); 813 assertNotNull(callAnalytics2.callTerminationReason); 814 assertEquals(DisconnectCause.ERROR, callAnalytics1.callTerminationReason.getCode()); 815 assertEquals(DisconnectCause.REMOTE, callAnalytics2.callTerminationReason.getCode()); 816 } 817 818 private void blockNumber(String phoneNumber) throws Exception { 819 blockNumberWithAnswer(phoneNumber, new Answer<Bundle>() { 820 @Override 821 public Bundle answer(InvocationOnMock invocation) throws Throwable { 822 Bundle bundle = new Bundle(); 823 bundle.putBoolean(BlockedNumberContract.RES_NUMBER_IS_BLOCKED, true); 824 return bundle; 825 } 826 }); 827 } 828 829 private void blockNumberWithAnswer(String phoneNumber, Answer answer) throws Exception { 830 when(getBlockedNumberProvider().call( 831 anyString(), 832 eq(BlockedNumberContract.SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER), 833 eq(phoneNumber), 834 isNull(Bundle.class))).thenAnswer(answer); 835 } 836 837 private void verifyNoBlockChecks() { 838 verifyZeroInteractions(getBlockedNumberProvider()); 839 } 840 841 private IContentProvider getBlockedNumberProvider() { 842 return mSpyContext.getContentResolver().acquireProvider(BlockedNumberContract.AUTHORITY); 843 } 844 845 private void disconnectCall(String callId, String connectionId) throws Exception { 846 mConnectionServiceFixtureA.sendSetDisconnected(connectionId, DisconnectCause.LOCAL); 847 assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureX.getCall(callId).getState()); 848 assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureY.getCall(callId).getState()); 849 } 850 851 /** 852 * Tests the {@link Call#pullExternalCall()} API. Ensures that an external call which is 853 * pullable can be pulled. 854 * 855 * @throws Exception 856 */ 857 @LargeTest 858 public void testPullExternalCall() throws Exception { 859 // TODO: Revisit this unit test once telecom support for filtering external calls from 860 // InCall services is implemented. 861 mConnectionServiceFixtureA.mConnectionServiceDelegate.mCapabilities = 862 Connection.CAPABILITY_CAN_PULL_CALL; 863 mConnectionServiceFixtureA.mConnectionServiceDelegate.mProperties = 864 Connection.PROPERTY_IS_EXTERNAL_CALL; 865 866 IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", 867 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 868 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 869 870 // Attempt to pull the call and verify the API call makes it through 871 mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId); 872 verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT)) 873 .pullExternalCall(eq(ids.mConnectionId), any()); 874 } 875 876 /** 877 * Tests the {@link Call#pullExternalCall()} API. Verifies that if an external call is not 878 * marked as pullable that the connection service does not get an API call to pull the external 879 * call. 880 * 881 * @throws Exception 882 */ 883 @LargeTest 884 public void testPullNonPullableExternalCall() throws Exception { 885 // TODO: Revisit this unit test once telecom support for filtering external calls from 886 // InCall services is implemented. 887 mConnectionServiceFixtureA.mConnectionServiceDelegate.mProperties = 888 Connection.PROPERTY_IS_EXTERNAL_CALL; 889 890 IdPair ids = startAndMakeActiveIncomingCall("650-555-1212", 891 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 892 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 893 894 // Attempt to pull the call and verify the API call makes it through 895 mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId); 896 Thread.sleep(TEST_TIMEOUT); 897 verify(mConnectionServiceFixtureA.getTestDouble(), never()) 898 .pullExternalCall(eq(ids.mConnectionId), any()); 899 } 900 901 @LargeTest 902 public void testEmergencyCallFailMoveToSecondSim() throws Exception { 903 IdPair ids = startAndMakeDialingEmergencyCall("650-555-1212", 904 mPhoneAccountE0.getAccountHandle(), mConnectionServiceFixtureA); 905 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 906 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 907 908 // The Emergency Call has failed on the default SIM with an ERROR Disconnect Cause. Retry 909 // with the other SIM PhoneAccount 910 IdPair newIds = triggerEmergencyRedial(mPhoneAccountE1.getAccountHandle(), 911 mConnectionServiceFixtureA, ids); 912 913 // Call should be active on the E1 PhoneAccount 914 mConnectionServiceFixtureA.sendSetActive(newIds.mConnectionId); 915 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(newIds.mCallId).getState()); 916 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(newIds.mCallId).getState()); 917 assertEquals(mInCallServiceFixtureX.getCall(ids.mCallId).getAccountHandle(), 918 mPhoneAccountE1.getAccountHandle()); 919 } 920} 921