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