TelecomSystemTest.java revision 6ab66c31dbd8373d777b0c680e47e5ef451d9d9c
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 PhoneNumberUtilsAdapter phoneNumberUtilsAdapter) { 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()); 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()); 671 // Wait for handleCreateConnectionComplete 672 waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT); 673 674 assertEquals(startingNumCalls + 1, mInCallServiceFixtureX.mCallById.size()); 675 assertEquals(startingNumCalls + 1, mInCallServiceFixtureY.mCallById.size()); 676 677 assertEquals(mInCallServiceFixtureX.mLatestCallId, mInCallServiceFixtureY.mLatestCallId); 678 679 return new IdPair(connectionServiceFixture.mLatestConnectionId, 680 mInCallServiceFixtureX.mLatestCallId); 681 } 682 683 protected IdPair startIncomingPhoneCall( 684 String number, 685 PhoneAccountHandle phoneAccountHandle, 686 final ConnectionServiceFixture connectionServiceFixture) throws Exception { 687 return startIncomingPhoneCall(number, phoneAccountHandle, VideoProfile.STATE_AUDIO_ONLY, 688 connectionServiceFixture); 689 } 690 691 protected IdPair startIncomingPhoneCall( 692 String number, 693 PhoneAccountHandle phoneAccountHandle, 694 int videoState, 695 final ConnectionServiceFixture connectionServiceFixture) throws Exception { 696 reset(connectionServiceFixture.getTestDouble(), mInCallServiceFixtureX.getTestDouble(), 697 mInCallServiceFixtureY.getTestDouble()); 698 699 assertEquals(mInCallServiceFixtureX.mCallById.size(), 700 mInCallServiceFixtureY.mCallById.size()); 701 assertEquals((mInCallServiceFixtureX.mInCallAdapter != null), 702 (mInCallServiceFixtureY.mInCallAdapter != null)); 703 final int startingNumConnections = connectionServiceFixture.mConnectionById.size(); 704 final int startingNumCalls = mInCallServiceFixtureX.mCallById.size(); 705 boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null; 706 connectionServiceFixture.mConnectionServiceDelegate.mVideoState = videoState; 707 708 Bundle extras = new Bundle(); 709 extras.putParcelable( 710 TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, 711 Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null)); 712 mTelecomSystem.getTelecomServiceImpl().getBinder() 713 .addNewIncomingCall(phoneAccountHandle, extras); 714 715 verify(connectionServiceFixture.getTestDouble()) 716 .createConnection(any(PhoneAccountHandle.class), anyString(), 717 any(ConnectionRequest.class), eq(true), eq(false)); 718 719 for (CallerInfoAsyncQueryFactoryFixture.Request request : 720 mCallerInfoAsyncQueryFactoryFixture.mRequests) { 721 request.reply(); 722 } 723 724 IContentProvider blockedNumberProvider = 725 mSpyContext.getContentResolver().acquireProvider(BlockedNumberContract.AUTHORITY); 726 verify(blockedNumberProvider, timeout(TEST_TIMEOUT)).call( 727 anyString(), 728 eq(BlockedNumberContract.SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER), 729 eq(number), 730 isNull(Bundle.class)); 731 732 // For the case of incoming calls, Telecom connecting the InCall services and adding the 733 // Call is triggered by the async completion of the CallerInfoAsyncQuery. Once the Call 734 // is added, future interactions as triggered by the ConnectionService, through the various 735 // test fixtures, will be synchronous. 736 737 if (!hasInCallAdapter) { 738 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) 739 .setInCallAdapter(any(IInCallAdapter.class)); 740 verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT)) 741 .setInCallAdapter(any(IInCallAdapter.class)); 742 } 743 744 // Give the InCallService time to respond 745 746 assertTrueWithTimeout(new Predicate<Void>() { 747 @Override 748 public boolean apply(Void v) { 749 return mInCallServiceFixtureX.mInCallAdapter != null; 750 } 751 }); 752 753 assertTrueWithTimeout(new Predicate<Void>() { 754 @Override 755 public boolean apply(Void v) { 756 return mInCallServiceFixtureY.mInCallAdapter != null; 757 } 758 }); 759 760 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)) 761 .addCall(any(ParcelableCall.class)); 762 verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT)) 763 .addCall(any(ParcelableCall.class)); 764 765 // Give the InCallService time to respond 766 767 assertTrueWithTimeout(new Predicate<Void>() { 768 @Override 769 public boolean apply(Void v) { 770 return startingNumConnections + 1 == 771 connectionServiceFixture.mConnectionById.size(); 772 } 773 }); 774 assertTrueWithTimeout(new Predicate<Void>() { 775 @Override 776 public boolean apply(Void v) { 777 return startingNumCalls + 1 == mInCallServiceFixtureX.mCallById.size(); 778 } 779 }); 780 assertTrueWithTimeout(new Predicate<Void>() { 781 @Override 782 public boolean apply(Void v) { 783 return startingNumCalls + 1 == mInCallServiceFixtureY.mCallById.size(); 784 } 785 }); 786 787 assertEquals(mInCallServiceFixtureX.mLatestCallId, mInCallServiceFixtureY.mLatestCallId); 788 789 return new IdPair(connectionServiceFixture.mLatestConnectionId, 790 mInCallServiceFixtureX.mLatestCallId); 791 } 792 793 protected IdPair startAndMakeActiveOutgoingCall( 794 String number, 795 PhoneAccountHandle phoneAccountHandle, 796 ConnectionServiceFixture connectionServiceFixture) throws Exception { 797 return startAndMakeActiveOutgoingCall(number, phoneAccountHandle, connectionServiceFixture, 798 VideoProfile.STATE_AUDIO_ONLY); 799 } 800 801 // A simple outgoing call, verifying that the appropriate connection service is contacted, 802 // the proper lifecycle is followed, and both In-Call Services are updated correctly. 803 protected IdPair startAndMakeActiveOutgoingCall( 804 String number, 805 PhoneAccountHandle phoneAccountHandle, 806 ConnectionServiceFixture connectionServiceFixture, int videoState) throws Exception { 807 IdPair ids = startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture, 808 Process.myUserHandle(), videoState); 809 810 connectionServiceFixture.sendSetDialing(ids.mConnectionId); 811 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 812 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 813 814 connectionServiceFixture.sendSetVideoState(ids.mConnectionId); 815 816 connectionServiceFixture.sendSetActive(ids.mConnectionId); 817 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 818 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 819 820 return ids; 821 } 822 823 protected IdPair startAndMakeActiveIncomingCall( 824 String number, 825 PhoneAccountHandle phoneAccountHandle, 826 ConnectionServiceFixture connectionServiceFixture) throws Exception { 827 return startAndMakeActiveIncomingCall(number, phoneAccountHandle, connectionServiceFixture, 828 VideoProfile.STATE_AUDIO_ONLY); 829 } 830 831 // A simple incoming call, similar in scope to the previous test 832 protected IdPair startAndMakeActiveIncomingCall( 833 String number, 834 PhoneAccountHandle phoneAccountHandle, 835 ConnectionServiceFixture connectionServiceFixture, 836 int videoState) throws Exception { 837 IdPair ids = startIncomingPhoneCall(number, phoneAccountHandle, connectionServiceFixture); 838 839 assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 840 assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 841 842 mInCallServiceFixtureX.mInCallAdapter 843 .answerCall(ids.mCallId, videoState); 844 845 if (!VideoProfile.isVideo(videoState)) { 846 verify(connectionServiceFixture.getTestDouble()) 847 .answer(ids.mConnectionId); 848 } else { 849 verify(connectionServiceFixture.getTestDouble()) 850 .answerVideo(ids.mConnectionId, videoState); 851 } 852 853 connectionServiceFixture.sendSetActive(ids.mConnectionId); 854 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 855 assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 856 857 return ids; 858 } 859 860 protected IdPair startAndMakeDialingEmergencyCall( 861 String number, 862 PhoneAccountHandle phoneAccountHandle, 863 ConnectionServiceFixture connectionServiceFixture) throws Exception { 864 IdPair ids = startOutgoingEmergencyCall(number, phoneAccountHandle, 865 connectionServiceFixture, Process.myUserHandle(), VideoProfile.STATE_AUDIO_ONLY); 866 867 connectionServiceFixture.sendSetDialing(ids.mConnectionId); 868 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); 869 assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); 870 871 return ids; 872 } 873 874 protected static void assertTrueWithTimeout(Predicate<Void> predicate) { 875 int elapsed = 0; 876 while (elapsed < TEST_TIMEOUT) { 877 if (predicate.apply(null)) { 878 return; 879 } else { 880 try { 881 Thread.sleep(TEST_POLL_INTERVAL); 882 elapsed += TEST_POLL_INTERVAL; 883 } catch (InterruptedException e) { 884 fail(e.toString()); 885 } 886 } 887 } 888 fail("Timeout in assertTrueWithTimeout"); 889 } 890} 891