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