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