TelecomSystemTest.java revision bcf23de07aed59ed34d0121a76d29b6ed9a14288
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 mPhoneAccountB0 = 264 PhoneAccount.builder( 265 new PhoneAccountHandle( 266 mConnectionServiceComponentNameB, 267 "id B 0"), 268 "Phone account service B ID 0") 269 .addSupportedUriScheme("tel") 270 .setCapabilities( 271 PhoneAccount.CAPABILITY_CALL_PROVIDER | 272 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION | 273 PhoneAccount.CAPABILITY_VIDEO_CALLING) 274 .build(); 275 final PhoneAccount mPhoneAccountE0 = 276 PhoneAccount.builder( 277 new PhoneAccountHandle( 278 mConnectionServiceComponentNameA, 279 "id E 0"), 280 "Phone account service E ID 0") 281 .addSupportedUriScheme("tel") 282 .setCapabilities( 283 PhoneAccount.CAPABILITY_CALL_PROVIDER | 284 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION | 285 PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS) 286 .build(); 287 288 final PhoneAccount mPhoneAccountE1 = 289 PhoneAccount.builder( 290 new PhoneAccountHandle( 291 mConnectionServiceComponentNameA, 292 "id E 1"), 293 "Phone account service E ID 1") 294 .addSupportedUriScheme("tel") 295 .setCapabilities( 296 PhoneAccount.CAPABILITY_CALL_PROVIDER | 297 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION | 298 PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS) 299 .build(); 300 301 ConnectionServiceFixture mConnectionServiceFixtureA; 302 ConnectionServiceFixture mConnectionServiceFixtureB; 303 Timeouts.Adapter mTimeoutsAdapter; 304 305 CallerInfoAsyncQueryFactoryFixture mCallerInfoAsyncQueryFactoryFixture; 306 307 IAudioService mAudioService; 308 309 TelecomSystem mTelecomSystem; 310 311 Context mSpyContext; 312 313 private int mNumOutgoingCallsMade; 314 315 private boolean mIsEmergencyCall; 316 317 class IdPair { 318 final String mConnectionId; 319 final String mCallId; 320 321 public IdPair(String connectionId, String callId) { 322 this.mConnectionId = connectionId; 323 this.mCallId = callId; 324 } 325 } 326 327 @Override 328 public void setUp() throws Exception { 329 super.setUp(); 330 mSpyContext = mComponentContextFixture.getTestDouble().getApplicationContext(); 331 doReturn(mSpyContext).when(mSpyContext).getApplicationContext(); 332 doNothing().when(mSpyContext).sendBroadcastAsUser(any(), any(), any()); 333 334 mNumOutgoingCallsMade = 0; 335 336 mIsEmergencyCall = false; 337 338 // First set up information about the In-Call services in the mock Context, since 339 // Telecom will search for these as soon as it is instantiated 340 setupInCallServices(); 341 342 // Next, create the TelecomSystem, our system under test 343 setupTelecomSystem(); 344 345 // Finally, register the ConnectionServices with the PhoneAccountRegistrar of the 346 // now-running TelecomSystem 347 setupConnectionServices(); 348 349 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 350 } 351 352 @Override 353 public void tearDown() throws Exception { 354 mTelecomSystem.getCallsManager().getCallAudioManager() 355 .getCallAudioRouteStateMachine().quitNow(); 356 mTelecomSystem.getCallsManager().getCallAudioManager() 357 .getCallAudioModeStateMachine().quitNow(); 358 mTelecomSystem = null; 359 super.tearDown(); 360 } 361 362 protected ParcelableCall makeConferenceCall() throws Exception { 363 IdPair callId1 = startAndMakeActiveOutgoingCall("650-555-1212", 364 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 365 366 IdPair callId2 = startAndMakeActiveOutgoingCall("650-555-1213", 367 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); 368 369 IInCallAdapter inCallAdapter = mInCallServiceFixtureX.getInCallAdapter(); 370 inCallAdapter.conference(callId1.mCallId, callId2.mCallId); 371 // Wait for wacky non-deterministic behavior 372 Thread.sleep(200); 373 ParcelableCall call1 = mInCallServiceFixtureX.getCall(callId1.mCallId); 374 ParcelableCall call2 = mInCallServiceFixtureX.getCall(callId2.mCallId); 375 // Check that the two calls end up with a parent in the end 376 assertNotNull(call1.getParentCallId()); 377 assertNotNull(call2.getParentCallId()); 378 assertEquals(call1.getParentCallId(), call2.getParentCallId()); 379 380 // Check to make sure that the parent call made it to the in-call service 381 String parentCallId = call1.getParentCallId(); 382 ParcelableCall conferenceCall = mInCallServiceFixtureX.getCall(parentCallId); 383 assertEquals(2, conferenceCall.getChildCallIds().size()); 384 assertTrue(conferenceCall.getChildCallIds().contains(callId1.mCallId)); 385 assertTrue(conferenceCall.getChildCallIds().contains(callId2.mCallId)); 386 return conferenceCall; 387 } 388 389 private void setupTelecomSystem() throws Exception { 390 // Use actual implementations instead of mocking the interface out. 391 HeadsetMediaButtonFactory headsetMediaButtonFactory = 392 spy(new HeadsetMediaButtonFactoryF()); 393 ProximitySensorManagerFactory proximitySensorManagerFactory = 394 spy(new ProximitySensorManagerFactoryF()); 395 InCallWakeLockControllerFactory inCallWakeLockControllerFactory = 396 spy(new InCallWakeLockControllerFactoryF()); 397 mAudioService = setupAudioService(); 398 399 mCallerInfoAsyncQueryFactoryFixture = new CallerInfoAsyncQueryFactoryFixture(); 400 401 mTimeoutsAdapter = mock(Timeouts.Adapter.class); 402 when(mTimeoutsAdapter.getCallScreeningTimeoutMillis(any(ContentResolver.class))) 403 .thenReturn(TEST_TIMEOUT / 5L); 404 mIncomingCallNotifier = mock(IncomingCallNotifier.class); 405 mClockProxy = mock(ClockProxy.class); 406 when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CREATE_TIME); 407 when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CREATE_ELAPSED_TIME); 408 mTelecomSystem = new TelecomSystem( 409 mComponentContextFixture.getTestDouble(), 410 new MissedCallNotifierImplFactory() { 411 @Override 412 public MissedCallNotifier makeMissedCallNotifierImpl(Context context, 413 PhoneAccountRegistrar phoneAccountRegistrar, 414 DefaultDialerCache defaultDialerCache) { 415 return mMissedCallNotifier; 416 } 417 }, 418 mCallerInfoAsyncQueryFactoryFixture.getTestDouble(), 419 headsetMediaButtonFactory, 420 proximitySensorManagerFactory, 421 inCallWakeLockControllerFactory, 422 new CallAudioManager.AudioServiceFactory() { 423 @Override 424 public IAudioService getAudioService() { 425 return mAudioService; 426 } 427 }, 428 new BluetoothPhoneServiceImpl.BluetoothPhoneServiceImplFactory() { 429 @Override 430 public BluetoothPhoneServiceImpl makeBluetoothPhoneServiceImpl(Context context, 431 TelecomSystem.SyncRoot lock, CallsManager callsManager, 432 PhoneAccountRegistrar phoneAccountRegistrar) { 433 return mBluetoothPhoneServiceImpl; 434 } 435 }, 436 mTimeoutsAdapter, 437 mAsyncRingtonePlayer, 438 mPhoneNumberUtilsAdapter, 439 mIncomingCallNotifier, 440 (streamType, volume) -> mock(ToneGenerator.class), 441 mClockProxy); 442 443 mComponentContextFixture.setTelecomManager(new TelecomManager( 444 mComponentContextFixture.getTestDouble(), 445 mTelecomSystem.getTelecomServiceImpl().getBinder())); 446 447 verify(headsetMediaButtonFactory).create( 448 eq(mComponentContextFixture.getTestDouble().getApplicationContext()), 449 any(CallsManager.class), 450 any(TelecomSystem.SyncRoot.class)); 451 verify(proximitySensorManagerFactory).create( 452 eq(mComponentContextFixture.getTestDouble().getApplicationContext()), 453 any(CallsManager.class)); 454 verify(inCallWakeLockControllerFactory).create( 455 eq(mComponentContextFixture.getTestDouble().getApplicationContext()), 456 any(CallsManager.class)); 457 } 458 459 private void setupConnectionServices() throws Exception { 460 mConnectionServiceFixtureA = new ConnectionServiceFixture(); 461 mConnectionServiceFixtureB = new ConnectionServiceFixture(); 462 463 mComponentContextFixture.addConnectionService(mConnectionServiceComponentNameA, 464 mConnectionServiceFixtureA.getTestDouble()); 465 mComponentContextFixture.addConnectionService(mConnectionServiceComponentNameB, 466 mConnectionServiceFixtureB.getTestDouble()); 467 468 mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA0); 469 mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA1); 470 mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA2); 471 mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountB0); 472 mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountE0); 473 mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountE1); 474 475 mTelecomSystem.getPhoneAccountRegistrar().setUserSelectedOutgoingPhoneAccount( 476 mPhoneAccountA0.getAccountHandle(), Process.myUserHandle()); 477 } 478 479 private void setupInCallServices() throws Exception { 480 mComponentContextFixture.putResource( 481 com.android.server.telecom.R.string.ui_default_package, 482 mInCallServiceComponentNameX.getPackageName()); 483 mComponentContextFixture.putResource( 484 com.android.server.telecom.R.string.incall_default_class, 485 mInCallServiceComponentNameX.getClassName()); 486 mComponentContextFixture.putBooleanResource( 487 com.android.internal.R.bool.config_voice_capable, true); 488 489 mInCallServiceFixtureX = new InCallServiceFixture(); 490 mInCallServiceFixtureY = new InCallServiceFixture(); 491 492 mComponentContextFixture.addInCallService(mInCallServiceComponentNameX, 493 mInCallServiceFixtureX.getTestDouble()); 494 mComponentContextFixture.addInCallService(mInCallServiceComponentNameY, 495 mInCallServiceFixtureY.getTestDouble()); 496 } 497 498 /** 499 * Helper method for setting up the fake audio service. 500 * Calls to the fake audio service need to toggle the return 501 * value of AudioManager#isMicrophoneMute. 502 * @return mock of IAudioService 503 */ 504 private IAudioService setupAudioService() { 505 IAudioService audioService = mock(IAudioService.class); 506 507 final AudioManager fakeAudioManager = 508 (AudioManager) mComponentContextFixture.getTestDouble() 509 .getApplicationContext().getSystemService(Context.AUDIO_SERVICE); 510 511 try { 512 doAnswer(new Answer() { 513 @Override 514 public Object answer(InvocationOnMock i) { 515 Object[] args = i.getArguments(); 516 doReturn(args[0]).when(fakeAudioManager).isMicrophoneMute(); 517 return null; 518 } 519 }).when(audioService) 520 .setMicrophoneMute(any(Boolean.class), any(String.class), any(Integer.class)); 521 522 } catch (android.os.RemoteException e) { 523 // Do nothing, leave the faked microphone state as-is 524 } 525 return audioService; 526 } 527 528 protected String startOutgoingPhoneCallWithNoPhoneAccount(String number, 529 ConnectionServiceFixture connectionServiceFixture) 530 throws Exception { 531 532 return startOutgoingPhoneCallPendingCreateConnection(number, null, 533 connectionServiceFixture, Process.myUserHandle(), VideoProfile.STATE_AUDIO_ONLY); 534 } 535 536 protected IdPair outgoingCallPhoneAccountSelected(PhoneAccountHandle phoneAccountHandle, 537 int startingNumConnections, int startingNumCalls, 538 ConnectionServiceFixture connectionServiceFixture) throws Exception { 539 540 IdPair ids = outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls, 541 phoneAccountHandle, connectionServiceFixture); 542 543 connectionServiceFixture.sendSetDialing(ids.mConnectionId); 544 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 545 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 546 547 connectionServiceFixture.sendSetVideoState(ids.mConnectionId); 548 549 connectionServiceFixture.sendSetActive(ids.mConnectionId); 550 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 551 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 552 553 return ids; 554 } 555 556 protected IdPair startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle, 557 ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser) 558 throws Exception { 559 560 return startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture, 561 initiatingUser, VideoProfile.STATE_AUDIO_ONLY); 562 } 563 564 protected IdPair startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle, 565 ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, 566 int videoState) throws Exception { 567 int startingNumConnections = connectionServiceFixture.mConnectionById.size(); 568 int startingNumCalls = mInCallServiceFixtureX.mCallById.size(); 569 570 startOutgoingPhoneCallPendingCreateConnection(number, phoneAccountHandle, 571 connectionServiceFixture, initiatingUser, videoState); 572 573 return outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls, 574 phoneAccountHandle, connectionServiceFixture); 575 } 576 577 protected IdPair triggerEmergencyRedial(PhoneAccountHandle phoneAccountHandle, 578 ConnectionServiceFixture connectionServiceFixture, IdPair emergencyIds) 579 throws Exception { 580 int startingNumConnections = connectionServiceFixture.mConnectionById.size(); 581 int startingNumCalls = mInCallServiceFixtureX.mCallById.size(); 582 583 // Send the message to disconnect the Emergency call due to an error. 584 // CreateConnectionProcessor should now try the second SIM account 585 connectionServiceFixture.sendSetDisconnected(emergencyIds.mConnectionId, 586 DisconnectCause.ERROR); 587 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 588 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall( 589 emergencyIds.mCallId).getState()); 590 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall( 591 emergencyIds.mCallId).getState()); 592 593 return redialingCallCreateConnectionComplete(startingNumConnections, startingNumCalls, 594 phoneAccountHandle, connectionServiceFixture); 595 } 596 597 protected IdPair startOutgoingEmergencyCall(String number, 598 PhoneAccountHandle phoneAccountHandle, 599 ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, 600 int videoState) throws Exception { 601 int startingNumConnections = connectionServiceFixture.mConnectionById.size(); 602 int startingNumCalls = mInCallServiceFixtureX.mCallById.size(); 603 604 mIsEmergencyCall = true; 605 // Call will not use the ordered broadcaster, since it is an Emergency Call 606 startOutgoingPhoneCallWaitForBroadcaster(number, phoneAccountHandle, 607 connectionServiceFixture, initiatingUser, videoState, true /*isEmergency*/); 608 609 return outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls, 610 phoneAccountHandle, connectionServiceFixture); 611 } 612 613 protected void startOutgoingPhoneCallWaitForBroadcaster(String number, 614 PhoneAccountHandle phoneAccountHandle, 615 ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, 616 int videoState, boolean isEmergency) throws Exception { 617 reset(connectionServiceFixture.getTestDouble(), mInCallServiceFixtureX.getTestDouble(), 618 mInCallServiceFixtureY.getTestDouble()); 619 620 assertEquals(mInCallServiceFixtureX.mCallById.size(), 621 mInCallServiceFixtureY.mCallById.size()); 622 assertEquals((mInCallServiceFixtureX.mInCallAdapter != null), 623 (mInCallServiceFixtureY.mInCallAdapter != null)); 624 625 mNumOutgoingCallsMade++; 626 627 boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null; 628 629 Intent actionCallIntent = new Intent(); 630 actionCallIntent.setData(Uri.parse("tel:" + number)); 631 actionCallIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number); 632 if(isEmergency) { 633 actionCallIntent.setAction(Intent.ACTION_CALL_EMERGENCY); 634 } else { 635 actionCallIntent.setAction(Intent.ACTION_CALL); 636 } 637 if (phoneAccountHandle != null) { 638 actionCallIntent.putExtra( 639 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, 640 phoneAccountHandle); 641 } 642 if (videoState != VideoProfile.STATE_AUDIO_ONLY) { 643 actionCallIntent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState); 644 } 645 646 final UserHandle userHandle = initiatingUser; 647 Context localAppContext = mComponentContextFixture.getTestDouble().getApplicationContext(); 648 new UserCallIntentProcessor(localAppContext, userHandle).processIntent( 649 actionCallIntent, null, true /* hasCallAppOp*/); 650 // UserCallIntentProcessor's mContext.sendBroadcastAsUser(...) will call to an empty method 651 // as to not actually try to send an intent to PrimaryCallReceiver. We verify that it was 652 // called correctly in order to continue. 653 verify(localAppContext).sendBroadcastAsUser(actionCallIntent, UserHandle.SYSTEM); 654 mTelecomSystem.getCallIntentProcessor().processIntent(actionCallIntent); 655 // Wait for handler to start CallerInfo lookup. 656 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 657 // Send the CallerInfo lookup reply. 658 mCallerInfoAsyncQueryFactoryFixture.mRequests.forEach( 659 CallerInfoAsyncQueryFactoryFixture.Request::reply); 660 661 if (!hasInCallAdapter) { 662 verify(mInCallServiceFixtureX.getTestDouble()) 663 .setInCallAdapter( 664 any(IInCallAdapter.class)); 665 verify(mInCallServiceFixtureY.getTestDouble()) 666 .setInCallAdapter( 667 any(IInCallAdapter.class)); 668 } 669 } 670 671 protected String startOutgoingPhoneCallPendingCreateConnection(String number, 672 PhoneAccountHandle phoneAccountHandle, 673 ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, 674 int videoState) throws Exception { 675 startOutgoingPhoneCallWaitForBroadcaster(number,phoneAccountHandle, 676 connectionServiceFixture, initiatingUser, videoState, false /*isEmergency*/); 677 678 ArgumentCaptor<Intent> newOutgoingCallIntent = 679 ArgumentCaptor.forClass(Intent.class); 680 ArgumentCaptor<BroadcastReceiver> newOutgoingCallReceiver = 681 ArgumentCaptor.forClass(BroadcastReceiver.class); 682 683 verify(mComponentContextFixture.getTestDouble().getApplicationContext(), 684 times(mNumOutgoingCallsMade)) 685 .sendOrderedBroadcastAsUser( 686 newOutgoingCallIntent.capture(), 687 any(UserHandle.class), 688 anyString(), 689 anyInt(), 690 newOutgoingCallReceiver.capture(), 691 nullable(Handler.class), 692 anyInt(), 693 anyString(), 694 nullable(Bundle.class)); 695 696 // Pass on the new outgoing call Intent 697 // Set a dummy PendingResult so the BroadcastReceiver agrees to accept onReceive() 698 newOutgoingCallReceiver.getValue().setPendingResult( 699 new BroadcastReceiver.PendingResult(0, "", null, 0, true, false, null, 0, 0)); 700 newOutgoingCallReceiver.getValue().setResultData( 701 newOutgoingCallIntent.getValue().getStringExtra(Intent.EXTRA_PHONE_NUMBER)); 702 newOutgoingCallReceiver.getValue().onReceive(mComponentContextFixture.getTestDouble(), 703 newOutgoingCallIntent.getValue()); 704 705 return mInCallServiceFixtureX.mLatestCallId; 706 } 707 708 // When Telecom is redialing due to an error, we need to make sure the number of connections 709 // increase, but not the number of Calls in the InCallService. 710 protected IdPair redialingCallCreateConnectionComplete(int startingNumConnections, 711 int startingNumCalls, PhoneAccountHandle phoneAccountHandle, 712 ConnectionServiceFixture connectionServiceFixture) throws Exception { 713 714 assertEquals(startingNumConnections + 1, connectionServiceFixture.mConnectionById.size()); 715 716 verify(connectionServiceFixture.getTestDouble()) 717 .createConnection(eq(phoneAccountHandle), anyString(), any(ConnectionRequest.class), 718 eq(false)/*isIncoming*/, anyBoolean(), any()); 719 // Wait for handleCreateConnectionComplete 720 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 721 722 // Make sure the number of registered InCallService Calls stays the same. 723 assertEquals(startingNumCalls, mInCallServiceFixtureX.mCallById.size()); 724 assertEquals(startingNumCalls, mInCallServiceFixtureY.mCallById.size()); 725 726 assertEquals(mInCallServiceFixtureX.mLatestCallId, mInCallServiceFixtureY.mLatestCallId); 727 728 return new IdPair(connectionServiceFixture.mLatestConnectionId, 729 mInCallServiceFixtureX.mLatestCallId); 730 } 731 732 protected IdPair outgoingCallCreateConnectionComplete(int startingNumConnections, 733 int startingNumCalls, PhoneAccountHandle phoneAccountHandle, 734 ConnectionServiceFixture connectionServiceFixture) throws Exception { 735 736 assertEquals(startingNumConnections + 1, connectionServiceFixture.mConnectionById.size()); 737 738 verify(connectionServiceFixture.getTestDouble()) 739 .createConnection(eq(phoneAccountHandle), anyString(), any(ConnectionRequest.class), 740 eq(false)/*isIncoming*/, anyBoolean(), any()); 741 // Wait for handleCreateConnectionComplete 742 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 743 // Wait for the callback in ConnectionService#onAdapterAttached to execute. 744 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 745 746 // Ensure callback to CS on successful creation happened. 747 verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT)) 748 .createConnectionComplete(anyString(), any()); 749 750 assertEquals(startingNumCalls + 1, mInCallServiceFixtureX.mCallById.size()); 751 assertEquals(startingNumCalls + 1, mInCallServiceFixtureY.mCallById.size()); 752 753 assertEquals(mInCallServiceFixtureX.mLatestCallId, mInCallServiceFixtureY.mLatestCallId); 754 755 return new IdPair(connectionServiceFixture.mLatestConnectionId, 756 mInCallServiceFixtureX.mLatestCallId); 757 } 758 759 protected IdPair startIncomingPhoneCall( 760 String number, 761 PhoneAccountHandle phoneAccountHandle, 762 final ConnectionServiceFixture connectionServiceFixture) throws Exception { 763 return startIncomingPhoneCall(number, phoneAccountHandle, VideoProfile.STATE_AUDIO_ONLY, 764 connectionServiceFixture); 765 } 766 767 protected IdPair startIncomingPhoneCall( 768 String number, 769 PhoneAccountHandle phoneAccountHandle, 770 int videoState, 771 final ConnectionServiceFixture connectionServiceFixture) throws Exception { 772 reset(connectionServiceFixture.getTestDouble(), mInCallServiceFixtureX.getTestDouble(), 773 mInCallServiceFixtureY.getTestDouble()); 774 775 assertEquals(mInCallServiceFixtureX.mCallById.size(), 776 mInCallServiceFixtureY.mCallById.size()); 777 assertEquals((mInCallServiceFixtureX.mInCallAdapter != null), 778 (mInCallServiceFixtureY.mInCallAdapter != null)); 779 final int startingNumConnections = connectionServiceFixture.mConnectionById.size(); 780 final int startingNumCalls = mInCallServiceFixtureX.mCallById.size(); 781 boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null; 782 connectionServiceFixture.mConnectionServiceDelegate.mVideoState = videoState; 783 CountDownLatch incomingCallAddedLatch = new CountDownLatch(1); 784 IncomingCallAddedListener callAddedListener = 785 new IncomingCallAddedListener(incomingCallAddedLatch); 786 mTelecomSystem.getCallsManager().addListener(callAddedListener); 787 788 Bundle extras = new Bundle(); 789 extras.putParcelable( 790 TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, 791 Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null)); 792 mTelecomSystem.getTelecomServiceImpl().getBinder() 793 .addNewIncomingCall(phoneAccountHandle, extras); 794 795 verify(connectionServiceFixture.getTestDouble()) 796 .createConnection(any(PhoneAccountHandle.class), anyString(), 797 any(ConnectionRequest.class), eq(true), eq(false), any()); 798 799 // Wait for the handler to start the CallerInfo lookup 800 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 801 802 // Ensure callback to CS on successful creation happened. 803 verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT)) 804 .createConnectionComplete(anyString(), any()); 805 806 807 // Process the CallerInfo lookup reply 808 mCallerInfoAsyncQueryFactoryFixture.mRequests.forEach( 809 CallerInfoAsyncQueryFactoryFixture.Request::reply); 810 811 //Wait for/Verify call blocking happened asynchronously 812 incomingCallAddedLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS); 813 814 IContentProvider blockedNumberProvider = 815 mSpyContext.getContentResolver().acquireProvider(BlockedNumberContract.AUTHORITY); 816 verify(blockedNumberProvider, timeout(TEST_TIMEOUT)).call( 817 anyString(), 818 eq(BlockedNumberContract.SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER), 819 eq(number), 820 isNull(Bundle.class)); 821 822 // For the case of incoming calls, Telecom connecting the InCall services and adding the 823 // Call is triggered by the async completion of the CallerInfoAsyncQuery. Once the Call 824 // is added, future interactions as triggered by the ConnectionService, through the various 825 // test fixtures, will be synchronous. 826 827 if (!hasInCallAdapter) { 828 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) 829 .setInCallAdapter(any(IInCallAdapter.class)); 830 verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT)) 831 .setInCallAdapter(any(IInCallAdapter.class)); 832 } 833 834 // Give the InCallService time to respond 835 836 assertTrueWithTimeout(new Predicate<Void>() { 837 @Override 838 public boolean apply(Void v) { 839 return mInCallServiceFixtureX.mInCallAdapter != null; 840 } 841 }); 842 843 assertTrueWithTimeout(new Predicate<Void>() { 844 @Override 845 public boolean apply(Void v) { 846 return mInCallServiceFixtureY.mInCallAdapter != null; 847 } 848 }); 849 850 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) 851 .addCall(any(ParcelableCall.class)); 852 verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT)) 853 .addCall(any(ParcelableCall.class)); 854 855 // Give the InCallService time to respond 856 857 assertTrueWithTimeout(new Predicate<Void>() { 858 @Override 859 public boolean apply(Void v) { 860 return startingNumConnections + 1 == 861 connectionServiceFixture.mConnectionById.size(); 862 } 863 }); 864 assertTrueWithTimeout(new Predicate<Void>() { 865 @Override 866 public boolean apply(Void v) { 867 return startingNumCalls + 1 == mInCallServiceFixtureX.mCallById.size(); 868 } 869 }); 870 assertTrueWithTimeout(new Predicate<Void>() { 871 @Override 872 public boolean apply(Void v) { 873 return startingNumCalls + 1 == mInCallServiceFixtureY.mCallById.size(); 874 } 875 }); 876 877 assertEquals(mInCallServiceFixtureX.mLatestCallId, mInCallServiceFixtureY.mLatestCallId); 878 879 return new IdPair(connectionServiceFixture.mLatestConnectionId, 880 mInCallServiceFixtureX.mLatestCallId); 881 } 882 883 protected IdPair startAndMakeActiveOutgoingCall( 884 String number, 885 PhoneAccountHandle phoneAccountHandle, 886 ConnectionServiceFixture connectionServiceFixture) throws Exception { 887 return startAndMakeActiveOutgoingCall(number, phoneAccountHandle, connectionServiceFixture, 888 VideoProfile.STATE_AUDIO_ONLY); 889 } 890 891 // A simple outgoing call, verifying that the appropriate connection service is contacted, 892 // the proper lifecycle is followed, and both In-Call Services are updated correctly. 893 protected IdPair startAndMakeActiveOutgoingCall( 894 String number, 895 PhoneAccountHandle phoneAccountHandle, 896 ConnectionServiceFixture connectionServiceFixture, int videoState) throws Exception { 897 IdPair ids = startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture, 898 Process.myUserHandle(), videoState); 899 900 connectionServiceFixture.sendSetDialing(ids.mConnectionId); 901 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 902 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 903 904 connectionServiceFixture.sendSetVideoState(ids.mConnectionId); 905 906 when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CONNECT_TIME); 907 when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CONNECT_ELAPSED_TIME); 908 connectionServiceFixture.sendSetActive(ids.mConnectionId); 909 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 910 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 911 912 return ids; 913 } 914 915 protected IdPair startAndMakeActiveIncomingCall( 916 String number, 917 PhoneAccountHandle phoneAccountHandle, 918 ConnectionServiceFixture connectionServiceFixture) throws Exception { 919 return startAndMakeActiveIncomingCall(number, phoneAccountHandle, connectionServiceFixture, 920 VideoProfile.STATE_AUDIO_ONLY); 921 } 922 923 // A simple incoming call, similar in scope to the previous test 924 protected IdPair startAndMakeActiveIncomingCall( 925 String number, 926 PhoneAccountHandle phoneAccountHandle, 927 ConnectionServiceFixture connectionServiceFixture, 928 int videoState) throws Exception { 929 IdPair ids = startIncomingPhoneCall(number, phoneAccountHandle, connectionServiceFixture); 930 931 assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 932 assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 933 934 mInCallServiceFixtureX.mInCallAdapter 935 .answerCall(ids.mCallId, videoState); 936 937 if (!VideoProfile.isVideo(videoState)) { 938 verify(connectionServiceFixture.getTestDouble()) 939 .answer(eq(ids.mConnectionId), any()); 940 } else { 941 verify(connectionServiceFixture.getTestDouble()) 942 .answerVideo(eq(ids.mConnectionId), eq(videoState), any()); 943 } 944 945 when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CONNECT_TIME); 946 when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CONNECT_ELAPSED_TIME); 947 connectionServiceFixture.sendSetActive(ids.mConnectionId); 948 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 949 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 950 951 return ids; 952 } 953 954 protected IdPair startAndMakeDialingEmergencyCall( 955 String number, 956 PhoneAccountHandle phoneAccountHandle, 957 ConnectionServiceFixture connectionServiceFixture) throws Exception { 958 IdPair ids = startOutgoingEmergencyCall(number, phoneAccountHandle, 959 connectionServiceFixture, Process.myUserHandle(), VideoProfile.STATE_AUDIO_ONLY); 960 961 connectionServiceFixture.sendSetDialing(ids.mConnectionId); 962 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 963 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 964 965 return ids; 966 } 967 968 protected static void assertTrueWithTimeout(Predicate<Void> predicate) { 969 int elapsed = 0; 970 while (elapsed < TEST_TIMEOUT) { 971 if (predicate.apply(null)) { 972 return; 973 } else { 974 try { 975 Thread.sleep(TEST_POLL_INTERVAL); 976 elapsed += TEST_POLL_INTERVAL; 977 } catch (InterruptedException e) { 978 fail(e.toString()); 979 } 980 } 981 } 982 fail("Timeout in assertTrueWithTimeout"); 983 } 984} 985