TelecomSystemTest.java revision 2c93c50e5be7d85b78c4af15aaa10e44f0bcdf3e
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 19 20import static org.mockito.Matchers.any; 21import static org.mockito.Matchers.anyBoolean; 22import static org.mockito.Matchers.anyInt; 23import static org.mockito.Matchers.anyString; 24import static org.mockito.Matchers.eq; 25import static org.mockito.Mockito.doAnswer; 26import static org.mockito.Mockito.doReturn; 27import static org.mockito.Mockito.mock; 28import static org.mockito.Mockito.reset; 29import static org.mockito.Mockito.timeout; 30import static org.mockito.Mockito.verify; 31import static org.mockito.Mockito.when; 32 33import android.content.BroadcastReceiver; 34import android.content.ComponentName; 35import android.content.Context; 36import android.content.Intent; 37import android.media.AudioManager; 38import android.media.IAudioService; 39import android.net.Uri; 40import android.os.Bundle; 41import android.os.Handler; 42import android.os.UserHandle; 43import android.telecom.Call; 44import android.telecom.CallAudioState; 45import android.telecom.Connection; 46import android.telecom.ConnectionRequest; 47import android.telecom.DisconnectCause; 48import android.telecom.ParcelableCall; 49import android.telecom.PhoneAccount; 50import android.telecom.PhoneAccountHandle; 51import android.telecom.TelecomManager; 52import android.telecom.VideoProfile; 53import android.telephony.TelephonyManager; 54 55import com.android.internal.telecom.IInCallAdapter; 56import com.android.server.telecom.CallAudioManager; 57import com.android.server.telecom.CallsManager; 58import com.android.server.telecom.HeadsetMediaButton; 59import com.android.server.telecom.HeadsetMediaButtonFactory; 60import com.android.server.telecom.InCallWakeLockController; 61import com.android.server.telecom.InCallWakeLockControllerFactory; 62import com.android.server.telecom.Log; 63import com.android.server.telecom.MissedCallNotifier; 64import com.android.server.telecom.ProximitySensorManager; 65import com.android.server.telecom.ProximitySensorManagerFactory; 66import com.android.server.telecom.TelecomSystem; 67 68import com.google.common.base.Predicate; 69 70import org.mockito.ArgumentCaptor; 71import org.mockito.Mock; 72import org.mockito.invocation.InvocationOnMock; 73import org.mockito.stubbing.Answer; 74 75import java.util.concurrent.BrokenBarrierException; 76import java.util.concurrent.CountDownLatch; 77import java.util.concurrent.CyclicBarrier; 78 79public class TelecomSystemTest extends TelecomTestCase { 80 81 static final int TEST_POLL_INTERVAL = 10; // milliseconds 82 static final int TEST_TIMEOUT = 1000; // milliseconds 83 84 @Mock MissedCallNotifier mMissedCallNotifier; 85 @Mock HeadsetMediaButton mHeadsetMediaButton; 86 @Mock ProximitySensorManager mProximitySensorManager; 87 @Mock InCallWakeLockController mInCallWakeLockController; 88 89 final ComponentName mInCallServiceComponentNameX = 90 new ComponentName( 91 "incall-service-package-X", 92 "incall-service-class-X"); 93 final ComponentName mInCallServiceComponentNameY = 94 new ComponentName( 95 "incall-service-package-Y", 96 "incall-service-class-Y"); 97 98 InCallServiceFixture mInCallServiceFixtureX; 99 InCallServiceFixture mInCallServiceFixtureY; 100 101 final ComponentName mConnectionServiceComponentNameA = 102 new ComponentName( 103 "connection-service-package-A", 104 "connection-service-class-A"); 105 final ComponentName mConnectionServiceComponentNameB = 106 new ComponentName( 107 "connection-service-package-B", 108 "connection-service-class-B"); 109 110 final PhoneAccount mPhoneAccountA0 = 111 PhoneAccount.builder( 112 new PhoneAccountHandle( 113 mConnectionServiceComponentNameA, 114 "id A 0"), 115 "Phone account service A ID 0") 116 .addSupportedUriScheme("tel") 117 .setCapabilities( 118 PhoneAccount.CAPABILITY_CALL_PROVIDER | 119 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) 120 .build(); 121 final PhoneAccount mPhoneAccountA1 = 122 PhoneAccount.builder( 123 new PhoneAccountHandle( 124 mConnectionServiceComponentNameA, 125 "id A 1"), 126 "Phone account service A ID 1") 127 .addSupportedUriScheme("tel") 128 .setCapabilities( 129 PhoneAccount.CAPABILITY_CALL_PROVIDER | 130 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) 131 .build(); 132 final PhoneAccount mPhoneAccountB0 = 133 PhoneAccount.builder( 134 new PhoneAccountHandle( 135 mConnectionServiceComponentNameB, 136 "id B 0"), 137 "Phone account service B ID 0") 138 .addSupportedUriScheme("tel") 139 .setCapabilities( 140 PhoneAccount.CAPABILITY_CALL_PROVIDER | 141 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) 142 .build(); 143 144 ConnectionServiceFixture mConnectionServiceFixtureA; 145 ConnectionServiceFixture mConnectionServiceFixtureB; 146 147 CallerInfoAsyncQueryFactoryFixture mCallerInfoAsyncQueryFactoryFixture; 148 149 IAudioService mAudioService; 150 151 TelecomSystem mTelecomSystem; 152 153 class IdPair { 154 final String mConnectionId; 155 final String mCallId; 156 157 public IdPair(String connectionId, String callId) { 158 this.mConnectionId = connectionId; 159 this.mCallId = callId; 160 } 161 } 162 163 @Override 164 public void setUp() throws Exception { 165 super.setUp(); 166 167 // First set up information about the In-Call services in the mock Context, since 168 // Telecom will search for these as soon as it is instantiated 169 setupInCallServices(); 170 171 // Next, create the TelecomSystem, our system under test 172 setupTelecomSystem(); 173 174 // Finally, register the ConnectionServices with the PhoneAccountRegistrar of the 175 // now-running TelecomSystem 176 setupConnectionServices(); 177 } 178 179 @Override 180 public void tearDown() throws Exception { 181 mTelecomSystem = null; 182 super.tearDown(); 183 } 184 185 private void setupTelecomSystem() throws Exception { 186 HeadsetMediaButtonFactory headsetMediaButtonFactory = 187 mock(HeadsetMediaButtonFactory.class); 188 ProximitySensorManagerFactory proximitySensorManagerFactory = 189 mock(ProximitySensorManagerFactory.class); 190 InCallWakeLockControllerFactory inCallWakeLockControllerFactory = 191 mock(InCallWakeLockControllerFactory.class); 192 mAudioService = setupAudioService(); 193 194 mCallerInfoAsyncQueryFactoryFixture = new CallerInfoAsyncQueryFactoryFixture(); 195 196 when(headsetMediaButtonFactory.create( 197 any(Context.class), 198 any(CallsManager.class), 199 any(TelecomSystem.SyncRoot.class))) 200 .thenReturn(mHeadsetMediaButton); 201 when(proximitySensorManagerFactory.create( 202 any(Context.class), 203 any(CallsManager.class))) 204 .thenReturn(mProximitySensorManager); 205 when(inCallWakeLockControllerFactory.create( 206 any(Context.class), 207 any(CallsManager.class))) 208 .thenReturn(mInCallWakeLockController); 209 210 mTelecomSystem = new TelecomSystem( 211 mComponentContextFixture.getTestDouble(), 212 mMissedCallNotifier, 213 mCallerInfoAsyncQueryFactoryFixture.getTestDouble(), 214 headsetMediaButtonFactory, 215 proximitySensorManagerFactory, 216 inCallWakeLockControllerFactory, 217 new CallAudioManager.AudioServiceFactory() { 218 @Override 219 public IAudioService getAudioService() { 220 return mAudioService; 221 } 222 }); 223 224 mComponentContextFixture.setTelecomManager(new TelecomManager( 225 mComponentContextFixture.getTestDouble(), 226 mTelecomSystem.getTelecomServiceImpl().getBinder())); 227 228 verify(headsetMediaButtonFactory).create( 229 eq(mComponentContextFixture.getTestDouble().getApplicationContext()), 230 any(CallsManager.class), 231 any(TelecomSystem.SyncRoot.class)); 232 verify(proximitySensorManagerFactory).create( 233 eq(mComponentContextFixture.getTestDouble().getApplicationContext()), 234 any(CallsManager.class)); 235 verify(inCallWakeLockControllerFactory).create( 236 eq(mComponentContextFixture.getTestDouble().getApplicationContext()), 237 any(CallsManager.class)); 238 } 239 240 private void setupConnectionServices() throws Exception { 241 mConnectionServiceFixtureA = new ConnectionServiceFixture(); 242 mConnectionServiceFixtureB = new ConnectionServiceFixture(); 243 244 mComponentContextFixture.addConnectionService( 245 mConnectionServiceComponentNameA, 246 mConnectionServiceFixtureA.getTestDouble()); 247 mComponentContextFixture.addConnectionService( 248 mConnectionServiceComponentNameB, 249 mConnectionServiceFixtureB.getTestDouble()); 250 251 mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA0); 252 mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA1); 253 mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountB0); 254 255 mTelecomSystem.getPhoneAccountRegistrar().setUserSelectedOutgoingPhoneAccount( 256 mPhoneAccountA0.getAccountHandle()); 257 } 258 259 private void setupInCallServices() throws Exception { 260 mComponentContextFixture.putResource( 261 com.android.server.telecom.R.string.ui_default_package, 262 mInCallServiceComponentNameX.getPackageName()); 263 mComponentContextFixture.putResource( 264 com.android.server.telecom.R.string.incall_default_class, 265 mInCallServiceComponentNameX.getClassName()); 266 267 mInCallServiceFixtureX = new InCallServiceFixture(); 268 mInCallServiceFixtureY = new InCallServiceFixture(); 269 270 mComponentContextFixture.addInCallService( 271 mInCallServiceComponentNameX, 272 mInCallServiceFixtureX.getTestDouble()); 273 mComponentContextFixture.addInCallService( 274 mInCallServiceComponentNameY, 275 mInCallServiceFixtureY.getTestDouble()); 276 } 277 278 /** 279 * Helper method for setting up the fake audio service. 280 * Calls to the fake audio service need to toggle the return 281 * value of AudioManager#isMicrophoneMute. 282 * @return mock of IAudioService 283 */ 284 private IAudioService setupAudioService() { 285 IAudioService audioService = mock(IAudioService.class); 286 final AudioManager fakeAudioManager = 287 (AudioManager) mComponentContextFixture.getTestDouble() 288 .getApplicationContext().getSystemService(Context.AUDIO_SERVICE); 289 290 try { 291 doAnswer(new Answer() { 292 @Override 293 public Object answer(InvocationOnMock i) { 294 Object[] args = i.getArguments(); 295 doReturn(args[0]).when(fakeAudioManager).isMicrophoneMute(); 296 return null; 297 } 298 }).when(audioService) 299 .setMicrophoneMute(any(Boolean.class), any(String.class), any(Integer.class)); 300 301 } catch (android.os.RemoteException e) { 302 // Do nothing, leave the faked microphone state as-is 303 } 304 return audioService; 305 } 306 307 private IdPair startOutgoingPhoneCall( 308 String number, 309 PhoneAccountHandle phoneAccountHandle, 310 ConnectionServiceFixture connectionServiceFixture) throws Exception { 311 reset( 312 connectionServiceFixture.getTestDouble(), 313 mInCallServiceFixtureX.getTestDouble(), 314 mInCallServiceFixtureY.getTestDouble()); 315 316 assertEquals( 317 mInCallServiceFixtureX.mCallById.size(), 318 mInCallServiceFixtureY.mCallById.size()); 319 assertEquals( 320 (mInCallServiceFixtureX.mInCallAdapter != null), 321 (mInCallServiceFixtureY.mInCallAdapter != null)); 322 323 int startingNumConnections = connectionServiceFixture.mConnectionById.size(); 324 int startingNumCalls = mInCallServiceFixtureX.mCallById.size(); 325 boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null; 326 327 Intent actionCallIntent = new Intent(); 328 actionCallIntent.setData(Uri.parse("tel:" + number)); 329 actionCallIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number); 330 actionCallIntent.setAction(Intent.ACTION_CALL); 331 if (phoneAccountHandle != null) { 332 actionCallIntent.putExtra( 333 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, 334 phoneAccountHandle); 335 } 336 337 mTelecomSystem.getCallIntentProcessor().processIntent(actionCallIntent); 338 339 if (!hasInCallAdapter) { 340 verify(mInCallServiceFixtureX.getTestDouble()) 341 .setInCallAdapter( 342 any(IInCallAdapter.class)); 343 verify(mInCallServiceFixtureY.getTestDouble()) 344 .setInCallAdapter( 345 any(IInCallAdapter.class)); 346 } 347 348 ArgumentCaptor<Intent> newOutgoingCallIntent = 349 ArgumentCaptor.forClass(Intent.class); 350 ArgumentCaptor<BroadcastReceiver> newOutgoingCallReceiver = 351 ArgumentCaptor.forClass(BroadcastReceiver.class); 352 353 verify(mComponentContextFixture.getTestDouble().getApplicationContext()) 354 .sendOrderedBroadcastAsUser( 355 newOutgoingCallIntent.capture(), 356 any(UserHandle.class), 357 anyString(), 358 anyInt(), 359 newOutgoingCallReceiver.capture(), 360 any(Handler.class), 361 anyInt(), 362 anyString(), 363 any(Bundle.class)); 364 365 // Pass on the new outgoing call Intent 366 // Set a dummy PendingResult so the BroadcastReceiver agrees to accept onReceive() 367 newOutgoingCallReceiver.getValue().setPendingResult( 368 new BroadcastReceiver.PendingResult(0, "", null, 0, true, false, null, 0, 0)); 369 newOutgoingCallReceiver.getValue().setResultData( 370 newOutgoingCallIntent.getValue().getStringExtra(Intent.EXTRA_PHONE_NUMBER)); 371 newOutgoingCallReceiver.getValue().onReceive( 372 mComponentContextFixture.getTestDouble(), 373 newOutgoingCallIntent.getValue()); 374 375 assertEquals(startingNumConnections + 1, connectionServiceFixture.mConnectionById.size()); 376 377 verify(connectionServiceFixture.getTestDouble()).createConnection( 378 eq(phoneAccountHandle), 379 anyString(), 380 any(ConnectionRequest.class), 381 anyBoolean(), 382 anyBoolean()); 383 384 connectionServiceFixture.sendHandleCreateConnectionComplete( 385 connectionServiceFixture.mLatestConnectionId); 386 387 assertEquals(startingNumCalls + 1, mInCallServiceFixtureX.mCallById.size()); 388 assertEquals(startingNumCalls + 1, mInCallServiceFixtureY.mCallById.size()); 389 390 assertEquals( 391 mInCallServiceFixtureX.mLatestCallId, 392 mInCallServiceFixtureY.mLatestCallId); 393 394 return new IdPair( 395 connectionServiceFixture.mLatestConnectionId, 396 mInCallServiceFixtureX.mLatestCallId); 397 } 398 399 private IdPair startIncomingPhoneCall( 400 String number, 401 PhoneAccountHandle phoneAccountHandle, 402 final ConnectionServiceFixture connectionServiceFixture) throws Exception { 403 reset( 404 connectionServiceFixture.getTestDouble(), 405 mInCallServiceFixtureX.getTestDouble(), 406 mInCallServiceFixtureY.getTestDouble()); 407 408 assertEquals( 409 mInCallServiceFixtureX.mCallById.size(), 410 mInCallServiceFixtureY.mCallById.size()); 411 assertEquals( 412 (mInCallServiceFixtureX.mInCallAdapter != null), 413 (mInCallServiceFixtureY.mInCallAdapter != null)); 414 415 final int startingNumConnections = connectionServiceFixture.mConnectionById.size(); 416 final int startingNumCalls = mInCallServiceFixtureX.mCallById.size(); 417 boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null; 418 419 Bundle extras = new Bundle(); 420 extras.putParcelable( 421 TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, 422 Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null)); 423 mTelecomSystem.getTelecomServiceImpl().getBinder() 424 .addNewIncomingCall(phoneAccountHandle, extras); 425 426 verify(connectionServiceFixture.getTestDouble()).createConnection( 427 any(PhoneAccountHandle.class), 428 anyString(), 429 any(ConnectionRequest.class), 430 eq(true), 431 eq(false)); 432 433 connectionServiceFixture.sendHandleCreateConnectionComplete( 434 connectionServiceFixture.mLatestConnectionId); 435 connectionServiceFixture.sendSetRinging( 436 connectionServiceFixture.mLatestConnectionId); 437 438 // For the case of incoming calls, Telecom connecting the InCall services and adding the 439 // Call is triggered by the async completion of the CallerInfoAsyncQuery. Once the Call 440 // is added, future interactions as triggered by the ConnectionService, through the various 441 // test fixtures, will be synchronous. 442 443 if (!hasInCallAdapter) { 444 verify( 445 mInCallServiceFixtureX.getTestDouble(), 446 timeout(TEST_TIMEOUT)) 447 .setInCallAdapter( 448 any(IInCallAdapter.class)); 449 verify( 450 mInCallServiceFixtureY.getTestDouble(), 451 timeout(TEST_TIMEOUT)) 452 .setInCallAdapter( 453 any(IInCallAdapter.class)); 454 } 455 456 // Give the InCallService time to respond 457 458 assertTrueWithTimeout(new Predicate<Void>() { 459 @Override 460 public boolean apply(Void v) { 461 return mInCallServiceFixtureX.mInCallAdapter != null; 462 } 463 }); 464 465 assertTrueWithTimeout(new Predicate<Void>() { 466 @Override 467 public boolean apply(Void v) { 468 return mInCallServiceFixtureY.mInCallAdapter != null; 469 } 470 }); 471 472 verify( 473 mInCallServiceFixtureX.getTestDouble(), 474 timeout(TEST_TIMEOUT)) 475 .addCall( 476 any(ParcelableCall.class)); 477 verify( 478 mInCallServiceFixtureY.getTestDouble(), 479 timeout(TEST_TIMEOUT)) 480 .addCall( 481 any(ParcelableCall.class)); 482 483 // Give the InCallService time to respond 484 485 assertTrueWithTimeout(new Predicate<Void>() { 486 @Override 487 public boolean apply(Void v) { 488 return startingNumConnections + 1 == 489 connectionServiceFixture.mConnectionById.size(); 490 } 491 }); 492 assertTrueWithTimeout(new Predicate<Void>() { 493 @Override 494 public boolean apply(Void v) { 495 return startingNumCalls + 1 == mInCallServiceFixtureX.mCallById.size(); 496 } 497 }); 498 assertTrueWithTimeout(new Predicate<Void>() { 499 @Override 500 public boolean apply(Void v) { 501 return startingNumCalls + 1 == mInCallServiceFixtureY.mCallById.size(); 502 } 503 }); 504 505 assertEquals( 506 mInCallServiceFixtureX.mLatestCallId, 507 mInCallServiceFixtureY.mLatestCallId); 508 509 return new IdPair( 510 connectionServiceFixture.mLatestConnectionId, 511 mInCallServiceFixtureX.mLatestCallId); 512 } 513 514 private void rapidFire(Runnable... tasks) { 515 final CyclicBarrier barrier = new CyclicBarrier(tasks.length); 516 final CountDownLatch latch = new CountDownLatch(tasks.length); 517 for (int i = 0; i < tasks.length; i++) { 518 final Runnable task = tasks[i]; 519 new Thread(new Runnable() { 520 @Override 521 public void run() { 522 try { 523 barrier.await(); 524 task.run(); 525 } catch (InterruptedException | BrokenBarrierException e){ 526 Log.e(TelecomSystemTest.this, e, "Unexpectedly interrupted"); 527 } finally { 528 latch.countDown(); 529 } 530 } 531 }).start(); 532 } 533 try { 534 latch.await(); 535 } catch (InterruptedException e) { 536 Log.e(TelecomSystemTest.this, e, "Unexpectedly interrupted"); 537 } 538 } 539 540 // A simple outgoing call, verifying that the appropriate connection service is contacted, 541 // the proper lifecycle is followed, and both In-Call Services are updated correctly. 542 private IdPair startAndMakeActiveOutgoingCall( 543 String number, 544 PhoneAccountHandle phoneAccountHandle, 545 ConnectionServiceFixture connectionServiceFixture) throws Exception { 546 IdPair ids = startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture); 547 548 connectionServiceFixture.sendSetDialing(ids.mConnectionId); 549 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 550 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 551 552 connectionServiceFixture.sendSetActive(ids.mConnectionId); 553 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 554 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 555 556 return ids; 557 } 558 559 public void testSingleOutgoingCallLocalDisconnect() throws Exception { 560 IdPair ids = startAndMakeActiveOutgoingCall( 561 "650-555-1212", 562 mPhoneAccountA0.getAccountHandle(), 563 mConnectionServiceFixtureA); 564 565 mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId); 566 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 567 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 568 569 mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL); 570 assertEquals(Call.STATE_DISCONNECTED, 571 mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 572 assertEquals(Call.STATE_DISCONNECTED, 573 mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 574 } 575 576 public void testSingleOutgoingCallRemoteDisconnect() throws Exception { 577 IdPair ids = startAndMakeActiveOutgoingCall( 578 "650-555-1212", 579 mPhoneAccountA0.getAccountHandle(), 580 mConnectionServiceFixtureA); 581 582 mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL); 583 assertEquals(Call.STATE_DISCONNECTED, 584 mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 585 assertEquals(Call.STATE_DISCONNECTED, 586 mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 587 } 588 589 // A simple incoming call, similar in scope to the previous test 590 private IdPair startAndMakeActiveIncomingCall( 591 String number, 592 PhoneAccountHandle phoneAccountHandle, 593 ConnectionServiceFixture connectionServiceFixture) throws Exception { 594 IdPair ids = startIncomingPhoneCall(number, phoneAccountHandle, connectionServiceFixture); 595 596 assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 597 assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 598 599 mInCallServiceFixtureX.mInCallAdapter 600 .answerCall(ids.mCallId, VideoProfile.STATE_AUDIO_ONLY); 601 602 verify(connectionServiceFixture.getTestDouble()) 603 .answer(ids.mConnectionId); 604 605 connectionServiceFixture.sendSetActive(ids.mConnectionId); 606 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 607 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 608 609 return ids; 610 } 611 612 public void testSingleIncomingCallLocalDisconnect() throws Exception { 613 IdPair ids = startAndMakeActiveIncomingCall( 614 "650-555-1212", 615 mPhoneAccountA0.getAccountHandle(), 616 mConnectionServiceFixtureA); 617 618 mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId); 619 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 620 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 621 622 mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL); 623 assertEquals(Call.STATE_DISCONNECTED, 624 mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 625 assertEquals(Call.STATE_DISCONNECTED, 626 mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 627 } 628 629 public void testSingleIncomingCallRemoteDisconnect() throws Exception { 630 IdPair ids = startAndMakeActiveIncomingCall( 631 "650-555-1212", 632 mPhoneAccountA0.getAccountHandle(), 633 mConnectionServiceFixtureA); 634 635 mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL); 636 assertEquals(Call.STATE_DISCONNECTED, 637 mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 638 assertEquals(Call.STATE_DISCONNECTED, 639 mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 640 } 641 642 public void do_testDeadlockOnOutgoingCall() throws Exception { 643 final IdPair ids = startOutgoingPhoneCall( 644 "650-555-1212", 645 mPhoneAccountA0.getAccountHandle(), 646 mConnectionServiceFixtureA); 647 rapidFire( 648 new Runnable() { 649 @Override 650 public void run() { 651 while (mCallerInfoAsyncQueryFactoryFixture.mRequests.size() > 0) { 652 mCallerInfoAsyncQueryFactoryFixture.mRequests.remove(0).reply(); 653 } 654 } 655 }, 656 new Runnable() { 657 @Override 658 public void run() { 659 try { 660 mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId); 661 } catch (Exception e) { 662 Log.e(this, e, ""); 663 } 664 } 665 }); 666 } 667 668 public void testDeadlockOnOutgoingCall() throws Exception { 669 for (int i = 0; i < 100; i++) { 670 TelecomSystemTest test = new TelecomSystemTest(); 671 test.setContext(getContext()); 672 test.setTestContext(getTestContext()); 673 test.setName(getName()); 674 test.setUp(); 675 test.do_testDeadlockOnOutgoingCall(); 676 test.tearDown(); 677 } 678 } 679 680 public void testIncomingThenOutgoingCalls() throws Exception { 681 // TODO: We have to use the same PhoneAccount for both; see http://b/18461539 682 IdPair incoming = startAndMakeActiveIncomingCall( 683 "650-555-2323", 684 mPhoneAccountA0.getAccountHandle(), 685 mConnectionServiceFixtureA); 686 IdPair outgoing = startAndMakeActiveOutgoingCall( 687 "650-555-1212", 688 mPhoneAccountA0.getAccountHandle(), 689 mConnectionServiceFixtureA); 690 } 691 692 public void testOutgoingThenIncomingCalls() throws Exception { 693 // TODO: We have to use the same PhoneAccount for both; see http://b/18461539 694 IdPair outgoing = startAndMakeActiveOutgoingCall( 695 "650-555-1212", 696 mPhoneAccountA0.getAccountHandle(), 697 mConnectionServiceFixtureA); 698 IdPair incoming = startAndMakeActiveIncomingCall( 699 "650-555-2323", 700 mPhoneAccountA0.getAccountHandle(), 701 mConnectionServiceFixtureA); 702 verify(mConnectionServiceFixtureA.getTestDouble()) 703 .hold(outgoing.mConnectionId); 704 mConnectionServiceFixtureA.mConnectionById.get(outgoing.mConnectionId).state = 705 Connection.STATE_HOLDING; 706 mConnectionServiceFixtureA.sendSetOnHold(outgoing.mConnectionId); 707 assertEquals( 708 Call.STATE_HOLDING, 709 mInCallServiceFixtureX.getCall(outgoing.mCallId).getState()); 710 assertEquals( 711 Call.STATE_HOLDING, 712 mInCallServiceFixtureY.getCall(outgoing.mCallId).getState()); 713 } 714 715 public void testAudioManagerOperations() throws Exception { 716 AudioManager audioManager = (AudioManager) mComponentContextFixture.getTestDouble() 717 .getApplicationContext().getSystemService(Context.AUDIO_SERVICE); 718 719 IdPair outgoing = startAndMakeActiveOutgoingCall( 720 "650-555-1212", 721 mPhoneAccountA0.getAccountHandle(), 722 mConnectionServiceFixtureA); 723 724 verify(audioManager, timeout(TEST_TIMEOUT)) 725 .requestAudioFocusForCall(anyInt(), anyInt()); 726 verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce()) 727 .setMode(AudioManager.MODE_IN_CALL); 728 729 mInCallServiceFixtureX.mInCallAdapter.mute(true); 730 verify(mAudioService, timeout(TEST_TIMEOUT)) 731 .setMicrophoneMute(eq(true), any(String.class), any(Integer.class)); 732 mInCallServiceFixtureX.mInCallAdapter.mute(false); 733 verify(mAudioService, timeout(TEST_TIMEOUT)) 734 .setMicrophoneMute(eq(false), any(String.class), any(Integer.class)); 735 736 mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_SPEAKER); 737 verify(audioManager, timeout(TEST_TIMEOUT)) 738 .setSpeakerphoneOn(true); 739 mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_EARPIECE); 740 verify(audioManager, timeout(TEST_TIMEOUT)) 741 .setSpeakerphoneOn(false); 742 743 mConnectionServiceFixtureA. 744 sendSetDisconnected(outgoing.mConnectionId, DisconnectCause.REMOTE); 745 746 verify(audioManager, timeout(TEST_TIMEOUT)) 747 .abandonAudioFocusForCall(); 748 verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce()) 749 .setMode(AudioManager.MODE_NORMAL); 750 } 751 752 protected static void assertTrueWithTimeout(Predicate<Void> predicate) { 753 int elapsed = 0; 754 while (elapsed < TEST_TIMEOUT) { 755 if (predicate.apply(null)) { 756 return; 757 } else { 758 try { 759 Thread.sleep(TEST_POLL_INTERVAL); 760 elapsed += TEST_POLL_INTERVAL; 761 } catch (InterruptedException e) { 762 fail(e.toString()); 763 } 764 } 765 } 766 fail("Timeout in assertTrueWithTimeout"); 767 } 768} 769