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