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