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