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