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