1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.telecom.tests; 18 19 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertTrue; 23 import static org.junit.Assert.fail; 24 import static org.mockito.ArgumentMatchers.isNotNull; 25 import static org.mockito.ArgumentMatchers.nullable; 26 import static org.mockito.Matchers.any; 27 import static org.mockito.Matchers.anyBoolean; 28 import static org.mockito.Matchers.anyInt; 29 import static org.mockito.Matchers.anyString; 30 import static org.mockito.Matchers.eq; 31 import static org.mockito.Matchers.isNull; 32 import static org.mockito.Mockito.doAnswer; 33 import static org.mockito.Mockito.doNothing; 34 import static org.mockito.Mockito.doReturn; 35 import static org.mockito.Mockito.mock; 36 import static org.mockito.Mockito.reset; 37 import static org.mockito.Mockito.spy; 38 import static org.mockito.Mockito.timeout; 39 import static org.mockito.Mockito.times; 40 import static org.mockito.Mockito.verify; 41 import static org.mockito.Mockito.when; 42 43 import android.content.BroadcastReceiver; 44 import android.content.ComponentName; 45 import android.content.ContentResolver; 46 import android.content.Context; 47 import android.content.IContentProvider; 48 import android.content.Intent; 49 import android.media.AudioManager; 50 import android.media.IAudioService; 51 import android.media.ToneGenerator; 52 import android.net.Uri; 53 import android.os.Bundle; 54 import android.os.Handler; 55 import android.os.Looper; 56 import android.os.Process; 57 import android.os.UserHandle; 58 import android.provider.BlockedNumberContract; 59 import android.telecom.Call; 60 import android.telecom.ConnectionRequest; 61 import android.telecom.DisconnectCause; 62 import android.telecom.ParcelableCall; 63 import android.telecom.PhoneAccount; 64 import android.telecom.PhoneAccountHandle; 65 import android.telecom.TelecomManager; 66 import android.telecom.VideoProfile; 67 68 import com.android.internal.telecom.IInCallAdapter; 69 import com.android.server.telecom.AsyncRingtonePlayer; 70 import com.android.server.telecom.BluetoothPhoneServiceImpl; 71 import com.android.server.telecom.CallAudioManager; 72 import com.android.server.telecom.CallAudioRouteStateMachine; 73 import com.android.server.telecom.CallerInfoLookupHelper; 74 import com.android.server.telecom.CallsManager; 75 import com.android.server.telecom.CallsManagerListenerBase; 76 import com.android.server.telecom.ClockProxy; 77 import com.android.server.telecom.ConnectionServiceFocusManager; 78 import com.android.server.telecom.DefaultDialerCache; 79 import com.android.server.telecom.HeadsetMediaButton; 80 import com.android.server.telecom.HeadsetMediaButtonFactory; 81 import com.android.server.telecom.InCallWakeLockController; 82 import com.android.server.telecom.InCallWakeLockControllerFactory; 83 import com.android.server.telecom.MissedCallNotifier; 84 import com.android.server.telecom.PhoneAccountRegistrar; 85 import com.android.server.telecom.PhoneNumberUtilsAdapter; 86 import com.android.server.telecom.PhoneNumberUtilsAdapterImpl; 87 import com.android.server.telecom.ProximitySensorManager; 88 import com.android.server.telecom.ProximitySensorManagerFactory; 89 import com.android.server.telecom.RoleManagerAdapter; 90 import com.android.server.telecom.StatusBarNotifier; 91 import com.android.server.telecom.TelecomSystem; 92 import com.android.server.telecom.Timeouts; 93 import com.android.server.telecom.WiredHeadsetManager; 94 import com.android.server.telecom.bluetooth.BluetoothRouteManager; 95 import com.android.server.telecom.components.UserCallIntentProcessor; 96 import com.android.server.telecom.ui.IncomingCallNotifier; 97 import com.android.server.telecom.ui.MissedCallNotifierImpl.MissedCallNotifierImplFactory; 98 99 import com.google.common.base.Predicate; 100 101 import org.mockito.ArgumentCaptor; 102 import org.mockito.Mock; 103 import org.mockito.invocation.InvocationOnMock; 104 import org.mockito.stubbing.Answer; 105 106 import java.io.File; 107 import java.util.ArrayList; 108 import java.util.Collections; 109 import java.util.List; 110 import java.util.concurrent.CountDownLatch; 111 import java.util.concurrent.TimeUnit; 112 113 /** 114 * Implements mocks and functionality required to implement telecom system tests. 115 */ 116 public class TelecomSystemTest extends TelecomTestCase { 117 118 static final int TEST_POLL_INTERVAL = 10; // milliseconds 119 static final int TEST_TIMEOUT = 1000; // milliseconds 120 121 // Purposely keep the connect time (which is wall clock) and elapsed time (which is time since 122 // boot) different to test that wall clock time operations and elapsed time operations perform 123 // as they individually should. 124 static final long TEST_CREATE_TIME = 100; 125 static final long TEST_CREATE_ELAPSED_TIME = 200; 126 static final long TEST_CONNECT_TIME = 1000; 127 static final long TEST_CONNECT_ELAPSED_TIME = 2000; 128 static final long TEST_DISCONNECT_TIME = 8000; 129 static final long TEST_DISCONNECT_ELAPSED_TIME = 4000; 130 131 public class HeadsetMediaButtonFactoryF implements HeadsetMediaButtonFactory { 132 @Override create(Context context, CallsManager callsManager, TelecomSystem.SyncRoot lock)133 public HeadsetMediaButton create(Context context, CallsManager callsManager, 134 TelecomSystem.SyncRoot lock) { 135 return mHeadsetMediaButton; 136 } 137 } 138 139 public class ProximitySensorManagerFactoryF implements ProximitySensorManagerFactory { 140 @Override create(Context context, CallsManager callsManager)141 public ProximitySensorManager create(Context context, CallsManager callsManager) { 142 return mProximitySensorManager; 143 } 144 } 145 146 public class InCallWakeLockControllerFactoryF implements InCallWakeLockControllerFactory { 147 @Override create(Context context, CallsManager callsManager)148 public InCallWakeLockController create(Context context, CallsManager callsManager) { 149 return mInCallWakeLockController; 150 } 151 } 152 153 public static class MissedCallNotifierFakeImpl extends CallsManagerListenerBase 154 implements MissedCallNotifier { 155 List<CallInfo> missedCallsNotified = new ArrayList<>(); 156 157 @Override clearMissedCalls(UserHandle userHandle)158 public void clearMissedCalls(UserHandle userHandle) { 159 160 } 161 162 @Override showMissedCallNotification(CallInfo call)163 public void showMissedCallNotification(CallInfo call) { 164 missedCallsNotified.add(call); 165 } 166 167 @Override reloadAfterBootComplete(CallerInfoLookupHelper callerInfoLookupHelper, CallInfoFactory callInfoFactory)168 public void reloadAfterBootComplete(CallerInfoLookupHelper callerInfoLookupHelper, 169 CallInfoFactory callInfoFactory) { } 170 171 @Override reloadFromDatabase(CallerInfoLookupHelper callerInfoLookupHelper, CallInfoFactory callInfoFactory, UserHandle userHandle)172 public void reloadFromDatabase(CallerInfoLookupHelper callerInfoLookupHelper, 173 CallInfoFactory callInfoFactory, UserHandle userHandle) { } 174 175 @Override setCurrentUserHandle(UserHandle userHandle)176 public void setCurrentUserHandle(UserHandle userHandle) { 177 178 } 179 } 180 181 MissedCallNotifierFakeImpl mMissedCallNotifier = new MissedCallNotifierFakeImpl(); 182 private class EmergencyNumberUtilsAdapter extends PhoneNumberUtilsAdapterImpl { 183 184 @Override isLocalEmergencyNumber(Context context, String number)185 public boolean isLocalEmergencyNumber(Context context, String number) { 186 return mIsEmergencyCall; 187 } 188 189 @Override isPotentialLocalEmergencyNumber(Context context, String number)190 public boolean isPotentialLocalEmergencyNumber(Context context, String number) { 191 return mIsEmergencyCall; 192 } 193 } 194 195 private class IncomingCallAddedListener extends CallsManagerListenerBase { 196 197 private final CountDownLatch mCountDownLatch; 198 IncomingCallAddedListener(CountDownLatch latch)199 public IncomingCallAddedListener(CountDownLatch latch) { 200 mCountDownLatch = latch; 201 } 202 203 @Override onCallAdded(com.android.server.telecom.Call call)204 public void onCallAdded(com.android.server.telecom.Call call) { 205 mCountDownLatch.countDown(); 206 } 207 } 208 209 PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter = new EmergencyNumberUtilsAdapter(); 210 211 @Mock HeadsetMediaButton mHeadsetMediaButton; 212 @Mock ProximitySensorManager mProximitySensorManager; 213 @Mock InCallWakeLockController mInCallWakeLockController; 214 @Mock BluetoothPhoneServiceImpl mBluetoothPhoneServiceImpl; 215 @Mock AsyncRingtonePlayer mAsyncRingtonePlayer; 216 @Mock IncomingCallNotifier mIncomingCallNotifier; 217 @Mock ClockProxy mClockProxy; 218 @Mock RoleManagerAdapter mRoleManagerAdapter; 219 220 final ComponentName mInCallServiceComponentNameX = 221 new ComponentName( 222 "incall-service-package-X", 223 "incall-service-class-X"); 224 final ComponentName mInCallServiceComponentNameY = 225 new ComponentName( 226 "incall-service-package-Y", 227 "incall-service-class-Y"); 228 229 InCallServiceFixture mInCallServiceFixtureX; 230 InCallServiceFixture mInCallServiceFixtureY; 231 232 final ComponentName mConnectionServiceComponentNameA = 233 new ComponentName( 234 "connection-service-package-A", 235 "connection-service-class-A"); 236 final ComponentName mConnectionServiceComponentNameB = 237 new ComponentName( 238 "connection-service-package-B", 239 "connection-service-class-B"); 240 241 final PhoneAccount mPhoneAccountA0 = 242 PhoneAccount.builder( 243 new PhoneAccountHandle( 244 mConnectionServiceComponentNameA, 245 "id A 0"), 246 "Phone account service A ID 0") 247 .addSupportedUriScheme("tel") 248 .setCapabilities( 249 PhoneAccount.CAPABILITY_CALL_PROVIDER | 250 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION | 251 PhoneAccount.CAPABILITY_VIDEO_CALLING) 252 .build(); 253 final PhoneAccount mPhoneAccountA1 = 254 PhoneAccount.builder( 255 new PhoneAccountHandle( 256 mConnectionServiceComponentNameA, 257 "id A 1"), 258 "Phone account service A ID 1") 259 .addSupportedUriScheme("tel") 260 .setCapabilities( 261 PhoneAccount.CAPABILITY_CALL_PROVIDER | 262 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION | 263 PhoneAccount.CAPABILITY_VIDEO_CALLING) 264 .build(); 265 final PhoneAccount mPhoneAccountA2 = 266 PhoneAccount.builder( 267 new PhoneAccountHandle( 268 mConnectionServiceComponentNameA, 269 "id A 2"), 270 "Phone account service A ID 2") 271 .addSupportedUriScheme("tel") 272 .setCapabilities( 273 PhoneAccount.CAPABILITY_CALL_PROVIDER | 274 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) 275 .build(); 276 final PhoneAccount mPhoneAccountSelfManaged = 277 PhoneAccount.builder( 278 new PhoneAccountHandle( 279 mConnectionServiceComponentNameA, 280 "id SM"), 281 "Phone account service A SM") 282 .addSupportedUriScheme("tel") 283 .setCapabilities( 284 PhoneAccount.CAPABILITY_SELF_MANAGED) 285 .build(); 286 final PhoneAccount mPhoneAccountB0 = 287 PhoneAccount.builder( 288 new PhoneAccountHandle( 289 mConnectionServiceComponentNameB, 290 "id B 0"), 291 "Phone account service B ID 0") 292 .addSupportedUriScheme("tel") 293 .setCapabilities( 294 PhoneAccount.CAPABILITY_CALL_PROVIDER | 295 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION | 296 PhoneAccount.CAPABILITY_VIDEO_CALLING) 297 .build(); 298 final PhoneAccount mPhoneAccountE0 = 299 PhoneAccount.builder( 300 new PhoneAccountHandle( 301 mConnectionServiceComponentNameA, 302 "id E 0"), 303 "Phone account service E ID 0") 304 .addSupportedUriScheme("tel") 305 .setCapabilities( 306 PhoneAccount.CAPABILITY_CALL_PROVIDER | 307 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION | 308 PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS) 309 .build(); 310 311 final PhoneAccount mPhoneAccountE1 = 312 PhoneAccount.builder( 313 new PhoneAccountHandle( 314 mConnectionServiceComponentNameA, 315 "id E 1"), 316 "Phone account service E ID 1") 317 .addSupportedUriScheme("tel") 318 .setCapabilities( 319 PhoneAccount.CAPABILITY_CALL_PROVIDER | 320 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION | 321 PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS) 322 .build(); 323 324 ConnectionServiceFixture mConnectionServiceFixtureA; 325 ConnectionServiceFixture mConnectionServiceFixtureB; 326 Timeouts.Adapter mTimeoutsAdapter; 327 328 CallerInfoAsyncQueryFactoryFixture mCallerInfoAsyncQueryFactoryFixture; 329 330 IAudioService mAudioService; 331 332 TelecomSystem mTelecomSystem; 333 334 Context mSpyContext; 335 336 private int mNumOutgoingCallsMade; 337 338 private boolean mIsEmergencyCall; 339 340 class IdPair { 341 final String mConnectionId; 342 final String mCallId; 343 IdPair(String connectionId, String callId)344 public IdPair(String connectionId, String callId) { 345 this.mConnectionId = connectionId; 346 this.mCallId = callId; 347 } 348 } 349 350 @Override setUp()351 public void setUp() throws Exception { 352 super.setUp(); 353 mSpyContext = mComponentContextFixture.getTestDouble().getApplicationContext(); 354 doReturn(mSpyContext).when(mSpyContext).getApplicationContext(); 355 doNothing().when(mSpyContext).sendBroadcastAsUser(any(), any(), any()); 356 357 mNumOutgoingCallsMade = 0; 358 359 mIsEmergencyCall = false; 360 361 // First set up information about the In-Call services in the mock Context, since 362 // Telecom will search for these as soon as it is instantiated 363 setupInCallServices(); 364 365 // Next, create the TelecomSystem, our system under test 366 setupTelecomSystem(); 367 368 // Finally, register the ConnectionServices with the PhoneAccountRegistrar of the 369 // now-running TelecomSystem 370 setupConnectionServices(); 371 372 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 373 } 374 375 @Override tearDown()376 public void tearDown() throws Exception { 377 mTelecomSystem.getCallsManager().getCallAudioManager() 378 .getCallAudioRouteStateMachine().quitNow(); 379 mTelecomSystem.getCallsManager().getCallAudioManager() 380 .getCallAudioModeStateMachine().quitNow(); 381 mTelecomSystem = null; 382 super.tearDown(); 383 } 384 makeConferenceCall()385 protected ParcelableCall makeConferenceCall() throws Exception { 386 IdPair callId1 = startAndMakeActiveOutgoingCall("650-555-1212", 387 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 388 389 IdPair callId2 = startAndMakeActiveOutgoingCall("650-555-1213", 390 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 391 392 IInCallAdapter inCallAdapter = mInCallServiceFixtureX.getInCallAdapter(); 393 inCallAdapter.conference(callId1.mCallId, callId2.mCallId); 394 // Wait for the handler in ConnectionService 395 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 396 ParcelableCall call1 = mInCallServiceFixtureX.getCall(callId1.mCallId); 397 ParcelableCall call2 = mInCallServiceFixtureX.getCall(callId2.mCallId); 398 // Check that the two calls end up with a parent in the end 399 assertNotNull(call1.getParentCallId()); 400 assertNotNull(call2.getParentCallId()); 401 assertEquals(call1.getParentCallId(), call2.getParentCallId()); 402 403 // Check to make sure that the parent call made it to the in-call service 404 String parentCallId = call1.getParentCallId(); 405 ParcelableCall conferenceCall = mInCallServiceFixtureX.getCall(parentCallId); 406 assertEquals(2, conferenceCall.getChildCallIds().size()); 407 assertTrue(conferenceCall.getChildCallIds().contains(callId1.mCallId)); 408 assertTrue(conferenceCall.getChildCallIds().contains(callId2.mCallId)); 409 return conferenceCall; 410 } 411 setupTelecomSystem()412 private void setupTelecomSystem() throws Exception { 413 // Remove any cached PhoneAccount xml 414 File phoneAccountFile = 415 new File(mComponentContextFixture.getTestDouble() 416 .getApplicationContext().getFilesDir(), 417 PhoneAccountRegistrar.FILE_NAME); 418 if (phoneAccountFile.exists()) { 419 phoneAccountFile.delete(); 420 } 421 422 // Use actual implementations instead of mocking the interface out. 423 HeadsetMediaButtonFactory headsetMediaButtonFactory = 424 spy(new HeadsetMediaButtonFactoryF()); 425 ProximitySensorManagerFactory proximitySensorManagerFactory = 426 spy(new ProximitySensorManagerFactoryF()); 427 InCallWakeLockControllerFactory inCallWakeLockControllerFactory = 428 spy(new InCallWakeLockControllerFactoryF()); 429 mAudioService = setupAudioService(); 430 431 mCallerInfoAsyncQueryFactoryFixture = new CallerInfoAsyncQueryFactoryFixture(); 432 433 mTimeoutsAdapter = mock(Timeouts.Adapter.class); 434 when(mTimeoutsAdapter.getCallScreeningTimeoutMillis(any(ContentResolver.class))) 435 .thenReturn(TEST_TIMEOUT / 5L); 436 mIncomingCallNotifier = mock(IncomingCallNotifier.class); 437 mClockProxy = mock(ClockProxy.class); 438 when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CREATE_TIME); 439 when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CREATE_ELAPSED_TIME); 440 when(mRoleManagerAdapter.getCallCompanionApps()).thenReturn(Collections.emptyList()); 441 when(mRoleManagerAdapter.getDefaultCallScreeningApp()).thenReturn(null); 442 when(mRoleManagerAdapter.getCarModeDialerApp()).thenReturn(null); 443 mTelecomSystem = new TelecomSystem( 444 mComponentContextFixture.getTestDouble(), 445 (context, phoneAccountRegistrar, defaultDialerCache) -> mMissedCallNotifier, 446 mCallerInfoAsyncQueryFactoryFixture.getTestDouble(), 447 headsetMediaButtonFactory, 448 proximitySensorManagerFactory, 449 inCallWakeLockControllerFactory, 450 () -> mAudioService, 451 (context, lock, callsManager, phoneAccountRegistrar) -> mBluetoothPhoneServiceImpl, 452 ConnectionServiceFocusManager::new, 453 mTimeoutsAdapter, 454 mAsyncRingtonePlayer, 455 mPhoneNumberUtilsAdapter, 456 mIncomingCallNotifier, 457 (streamType, volume) -> mock(ToneGenerator.class), 458 new CallAudioRouteStateMachine.Factory() { 459 @Override 460 public CallAudioRouteStateMachine create( 461 Context context, 462 CallsManager callsManager, 463 BluetoothRouteManager bluetoothManager, 464 WiredHeadsetManager wiredHeadsetManager, 465 StatusBarNotifier statusBarNotifier, 466 CallAudioManager.AudioServiceFactory audioServiceFactory, 467 int earpieceControl) { 468 return new CallAudioRouteStateMachine(context, 469 callsManager, 470 bluetoothManager, 471 wiredHeadsetManager, 472 statusBarNotifier, 473 audioServiceFactory, 474 // Force enable an earpiece for the end-to-end tests 475 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED); 476 } 477 }, 478 mClockProxy, 479 mRoleManagerAdapter); 480 481 mComponentContextFixture.setTelecomManager(new TelecomManager( 482 mComponentContextFixture.getTestDouble(), 483 mTelecomSystem.getTelecomServiceImpl().getBinder())); 484 485 verify(headsetMediaButtonFactory).create( 486 eq(mComponentContextFixture.getTestDouble().getApplicationContext()), 487 any(CallsManager.class), 488 any(TelecomSystem.SyncRoot.class)); 489 verify(proximitySensorManagerFactory).create( 490 eq(mComponentContextFixture.getTestDouble().getApplicationContext()), 491 any(CallsManager.class)); 492 verify(inCallWakeLockControllerFactory).create( 493 eq(mComponentContextFixture.getTestDouble().getApplicationContext()), 494 any(CallsManager.class)); 495 } 496 setupConnectionServices()497 private void setupConnectionServices() throws Exception { 498 mConnectionServiceFixtureA = new ConnectionServiceFixture(mContext); 499 mConnectionServiceFixtureB = new ConnectionServiceFixture(mContext); 500 501 mComponentContextFixture.addConnectionService(mConnectionServiceComponentNameA, 502 mConnectionServiceFixtureA.getTestDouble()); 503 mComponentContextFixture.addConnectionService(mConnectionServiceComponentNameB, 504 mConnectionServiceFixtureB.getTestDouble()); 505 506 mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA0); 507 mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA1); 508 mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA2); 509 mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountSelfManaged); 510 mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountB0); 511 mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountE0); 512 mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountE1); 513 514 mTelecomSystem.getPhoneAccountRegistrar().setUserSelectedOutgoingPhoneAccount( 515 mPhoneAccountA0.getAccountHandle(), Process.myUserHandle()); 516 } 517 setupInCallServices()518 private void setupInCallServices() throws Exception { 519 mComponentContextFixture.putResource( 520 com.android.internal.R.string.config_defaultDialer, 521 mInCallServiceComponentNameX.getPackageName()); 522 mComponentContextFixture.putResource( 523 com.android.server.telecom.R.string.incall_default_class, 524 mInCallServiceComponentNameX.getClassName()); 525 mComponentContextFixture.putBooleanResource( 526 com.android.internal.R.bool.config_voice_capable, true); 527 528 mInCallServiceFixtureX = new InCallServiceFixture(); 529 mInCallServiceFixtureY = new InCallServiceFixture(); 530 531 mComponentContextFixture.addInCallService(mInCallServiceComponentNameX, 532 mInCallServiceFixtureX.getTestDouble()); 533 mComponentContextFixture.addInCallService(mInCallServiceComponentNameY, 534 mInCallServiceFixtureY.getTestDouble()); 535 } 536 537 /** 538 * Helper method for setting up the fake audio service. 539 * Calls to the fake audio service need to toggle the return 540 * value of AudioManager#isMicrophoneMute. 541 * @return mock of IAudioService 542 */ setupAudioService()543 private IAudioService setupAudioService() { 544 IAudioService audioService = mock(IAudioService.class); 545 546 final AudioManager fakeAudioManager = 547 (AudioManager) mComponentContextFixture.getTestDouble() 548 .getApplicationContext().getSystemService(Context.AUDIO_SERVICE); 549 550 try { 551 doAnswer(new Answer() { 552 @Override 553 public Object answer(InvocationOnMock i) { 554 Object[] args = i.getArguments(); 555 doReturn(args[0]).when(fakeAudioManager).isMicrophoneMute(); 556 return null; 557 } 558 }).when(audioService) 559 .setMicrophoneMute(any(Boolean.class), any(String.class), any(Integer.class)); 560 561 } catch (android.os.RemoteException e) { 562 // Do nothing, leave the faked microphone state as-is 563 } 564 return audioService; 565 } 566 startOutgoingPhoneCallWithNoPhoneAccount(String number, ConnectionServiceFixture connectionServiceFixture)567 protected String startOutgoingPhoneCallWithNoPhoneAccount(String number, 568 ConnectionServiceFixture connectionServiceFixture) 569 throws Exception { 570 571 startOutgoingPhoneCallWaitForBroadcaster(number, null, 572 connectionServiceFixture, Process.myUserHandle(), VideoProfile.STATE_AUDIO_ONLY, 573 false /*isEmergency*/); 574 575 return mInCallServiceFixtureX.mLatestCallId; 576 } 577 outgoingCallPhoneAccountSelected(PhoneAccountHandle phoneAccountHandle, int startingNumConnections, int startingNumCalls, ConnectionServiceFixture connectionServiceFixture)578 protected IdPair outgoingCallPhoneAccountSelected(PhoneAccountHandle phoneAccountHandle, 579 int startingNumConnections, int startingNumCalls, 580 ConnectionServiceFixture connectionServiceFixture) throws Exception { 581 582 IdPair ids = outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls, 583 phoneAccountHandle, connectionServiceFixture); 584 585 connectionServiceFixture.sendSetDialing(ids.mConnectionId); 586 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 587 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 588 589 connectionServiceFixture.sendSetVideoState(ids.mConnectionId); 590 591 connectionServiceFixture.sendSetActive(ids.mConnectionId); 592 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 593 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 594 595 return ids; 596 } 597 startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser)598 protected IdPair startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle, 599 ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser) 600 throws Exception { 601 602 return startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture, 603 initiatingUser, VideoProfile.STATE_AUDIO_ONLY); 604 } 605 startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, int videoState)606 protected IdPair startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle, 607 ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, 608 int videoState) throws Exception { 609 int startingNumConnections = connectionServiceFixture.mConnectionById.size(); 610 int startingNumCalls = mInCallServiceFixtureX.mCallById.size(); 611 612 startOutgoingPhoneCallPendingCreateConnection(number, phoneAccountHandle, 613 connectionServiceFixture, initiatingUser, videoState); 614 615 verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT)) 616 .createConnectionComplete(anyString(), any()); 617 618 return outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls, 619 phoneAccountHandle, connectionServiceFixture); 620 } 621 triggerEmergencyRedial(PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, IdPair emergencyIds)622 protected IdPair triggerEmergencyRedial(PhoneAccountHandle phoneAccountHandle, 623 ConnectionServiceFixture connectionServiceFixture, IdPair emergencyIds) 624 throws Exception { 625 int startingNumConnections = connectionServiceFixture.mConnectionById.size(); 626 int startingNumCalls = mInCallServiceFixtureX.mCallById.size(); 627 628 // Send the message to disconnect the Emergency call due to an error. 629 // CreateConnectionProcessor should now try the second SIM account 630 connectionServiceFixture.sendSetDisconnected(emergencyIds.mConnectionId, 631 DisconnectCause.ERROR); 632 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 633 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall( 634 emergencyIds.mCallId).getState()); 635 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall( 636 emergencyIds.mCallId).getState()); 637 638 return redialingCallCreateConnectionComplete(startingNumConnections, startingNumCalls, 639 phoneAccountHandle, connectionServiceFixture); 640 } 641 startOutgoingEmergencyCall(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, int videoState)642 protected IdPair startOutgoingEmergencyCall(String number, 643 PhoneAccountHandle phoneAccountHandle, 644 ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, 645 int videoState) throws Exception { 646 int startingNumConnections = connectionServiceFixture.mConnectionById.size(); 647 int startingNumCalls = mInCallServiceFixtureX.mCallById.size(); 648 649 mIsEmergencyCall = true; 650 // Call will not use the ordered broadcaster, since it is an Emergency Call 651 startOutgoingPhoneCallWaitForBroadcaster(number, phoneAccountHandle, 652 connectionServiceFixture, initiatingUser, videoState, true /*isEmergency*/); 653 654 return outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls, 655 phoneAccountHandle, connectionServiceFixture); 656 } 657 startOutgoingPhoneCallWaitForBroadcaster(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, int videoState, boolean isEmergency)658 protected void startOutgoingPhoneCallWaitForBroadcaster(String number, 659 PhoneAccountHandle phoneAccountHandle, 660 ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, 661 int videoState, boolean isEmergency) throws Exception { 662 reset(connectionServiceFixture.getTestDouble(), mInCallServiceFixtureX.getTestDouble(), 663 mInCallServiceFixtureY.getTestDouble()); 664 665 assertEquals(mInCallServiceFixtureX.mCallById.size(), 666 mInCallServiceFixtureY.mCallById.size()); 667 assertEquals((mInCallServiceFixtureX.mInCallAdapter != null), 668 (mInCallServiceFixtureY.mInCallAdapter != null)); 669 670 mNumOutgoingCallsMade++; 671 672 boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null; 673 674 Intent actionCallIntent = new Intent(); 675 actionCallIntent.setData(Uri.parse("tel:" + number)); 676 actionCallIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number); 677 if(isEmergency) { 678 actionCallIntent.setAction(Intent.ACTION_CALL_EMERGENCY); 679 } else { 680 actionCallIntent.setAction(Intent.ACTION_CALL); 681 } 682 if (phoneAccountHandle != null) { 683 actionCallIntent.putExtra( 684 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, 685 phoneAccountHandle); 686 } 687 if (videoState != VideoProfile.STATE_AUDIO_ONLY) { 688 actionCallIntent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState); 689 } 690 691 final UserHandle userHandle = initiatingUser; 692 Context localAppContext = mComponentContextFixture.getTestDouble().getApplicationContext(); 693 new UserCallIntentProcessor(localAppContext, userHandle).processIntent( 694 actionCallIntent, null, true /* hasCallAppOp*/, false /* isLocal */); 695 // Wait for handler to start CallerInfo lookup. 696 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 697 // Send the CallerInfo lookup reply. 698 mCallerInfoAsyncQueryFactoryFixture.mRequests.forEach( 699 CallerInfoAsyncQueryFactoryFixture.Request::reply); 700 if (phoneAccountHandle != null) { 701 mTelecomSystem.getCallsManager().getLatestPostSelectionProcessingFuture().join(); 702 } 703 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 704 705 boolean isSelfManaged = phoneAccountHandle == mPhoneAccountSelfManaged.getAccountHandle(); 706 if (!hasInCallAdapter && !isSelfManaged) { 707 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) 708 .setInCallAdapter( 709 any(IInCallAdapter.class)); 710 verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT)) 711 .setInCallAdapter( 712 any(IInCallAdapter.class)); 713 } 714 } 715 startOutgoingPhoneCallPendingCreateConnection(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, int videoState)716 protected String startOutgoingPhoneCallPendingCreateConnection(String number, 717 PhoneAccountHandle phoneAccountHandle, 718 ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, 719 int videoState) throws Exception { 720 startOutgoingPhoneCallWaitForBroadcaster(number,phoneAccountHandle, 721 connectionServiceFixture, initiatingUser, videoState, false /*isEmergency*/); 722 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 723 724 verifyAndProcessOutgoingCallBroadcast(phoneAccountHandle); 725 return mInCallServiceFixtureX.mLatestCallId; 726 } 727 verifyAndProcessOutgoingCallBroadcast(PhoneAccountHandle phoneAccountHandle)728 protected void verifyAndProcessOutgoingCallBroadcast(PhoneAccountHandle phoneAccountHandle) { 729 ArgumentCaptor<Intent> newOutgoingCallIntent = 730 ArgumentCaptor.forClass(Intent.class); 731 ArgumentCaptor<BroadcastReceiver> newOutgoingCallReceiver = 732 ArgumentCaptor.forClass(BroadcastReceiver.class); 733 734 if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) { 735 verify(mComponentContextFixture.getTestDouble().getApplicationContext(), 736 times(mNumOutgoingCallsMade)) 737 .sendOrderedBroadcastAsUser( 738 newOutgoingCallIntent.capture(), 739 any(UserHandle.class), 740 anyString(), 741 anyInt(), 742 any(Bundle.class), 743 newOutgoingCallReceiver.capture(), 744 nullable(Handler.class), 745 anyInt(), 746 anyString(), 747 nullable(Bundle.class)); 748 // Pass on the new outgoing call Intent 749 // Set a dummy PendingResult so the BroadcastReceiver agrees to accept onReceive() 750 newOutgoingCallReceiver.getValue().setPendingResult( 751 new BroadcastReceiver.PendingResult(0, "", null, 0, true, false, null, 0, 0)); 752 newOutgoingCallReceiver.getValue().setResultData( 753 newOutgoingCallIntent.getValue().getStringExtra(Intent.EXTRA_PHONE_NUMBER)); 754 newOutgoingCallReceiver.getValue().onReceive(mComponentContextFixture.getTestDouble(), 755 newOutgoingCallIntent.getValue()); 756 } 757 758 } 759 760 // When Telecom is redialing due to an error, we need to make sure the number of connections 761 // increase, but not the number of Calls in the InCallService. redialingCallCreateConnectionComplete(int startingNumConnections, int startingNumCalls, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture)762 protected IdPair redialingCallCreateConnectionComplete(int startingNumConnections, 763 int startingNumCalls, PhoneAccountHandle phoneAccountHandle, 764 ConnectionServiceFixture connectionServiceFixture) throws Exception { 765 766 assertEquals(startingNumConnections + 1, connectionServiceFixture.mConnectionById.size()); 767 768 verify(connectionServiceFixture.getTestDouble()) 769 .createConnection(eq(phoneAccountHandle), anyString(), any(ConnectionRequest.class), 770 eq(false)/*isIncoming*/, anyBoolean(), any()); 771 // Wait for handleCreateConnectionComplete 772 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 773 774 // Make sure the number of registered InCallService Calls stays the same. 775 assertEquals(startingNumCalls, mInCallServiceFixtureX.mCallById.size()); 776 assertEquals(startingNumCalls, mInCallServiceFixtureY.mCallById.size()); 777 778 assertEquals(mInCallServiceFixtureX.mLatestCallId, mInCallServiceFixtureY.mLatestCallId); 779 780 return new IdPair(connectionServiceFixture.mLatestConnectionId, 781 mInCallServiceFixtureX.mLatestCallId); 782 } 783 outgoingCallCreateConnectionComplete(int startingNumConnections, int startingNumCalls, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture)784 protected IdPair outgoingCallCreateConnectionComplete(int startingNumConnections, 785 int startingNumCalls, PhoneAccountHandle phoneAccountHandle, 786 ConnectionServiceFixture connectionServiceFixture) throws Exception { 787 788 // Wait for the focus tracker. 789 waitForHandlerAction(mTelecomSystem.getCallsManager() 790 .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT); 791 792 verify(connectionServiceFixture.getTestDouble()) 793 .createConnection(eq(phoneAccountHandle), anyString(), any(ConnectionRequest.class), 794 eq(false)/*isIncoming*/, anyBoolean(), any()); 795 // Wait for handleCreateConnectionComplete 796 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 797 assertEquals(startingNumConnections + 1, 798 connectionServiceFixture.mConnectionById.size()); 799 800 // Wait for the callback in ConnectionService#onAdapterAttached to execute. 801 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 802 803 // Ensure callback to CS on successful creation happened. 804 verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT)) 805 .createConnectionComplete(anyString(), any()); 806 807 if (phoneAccountHandle == mPhoneAccountSelfManaged.getAccountHandle()) { 808 assertEquals(startingNumCalls, mInCallServiceFixtureX.mCallById.size()); 809 assertEquals(startingNumCalls, mInCallServiceFixtureY.mCallById.size()); 810 } else { 811 assertEquals(startingNumCalls + 1, mInCallServiceFixtureX.mCallById.size()); 812 assertEquals(startingNumCalls + 1, mInCallServiceFixtureY.mCallById.size()); 813 } 814 815 assertEquals(mInCallServiceFixtureX.mLatestCallId, mInCallServiceFixtureY.mLatestCallId); 816 817 return new IdPair(connectionServiceFixture.mLatestConnectionId, 818 mInCallServiceFixtureX.mLatestCallId); 819 } 820 startIncomingPhoneCall( String number, PhoneAccountHandle phoneAccountHandle, final ConnectionServiceFixture connectionServiceFixture)821 protected IdPair startIncomingPhoneCall( 822 String number, 823 PhoneAccountHandle phoneAccountHandle, 824 final ConnectionServiceFixture connectionServiceFixture) throws Exception { 825 return startIncomingPhoneCall(number, phoneAccountHandle, VideoProfile.STATE_AUDIO_ONLY, 826 connectionServiceFixture); 827 } 828 startIncomingPhoneCall( String number, PhoneAccountHandle phoneAccountHandle, int videoState, final ConnectionServiceFixture connectionServiceFixture)829 protected IdPair startIncomingPhoneCall( 830 String number, 831 PhoneAccountHandle phoneAccountHandle, 832 int videoState, 833 final ConnectionServiceFixture connectionServiceFixture) throws Exception { 834 reset(connectionServiceFixture.getTestDouble(), mInCallServiceFixtureX.getTestDouble(), 835 mInCallServiceFixtureY.getTestDouble()); 836 837 assertEquals(mInCallServiceFixtureX.mCallById.size(), 838 mInCallServiceFixtureY.mCallById.size()); 839 assertEquals((mInCallServiceFixtureX.mInCallAdapter != null), 840 (mInCallServiceFixtureY.mInCallAdapter != null)); 841 final int startingNumConnections = connectionServiceFixture.mConnectionById.size(); 842 final int startingNumCalls = mInCallServiceFixtureX.mCallById.size(); 843 boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null; 844 connectionServiceFixture.mConnectionServiceDelegate.mVideoState = videoState; 845 CountDownLatch incomingCallAddedLatch = new CountDownLatch(1); 846 IncomingCallAddedListener callAddedListener = 847 new IncomingCallAddedListener(incomingCallAddedLatch); 848 mTelecomSystem.getCallsManager().addListener(callAddedListener); 849 850 Bundle extras = new Bundle(); 851 extras.putParcelable( 852 TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, 853 Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null)); 854 mTelecomSystem.getTelecomServiceImpl().getBinder() 855 .addNewIncomingCall(phoneAccountHandle, extras); 856 857 verify(connectionServiceFixture.getTestDouble()) 858 .createConnection(any(PhoneAccountHandle.class), anyString(), 859 any(ConnectionRequest.class), eq(true), eq(false), any()); 860 861 // Wait for the handler to start the CallerInfo lookup 862 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 863 864 // Ensure callback to CS on successful creation happened. 865 verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT)) 866 .createConnectionComplete(anyString(), any()); 867 868 // Process the CallerInfo lookup reply 869 mCallerInfoAsyncQueryFactoryFixture.mRequests.forEach( 870 CallerInfoAsyncQueryFactoryFixture.Request::reply); 871 872 //Wait for/Verify call blocking happened asynchronously 873 incomingCallAddedLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS); 874 875 // For the case of incoming calls, Telecom connecting the InCall services and adding the 876 // Call is triggered by the async completion of the CallerInfoAsyncQuery. Once the Call 877 // is added, future interactions as triggered by the ConnectionService, through the various 878 // test fixtures, will be synchronous. 879 880 if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) { 881 if (!hasInCallAdapter) { 882 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) 883 .setInCallAdapter(any(IInCallAdapter.class)); 884 verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT)) 885 .setInCallAdapter(any(IInCallAdapter.class)); 886 887 // Give the InCallService time to respond 888 assertTrueWithTimeout(new Predicate<Void>() { 889 @Override 890 public boolean apply(Void v) { 891 return mInCallServiceFixtureX.mInCallAdapter != null; 892 } 893 }); 894 895 assertTrueWithTimeout(new Predicate<Void>() { 896 @Override 897 public boolean apply(Void v) { 898 return mInCallServiceFixtureY.mInCallAdapter != null; 899 } 900 }); 901 902 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) 903 .addCall(any(ParcelableCall.class)); 904 verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT)) 905 .addCall(any(ParcelableCall.class)); 906 907 // Give the InCallService time to respond 908 } 909 910 assertTrueWithTimeout(new Predicate<Void>() { 911 @Override 912 public boolean apply(Void v) { 913 return startingNumConnections + 1 == 914 connectionServiceFixture.mConnectionById.size(); 915 } 916 }); 917 918 mInCallServiceFixtureX.waitUntilNumCalls(startingNumCalls + 1); 919 mInCallServiceFixtureY.waitUntilNumCalls(startingNumCalls + 1); 920 assertEquals(startingNumCalls + 1, mInCallServiceFixtureX.mCallById.size()); 921 assertEquals(startingNumCalls + 1, mInCallServiceFixtureY.mCallById.size()); 922 923 assertEquals(mInCallServiceFixtureX.mLatestCallId, 924 mInCallServiceFixtureY.mLatestCallId); 925 } 926 927 return new IdPair(connectionServiceFixture.mLatestConnectionId, 928 mInCallServiceFixtureX.mLatestCallId); 929 } 930 startAndMakeActiveOutgoingCall( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture)931 protected IdPair startAndMakeActiveOutgoingCall( 932 String number, 933 PhoneAccountHandle phoneAccountHandle, 934 ConnectionServiceFixture connectionServiceFixture) throws Exception { 935 return startAndMakeActiveOutgoingCall(number, phoneAccountHandle, connectionServiceFixture, 936 VideoProfile.STATE_AUDIO_ONLY); 937 } 938 939 // A simple outgoing call, verifying that the appropriate connection service is contacted, 940 // the proper lifecycle is followed, and both In-Call Services are updated correctly. startAndMakeActiveOutgoingCall( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, int videoState)941 protected IdPair startAndMakeActiveOutgoingCall( 942 String number, 943 PhoneAccountHandle phoneAccountHandle, 944 ConnectionServiceFixture connectionServiceFixture, int videoState) throws Exception { 945 IdPair ids = startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture, 946 Process.myUserHandle(), videoState); 947 948 connectionServiceFixture.sendSetDialing(ids.mConnectionId); 949 if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) { 950 assertEquals(Call.STATE_DIALING, 951 mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 952 assertEquals(Call.STATE_DIALING, 953 mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 954 } 955 956 connectionServiceFixture.sendSetVideoState(ids.mConnectionId); 957 958 when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CONNECT_TIME); 959 when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CONNECT_ELAPSED_TIME); 960 connectionServiceFixture.sendSetActive(ids.mConnectionId); 961 if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) { 962 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 963 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 964 } 965 return ids; 966 } 967 startAndMakeActiveIncomingCall( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture)968 protected IdPair startAndMakeActiveIncomingCall( 969 String number, 970 PhoneAccountHandle phoneAccountHandle, 971 ConnectionServiceFixture connectionServiceFixture) throws Exception { 972 return startAndMakeActiveIncomingCall(number, phoneAccountHandle, connectionServiceFixture, 973 VideoProfile.STATE_AUDIO_ONLY); 974 } 975 976 // A simple incoming call, similar in scope to the previous test startAndMakeActiveIncomingCall( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, int videoState)977 protected IdPair startAndMakeActiveIncomingCall( 978 String number, 979 PhoneAccountHandle phoneAccountHandle, 980 ConnectionServiceFixture connectionServiceFixture, 981 int videoState) throws Exception { 982 IdPair ids = startIncomingPhoneCall(number, phoneAccountHandle, connectionServiceFixture); 983 984 if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) { 985 assertEquals(Call.STATE_RINGING, 986 mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 987 assertEquals(Call.STATE_RINGING, 988 mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 989 990 mInCallServiceFixtureX.mInCallAdapter 991 .answerCall(ids.mCallId, videoState); 992 // Wait on the CS focus manager handler 993 waitForHandlerAction(mTelecomSystem.getCallsManager() 994 .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT); 995 996 if (!VideoProfile.isVideo(videoState)) { 997 verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT)) 998 .answer(eq(ids.mConnectionId), any()); 999 } else { 1000 verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT)) 1001 .answerVideo(eq(ids.mConnectionId), eq(videoState), any()); 1002 } 1003 } 1004 1005 when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CONNECT_TIME); 1006 when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CONNECT_ELAPSED_TIME); 1007 connectionServiceFixture.sendSetActive(ids.mConnectionId); 1008 1009 if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) { 1010 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 1011 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 1012 } 1013 return ids; 1014 } 1015 startAndMakeDialingEmergencyCall( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture)1016 protected IdPair startAndMakeDialingEmergencyCall( 1017 String number, 1018 PhoneAccountHandle phoneAccountHandle, 1019 ConnectionServiceFixture connectionServiceFixture) throws Exception { 1020 IdPair ids = startOutgoingEmergencyCall(number, phoneAccountHandle, 1021 connectionServiceFixture, Process.myUserHandle(), VideoProfile.STATE_AUDIO_ONLY); 1022 1023 connectionServiceFixture.sendSetDialing(ids.mConnectionId); 1024 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 1025 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 1026 1027 return ids; 1028 } 1029 assertTrueWithTimeout(Predicate<Void> predicate)1030 protected static void assertTrueWithTimeout(Predicate<Void> predicate) { 1031 int elapsed = 0; 1032 while (elapsed < TEST_TIMEOUT) { 1033 if (predicate.apply(null)) { 1034 return; 1035 } else { 1036 try { 1037 Thread.sleep(TEST_POLL_INTERVAL); 1038 elapsed += TEST_POLL_INTERVAL; 1039 } catch (InterruptedException e) { 1040 fail(e.toString()); 1041 } 1042 } 1043 } 1044 fail("Timeout in assertTrueWithTimeout"); 1045 } 1046 } 1047