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