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