• 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 import android.text.TextUtils;
70 
71 import com.android.internal.telecom.IInCallAdapter;
72 import com.android.server.telecom.AsyncRingtonePlayer;
73 import com.android.server.telecom.CallAudioManager;
74 import com.android.server.telecom.CallAudioModeStateMachine;
75 import com.android.server.telecom.CallAudioRouteStateMachine;
76 import com.android.server.telecom.CallerInfoLookupHelper;
77 import com.android.server.telecom.CallsManager;
78 import com.android.server.telecom.CallsManagerListenerBase;
79 import com.android.server.telecom.ClockProxy;
80 import com.android.server.telecom.ConnectionServiceFocusManager;
81 import com.android.server.telecom.ContactsAsyncHelper;
82 import com.android.server.telecom.DeviceIdleControllerAdapter;
83 import com.android.server.telecom.HeadsetMediaButton;
84 import com.android.server.telecom.HeadsetMediaButtonFactory;
85 import com.android.server.telecom.InCallWakeLockController;
86 import com.android.server.telecom.InCallWakeLockControllerFactory;
87 import com.android.server.telecom.MissedCallNotifier;
88 import com.android.server.telecom.PhoneAccountRegistrar;
89 import com.android.server.telecom.PhoneNumberUtilsAdapterImpl;
90 import com.android.server.telecom.ProximitySensorManager;
91 import com.android.server.telecom.ProximitySensorManagerFactory;
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.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 AsyncRingtonePlayer mAsyncRingtonePlayer;
205     @Mock IncomingCallNotifier mIncomingCallNotifier;
206     @Mock ClockProxy mClockProxy;
207     @Mock RoleManagerAdapter mRoleManagerAdapter;
208     @Mock ToneGenerator mToneGenerator;
209     @Mock DeviceIdleControllerAdapter mDeviceIdleControllerAdapter;
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         doReturn(mock(AppOpsManager.class)).when(mSpyContext).getSystemService(AppOpsManager.class);
352         doReturn(mock(BluetoothManager.class)).when(mSpyContext).getSystemService(BluetoothManager.class);
353 
354         mHandlerThread = new HandlerThread("TelecomHandlerThread");
355         mHandlerThread.start();
356 
357         mNumOutgoingCallsMade = 0;
358 
359         doReturn(false).when(mComponentContextFixture.getTelephonyManager())
360                 .isEmergencyNumber(any());
361         doReturn(false).when(mComponentContextFixture.getTelephonyManager())
362                 .isPotentialEmergencyNumber(any());
363 
364         // First set up information about the In-Call services in the mock Context, since
365         // Telecom will search for these as soon as it is instantiated
366         setupInCallServices();
367 
368         // Next, create the TelecomSystem, our system under test
369         setupTelecomSystem();
370         // Need to reset testing tag here
371         Log.setTag(TESTING_TAG);
372 
373         // Finally, register the ConnectionServices with the PhoneAccountRegistrar of the
374         // now-running TelecomSystem
375         setupConnectionServices();
376 
377         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
378     }
379 
380     @Override
tearDown()381     public void tearDown() throws Exception {
382         mTelecomSystem.getCallsManager().waitOnHandlers();
383         LinkedList<HandlerThread> handlerThreads = mTelecomSystem.getCallsManager()
384                 .getGraphHandlerThreads();
385         for (HandlerThread handlerThread : handlerThreads) {
386             handlerThread.quitSafely();
387         }
388         handlerThreads.clear();
389         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
390         waitForHandlerAction(mHandlerThread.getThreadHandler(), TEST_TIMEOUT);
391         // Bring down the threads that are active.
392         mHandlerThread.quit();
393         try {
394             mHandlerThread.join();
395         } catch (InterruptedException e) {
396             // don't do anything
397         }
398 
399         mConnectionServiceFocusManager.getHandler().removeCallbacksAndMessages(null);
400         waitForHandlerAction(mConnectionServiceFocusManager.getHandler(), TEST_TIMEOUT);
401         mConnectionServiceFocusManager.getHandler().getLooper().quit();
402 
403         mConnectionServiceFixtureA.waitForHandlerToClear();
404         mConnectionServiceFixtureB.waitForHandlerToClear();
405 
406         // Forcefully clean all sessions at the end of the test, which will also log any stale
407         // sessions for debugging.
408         Log.getSessionManager().cleanupStaleSessions(0);
409 
410         mTelecomSystem = null;
411         super.tearDown();
412     }
413 
makeConferenceCall( Intent callIntentExtras1, Intent callIntentExtras2)414     protected ParcelableCall makeConferenceCall(
415             Intent callIntentExtras1, Intent callIntentExtras2) throws Exception {
416         IdPair callId1 = startAndMakeActiveOutgoingCallWithExtras("650-555-1212",
417                 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, callIntentExtras1);
418 
419         IdPair callId2 = startAndMakeActiveOutgoingCallWithExtras("650-555-1213",
420                 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, callIntentExtras2);
421 
422         IInCallAdapter inCallAdapter = mInCallServiceFixtureX.getInCallAdapter();
423         inCallAdapter.conference(callId1.mCallId, callId2.mCallId);
424         // Wait for the handler in ConnectionService
425         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
426         ParcelableCall call1 = mInCallServiceFixtureX.getCall(callId1.mCallId);
427         ParcelableCall call2 = mInCallServiceFixtureX.getCall(callId2.mCallId);
428         // Check that the two calls end up with a parent in the end
429         assertNotNull(call1.getParentCallId());
430         assertNotNull(call2.getParentCallId());
431         assertEquals(call1.getParentCallId(), call2.getParentCallId());
432 
433         // Check to make sure that the parent call made it to the in-call service
434         String parentCallId = call1.getParentCallId();
435         ParcelableCall conferenceCall = mInCallServiceFixtureX.getCall(parentCallId);
436         assertEquals(2, conferenceCall.getChildCallIds().size());
437         assertTrue(conferenceCall.getChildCallIds().contains(callId1.mCallId));
438         assertTrue(conferenceCall.getChildCallIds().contains(callId2.mCallId));
439         return conferenceCall;
440     }
441 
setupTelecomSystem()442     private void setupTelecomSystem() throws Exception {
443         // Remove any cached PhoneAccount xml
444         File phoneAccountFile =
445                 new File(mComponentContextFixture.getTestDouble()
446                         .getApplicationContext().getFilesDir(),
447                         PhoneAccountRegistrar.FILE_NAME);
448         if (phoneAccountFile.exists()) {
449             phoneAccountFile.delete();
450         }
451 
452         // Use actual implementations instead of mocking the interface out.
453         HeadsetMediaButtonFactory headsetMediaButtonFactory =
454                 spy(new HeadsetMediaButtonFactoryF());
455         ProximitySensorManagerFactory proximitySensorManagerFactory =
456                 spy(new ProximitySensorManagerFactoryF());
457         InCallWakeLockControllerFactory inCallWakeLockControllerFactory =
458                 spy(new InCallWakeLockControllerFactoryF());
459         mAudioService = setupAudioService();
460 
461         mCallerInfoAsyncQueryFactoryFixture = new CallerInfoAsyncQueryFactoryFixture();
462 
463         ConnectionServiceFocusManager.ConnectionServiceFocusManagerFactory mConnServFMFactory =
464                 requester -> {
465                     mConnectionServiceFocusManager = new ConnectionServiceFocusManager(requester);
466                     return mConnectionServiceFocusManager;
467                 };
468 
469         mTimeoutsAdapter = mock(Timeouts.Adapter.class);
470         when(mTimeoutsAdapter.getCallScreeningTimeoutMillis(any(ContentResolver.class)))
471                 .thenReturn(TEST_TIMEOUT / 5L);
472         mIncomingCallNotifier = mock(IncomingCallNotifier.class);
473         mClockProxy = mock(ClockProxy.class);
474         when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CREATE_TIME);
475         when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CREATE_ELAPSED_TIME);
476         when(mRoleManagerAdapter.getCallCompanionApps()).thenReturn(Collections.emptyList());
477         when(mRoleManagerAdapter.getDefaultCallScreeningApp()).thenReturn(null);
478         mTelecomSystem = new TelecomSystem(
479                 mComponentContextFixture.getTestDouble(),
480                 (context, phoneAccountRegistrar, defaultDialerCache, mDeviceIdleControllerAdapter)
481                         -> mMissedCallNotifier,
482                 mCallerInfoAsyncQueryFactoryFixture.getTestDouble(),
483                 headsetMediaButtonFactory,
484                 proximitySensorManagerFactory,
485                 inCallWakeLockControllerFactory,
486                 () -> mAudioService,
487                 mConnServFMFactory,
488                 mTimeoutsAdapter,
489                 mAsyncRingtonePlayer,
490                 new PhoneNumberUtilsAdapterImpl(),
491                 mIncomingCallNotifier,
492                 (streamType, volume) -> mToneGenerator,
493                 new CallAudioRouteStateMachine.Factory() {
494                     @Override
495                     public CallAudioRouteStateMachine create(
496                             Context context,
497                             CallsManager callsManager,
498                             BluetoothRouteManager bluetoothManager,
499                             WiredHeadsetManager wiredHeadsetManager,
500                             StatusBarNotifier statusBarNotifier,
501                             CallAudioManager.AudioServiceFactory audioServiceFactory,
502                             int earpieceControl) {
503                         return new CallAudioRouteStateMachine(context,
504                                 callsManager,
505                                 bluetoothManager,
506                                 wiredHeadsetManager,
507                                 statusBarNotifier,
508                                 audioServiceFactory,
509                                 // Force enable an earpiece for the end-to-end tests
510                                 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED,
511                                 mHandlerThread.getLooper());
512                     }
513                 },
514                 new CallAudioModeStateMachine.Factory() {
515                     @Override
516                     public CallAudioModeStateMachine create(SystemStateHelper systemStateHelper,
517                             AudioManager am) {
518                         return new CallAudioModeStateMachine(systemStateHelper, am,
519                                 mHandlerThread.getLooper());
520                     }
521                 },
522                 mClockProxy,
523                 mRoleManagerAdapter,
524                 new ContactsAsyncHelper.Factory() {
525                     @Override
526                     public ContactsAsyncHelper create(
527                             ContactsAsyncHelper.ContentResolverAdapter adapter) {
528                         return new ContactsAsyncHelper(adapter, mHandlerThread.getLooper());
529                     }
530                 }, mDeviceIdleControllerAdapter);
531 
532         mComponentContextFixture.setTelecomManager(new TelecomManager(
533                 mComponentContextFixture.getTestDouble(),
534                 mTelecomSystem.getTelecomServiceImpl().getBinder()));
535 
536         verify(headsetMediaButtonFactory).create(
537                 eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
538                 any(CallsManager.class),
539                 any(TelecomSystem.SyncRoot.class));
540         verify(proximitySensorManagerFactory).create(
541                 eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
542                 any(CallsManager.class));
543         verify(inCallWakeLockControllerFactory).create(
544                 eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
545                 any(CallsManager.class));
546     }
547 
setupConnectionServices()548     private void setupConnectionServices() throws Exception {
549         mConnectionServiceFixtureA = new ConnectionServiceFixture(mContext);
550         mConnectionServiceFixtureB = new ConnectionServiceFixture(mContext);
551 
552         mComponentContextFixture.addConnectionService(mConnectionServiceComponentNameA,
553                 mConnectionServiceFixtureA.getTestDouble());
554         mComponentContextFixture.addConnectionService(mConnectionServiceComponentNameB,
555                 mConnectionServiceFixtureB.getTestDouble());
556 
557         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA0);
558         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA1);
559         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA2);
560         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountSelfManaged);
561         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountB0);
562         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountE0);
563         mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountE1);
564 
565         mTelecomSystem.getPhoneAccountRegistrar().setUserSelectedOutgoingPhoneAccount(
566                 mPhoneAccountA0.getAccountHandle(), Process.myUserHandle());
567     }
568 
setupInCallServices()569     private void setupInCallServices() throws Exception {
570         mComponentContextFixture.putResource(
571                 com.android.internal.R.string.config_defaultDialer,
572                 mInCallServiceComponentNameX.getPackageName());
573         mComponentContextFixture.putResource(
574                 com.android.server.telecom.R.string.incall_default_class,
575                 mInCallServiceComponentNameX.getClassName());
576 
577         mInCallServiceFixtureX = new InCallServiceFixture();
578         mInCallServiceFixtureY = new InCallServiceFixture();
579 
580         mComponentContextFixture.addInCallService(mInCallServiceComponentNameX,
581                 mInCallServiceFixtureX.getTestDouble(), SERVICE_X_UID);
582         mComponentContextFixture.addInCallService(mInCallServiceComponentNameY,
583                 mInCallServiceFixtureY.getTestDouble(), SERVICE_Y_UID);
584     }
585 
586     /**
587      * Helper method for setting up the fake audio service.
588      * Calls to the fake audio service need to toggle the return
589      * value of AudioManager#isMicrophoneMute.
590      * @return mock of IAudioService
591      */
setupAudioService()592     private IAudioService setupAudioService() {
593         IAudioService audioService = mock(IAudioService.class);
594 
595         final AudioManager fakeAudioManager =
596                 (AudioManager) mComponentContextFixture.getTestDouble()
597                         .getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
598 
599         try {
600             doAnswer(new Answer() {
601                 @Override
602                 public Object answer(InvocationOnMock i) {
603                     Object[] args = i.getArguments();
604                     doReturn(args[0]).when(fakeAudioManager).isMicrophoneMute();
605                     return null;
606                 }
607             }).when(audioService).setMicrophoneMute(any(Boolean.class), any(String.class),
608                     any(Integer.class), nullable(String.class));
609 
610         } catch (android.os.RemoteException e) {
611             // Do nothing, leave the faked microphone state as-is
612         }
613         return audioService;
614     }
615 
startOutgoingPhoneCallWithNoPhoneAccount(String number, ConnectionServiceFixture connectionServiceFixture)616     protected String startOutgoingPhoneCallWithNoPhoneAccount(String number,
617             ConnectionServiceFixture connectionServiceFixture)
618             throws Exception {
619 
620         startOutgoingPhoneCallWaitForBroadcaster(number, null,
621                 connectionServiceFixture, Process.myUserHandle(), VideoProfile.STATE_AUDIO_ONLY,
622                 false /*isEmergency*/, null);
623 
624         return mInCallServiceFixtureX.mLatestCallId;
625     }
626 
outgoingCallPhoneAccountSelected(PhoneAccountHandle phoneAccountHandle, int startingNumConnections, int startingNumCalls, ConnectionServiceFixture connectionServiceFixture)627     protected IdPair outgoingCallPhoneAccountSelected(PhoneAccountHandle phoneAccountHandle,
628             int startingNumConnections, int startingNumCalls,
629             ConnectionServiceFixture connectionServiceFixture) throws Exception {
630 
631         IdPair ids = outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls,
632                 phoneAccountHandle, connectionServiceFixture);
633 
634         connectionServiceFixture.sendSetDialing(ids.mConnectionId);
635         assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
636         assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
637 
638         connectionServiceFixture.sendSetVideoState(ids.mConnectionId);
639 
640         connectionServiceFixture.sendSetActive(ids.mConnectionId);
641         assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
642         assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
643 
644         return ids;
645     }
646 
startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser)647     protected IdPair startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle,
648             ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser)
649             throws Exception {
650 
651         return startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture,
652                 initiatingUser, VideoProfile.STATE_AUDIO_ONLY, null);
653     }
654 
startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, int videoState, Intent callIntentExtras)655     protected IdPair startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle,
656             ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser,
657             int videoState, Intent callIntentExtras) throws Exception {
658         int startingNumConnections = connectionServiceFixture.mConnectionById.size();
659         int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
660 
661         startOutgoingPhoneCallPendingCreateConnection(number, phoneAccountHandle,
662                 connectionServiceFixture, initiatingUser, videoState, callIntentExtras);
663 
664         verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
665                 .createConnectionComplete(anyString(), any());
666 
667         return outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls,
668                 phoneAccountHandle, connectionServiceFixture);
669     }
670 
triggerEmergencyRedial(PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, IdPair emergencyIds)671     protected IdPair triggerEmergencyRedial(PhoneAccountHandle phoneAccountHandle,
672             ConnectionServiceFixture connectionServiceFixture, IdPair emergencyIds)
673             throws Exception {
674         int startingNumConnections = connectionServiceFixture.mConnectionById.size();
675         int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
676 
677         // Send the message to disconnect the Emergency call due to an error.
678         // CreateConnectionProcessor should now try the second SIM account
679         connectionServiceFixture.sendSetDisconnected(emergencyIds.mConnectionId,
680                 DisconnectCause.ERROR);
681         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
682         assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(
683                 emergencyIds.mCallId).getState());
684         assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(
685                 emergencyIds.mCallId).getState());
686 
687         return redialingCallCreateConnectionComplete(startingNumConnections, startingNumCalls,
688                 phoneAccountHandle, connectionServiceFixture);
689     }
690 
startOutgoingEmergencyCall(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, int videoState)691     protected IdPair startOutgoingEmergencyCall(String number,
692             PhoneAccountHandle phoneAccountHandle,
693             ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser,
694             int videoState) throws Exception {
695         int startingNumConnections = connectionServiceFixture.mConnectionById.size();
696         int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
697 
698         doReturn(true).when(mComponentContextFixture.getTelephonyManager())
699                 .isEmergencyNumber(any());
700         doReturn(true).when(mComponentContextFixture.getTelephonyManager())
701                 .isPotentialEmergencyNumber(any());
702 
703         // Call will not use the ordered broadcaster, since it is an Emergency Call
704         startOutgoingPhoneCallWaitForBroadcaster(number, phoneAccountHandle,
705                 connectionServiceFixture, initiatingUser, videoState, true /*isEmergency*/, null);
706 
707         return outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls,
708                 phoneAccountHandle, connectionServiceFixture);
709     }
710 
startOutgoingPhoneCallWaitForBroadcaster(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, int videoState, boolean isEmergency, Intent actionCallIntent)711     protected void startOutgoingPhoneCallWaitForBroadcaster(String number,
712             PhoneAccountHandle phoneAccountHandle,
713             ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser,
714             int videoState, boolean isEmergency, Intent actionCallIntent) throws Exception {
715         reset(connectionServiceFixture.getTestDouble(), mInCallServiceFixtureX.getTestDouble(),
716                 mInCallServiceFixtureY.getTestDouble());
717 
718         assertEquals(mInCallServiceFixtureX.mCallById.size(),
719                 mInCallServiceFixtureY.mCallById.size());
720         assertEquals((mInCallServiceFixtureX.mInCallAdapter != null),
721                 (mInCallServiceFixtureY.mInCallAdapter != null));
722 
723         mNumOutgoingCallsMade++;
724 
725         boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null;
726 
727         if (actionCallIntent == null) {
728             actionCallIntent = new Intent();
729         }
730         actionCallIntent.setData(Uri.parse("tel:" + number));
731         actionCallIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
732         if(isEmergency) {
733             actionCallIntent.setAction(Intent.ACTION_CALL_EMERGENCY);
734         } else {
735             actionCallIntent.setAction(Intent.ACTION_CALL);
736         }
737         if (phoneAccountHandle != null) {
738             actionCallIntent.putExtra(
739                     TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
740                     phoneAccountHandle);
741         }
742         if (videoState != VideoProfile.STATE_AUDIO_ONLY) {
743             actionCallIntent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);
744         }
745 
746         final UserHandle userHandle = initiatingUser;
747         Context localAppContext = mComponentContextFixture.getTestDouble().getApplicationContext();
748         new UserCallIntentProcessor(localAppContext, userHandle).processIntent(
749                 actionCallIntent, null, true /* hasCallAppOp*/, false /* isLocal */);
750         // Wait for handler to start CallerInfo lookup.
751         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
752         // Send the CallerInfo lookup reply.
753         mCallerInfoAsyncQueryFactoryFixture.mRequests.forEach(
754                 CallerInfoAsyncQueryFactoryFixture.Request::reply);
755         if (phoneAccountHandle != null) {
756             mTelecomSystem.getCallsManager().getLatestPostSelectionProcessingFuture().join();
757         }
758         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
759 
760         boolean isSelfManaged = phoneAccountHandle == mPhoneAccountSelfManaged.getAccountHandle();
761         if (!hasInCallAdapter && !isSelfManaged) {
762             verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
763                     .setInCallAdapter(
764                             any(IInCallAdapter.class));
765             verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT))
766                     .setInCallAdapter(
767                             any(IInCallAdapter.class));
768         }
769     }
770 
startOutgoingPhoneCallPendingCreateConnection(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, int videoState, Intent callIntentExtras)771     protected String startOutgoingPhoneCallPendingCreateConnection(String number,
772             PhoneAccountHandle phoneAccountHandle,
773             ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser,
774             int videoState, Intent callIntentExtras) throws Exception {
775         startOutgoingPhoneCallWaitForBroadcaster(number,phoneAccountHandle,
776                 connectionServiceFixture, initiatingUser,
777                 videoState, false /*isEmergency*/, callIntentExtras);
778         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
779 
780         verifyAndProcessOutgoingCallBroadcast(phoneAccountHandle);
781         return mInCallServiceFixtureX.mLatestCallId;
782     }
783 
verifyAndProcessOutgoingCallBroadcast(PhoneAccountHandle phoneAccountHandle)784     protected void verifyAndProcessOutgoingCallBroadcast(PhoneAccountHandle phoneAccountHandle) {
785         ArgumentCaptor<Intent> newOutgoingCallIntent =
786                 ArgumentCaptor.forClass(Intent.class);
787         ArgumentCaptor<BroadcastReceiver> newOutgoingCallReceiver =
788                 ArgumentCaptor.forClass(BroadcastReceiver.class);
789 
790         if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
791             verify(mComponentContextFixture.getTestDouble().getApplicationContext(),
792                     times(mNumOutgoingCallsMade))
793                     .sendOrderedBroadcastAsUser(
794                             newOutgoingCallIntent.capture(),
795                             any(UserHandle.class),
796                             anyString(),
797                             anyInt(),
798                             any(Bundle.class),
799                             newOutgoingCallReceiver.capture(),
800                             nullable(Handler.class),
801                             anyInt(),
802                             anyString(),
803                             nullable(Bundle.class));
804             // Pass on the new outgoing call Intent
805             // Set a dummy PendingResult so the BroadcastReceiver agrees to accept onReceive()
806             newOutgoingCallReceiver.getValue().setPendingResult(
807                     new BroadcastReceiver.PendingResult(0, "", null, 0, true, false, null, 0, 0));
808             newOutgoingCallReceiver.getValue().setResultData(
809                     newOutgoingCallIntent.getValue().getStringExtra(Intent.EXTRA_PHONE_NUMBER));
810             newOutgoingCallReceiver.getValue().onReceive(mComponentContextFixture.getTestDouble(),
811                     newOutgoingCallIntent.getValue());
812         }
813 
814     }
815 
816     // When Telecom is redialing due to an error, we need to make sure the number of connections
817     // increase, but not the number of Calls in the InCallService.
redialingCallCreateConnectionComplete(int startingNumConnections, int startingNumCalls, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture)818     protected IdPair redialingCallCreateConnectionComplete(int startingNumConnections,
819             int startingNumCalls, PhoneAccountHandle phoneAccountHandle,
820             ConnectionServiceFixture connectionServiceFixture) throws Exception {
821 
822         assertEquals(startingNumConnections + 1, connectionServiceFixture.mConnectionById.size());
823 
824         verify(connectionServiceFixture.getTestDouble())
825                 .createConnection(eq(phoneAccountHandle), anyString(), any(ConnectionRequest.class),
826                         eq(false)/*isIncoming*/, anyBoolean(), any());
827         // Wait for handleCreateConnectionComplete
828         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
829 
830         // Make sure the number of registered InCallService Calls stays the same.
831         assertEquals(startingNumCalls, mInCallServiceFixtureX.mCallById.size());
832         assertEquals(startingNumCalls, mInCallServiceFixtureY.mCallById.size());
833 
834         assertEquals(mInCallServiceFixtureX.mLatestCallId, mInCallServiceFixtureY.mLatestCallId);
835 
836         return new IdPair(connectionServiceFixture.mLatestConnectionId,
837                 mInCallServiceFixtureX.mLatestCallId);
838     }
839 
outgoingCallCreateConnectionComplete(int startingNumConnections, int startingNumCalls, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture)840     protected IdPair outgoingCallCreateConnectionComplete(int startingNumConnections,
841             int startingNumCalls, PhoneAccountHandle phoneAccountHandle,
842             ConnectionServiceFixture connectionServiceFixture) throws Exception {
843 
844         // Wait for the focus tracker.
845         waitForHandlerAction(mTelecomSystem.getCallsManager()
846                 .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT);
847 
848         verify(connectionServiceFixture.getTestDouble())
849                 .createConnection(eq(phoneAccountHandle), anyString(), any(ConnectionRequest.class),
850                         eq(false)/*isIncoming*/, anyBoolean(), any());
851         // Wait for handleCreateConnectionComplete
852         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
853         assertEquals(startingNumConnections + 1,
854                 connectionServiceFixture.mConnectionById.size());
855 
856         // Wait for the callback in ConnectionService#onAdapterAttached to execute.
857         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
858 
859         // Ensure callback to CS on successful creation happened.
860         verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
861                 .createConnectionComplete(anyString(), any());
862 
863         if (phoneAccountHandle == mPhoneAccountSelfManaged.getAccountHandle()) {
864             assertEquals(startingNumCalls, mInCallServiceFixtureX.mCallById.size());
865             assertEquals(startingNumCalls, mInCallServiceFixtureY.mCallById.size());
866         } else {
867             assertEquals(startingNumCalls + 1, mInCallServiceFixtureX.mCallById.size());
868             assertEquals(startingNumCalls + 1, mInCallServiceFixtureY.mCallById.size());
869         }
870 
871         assertEquals(mInCallServiceFixtureX.mLatestCallId, mInCallServiceFixtureY.mLatestCallId);
872 
873         return new IdPair(connectionServiceFixture.mLatestConnectionId,
874                 mInCallServiceFixtureX.mLatestCallId);
875     }
876 
startIncomingPhoneCall( String number, PhoneAccountHandle phoneAccountHandle, final ConnectionServiceFixture connectionServiceFixture)877     protected IdPair startIncomingPhoneCall(
878             String number,
879             PhoneAccountHandle phoneAccountHandle,
880             final ConnectionServiceFixture connectionServiceFixture) throws Exception {
881         return startIncomingPhoneCall(number, phoneAccountHandle, VideoProfile.STATE_AUDIO_ONLY,
882                 connectionServiceFixture, null);
883     }
884 
startIncomingPhoneCallWithExtras( String number, PhoneAccountHandle phoneAccountHandle, final ConnectionServiceFixture connectionServiceFixture, Bundle extras)885     protected IdPair startIncomingPhoneCallWithExtras(
886             String number,
887             PhoneAccountHandle phoneAccountHandle,
888             final ConnectionServiceFixture connectionServiceFixture,
889             Bundle extras) throws Exception {
890         return startIncomingPhoneCall(number, phoneAccountHandle, VideoProfile.STATE_AUDIO_ONLY,
891                 connectionServiceFixture, extras);
892     }
893 
startIncomingPhoneCall( String number, PhoneAccountHandle phoneAccountHandle, int videoState, final ConnectionServiceFixture connectionServiceFixture, Bundle extras)894     protected IdPair startIncomingPhoneCall(
895             String number,
896             PhoneAccountHandle phoneAccountHandle,
897             int videoState,
898             final ConnectionServiceFixture connectionServiceFixture,
899             Bundle extras) throws Exception {
900         reset(connectionServiceFixture.getTestDouble(), mInCallServiceFixtureX.getTestDouble(),
901                 mInCallServiceFixtureY.getTestDouble());
902 
903         assertEquals(mInCallServiceFixtureX.mCallById.size(),
904                 mInCallServiceFixtureY.mCallById.size());
905         assertEquals((mInCallServiceFixtureX.mInCallAdapter != null),
906                 (mInCallServiceFixtureY.mInCallAdapter != null));
907         final int startingNumConnections = connectionServiceFixture.mConnectionById.size();
908         final int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
909         boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null;
910         connectionServiceFixture.mConnectionServiceDelegate.mVideoState = videoState;
911         CountDownLatch incomingCallAddedLatch = new CountDownLatch(1);
912         IncomingCallAddedListener callAddedListener =
913                 new IncomingCallAddedListener(incomingCallAddedLatch);
914         mTelecomSystem.getCallsManager().addListener(callAddedListener);
915 
916         if (extras == null) {
917             extras = new Bundle();
918         }
919         extras.putParcelable(
920                 TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
921                 Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null));
922         mTelecomSystem.getTelecomServiceImpl().getBinder()
923                 .addNewIncomingCall(phoneAccountHandle, extras);
924 
925         verify(connectionServiceFixture.getTestDouble())
926                 .createConnection(any(PhoneAccountHandle.class), anyString(),
927                         any(ConnectionRequest.class), eq(true), eq(false), any());
928 
929         // Wait for the handler to start the CallerInfo lookup
930         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
931 
932         // Wait a few more times to address flakiness due to timing issues.
933         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
934         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
935 
936         // Ensure callback to CS on successful creation happened.
937 
938         verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
939                 .createConnectionComplete(anyString(), any());
940 
941         // Process the CallerInfo lookup reply
942         mCallerInfoAsyncQueryFactoryFixture.mRequests.forEach(
943                 CallerInfoAsyncQueryFactoryFixture.Request::reply);
944 
945         //Wait for/Verify call blocking happened asynchronously
946         incomingCallAddedLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
947 
948         // For the case of incoming calls, Telecom connecting the InCall services and adding the
949         // Call is triggered by the async completion of the CallerInfoAsyncQuery. Once the Call
950         // is added, future interactions as triggered by the ConnectionService, through the various
951         // test fixtures, will be synchronous.
952 
953         if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
954             if (!hasInCallAdapter) {
955                 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
956                         .setInCallAdapter(any(IInCallAdapter.class));
957                 verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT))
958                         .setInCallAdapter(any(IInCallAdapter.class));
959 
960                 // Give the InCallService time to respond
961                 assertTrueWithTimeout(new Predicate<Void>() {
962                     @Override
963                     public boolean apply(Void v) {
964                         return mInCallServiceFixtureX.mInCallAdapter != null;
965                     }
966                 });
967 
968                 assertTrueWithTimeout(new Predicate<Void>() {
969                     @Override
970                     public boolean apply(Void v) {
971                         return mInCallServiceFixtureY.mInCallAdapter != null;
972                     }
973                 });
974 
975                 verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
976                         .addCall(any(ParcelableCall.class));
977                 verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT))
978                         .addCall(any(ParcelableCall.class));
979 
980                 // Give the InCallService time to respond
981             }
982 
983             assertTrueWithTimeout(new Predicate<Void>() {
984                 @Override
985                 public boolean apply(Void v) {
986                     return startingNumConnections + 1 ==
987                             connectionServiceFixture.mConnectionById.size();
988                 }
989             });
990 
991             mInCallServiceFixtureX.waitUntilNumCalls(startingNumCalls + 1);
992             mInCallServiceFixtureY.waitUntilNumCalls(startingNumCalls + 1);
993             assertEquals(startingNumCalls + 1, mInCallServiceFixtureX.mCallById.size());
994             assertEquals(startingNumCalls + 1, mInCallServiceFixtureY.mCallById.size());
995 
996             assertEquals(mInCallServiceFixtureX.mLatestCallId,
997                     mInCallServiceFixtureY.mLatestCallId);
998         }
999 
1000         return new IdPair(connectionServiceFixture.mLatestConnectionId,
1001                 mInCallServiceFixtureX.mLatestCallId);
1002     }
1003 
startAndMakeActiveOutgoingCall( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture)1004     protected IdPair startAndMakeActiveOutgoingCall(
1005             String number,
1006             PhoneAccountHandle phoneAccountHandle,
1007             ConnectionServiceFixture connectionServiceFixture) throws Exception {
1008         return startAndMakeActiveOutgoingCall(number, phoneAccountHandle, connectionServiceFixture,
1009                 VideoProfile.STATE_AUDIO_ONLY, null);
1010     }
1011 
startAndMakeActiveOutgoingCallWithExtras( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, Intent callIntentExtras)1012     protected IdPair startAndMakeActiveOutgoingCallWithExtras(
1013             String number,
1014             PhoneAccountHandle phoneAccountHandle,
1015             ConnectionServiceFixture connectionServiceFixture,
1016             Intent callIntentExtras) throws Exception {
1017         return startAndMakeActiveOutgoingCall(number, phoneAccountHandle, connectionServiceFixture,
1018                 VideoProfile.STATE_AUDIO_ONLY, callIntentExtras);
1019     }
1020 
1021     // A simple outgoing call, verifying that the appropriate connection service is contacted,
1022     // the proper lifecycle is followed, and both In-Call Services are updated correctly.
startAndMakeActiveOutgoingCall( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, int videoState, Intent callIntentExtras)1023     protected IdPair startAndMakeActiveOutgoingCall(
1024             String number,
1025             PhoneAccountHandle phoneAccountHandle,
1026             ConnectionServiceFixture connectionServiceFixture, int videoState,
1027             Intent callIntentExtras) throws Exception {
1028         IdPair ids = startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture,
1029                 Process.myUserHandle(), videoState, callIntentExtras);
1030 
1031         connectionServiceFixture.sendSetDialing(ids.mConnectionId);
1032         if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
1033             assertEquals(Call.STATE_DIALING,
1034                     mInCallServiceFixtureX.getCall(ids.mCallId).getState());
1035             assertEquals(Call.STATE_DIALING,
1036                     mInCallServiceFixtureY.getCall(ids.mCallId).getState());
1037         }
1038 
1039         connectionServiceFixture.sendSetVideoState(ids.mConnectionId);
1040 
1041         when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CONNECT_TIME);
1042         when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CONNECT_ELAPSED_TIME);
1043         connectionServiceFixture.sendSetActive(ids.mConnectionId);
1044         if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
1045             assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
1046             assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
1047 
1048             if ((mInCallServiceFixtureX.getCall(ids.mCallId).getProperties() &
1049                     Call.Details.PROPERTY_IS_EXTERNAL_CALL) == 0) {
1050                 // Test the PhoneStateBroadcaster functionality if the call is not external.
1051                 verify(mContext.getSystemService(TelephonyRegistryManager.class),
1052                         timeout(TEST_TIMEOUT).atLeastOnce())
1053                         .notifyCallStateChangedForAllSubscriptions(
1054                                 eq(TelephonyManager.CALL_STATE_OFFHOOK),
1055                                 nullable(String.class));
1056             }
1057         }
1058         return ids;
1059     }
1060 
startAndMakeActiveIncomingCall( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture)1061     protected IdPair startAndMakeActiveIncomingCall(
1062             String number,
1063             PhoneAccountHandle phoneAccountHandle,
1064             ConnectionServiceFixture connectionServiceFixture) throws Exception {
1065         return startAndMakeActiveIncomingCall(number, phoneAccountHandle, connectionServiceFixture,
1066                 VideoProfile.STATE_AUDIO_ONLY);
1067     }
1068 
1069     // A simple incoming call, similar in scope to the previous test
startAndMakeActiveIncomingCall( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, int videoState)1070     protected IdPair startAndMakeActiveIncomingCall(
1071             String number,
1072             PhoneAccountHandle phoneAccountHandle,
1073             ConnectionServiceFixture connectionServiceFixture,
1074             int videoState) throws Exception {
1075         IdPair ids = startIncomingPhoneCall(number, phoneAccountHandle, connectionServiceFixture);
1076 
1077         if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
1078             assertEquals(Call.STATE_RINGING,
1079                     mInCallServiceFixtureX.getCall(ids.mCallId).getState());
1080             assertEquals(Call.STATE_RINGING,
1081                     mInCallServiceFixtureY.getCall(ids.mCallId).getState());
1082 
1083             mInCallServiceFixtureX.mInCallAdapter
1084                     .answerCall(ids.mCallId, videoState);
1085             // Wait on the CS focus manager handler
1086             waitForHandlerAction(mTelecomSystem.getCallsManager()
1087                     .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT);
1088 
1089             if (!VideoProfile.isVideo(videoState)) {
1090                 verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
1091                         .answer(eq(ids.mConnectionId), any());
1092             } else {
1093                 verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
1094                         .answerVideo(eq(ids.mConnectionId), eq(videoState), any());
1095             }
1096         }
1097 
1098         when(mClockProxy.currentTimeMillis()).thenReturn(TEST_CONNECT_TIME);
1099         when(mClockProxy.elapsedRealtime()).thenReturn(TEST_CONNECT_ELAPSED_TIME);
1100         connectionServiceFixture.sendSetActive(ids.mConnectionId);
1101 
1102         if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
1103             assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
1104             assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
1105 
1106             if ((mInCallServiceFixtureX.getCall(ids.mCallId).getProperties() &
1107                     Call.Details.PROPERTY_IS_EXTERNAL_CALL) == 0) {
1108                 // Test the PhoneStateBroadcaster functionality if the call is not external.
1109                 verify(mContext.getSystemService(TelephonyRegistryManager.class),
1110                         timeout(TEST_TIMEOUT).atLeastOnce())
1111                         .notifyCallStateChangedForAllSubscriptions(
1112                                 eq(TelephonyManager.CALL_STATE_OFFHOOK),
1113                                 nullable(String.class));
1114             }
1115         }
1116         return ids;
1117     }
1118 
startAndMakeDialingEmergencyCall( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture)1119     protected IdPair startAndMakeDialingEmergencyCall(
1120             String number,
1121             PhoneAccountHandle phoneAccountHandle,
1122             ConnectionServiceFixture connectionServiceFixture) throws Exception {
1123         IdPair ids = startOutgoingEmergencyCall(number, phoneAccountHandle,
1124                 connectionServiceFixture, Process.myUserHandle(), VideoProfile.STATE_AUDIO_ONLY);
1125 
1126         connectionServiceFixture.sendSetDialing(ids.mConnectionId);
1127         assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
1128         assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
1129 
1130         return ids;
1131     }
1132 
startAndMakeDialingOutgoingCall( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture)1133     protected IdPair startAndMakeDialingOutgoingCall(
1134             String number,
1135             PhoneAccountHandle phoneAccountHandle,
1136             ConnectionServiceFixture connectionServiceFixture) throws Exception {
1137         IdPair ids = startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture,
1138                 Process.myUserHandle(), VideoProfile.STATE_AUDIO_ONLY, null);
1139 
1140         connectionServiceFixture.sendSetDialing(ids.mConnectionId);
1141         if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
1142             assertEquals(Call.STATE_DIALING,
1143                     mInCallServiceFixtureX.getCall(ids.mCallId).getState());
1144             assertEquals(Call.STATE_DIALING,
1145                     mInCallServiceFixtureY.getCall(ids.mCallId).getState());
1146         }
1147 
1148         return ids;
1149     }
1150 
startAndMakeRingingIncomingCall( String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture)1151     protected IdPair startAndMakeRingingIncomingCall(
1152             String number,
1153             PhoneAccountHandle phoneAccountHandle,
1154             ConnectionServiceFixture connectionServiceFixture) throws Exception {
1155         IdPair ids = startIncomingPhoneCall(number, phoneAccountHandle, connectionServiceFixture);
1156 
1157         if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
1158             assertEquals(Call.STATE_RINGING,
1159                     mInCallServiceFixtureX.getCall(ids.mCallId).getState());
1160             assertEquals(Call.STATE_RINGING,
1161                     mInCallServiceFixtureY.getCall(ids.mCallId).getState());
1162 
1163             mInCallServiceFixtureX.mInCallAdapter
1164                     .answerCall(ids.mCallId, VideoProfile.STATE_AUDIO_ONLY);
1165 
1166             waitForHandlerAction(mTelecomSystem.getCallsManager()
1167                     .getConnectionServiceFocusManager().getHandler(), TEST_TIMEOUT);
1168 
1169             if (!VideoProfile.isVideo(VideoProfile.STATE_AUDIO_ONLY)) {
1170                 verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
1171                         .answer(eq(ids.mConnectionId), any());
1172             } else {
1173                 verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
1174                         .answerVideo(eq(ids.mConnectionId), eq(VideoProfile.STATE_AUDIO_ONLY),
1175                                 any());
1176             }
1177         }
1178         return ids;
1179     }
1180 
assertTrueWithTimeout(Predicate<Void> predicate)1181     protected static void assertTrueWithTimeout(Predicate<Void> predicate) {
1182         int elapsed = 0;
1183         while (elapsed < TEST_TIMEOUT) {
1184             if (predicate.apply(null)) {
1185                 return;
1186             } else {
1187                 try {
1188                     Thread.sleep(TEST_POLL_INTERVAL);
1189                     elapsed += TEST_POLL_INTERVAL;
1190                 } catch (InterruptedException e) {
1191                     fail(e.toString());
1192                 }
1193             }
1194         }
1195         fail("Timeout in assertTrueWithTimeout");
1196     }
1197 }
1198