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