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