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