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