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