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