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