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