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