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