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 
17 package com.android.server.telecom.tests;
18 
19 
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertTrue;
23 import static org.junit.Assert.fail;
24 import static org.mockito.ArgumentMatchers.nullable;
25 import static org.mockito.Matchers.any;
26 import static org.mockito.Matchers.anyBoolean;
27 import static org.mockito.Matchers.anyInt;
28 import static org.mockito.Matchers.anyString;
29 import static org.mockito.Matchers.eq;
30 import static org.mockito.Mockito.doAnswer;
31 import static org.mockito.Mockito.doNothing;
32 import static org.mockito.Mockito.doReturn;
33 import static org.mockito.Mockito.mock;
34 import static org.mockito.Mockito.reset;
35 import static org.mockito.Mockito.spy;
36 import static org.mockito.Mockito.timeout;
37 import static org.mockito.Mockito.times;
38 import static org.mockito.Mockito.verify;
39 import static org.mockito.Mockito.when;
40 
41 import android.content.BroadcastReceiver;
42 import android.content.ComponentName;
43 import android.content.ContentResolver;
44 import android.content.Context;
45 import android.content.Intent;
46 import android.media.AudioManager;
47 import android.media.IAudioService;
48 import android.media.ToneGenerator;
49 import android.net.Uri;
50 import android.os.Bundle;
51 import android.os.Handler;
52 import android.os.HandlerThread;
53 import android.os.Looper;
54 import android.os.Process;
55 import android.os.UserHandle;
56 import android.telecom.Call;
57 import android.telecom.ConnectionRequest;
58 import android.telecom.DisconnectCause;
59 import android.telecom.Log;
60 import android.telecom.ParcelableCall;
61 import android.telecom.PhoneAccount;
62 import android.telecom.PhoneAccountHandle;
63 import android.telecom.TelecomManager;
64 import android.telecom.VideoProfile;
65 import android.telephony.TelephonyManager;
66 import android.telephony.TelephonyRegistryManager;
67 import android.text.TextUtils;
68 
69 import com.android.internal.telecom.IInCallAdapter;
70 import com.android.server.telecom.AsyncRingtonePlayer;
71 import com.android.server.telecom.BluetoothPhoneServiceImpl;
72 import com.android.server.telecom.CallAudioManager;
73 import com.android.server.telecom.CallAudioModeStateMachine;
74 import com.android.server.telecom.CallAudioRouteStateMachine;
75 import com.android.server.telecom.CallerInfoLookupHelper;
76 import com.android.server.telecom.CallsManager;
77 import com.android.server.telecom.CallsManagerListenerBase;
78 import com.android.server.telecom.ClockProxy;
79 import com.android.server.telecom.ConnectionServiceFocusManager;
80 import com.android.server.telecom.ContactsAsyncHelper;
81 import com.android.server.telecom.HeadsetMediaButton;
82 import com.android.server.telecom.HeadsetMediaButtonFactory;
83 import com.android.server.telecom.InCallWakeLockController;
84 import com.android.server.telecom.InCallWakeLockControllerFactory;
85 import com.android.server.telecom.MissedCallNotifier;
86 import com.android.server.telecom.PhoneAccountRegistrar;
87 import com.android.server.telecom.PhoneNumberUtilsAdapterImpl;
88 import com.android.server.telecom.ProximitySensorManager;
89 import com.android.server.telecom.ProximitySensorManagerFactory;
90 import com.android.server.telecom.RoleManagerAdapter;
91 import com.android.server.telecom.StatusBarNotifier;
92 import com.android.server.telecom.SystemStateHelper;
93 import com.android.server.telecom.TelecomSystem;
94 import com.android.server.telecom.Timeouts;
95 import com.android.server.telecom.WiredHeadsetManager;
96 import com.android.server.telecom.bluetooth.BluetoothRouteManager;
97 import com.android.server.telecom.callfiltering.CallFilterResultCallback;
98 import com.android.server.telecom.callfiltering.IncomingCallFilter;
99 import com.android.server.telecom.components.UserCallIntentProcessor;
100 import com.android.server.telecom.ui.IncomingCallNotifier;
101 
102 import com.google.common.base.Predicate;
103 
104 import org.mockito.ArgumentCaptor;
105 import org.mockito.Mock;
106 import org.mockito.invocation.InvocationOnMock;
107 import org.mockito.stubbing.Answer;
108 
109 import java.io.File;
110 import java.util.ArrayList;
111 import java.util.Collections;
112 import java.util.LinkedList;
113 import java.util.List;
114 import java.util.concurrent.CountDownLatch;
115 import java.util.concurrent.TimeUnit;
116 
117 /**
118  * Implements mocks and functionality required to implement telecom system tests.
119  */
120 public class TelecomSystemTest extends TelecomTestCase {
121 
122     static final int TEST_POLL_INTERVAL = 10;  // milliseconds
123     static final int TEST_TIMEOUT = 1000;  // milliseconds
124 
125     // Purposely keep the connect time (which is wall clock) and elapsed time (which is time since
126     // boot) different to test that wall clock time operations and elapsed time operations perform
127     // as they individually should.
128     static final long TEST_CREATE_TIME = 100;
129     static final long TEST_CREATE_ELAPSED_TIME = 200;
130     static final long TEST_CONNECT_TIME = 1000;
131     static final long TEST_CONNECT_ELAPSED_TIME = 2000;
132     static final long TEST_DISCONNECT_TIME = 8000;
133     static final long TEST_DISCONNECT_ELAPSED_TIME = 4000;
134 
135     public class HeadsetMediaButtonFactoryF implements HeadsetMediaButtonFactory  {
136         @Override
create(Context context, CallsManager callsManager, TelecomSystem.SyncRoot lock)137         public HeadsetMediaButton create(Context context, CallsManager callsManager,
138                 TelecomSystem.SyncRoot lock) {
139             return mHeadsetMediaButton;
140         }
141     }
142 
143     public class ProximitySensorManagerFactoryF implements ProximitySensorManagerFactory {
144         @Override
create(Context context, CallsManager callsManager)145         public ProximitySensorManager create(Context context, CallsManager callsManager) {
146             return mProximitySensorManager;
147         }
148     }
149 
150     public class InCallWakeLockControllerFactoryF implements InCallWakeLockControllerFactory {
151         @Override
create(Context context, CallsManager callsManager)152         public InCallWakeLockController create(Context context, CallsManager callsManager) {
153             return mInCallWakeLockController;
154         }
155     }
156 
157     public static class MissedCallNotifierFakeImpl extends CallsManagerListenerBase
158             implements MissedCallNotifier {
159         List<CallInfo> missedCallsNotified = new ArrayList<>();
160 
161         @Override
clearMissedCalls(UserHandle userHandle)162         public void clearMissedCalls(UserHandle userHandle) {
163 
164         }
165 
166         @Override
showMissedCallNotification(CallInfo call)167         public void showMissedCallNotification(CallInfo call) {
168             missedCallsNotified.add(call);
169         }
170 
171         @Override
reloadAfterBootComplete(CallerInfoLookupHelper callerInfoLookupHelper, CallInfoFactory callInfoFactory)172         public void reloadAfterBootComplete(CallerInfoLookupHelper callerInfoLookupHelper,
173                 CallInfoFactory callInfoFactory) { }
174 
175         @Override
reloadFromDatabase(CallerInfoLookupHelper callerInfoLookupHelper, CallInfoFactory callInfoFactory, UserHandle userHandle)176         public void reloadFromDatabase(CallerInfoLookupHelper callerInfoLookupHelper,
177                 CallInfoFactory callInfoFactory, UserHandle userHandle) { }
178 
179         @Override
setCurrentUserHandle(UserHandle userHandle)180         public void setCurrentUserHandle(UserHandle userHandle) {
181 
182         }
183     }
184 
185     MissedCallNotifierFakeImpl mMissedCallNotifier = new MissedCallNotifierFakeImpl();
186 
187     private class IncomingCallAddedListener extends CallsManagerListenerBase {
188 
189         private final CountDownLatch mCountDownLatch;
190 
IncomingCallAddedListener(CountDownLatch latch)191         public IncomingCallAddedListener(CountDownLatch latch) {
192             mCountDownLatch = latch;
193         }
194 
195         @Override
onCallAdded(com.android.server.telecom.Call call)196         public void onCallAdded(com.android.server.telecom.Call call) {
197             mCountDownLatch.countDown();
198         }
199     }
200 
201     @Mock HeadsetMediaButton mHeadsetMediaButton;
202     @Mock ProximitySensorManager mProximitySensorManager;
203     @Mock InCallWakeLockController mInCallWakeLockController;
204     @Mock BluetoothPhoneServiceImpl mBluetoothPhoneServiceImpl;
205     @Mock AsyncRingtonePlayer mAsyncRingtonePlayer;
206     @Mock IncomingCallNotifier mIncomingCallNotifier;
207     @Mock ClockProxy mClockProxy;
208     @Mock RoleManagerAdapter mRoleManagerAdapter;
209     @Mock ToneGenerator mToneGenerator;
210 
211     final ComponentName mInCallServiceComponentNameX =
212             new ComponentName(
213                     "incall-service-package-X",
214                     "incall-service-class-X");
215     private static final int SERVICE_X_UID = 1;
216     final ComponentName mInCallServiceComponentNameY =
217             new ComponentName(
218                     "incall-service-package-Y",
219                     "incall-service-class-Y");
220     private static final int SERVICE_Y_UID = 1;
221     InCallServiceFixture mInCallServiceFixtureX;
222     InCallServiceFixture mInCallServiceFixtureY;
223 
224     final ComponentName mConnectionServiceComponentNameA =
225             new ComponentName(
226                     "connection-service-package-A",
227                     "connection-service-class-A");
228     final ComponentName mConnectionServiceComponentNameB =
229             new ComponentName(
230                     "connection-service-package-B",
231                     "connection-service-class-B");
232 
233     final PhoneAccount mPhoneAccountA0 =
234             PhoneAccount.builder(
235                     new PhoneAccountHandle(
236                             mConnectionServiceComponentNameA,
237                             "id A 0"),
238                     "Phone account service A ID 0")
239                     .addSupportedUriScheme("tel")
240                     .setCapabilities(
241                             PhoneAccount.CAPABILITY_CALL_PROVIDER |
242                                     PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
243                                     PhoneAccount.CAPABILITY_VIDEO_CALLING)
244                     .build();
245     final PhoneAccount mPhoneAccountA1 =
246             PhoneAccount.builder(
247                     new PhoneAccountHandle(
248                             mConnectionServiceComponentNameA,
249                             "id A 1"),
250                     "Phone account service A ID 1")
251                     .addSupportedUriScheme("tel")
252                     .setCapabilities(
253                             PhoneAccount.CAPABILITY_CALL_PROVIDER |
254                                     PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
255                                     PhoneAccount.CAPABILITY_VIDEO_CALLING)
256                     .build();
257     final PhoneAccount mPhoneAccountA2 =
258             PhoneAccount.builder(
259                     new PhoneAccountHandle(
260                             mConnectionServiceComponentNameA,
261                             "id A 2"),
262                     "Phone account service A ID 2")
263                     .addSupportedUriScheme("tel")
264                     .setCapabilities(
265                             PhoneAccount.CAPABILITY_CALL_PROVIDER |
266                                     PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
267                     .build();
268     final PhoneAccount mPhoneAccountSelfManaged =
269             PhoneAccount.builder(
270                     new PhoneAccountHandle(
271                             mConnectionServiceComponentNameA,
272                             "id SM"),
273                     "Phone account service A SM")
274                     .addSupportedUriScheme("tel")
275                     .setCapabilities(
276                             PhoneAccount.CAPABILITY_SELF_MANAGED)
277                     .build();
278     final PhoneAccount mPhoneAccountB0 =
279             PhoneAccount.builder(
280                     new PhoneAccountHandle(
281                             mConnectionServiceComponentNameB,
282                             "id B 0"),
283                     "Phone account service B ID 0")
284                     .addSupportedUriScheme("tel")
285                     .setCapabilities(
286                             PhoneAccount.CAPABILITY_CALL_PROVIDER |
287                                     PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
288                                     PhoneAccount.CAPABILITY_VIDEO_CALLING)
289                     .build();
290     final PhoneAccount mPhoneAccountE0 =
291             PhoneAccount.builder(
292                     new PhoneAccountHandle(
293                             mConnectionServiceComponentNameA,
294                             "id E 0"),
295                     "Phone account service E ID 0")
296                     .addSupportedUriScheme("tel")
297                     .setCapabilities(
298                             PhoneAccount.CAPABILITY_CALL_PROVIDER |
299                                     PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
300                                     PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)
301                     .build();
302 
303     final PhoneAccount mPhoneAccountE1 =
304             PhoneAccount.builder(
305                     new PhoneAccountHandle(
306                             mConnectionServiceComponentNameA,
307                             "id E 1"),
308                     "Phone account service E ID 1")
309                     .addSupportedUriScheme("tel")
310                     .setCapabilities(
311                             PhoneAccount.CAPABILITY_CALL_PROVIDER |
312                                     PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION |
313                                     PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS)
314                     .build();
315 
316     ConnectionServiceFixture mConnectionServiceFixtureA;
317     ConnectionServiceFixture mConnectionServiceFixtureB;
318     Timeouts.Adapter mTimeoutsAdapter;
319 
320     CallerInfoAsyncQueryFactoryFixture mCallerInfoAsyncQueryFactoryFixture;
321 
322     IAudioService mAudioService;
323 
324     TelecomSystem mTelecomSystem;
325 
326     Context mSpyContext;
327 
328     ConnectionServiceFocusManager mConnectionServiceFocusManager;
329 
330     private HandlerThread mHandlerThread;
331 
332     private int mNumOutgoingCallsMade;
333 
334     class IdPair {
335         final String mConnectionId;
336         final String mCallId;
337 
IdPair(String connectionId, String callId)338         public IdPair(String connectionId, String callId) {
339             this.mConnectionId = connectionId;
340             this.mCallId = callId;
341         }
342     }
343 
344     @Override
setUp()345     public void setUp() throws Exception {
346         super.setUp();
347         mSpyContext = mComponentContextFixture.getTestDouble().getApplicationContext();
348         doReturn(mSpyContext).when(mSpyContext).getApplicationContext();
349         doNothing().when(mSpyContext).sendBroadcastAsUser(any(), any(), any());
350 
351         mHandlerThread = new HandlerThread("TelecomHandlerThread");
352         mHandlerThread.start();
353 
354         mNumOutgoingCallsMade = 0;
355 
356         doReturn(false).when(mComponentContextFixture.getTelephonyManager())
357                 .isEmergencyNumber(any());
358         doReturn(false).when(mComponentContextFixture.getTelephonyManager())
359                 .isPotentialEmergencyNumber(any());
360 
361         // First set up information about the In-Call services in the mock Context, since
362         // Telecom will search for these as soon as it is instantiated
363         setupInCallServices();
364 
365         // Next, create the TelecomSystem, our system under test
366         setupTelecomSystem();
367         // Need to reset teseting tag here
368         Log.setTag(TESTING_TAG);
369 
370         // Finally, register the ConnectionServices with the PhoneAccountRegistrar of the
371         // now-running TelecomSystem
372         setupConnectionServices();
373 
374         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
375     }
376 
377     @Override
tearDown()378     public void tearDown() throws Exception {
379         mTelecomSystem.getCallsManager().waitOnHandlers();
380         LinkedList<HandlerThread> handlerThreads = mTelecomSystem.getCallsManager()
381                 .getGraphHandlerThreads();
382         for (HandlerThread handlerThread : handlerThreads) {
383             handlerThread.quitSafely();
384         }
385         handlerThreads.clear();
386         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
387         waitForHandlerAction(mHandlerThread.getThreadHandler(), TEST_TIMEOUT);
388         // Bring down the threads that are active.
389         mHandlerThread.quit();
390         try {
391             mHandlerThread.join();
392         } catch (InterruptedException e) {
393             // don't do anything
394         }
395 
396         mConnectionServiceFocusManager.getHandler().removeCallbacksAndMessages(null);
397         waitForHandlerAction(mConnectionServiceFocusManager.getHandler(), TEST_TIMEOUT);
398         mConnectionServiceFocusManager.getHandler().getLooper().quit();
399 
400         mConnectionServiceFixtureA.waitForHandlerToClear();
401         mConnectionServiceFixtureB.waitForHandlerToClear();
402 
403         // Print out any incomplete sessions for debugging tests
404         String sessions = Log.getSessionManager().printActiveSessions();
405         if (!TextUtils.isEmpty(sessions)) {
406             Log.w(this, "Active Sessions:\n" + sessions);
407         }
408 
409         mTelecomSystem = null;
410         super.tearDown();
411     }
412 
makeConferenceCall()413     protected ParcelableCall makeConferenceCall() throws Exception {
414         IdPair callId1 = startAndMakeActiveOutgoingCall("650-555-1212",
415                 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
416 
417         IdPair callId2 = startAndMakeActiveOutgoingCall("650-555-1213",
418                 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
419 
420         IInCallAdapter inCallAdapter = mInCallServiceFixtureX.getInCallAdapter();
421         inCallAdapter.conference(callId1.mCallId, callId2.mCallId);
422         // Wait for the handler in ConnectionService
423         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
424         ParcelableCall call1 = mInCallServiceFixtureX.getCall(callId1.mCallId);
425         ParcelableCall call2 = mInCallServiceFixtureX.getCall(callId2.mCallId);
426         // Check that the two calls end up with a parent in the end
427         assertNotNull(call1.getParentCallId());
428         assertNotNull(call2.getParentCallId());
429         assertEquals(call1.getParentCallId(), call2.getParentCallId());
430 
431         // Check to make sure that the parent call made it to the in-call service
432         String parentCallId = call1.getParentCallId();
433         ParcelableCall conferenceCall = mInCallServiceFixtureX.getCall(parentCallId);
434         assertEquals(2, conferenceCall.getChildCallIds().size());
435         assertTrue(conferenceCall.getChildCallIds().contains(callId1.mCallId));
436         assertTrue(conferenceCall.getChildCallIds().contains(callId2.mCallId));
437         return conferenceCall;
438     }
439 
setupTelecomSystem()440     private void setupTelecomSystem() throws Exception {
441         // Remove any cached PhoneAccount xml
442         File phoneAccountFile =
443                 new File(mComponentContextFixture.getTestDouble()
444                         .getApplicationContext().getFilesDir(),
445                         PhoneAccountRegistrar.FILE_NAME);
446         if (phoneAccountFile.exists()) {
447             phoneAccountFile.delete();
448         }
449 
450         // Use actual implementations instead of mocking the interface out.
451         HeadsetMediaButtonFactory headsetMediaButtonFactory =
452                 spy(new HeadsetMediaButtonFactoryF());
453         ProximitySensorManagerFactory proximitySensorManagerFactory =
454                 spy(new ProximitySensorManagerFactoryF());
455         InCallWakeLockControllerFactory inCallWakeLockControllerFactory =
456                 spy(new InCallWakeLockControllerFactoryF());
457         mAudioService = setupAudioService();
458 
459         mCallerInfoAsyncQueryFactoryFixture = new CallerInfoAsyncQueryFactoryFixture();
460 
461         ConnectionServiceFocusManager.ConnectionServiceFocusManagerFactory mConnServFMFactory =
462                 requester -> {
463                     mConnectionServiceFocusManager = new ConnectionServiceFocusManager(requester);
464                     return mConnectionServiceFocusManager;
465                 };
466 
467         mTimeoutsAdapter = mock(Timeouts.Adapter.class);
468         when(mTimeoutsAdapter.getCallScreeningTimeoutMillis(any(ContentResolver.class)))
469                 .thenReturn(TEST_TIMEOUT / 5L);
470         mIncomingCallNotifier = mock(IncomingCallNotifier.class);
471         mClockProxy = mock(ClockProxy.class);
472         when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CREATE_TIME);
473         when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CREATE_ELAPSED_TIME);
474         when(mRoleManagerAdapter.getCallCompanionApps()).thenReturn(Collections.emptyList());
475         when(mRoleManagerAdapter.getDefaultCallScreeningApp()).thenReturn(null);
476         mTelecomSystem = new TelecomSystem(
477                 mComponentContextFixture.getTestDouble(),
478                 (context, phoneAccountRegistrar, defaultDialerCache) -> mMissedCallNotifier,
479                 mCallerInfoAsyncQueryFactoryFixture.getTestDouble(),
480                 headsetMediaButtonFactory,
481                 proximitySensorManagerFactory,
482                 inCallWakeLockControllerFactory,
483                 () -> mAudioService,
484                 (context, lock, callsManager, phoneAccountRegistrar) -> mBluetoothPhoneServiceImpl,
485                 mConnServFMFactory,
486                 mTimeoutsAdapter,
487                 mAsyncRingtonePlayer,
488                 new PhoneNumberUtilsAdapterImpl(),
489                 mIncomingCallNotifier,
490                 (streamType, volume) -> mToneGenerator,
491                 new CallAudioRouteStateMachine.Factory() {
492                     @Override
493                     public CallAudioRouteStateMachine create(
494                             Context context,
495                             CallsManager callsManager,
496                             BluetoothRouteManager bluetoothManager,
497                             WiredHeadsetManager wiredHeadsetManager,
498                             StatusBarNotifier statusBarNotifier,
499                             CallAudioManager.AudioServiceFactory audioServiceFactory,
500                             int earpieceControl) {
501                         return new CallAudioRouteStateMachine(context,
502                                 callsManager,
503                                 bluetoothManager,
504                                 wiredHeadsetManager,
505                                 statusBarNotifier,
506                                 audioServiceFactory,
507                                 // Force enable an earpiece for the end-to-end tests
508                                 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED,
509                                 mHandlerThread.getLooper());
510                     }
511                 },
512                 new CallAudioModeStateMachine.Factory() {
513                     @Override
514                     public CallAudioModeStateMachine create(SystemStateHelper systemStateHelper,
515                             AudioManager am) {
516                         return new CallAudioModeStateMachine(systemStateHelper, am,
517                                 mHandlerThread.getLooper());
518                     }
519                 },
520                 mClockProxy,
521                 mRoleManagerAdapter,
522                 new IncomingCallFilter.Factory() {
523                     @Override
524                     public IncomingCallFilter create(Context context,
525                             CallFilterResultCallback listener, com.android.server.telecom.Call call,
526                             TelecomSystem.SyncRoot lock, Timeouts.Adapter timeoutsAdapter,
527                             List<IncomingCallFilter.CallFilter> filters) {
528                         return new IncomingCallFilter(context, listener, call, lock,
529                                 timeoutsAdapter, filters, mHandlerThread.getThreadHandler());
530                     }
531                 },
532                 new ContactsAsyncHelper.Factory() {
533                     @Override
534                     public ContactsAsyncHelper create(
535                             ContactsAsyncHelper.ContentResolverAdapter adapter) {
536                         return new ContactsAsyncHelper(adapter, mHandlerThread.getLooper());
537                     }
538                 });
539 
540         mComponentContextFixture.setTelecomManager(new TelecomManager(
541                 mComponentContextFixture.getTestDouble(),
542                 mTelecomSystem.getTelecomServiceImpl().getBinder()));
543 
544         verify(headsetMediaButtonFactory).create(
545                 eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
546                 any(CallsManager.class),
547                 any(TelecomSystem.SyncRoot.class));
548         verify(proximitySensorManagerFactory).create(
549                 eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
550                 any(CallsManager.class));
551         verify(inCallWakeLockControllerFactory).create(
552                 eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
553                 any(CallsManager.class));
554     }
555 
setupConnectionServices()556     private void setupConnectionServices() throws Exception {
557         mConnectionServiceFixtureA = new ConnectionServiceFixture(mContext);
558         mConnectionServiceFixtureB = new ConnectionServiceFixture(mContext);
559 
560         mComponentContextFixture.addConnectionService(mConnectionServiceComponentNameA,
561                 mConnectionServiceFixtureA.getTestDouble());
562         mComponentContextFixture.addConnectionService(mConnectionServiceComponentNameB,
563                 mConnectionServiceFixtureB.getTestDouble());
564 
565         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA0);
566         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA1);
567         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA2);
568         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountSelfManaged);
569         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountB0);
570         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountE0);
571         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountE1);
572 
573         mTelecomSystem.getPhoneAccountRegistrar().setUserSelectedOutgoingPhoneAccount(
574                 mPhoneAccountA0.getAccountHandle(), Process.myUserHandle());
575     }
576 
setupInCallServices()577     private void setupInCallServices() throws Exception {
578         mComponentContextFixture.putResource(
579                 com.android.internal.R.string.config_defaultDialer,
580                 mInCallServiceComponentNameX.getPackageName());
581         mComponentContextFixture.putResource(
582                 com.android.server.telecom.R.string.incall_default_class,
583                 mInCallServiceComponentNameX.getClassName());
584 
585         doReturn(true).when(mComponentContextFixture.getTelephonyManager())
586                 .isVoiceCapable();
587 
588         mInCallServiceFixtureX = new InCallServiceFixture();
589         mInCallServiceFixtureY = new InCallServiceFixture();
590 
591         mComponentContextFixture.addInCallService(mInCallServiceComponentNameX,
592                 mInCallServiceFixtureX.getTestDouble(), SERVICE_X_UID);
593         mComponentContextFixture.addInCallService(mInCallServiceComponentNameY,
594                 mInCallServiceFixtureY.getTestDouble(), SERVICE_Y_UID);
595     }
596 
597     /**
598      * Helper method for setting up the fake audio service.
599      * Calls to the fake audio service need to toggle the return
600      * value of AudioManager#isMicrophoneMute.
601      * @return mock of IAudioService
602      */
setupAudioService()603     private IAudioService setupAudioService() {
604         IAudioService audioService = mock(IAudioService.class);
605 
606         final AudioManager fakeAudioManager =
607                 (AudioManager) mComponentContextFixture.getTestDouble()
608                         .getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
609 
610         try {
611             doAnswer(new Answer() {
612                 @Override
613                 public Object answer(InvocationOnMock i) {
614                     Object[] args = i.getArguments();
615                     doReturn(args[0]).when(fakeAudioManager).isMicrophoneMute();
616                     return null;
617                 }
618             }).when(audioService)
619                     .setMicrophoneMute(any(Boolean.class), any(String.class), any(Integer.class));
620 
621         } catch (android.os.RemoteException e) {
622             // Do nothing, leave the faked microphone state as-is
623         }
624         return audioService;
625     }
626 
startOutgoingPhoneCallWithNoPhoneAccount(String number, ConnectionServiceFixture connectionServiceFixture)627     protected String startOutgoingPhoneCallWithNoPhoneAccount(String number,
628             ConnectionServiceFixture connectionServiceFixture)
629             throws Exception {
630 
631         startOutgoingPhoneCallWaitForBroadcaster(number, null,
632                 connectionServiceFixture, Process.myUserHandle(), VideoProfile.STATE_AUDIO_ONLY,
633                 false /*isEmergency*/);
634 
635         return mInCallServiceFixtureX.mLatestCallId;
636     }
637 
outgoingCallPhoneAccountSelected(PhoneAccountHandle phoneAccountHandle, int startingNumConnections, int startingNumCalls, ConnectionServiceFixture connectionServiceFixture)638     protected IdPair outgoingCallPhoneAccountSelected(PhoneAccountHandle phoneAccountHandle,
639             int startingNumConnections, int startingNumCalls,
640             ConnectionServiceFixture connectionServiceFixture) throws Exception {
641 
642         IdPair ids = outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls,
643                 phoneAccountHandle, connectionServiceFixture);
644 
645         connectionServiceFixture.sendSetDialing(ids.mConnectionId);
646         assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
647         assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
648 
649         connectionServiceFixture.sendSetVideoState(ids.mConnectionId);
650 
651         connectionServiceFixture.sendSetActive(ids.mConnectionId);
652         assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
653         assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
654 
655         return ids;
656     }
657 
startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser)658     protected IdPair startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle,
659             ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser)
660             throws Exception {
661 
662         return startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture,
663                 initiatingUser, VideoProfile.STATE_AUDIO_ONLY);
664     }
665 
startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, int videoState)666     protected IdPair startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle,
667             ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser,
668             int videoState) throws Exception {
669         int startingNumConnections = connectionServiceFixture.mConnectionById.size();
670         int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
671 
672         startOutgoingPhoneCallPendingCreateConnection(number, phoneAccountHandle,
673                 connectionServiceFixture, initiatingUser, videoState);
674 
675         verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
676                 .createConnectionComplete(anyString(), any());
677 
678         return outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls,
679                 phoneAccountHandle, connectionServiceFixture);
680     }
681 
triggerEmergencyRedial(PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, IdPair emergencyIds)682     protected IdPair triggerEmergencyRedial(PhoneAccountHandle phoneAccountHandle,
683             ConnectionServiceFixture connectionServiceFixture, IdPair emergencyIds)
684             throws Exception {
685         int startingNumConnections = connectionServiceFixture.mConnectionById.size();
686         int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
687 
688         // Send the message to disconnect the Emergency call due to an error.
689         // CreateConnectionProcessor should now try the second SIM account
690         connectionServiceFixture.sendSetDisconnected(emergencyIds.mConnectionId,
691                 DisconnectCause.ERROR);
692         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
693         assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(
694                 emergencyIds.mCallId).getState());
695         assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(
696                 emergencyIds.mCallId).getState());
697 
698         return redialingCallCreateConnectionComplete(startingNumConnections, startingNumCalls,
699                 phoneAccountHandle, connectionServiceFixture);
700     }
701 
startOutgoingEmergencyCall(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, int videoState)702     protected IdPair startOutgoingEmergencyCall(String number,
703             PhoneAccountHandle phoneAccountHandle,
704             ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser,
705             int videoState) throws Exception {
706         int startingNumConnections = connectionServiceFixture.mConnectionById.size();
707         int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
708 
709         doReturn(true).when(mComponentContextFixture.getTelephonyManager())
710                 .isEmergencyNumber(any());
711         doReturn(true).when(mComponentContextFixture.getTelephonyManager())
712                 .isPotentialEmergencyNumber(any());
713 
714         // Call will not use the ordered broadcaster, since it is an Emergency Call
715         startOutgoingPhoneCallWaitForBroadcaster(number, phoneAccountHandle,
716                 connectionServiceFixture, initiatingUser, videoState, true /*isEmergency*/);
717 
718         return outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls,
719                 phoneAccountHandle, connectionServiceFixture);
720     }
721 
startOutgoingPhoneCallWaitForBroadcaster(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, int videoState, boolean isEmergency)722     protected void startOutgoingPhoneCallWaitForBroadcaster(String number,
723             PhoneAccountHandle phoneAccountHandle,
724             ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser,
725             int videoState, boolean isEmergency) throws Exception {
726         reset(connectionServiceFixture.getTestDouble(), mInCallServiceFixtureX.getTestDouble(),
727                 mInCallServiceFixtureY.getTestDouble());
728 
729         assertEquals(mInCallServiceFixtureX.mCallById.size(),
730                 mInCallServiceFixtureY.mCallById.size());
731         assertEquals((mInCallServiceFixtureX.mInCallAdapter != null),
732                 (mInCallServiceFixtureY.mInCallAdapter != null));
733 
734         mNumOutgoingCallsMade++;
735 
736         boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null;
737 
738         Intent actionCallIntent = new Intent();
739         actionCallIntent.setData(Uri.parse("tel:" + number));
740         actionCallIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
741         if(isEmergency) {
742             actionCallIntent.setAction(Intent.ACTION_CALL_EMERGENCY);
743         } else {
744             actionCallIntent.setAction(Intent.ACTION_CALL);
745         }
746         if (phoneAccountHandle != null) {
747             actionCallIntent.putExtra(
748                     TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
749                     phoneAccountHandle);
750         }
751         if (videoState != VideoProfile.STATE_AUDIO_ONLY) {
752             actionCallIntent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);
753         }
754 
755         final UserHandle userHandle = initiatingUser;
756         Context localAppContext = mComponentContextFixture.getTestDouble().getApplicationContext();
757         new UserCallIntentProcessor(localAppContext, userHandle).processIntent(
758                 actionCallIntent, null, true /* hasCallAppOp*/, false /* isLocal */);
759         // Wait for handler to start CallerInfo lookup.
760         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
761         // Send the CallerInfo lookup reply.
762         mCallerInfoAsyncQueryFactoryFixture.mRequests.forEach(
763                 CallerInfoAsyncQueryFactoryFixture.Request::reply);
764         if (phoneAccountHandle != null) {
765             mTelecomSystem.getCallsManager().getLatestPostSelectionProcessingFuture().join();
766         }
767         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
768 
769         boolean isSelfManaged = phoneAccountHandle == mPhoneAccountSelfManaged.getAccountHandle();
770         if (!hasInCallAdapter && !isSelfManaged) {
771             verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
772                     .setInCallAdapter(
773                             any(IInCallAdapter.class));
774             verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT))
775                     .setInCallAdapter(
776                             any(IInCallAdapter.class));
777         }
778     }
779 
startOutgoingPhoneCallPendingCreateConnection(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, int videoState)780     protected String startOutgoingPhoneCallPendingCreateConnection(String number,
781             PhoneAccountHandle phoneAccountHandle,
782             ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser,
783             int videoState) throws Exception {
784         startOutgoingPhoneCallWaitForBroadcaster(number,phoneAccountHandle,
785                 connectionServiceFixture, initiatingUser, videoState, false /*isEmergency*/);
786         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
787 
788         verifyAndProcessOutgoingCallBroadcast(phoneAccountHandle);
789         return mInCallServiceFixtureX.mLatestCallId;
790     }
791 
verifyAndProcessOutgoingCallBroadcast(PhoneAccountHandle phoneAccountHandle)792     protected void verifyAndProcessOutgoingCallBroadcast(PhoneAccountHandle phoneAccountHandle) {
793         ArgumentCaptor<Intent> newOutgoingCallIntent =
794                 ArgumentCaptor.forClass(Intent.class);
795         ArgumentCaptor<BroadcastReceiver> newOutgoingCallReceiver =
796                 ArgumentCaptor.forClass(BroadcastReceiver.class);
797 
798         if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
799             verify(mComponentContextFixture.getTestDouble().getApplicationContext(),
800                     times(mNumOutgoingCallsMade))
801                     .sendOrderedBroadcastAsUser(
802                             newOutgoingCallIntent.capture(),
803                             any(UserHandle.class),
804                             anyString(),
805                             anyInt(),
806                             any(Bundle.class),
807                             newOutgoingCallReceiver.capture(),
808                             nullable(Handler.class),
809                             anyInt(),
810                             anyString(),
811                             nullable(Bundle.class));
812             // Pass on the new outgoing call Intent
813             // Set a dummy PendingResult so the BroadcastReceiver agrees to accept onReceive()
814             newOutgoingCallReceiver.getValue().setPendingResult(
815                     new BroadcastReceiver.PendingResult(0, "", null, 0, true, false, null, 0, 0));
816             newOutgoingCallReceiver.getValue().setResultData(
817                     newOutgoingCallIntent.getValue().getStringExtra(Intent.EXTRA_PHONE_NUMBER));
818             newOutgoingCallReceiver.getValue().onReceive(mComponentContextFixture.getTestDouble(),
819                     newOutgoingCallIntent.getValue());
820         }
821 
822     }
823 
824     // When Telecom is redialing due to an error, we need to make sure the number of connections
825     // increase, but not the number of Calls in the InCallService.
redialingCallCreateConnectionComplete(int startingNumConnections, int startingNumCalls, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture)826     protected IdPair redialingCallCreateConnectionComplete(int startingNumConnections,
827             int startingNumCalls, PhoneAccountHandle phoneAccountHandle,
828             ConnectionServiceFixture connectionServiceFixture) throws Exception {
829 
830         assertEquals(startingNumConnections + 1, connectionServiceFixture.mConnectionById.size());
831 
832         verify(connectionServiceFixture.getTestDouble())
833                 .createConnection(eq(phoneAccountHandle), anyString(), any(ConnectionRequest.class),
834                         eq(false)/*isIncoming*/, anyBoolean(), any());
835         // Wait for handleCreateConnectionComplete
836         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
837 
838         // Make sure the number of registered InCallService Calls stays the same.
839         assertEquals(startingNumCalls, mInCallServiceFixtureX.mCallById.size());
840         assertEquals(startingNumCalls, mInCallServiceFixtureY.mCallById.size());
841 
842         assertEquals(mInCallServiceFixtureX.mLatestCallId, mInCallServiceFixtureY.mLatestCallId);
843 
844         return new IdPair(connectionServiceFixture.mLatestConnectionId,
845                 mInCallServiceFixtureX.mLatestCallId);
846     }
847 
outgoingCallCreateConnectionComplete(int startingNumConnections, int startingNumCalls, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture)848     protected IdPair outgoingCallCreateConnectionComplete(int startingNumConnections,
849             int startingNumCalls, PhoneAccountHandle phoneAccountHandle,
850             ConnectionServiceFixture connectionServiceFixture) throws Exception {
851 
852         // Wait for the focus tracker.
853         waitForHandlerAction(mTelecomSystem.getCallsManager()
854                 .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT);
855 
856         verify(connectionServiceFixture.getTestDouble())
857                 .createConnection(eq(phoneAccountHandle), anyString(), any(ConnectionRequest.class),
858                         eq(false)/*isIncoming*/, anyBoolean(), any());
859         // Wait for handleCreateConnectionComplete
860         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
861         assertEquals(startingNumConnections + 1,
862                 connectionServiceFixture.mConnectionById.size());
863 
864         // Wait for the callback in ConnectionService#onAdapterAttached to execute.
865         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
866 
867         // Ensure callback to CS on successful creation happened.
868         verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
869                 .createConnectionComplete(anyString(), any());
870 
871         if (phoneAccountHandle == mPhoneAccountSelfManaged.getAccountHandle()) {
872             assertEquals(startingNumCalls, mInCallServiceFixtureX.mCallById.size());
873             assertEquals(startingNumCalls, mInCallServiceFixtureY.mCallById.size());
874         } else {
875             assertEquals(startingNumCalls + 1, mInCallServiceFixtureX.mCallById.size());
876             assertEquals(startingNumCalls + 1, mInCallServiceFixtureY.mCallById.size());
877         }
878 
879         assertEquals(mInCallServiceFixtureX.mLatestCallId, mInCallServiceFixtureY.mLatestCallId);
880 
881         return new IdPair(connectionServiceFixture.mLatestConnectionId,
882                 mInCallServiceFixtureX.mLatestCallId);
883     }
884 
startIncomingPhoneCall( String number, PhoneAccountHandle phoneAccountHandle, final ConnectionServiceFixture connectionServiceFixture)885     protected IdPair startIncomingPhoneCall(
886             String number,
887             PhoneAccountHandle phoneAccountHandle,
888             final ConnectionServiceFixture connectionServiceFixture) throws Exception {
889         return startIncomingPhoneCall(number, phoneAccountHandle, VideoProfile.STATE_AUDIO_ONLY,
890                 connectionServiceFixture);
891     }
892 
startIncomingPhoneCall( String number, PhoneAccountHandle phoneAccountHandle, int videoState, final ConnectionServiceFixture connectionServiceFixture)893     protected IdPair startIncomingPhoneCall(
894             String number,
895             PhoneAccountHandle phoneAccountHandle,
896             int videoState,
897             final ConnectionServiceFixture connectionServiceFixture) throws Exception {
898         reset(connectionServiceFixture.getTestDouble(), mInCallServiceFixtureX.getTestDouble(),
899                 mInCallServiceFixtureY.getTestDouble());
900 
901         assertEquals(mInCallServiceFixtureX.mCallById.size(),
902                 mInCallServiceFixtureY.mCallById.size());
903         assertEquals((mInCallServiceFixtureX.mInCallAdapter != null),
904                 (mInCallServiceFixtureY.mInCallAdapter != null));
905         final int startingNumConnections = connectionServiceFixture.mConnectionById.size();
906         final int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
907         boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null;
908         connectionServiceFixture.mConnectionServiceDelegate.mVideoState = videoState;
909         CountDownLatch incomingCallAddedLatch = new CountDownLatch(1);
910         IncomingCallAddedListener callAddedListener =
911                 new IncomingCallAddedListener(incomingCallAddedLatch);
912         mTelecomSystem.getCallsManager().addListener(callAddedListener);
913 
914         Bundle extras = new Bundle();
915         extras.putParcelable(
916                 TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
917                 Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null));
918         mTelecomSystem.getTelecomServiceImpl().getBinder()
919                 .addNewIncomingCall(phoneAccountHandle, extras);
920 
921         verify(connectionServiceFixture.getTestDouble())
922                 .createConnection(any(PhoneAccountHandle.class), anyString(),
923                         any(ConnectionRequest.class), eq(true), eq(false), any());
924 
925         // Wait for the handler to start the CallerInfo lookup
926         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
927 
928         // Ensure callback to CS on successful creation happened.
929         verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
930                 .createConnectionComplete(anyString(), any());
931 
932         // Process the CallerInfo lookup reply
933         mCallerInfoAsyncQueryFactoryFixture.mRequests.forEach(
934                 CallerInfoAsyncQueryFactoryFixture.Request::reply);
935 
936         //Wait for/Verify call blocking happened asynchronously
937         incomingCallAddedLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
938 
939         // For the case of incoming calls, Telecom connecting the InCall services and adding the
940         // Call is triggered by the async completion of the CallerInfoAsyncQuery. Once the Call
941         // is added, future interactions as triggered by the ConnectionService, through the various
942         // test fixtures, will be synchronous.
943 
944         if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
945             if (!hasInCallAdapter) {
946                 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
947                         .setInCallAdapter(any(IInCallAdapter.class));
948                 verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT))
949                         .setInCallAdapter(any(IInCallAdapter.class));
950 
951                 // Give the InCallService time to respond
952                 assertTrueWithTimeout(new Predicate<Void>() {
953                     @Override
954                     public boolean apply(Void v) {
955                         return mInCallServiceFixtureX.mInCallAdapter != null;
956                     }
957                 });
958 
959                 assertTrueWithTimeout(new Predicate<Void>() {
960                     @Override
961                     public boolean apply(Void v) {
962                         return mInCallServiceFixtureY.mInCallAdapter != null;
963                     }
964                 });
965 
966                 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
967                         .addCall(any(ParcelableCall.class));
968                 verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT))
969                         .addCall(any(ParcelableCall.class));
970 
971                 // Give the InCallService time to respond
972             }
973 
974             assertTrueWithTimeout(new Predicate<Void>() {
975                 @Override
976                 public boolean apply(Void v) {
977                     return startingNumConnections + 1 ==
978                             connectionServiceFixture.mConnectionById.size();
979                 }
980             });
981 
982             mInCallServiceFixtureX.waitUntilNumCalls(startingNumCalls + 1);
983             mInCallServiceFixtureY.waitUntilNumCalls(startingNumCalls + 1);
984             assertEquals(startingNumCalls + 1, mInCallServiceFixtureX.mCallById.size());
985             assertEquals(startingNumCalls + 1, mInCallServiceFixtureY.mCallById.size());
986 
987             assertEquals(mInCallServiceFixtureX.mLatestCallId,
988                     mInCallServiceFixtureY.mLatestCallId);
989         }
990 
991         return new IdPair(connectionServiceFixture.mLatestConnectionId,
992                 mInCallServiceFixtureX.mLatestCallId);
993     }
994 
startAndMakeActiveOutgoingCall( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture)995     protected IdPair startAndMakeActiveOutgoingCall(
996             String number,
997             PhoneAccountHandle phoneAccountHandle,
998             ConnectionServiceFixture connectionServiceFixture) throws Exception {
999         return startAndMakeActiveOutgoingCall(number, phoneAccountHandle, connectionServiceFixture,
1000                 VideoProfile.STATE_AUDIO_ONLY);
1001     }
1002 
1003     // A simple outgoing call, verifying that the appropriate connection service is contacted,
1004     // the proper lifecycle is followed, and both In-Call Services are updated correctly.
startAndMakeActiveOutgoingCall( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, int videoState)1005     protected IdPair startAndMakeActiveOutgoingCall(
1006             String number,
1007             PhoneAccountHandle phoneAccountHandle,
1008             ConnectionServiceFixture connectionServiceFixture, int videoState) throws Exception {
1009         IdPair ids = startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture,
1010                 Process.myUserHandle(), videoState);
1011 
1012         connectionServiceFixture.sendSetDialing(ids.mConnectionId);
1013         if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
1014             assertEquals(Call.STATE_DIALING,
1015                     mInCallServiceFixtureX.getCall(ids.mCallId).getState());
1016             assertEquals(Call.STATE_DIALING,
1017                     mInCallServiceFixtureY.getCall(ids.mCallId).getState());
1018         }
1019 
1020         connectionServiceFixture.sendSetVideoState(ids.mConnectionId);
1021 
1022         when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CONNECT_TIME);
1023         when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CONNECT_ELAPSED_TIME);
1024         connectionServiceFixture.sendSetActive(ids.mConnectionId);
1025         if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
1026             assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
1027             assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
1028 
1029             if ((mInCallServiceFixtureX.getCall(ids.mCallId).getProperties() &
1030                     Call.Details.PROPERTY_IS_EXTERNAL_CALL) == 0) {
1031                 // Test the PhoneStateBroadcaster functionality if the call is not external.
1032                 verify(mContext.getSystemService(TelephonyRegistryManager.class),
1033                         timeout(TEST_TIMEOUT).atLeastOnce())
1034                         .notifyCallStateChangedForAllSubscriptions(
1035                                 eq(TelephonyManager.CALL_STATE_OFFHOOK),
1036                                 nullable(String.class));
1037             }
1038         }
1039         return ids;
1040     }
1041 
startAndMakeActiveIncomingCall( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture)1042     protected IdPair startAndMakeActiveIncomingCall(
1043             String number,
1044             PhoneAccountHandle phoneAccountHandle,
1045             ConnectionServiceFixture connectionServiceFixture) throws Exception {
1046         return startAndMakeActiveIncomingCall(number, phoneAccountHandle, connectionServiceFixture,
1047                 VideoProfile.STATE_AUDIO_ONLY);
1048     }
1049 
1050     // A simple incoming call, similar in scope to the previous test
startAndMakeActiveIncomingCall( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, int videoState)1051     protected IdPair startAndMakeActiveIncomingCall(
1052             String number,
1053             PhoneAccountHandle phoneAccountHandle,
1054             ConnectionServiceFixture connectionServiceFixture,
1055             int videoState) throws Exception {
1056         IdPair ids = startIncomingPhoneCall(number, phoneAccountHandle, connectionServiceFixture);
1057 
1058         if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
1059             assertEquals(Call.STATE_RINGING,
1060                     mInCallServiceFixtureX.getCall(ids.mCallId).getState());
1061             assertEquals(Call.STATE_RINGING,
1062                     mInCallServiceFixtureY.getCall(ids.mCallId).getState());
1063 
1064             mInCallServiceFixtureX.mInCallAdapter
1065                     .answerCall(ids.mCallId, videoState);
1066             // Wait on the CS focus manager handler
1067             waitForHandlerAction(mTelecomSystem.getCallsManager()
1068                     .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT);
1069 
1070             if (!VideoProfile.isVideo(videoState)) {
1071                 verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
1072                         .answer(eq(ids.mConnectionId), any());
1073             } else {
1074                 verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
1075                         .answerVideo(eq(ids.mConnectionId), eq(videoState), any());
1076             }
1077         }
1078 
1079         when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CONNECT_TIME);
1080         when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CONNECT_ELAPSED_TIME);
1081         connectionServiceFixture.sendSetActive(ids.mConnectionId);
1082 
1083         if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
1084             assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
1085             assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
1086 
1087             if ((mInCallServiceFixtureX.getCall(ids.mCallId).getProperties() &
1088                     Call.Details.PROPERTY_IS_EXTERNAL_CALL) == 0) {
1089                 // Test the PhoneStateBroadcaster functionality if the call is not external.
1090                 verify(mContext.getSystemService(TelephonyRegistryManager.class),
1091                         timeout(TEST_TIMEOUT).atLeastOnce())
1092                         .notifyCallStateChangedForAllSubscriptions(
1093                                 eq(TelephonyManager.CALL_STATE_OFFHOOK),
1094                                 nullable(String.class));
1095             }
1096         }
1097         return ids;
1098     }
1099 
startAndMakeDialingEmergencyCall( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture)1100     protected IdPair startAndMakeDialingEmergencyCall(
1101             String number,
1102             PhoneAccountHandle phoneAccountHandle,
1103             ConnectionServiceFixture connectionServiceFixture) throws Exception {
1104         IdPair ids = startOutgoingEmergencyCall(number, phoneAccountHandle,
1105                 connectionServiceFixture, Process.myUserHandle(), VideoProfile.STATE_AUDIO_ONLY);
1106 
1107         connectionServiceFixture.sendSetDialing(ids.mConnectionId);
1108         assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
1109         assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
1110 
1111         return ids;
1112     }
1113 
assertTrueWithTimeout(Predicate<Void> predicate)1114     protected static void assertTrueWithTimeout(Predicate<Void> predicate) {
1115         int elapsed = 0;
1116         while (elapsed < TEST_TIMEOUT) {
1117             if (predicate.apply(null)) {
1118                 return;
1119             } else {
1120                 try {
1121                     Thread.sleep(TEST_POLL_INTERVAL);
1122                     elapsed += TEST_POLL_INTERVAL;
1123                 } catch (InterruptedException e) {
1124                     fail(e.toString());
1125                 }
1126             }
1127         }
1128         fail("Timeout in assertTrueWithTimeout");
1129     }
1130 }
1131