TelecomSystemTest.java revision b2cadb6851ef78ab62c328bf23e327c14aeda536
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
17package com.android.server.telecom.tests;
18
19
20import static org.mockito.Matchers.any;
21import static org.mockito.Matchers.anyBoolean;
22import static org.mockito.Matchers.anyInt;
23import static org.mockito.Matchers.anyString;
24import static org.mockito.Matchers.eq;
25import static org.mockito.Mockito.doAnswer;
26import static org.mockito.Mockito.doReturn;
27import static org.mockito.Mockito.mock;
28import static org.mockito.Mockito.reset;
29import static org.mockito.Mockito.spy;
30import static org.mockito.Mockito.timeout;
31import static org.mockito.Mockito.times;
32import static org.mockito.Mockito.verify;
33
34import android.content.BroadcastReceiver;
35import android.content.ComponentName;
36import android.content.Context;
37import android.content.Intent;
38import android.media.AudioManager;
39import android.media.IAudioService;
40import android.net.Uri;
41import android.os.Bundle;
42import android.os.Handler;
43import android.os.Process;
44import android.os.UserHandle;
45import android.telecom.Call;
46import android.telecom.CallAudioState;
47import android.telecom.Connection;
48import android.telecom.ConnectionRequest;
49import android.telecom.DisconnectCause;
50import android.telecom.ParcelableCall;
51import android.telecom.PhoneAccount;
52import android.telecom.PhoneAccountHandle;
53import android.telecom.TelecomManager;
54import android.telecom.VideoProfile;
55
56import com.android.internal.telecom.IInCallAdapter;
57import com.android.internal.util.IndentingPrintWriter;
58import com.android.server.telecom.Analytics;
59import com.android.server.telecom.BluetoothPhoneServiceImpl;
60import com.android.server.telecom.CallAudioManager;
61import com.android.server.telecom.CallIntentProcessor;
62import com.android.server.telecom.CallerInfoAsyncQueryFactory;
63import com.android.server.telecom.CallsManager;
64import com.android.server.telecom.CallsManagerListenerBase;
65import com.android.server.telecom.ContactsAsyncHelper;
66import com.android.server.telecom.HeadsetMediaButton;
67import com.android.server.telecom.HeadsetMediaButtonFactory;
68import com.android.server.telecom.InCallWakeLockController;
69import com.android.server.telecom.InCallWakeLockControllerFactory;
70import com.android.server.telecom.Log;
71import com.android.server.telecom.MissedCallNotifier;
72import com.android.server.telecom.PhoneAccountRegistrar;
73import com.android.server.telecom.ProximitySensorManager;
74import com.android.server.telecom.ProximitySensorManagerFactory;
75import com.android.server.telecom.TelecomSystem;
76import com.android.server.telecom.components.UserCallIntentProcessor;
77
78import com.google.common.base.Predicate;
79
80import org.mockito.ArgumentCaptor;
81import org.mockito.Mock;
82import org.mockito.invocation.InvocationOnMock;
83import org.mockito.stubbing.Answer;
84
85import java.io.StringWriter;
86import java.util.Map;
87import java.util.concurrent.BrokenBarrierException;
88import java.util.concurrent.CountDownLatch;
89import java.util.concurrent.CyclicBarrier;
90
91public class TelecomSystemTest extends TelecomTestCase {
92
93    static final int TEST_POLL_INTERVAL = 10;  // milliseconds
94    static final int TEST_TIMEOUT = 1000;  // milliseconds
95
96    public class HeadsetMediaButtonFactoryF implements HeadsetMediaButtonFactory  {
97        @Override
98        public HeadsetMediaButton create(Context context, CallsManager callsManager,
99                TelecomSystem.SyncRoot lock) {
100            return mHeadsetMediaButton;
101        }
102    }
103
104    public class ProximitySensorManagerFactoryF implements ProximitySensorManagerFactory {
105        @Override
106        public ProximitySensorManager create(Context context, CallsManager callsManager) {
107            return mProximitySensorManager;
108        }
109    }
110
111    public class InCallWakeLockControllerFactoryF implements InCallWakeLockControllerFactory {
112        @Override
113        public InCallWakeLockController create(Context context, CallsManager callsManager) {
114            return mInCallWakeLockController;
115        }
116    }
117
118    public static class MissedCallNotifierFakeImpl extends CallsManagerListenerBase
119            implements MissedCallNotifier {
120        @Override
121        public void clearMissedCalls() {
122
123        }
124
125        @Override
126        public void showMissedCallNotification(com.android.server.telecom.Call call) {
127
128        }
129
130        @Override
131        public void updateOnStartup(TelecomSystem.SyncRoot lock, CallsManager callsManager,
132                ContactsAsyncHelper contactsAsyncHelper,
133                CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory) {
134
135        }
136    }
137
138    MissedCallNotifier mMissedCallNotifier = new MissedCallNotifierFakeImpl();
139    @Mock HeadsetMediaButton mHeadsetMediaButton;
140    @Mock ProximitySensorManager mProximitySensorManager;
141    @Mock InCallWakeLockController mInCallWakeLockController;
142    @Mock BluetoothPhoneServiceImpl mBluetoothPhoneServiceImpl;
143
144    final ComponentName mInCallServiceComponentNameX =
145            new ComponentName(
146                    "incall-service-package-X",
147                    "incall-service-class-X");
148    final ComponentName mInCallServiceComponentNameY =
149            new ComponentName(
150                    "incall-service-package-Y",
151                    "incall-service-class-Y");
152
153    InCallServiceFixture mInCallServiceFixtureX;
154    InCallServiceFixture mInCallServiceFixtureY;
155
156    final ComponentName mConnectionServiceComponentNameA =
157            new ComponentName(
158                    "connection-service-package-A",
159                    "connection-service-class-A");
160    final ComponentName mConnectionServiceComponentNameB =
161            new ComponentName(
162                    "connection-service-package-B",
163                    "connection-service-class-B");
164
165    final PhoneAccount mPhoneAccountA0 =
166            PhoneAccount.builder(
167                    new PhoneAccountHandle(
168                            mConnectionServiceComponentNameA,
169                            "id A 0"),
170                    "Phone account service A ID 0")
171                    .addSupportedUriScheme("tel")
172                    .setCapabilities(
173                            PhoneAccount.CAPABILITY_CALL_PROVIDER |
174                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
175                    .build();
176    final PhoneAccount mPhoneAccountA1 =
177            PhoneAccount.builder(
178                    new PhoneAccountHandle(
179                            mConnectionServiceComponentNameA,
180                            "id A 1"),
181                    "Phone account service A ID 1")
182                    .addSupportedUriScheme("tel")
183                    .setCapabilities(
184                            PhoneAccount.CAPABILITY_CALL_PROVIDER |
185                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
186                    .build();
187    final PhoneAccount mPhoneAccountB0 =
188            PhoneAccount.builder(
189                    new PhoneAccountHandle(
190                            mConnectionServiceComponentNameB,
191                            "id B 0"),
192                    "Phone account service B ID 0")
193                    .addSupportedUriScheme("tel")
194                    .setCapabilities(
195                            PhoneAccount.CAPABILITY_CALL_PROVIDER |
196                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
197                    .build();
198
199    ConnectionServiceFixture mConnectionServiceFixtureA;
200    ConnectionServiceFixture mConnectionServiceFixtureB;
201
202    CallerInfoAsyncQueryFactoryFixture mCallerInfoAsyncQueryFactoryFixture;
203
204    IAudioService mAudioService;
205
206    TelecomSystem mTelecomSystem;
207
208    private int mNumOutgoingCallsMade;
209
210    class IdPair {
211        final String mConnectionId;
212        final String mCallId;
213
214        public IdPair(String connectionId, String callId) {
215            this.mConnectionId = connectionId;
216            this.mCallId = callId;
217        }
218    }
219
220    @Override
221    public void setUp() throws Exception {
222        super.setUp();
223        mNumOutgoingCallsMade = 0;
224
225        // First set up information about the In-Call services in the mock Context, since
226        // Telecom will search for these as soon as it is instantiated
227        setupInCallServices();
228
229        // Next, create the TelecomSystem, our system under test
230        setupTelecomSystem();
231
232        // Finally, register the ConnectionServices with the PhoneAccountRegistrar of the
233        // now-running TelecomSystem
234        setupConnectionServices();
235    }
236
237    @Override
238    public void tearDown() throws Exception {
239        mTelecomSystem = null;
240        super.tearDown();
241    }
242
243    private void setupTelecomSystem() throws Exception {
244        // Use actual implementations instead of mocking the interface out.
245        HeadsetMediaButtonFactory headsetMediaButtonFactory =
246                spy(new HeadsetMediaButtonFactoryF());
247        ProximitySensorManagerFactory proximitySensorManagerFactory =
248                spy(new ProximitySensorManagerFactoryF());
249        InCallWakeLockControllerFactory inCallWakeLockControllerFactory =
250                spy(new InCallWakeLockControllerFactoryF());
251        mAudioService = setupAudioService();
252
253        mCallerInfoAsyncQueryFactoryFixture = new CallerInfoAsyncQueryFactoryFixture();
254
255        mTelecomSystem = new TelecomSystem(
256                mComponentContextFixture.getTestDouble(),
257                mMissedCallNotifier,
258                mCallerInfoAsyncQueryFactoryFixture.getTestDouble(),
259                headsetMediaButtonFactory,
260                proximitySensorManagerFactory,
261                inCallWakeLockControllerFactory,
262                new CallAudioManager.AudioServiceFactory() {
263                    @Override
264                    public IAudioService getAudioService() {
265                        return mAudioService;
266                    }
267                },
268                new BluetoothPhoneServiceImpl.BluetoothPhoneServiceImplFactory() {
269                    @Override
270                    public BluetoothPhoneServiceImpl makeBluetoothPhoneServiceImpl(Context context,
271                            TelecomSystem.SyncRoot lock, CallsManager callsManager,
272                            PhoneAccountRegistrar phoneAccountRegistrar) {
273                        return mBluetoothPhoneServiceImpl;
274                    }
275                });
276
277        mComponentContextFixture.setTelecomManager(new TelecomManager(
278                mComponentContextFixture.getTestDouble(),
279                mTelecomSystem.getTelecomServiceImpl().getBinder()));
280
281        verify(headsetMediaButtonFactory).create(
282                eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
283                any(CallsManager.class),
284                any(TelecomSystem.SyncRoot.class));
285        verify(proximitySensorManagerFactory).create(
286                eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
287                any(CallsManager.class));
288        verify(inCallWakeLockControllerFactory).create(
289                eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
290                any(CallsManager.class));
291    }
292
293    private void setupConnectionServices() throws Exception {
294        mConnectionServiceFixtureA = new ConnectionServiceFixture();
295        mConnectionServiceFixtureB = new ConnectionServiceFixture();
296
297        mComponentContextFixture.addConnectionService(
298                mConnectionServiceComponentNameA,
299                mConnectionServiceFixtureA.getTestDouble());
300        mComponentContextFixture.addConnectionService(
301                mConnectionServiceComponentNameB,
302                mConnectionServiceFixtureB.getTestDouble());
303
304        mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA0);
305        mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA1);
306        mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountB0);
307
308        mTelecomSystem.getPhoneAccountRegistrar().setUserSelectedOutgoingPhoneAccount(
309                mPhoneAccountA0.getAccountHandle(), Process.myUserHandle());
310    }
311
312    private void setupInCallServices() throws Exception {
313        mComponentContextFixture.putResource(
314                com.android.server.telecom.R.string.ui_default_package,
315                mInCallServiceComponentNameX.getPackageName());
316        mComponentContextFixture.putResource(
317                com.android.server.telecom.R.string.incall_default_class,
318                mInCallServiceComponentNameX.getClassName());
319
320        mInCallServiceFixtureX = new InCallServiceFixture();
321        mInCallServiceFixtureY = new InCallServiceFixture();
322
323        mComponentContextFixture.addInCallService(
324                mInCallServiceComponentNameX,
325                mInCallServiceFixtureX.getTestDouble());
326        mComponentContextFixture.addInCallService(
327                mInCallServiceComponentNameY,
328                mInCallServiceFixtureY.getTestDouble());
329    }
330
331    /**
332     * Helper method for setting up the fake audio service.
333     * Calls to the fake audio service need to toggle the return
334     * value of AudioManager#isMicrophoneMute.
335     * @return mock of IAudioService
336     */
337    private IAudioService setupAudioService() {
338        IAudioService audioService = mock(IAudioService.class);
339
340        final AudioManager fakeAudioManager =
341                (AudioManager) mComponentContextFixture.getTestDouble()
342                        .getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
343
344        try {
345            doAnswer(new Answer() {
346                @Override
347                public Object answer(InvocationOnMock i) {
348                    Object[] args = i.getArguments();
349                    doReturn(args[0]).when(fakeAudioManager).isMicrophoneMute();
350                    return null;
351                }
352            }).when(audioService)
353                    .setMicrophoneMute(any(Boolean.class), any(String.class), any(Integer.class));
354
355        } catch (android.os.RemoteException e) {
356            // Do nothing, leave the faked microphone state as-is
357        }
358        return audioService;
359    }
360
361    private IdPair startOutgoingPhoneCall(
362            String number,
363            PhoneAccountHandle phoneAccountHandle,
364            ConnectionServiceFixture connectionServiceFixture,
365            UserHandle initiatingUser) throws Exception {
366        reset(
367                connectionServiceFixture.getTestDouble(),
368                mInCallServiceFixtureX.getTestDouble(),
369                mInCallServiceFixtureY.getTestDouble());
370
371        assertEquals(
372                mInCallServiceFixtureX.mCallById.size(),
373                mInCallServiceFixtureY.mCallById.size());
374        assertEquals(
375                (mInCallServiceFixtureX.mInCallAdapter != null),
376                (mInCallServiceFixtureY.mInCallAdapter != null));
377
378        mNumOutgoingCallsMade++;
379        int startingNumConnections = connectionServiceFixture.mConnectionById.size();
380        int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
381        boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null;
382
383        Intent actionCallIntent = new Intent();
384        actionCallIntent.setData(Uri.parse("tel:" + number));
385        actionCallIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
386        actionCallIntent.setAction(Intent.ACTION_CALL);
387        if (phoneAccountHandle != null) {
388            actionCallIntent.putExtra(
389                    TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
390                    phoneAccountHandle);
391        }
392
393        final UserHandle userHandle = initiatingUser;
394        new UserCallIntentProcessor(mContext, userHandle)
395                .processIntent(actionCallIntent, null, true /* hasCallAppOp*/);
396        mTelecomSystem.getCallIntentProcessor().processIntent(actionCallIntent);
397
398        assertEquals(userHandle,
399                actionCallIntent.getParcelableExtra(CallIntentProcessor.KEY_INITIATING_USER));
400
401        if (!hasInCallAdapter) {
402            verify(mInCallServiceFixtureX.getTestDouble())
403                    .setInCallAdapter(
404                            any(IInCallAdapter.class));
405            verify(mInCallServiceFixtureY.getTestDouble())
406                    .setInCallAdapter(
407                            any(IInCallAdapter.class));
408        }
409
410        ArgumentCaptor<Intent> newOutgoingCallIntent =
411                ArgumentCaptor.forClass(Intent.class);
412        ArgumentCaptor<BroadcastReceiver> newOutgoingCallReceiver =
413                ArgumentCaptor.forClass(BroadcastReceiver.class);
414
415        verify(mComponentContextFixture.getTestDouble().getApplicationContext(),
416                times(mNumOutgoingCallsMade))
417                .sendOrderedBroadcastAsUser(
418                        newOutgoingCallIntent.capture(),
419                        any(UserHandle.class),
420                        anyString(),
421                        anyInt(),
422                        newOutgoingCallReceiver.capture(),
423                        any(Handler.class),
424                        anyInt(),
425                        anyString(),
426                        any(Bundle.class));
427
428        // Pass on the new outgoing call Intent
429        // Set a dummy PendingResult so the BroadcastReceiver agrees to accept onReceive()
430        newOutgoingCallReceiver.getValue().setPendingResult(
431                new BroadcastReceiver.PendingResult(0, "", null, 0, true, false, null, 0, 0));
432        newOutgoingCallReceiver.getValue().setResultData(
433                newOutgoingCallIntent.getValue().getStringExtra(Intent.EXTRA_PHONE_NUMBER));
434        newOutgoingCallReceiver.getValue().onReceive(
435                mComponentContextFixture.getTestDouble(),
436                newOutgoingCallIntent.getValue());
437
438        assertEquals(startingNumConnections + 1, connectionServiceFixture.mConnectionById.size());
439
440        verify(connectionServiceFixture.getTestDouble()).createConnection(
441                eq(phoneAccountHandle),
442                anyString(),
443                any(ConnectionRequest.class),
444                anyBoolean(),
445                anyBoolean());
446
447        connectionServiceFixture.sendHandleCreateConnectionComplete(
448                connectionServiceFixture.mLatestConnectionId);
449
450        assertEquals(startingNumCalls + 1, mInCallServiceFixtureX.mCallById.size());
451        assertEquals(startingNumCalls + 1, mInCallServiceFixtureY.mCallById.size());
452
453        assertEquals(
454                mInCallServiceFixtureX.mLatestCallId,
455                mInCallServiceFixtureY.mLatestCallId);
456
457        return new IdPair(
458                connectionServiceFixture.mLatestConnectionId,
459                mInCallServiceFixtureX.mLatestCallId);
460    }
461
462    private IdPair startIncomingPhoneCall(
463            String number,
464            PhoneAccountHandle phoneAccountHandle,
465            final ConnectionServiceFixture connectionServiceFixture) throws Exception {
466        return startIncomingPhoneCall(number, phoneAccountHandle, VideoProfile.STATE_AUDIO_ONLY,
467                connectionServiceFixture);
468    }
469
470    private IdPair startIncomingPhoneCall(
471            String number,
472            PhoneAccountHandle phoneAccountHandle,
473            int videoState,
474            final ConnectionServiceFixture connectionServiceFixture) throws Exception {
475        reset(
476                connectionServiceFixture.getTestDouble(),
477                mInCallServiceFixtureX.getTestDouble(),
478                mInCallServiceFixtureY.getTestDouble());
479
480        assertEquals(
481                mInCallServiceFixtureX.mCallById.size(),
482                mInCallServiceFixtureY.mCallById.size());
483        assertEquals(
484                (mInCallServiceFixtureX.mInCallAdapter != null),
485                (mInCallServiceFixtureY.mInCallAdapter != null));
486
487        final int startingNumConnections = connectionServiceFixture.mConnectionById.size();
488        final int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
489        boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null;
490
491        Bundle extras = new Bundle();
492        extras.putParcelable(
493                TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
494                Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null));
495        mTelecomSystem.getTelecomServiceImpl().getBinder()
496                .addNewIncomingCall(phoneAccountHandle, extras);
497
498        verify(connectionServiceFixture.getTestDouble()).createConnection(
499                any(PhoneAccountHandle.class),
500                anyString(),
501                any(ConnectionRequest.class),
502                eq(true),
503                eq(false));
504
505        mConnectionServiceFixtureA.mConnectionById.get(
506                connectionServiceFixture.mLatestConnectionId).videoState = videoState;
507
508        connectionServiceFixture.sendHandleCreateConnectionComplete(
509                connectionServiceFixture.mLatestConnectionId);
510        connectionServiceFixture.sendSetRinging(
511                connectionServiceFixture.mLatestConnectionId);
512        connectionServiceFixture.sendSetVideoState(
513                connectionServiceFixture.mLatestConnectionId);
514
515        // For the case of incoming calls, Telecom connecting the InCall services and adding the
516        // Call is triggered by the async completion of the CallerInfoAsyncQuery. Once the Call
517        // is added, future interactions as triggered by the ConnectionService, through the various
518        // test fixtures, will be synchronous.
519
520        if (!hasInCallAdapter) {
521            verify(
522                    mInCallServiceFixtureX.getTestDouble(),
523                    timeout(TEST_TIMEOUT))
524                    .setInCallAdapter(
525                            any(IInCallAdapter.class));
526            verify(
527                    mInCallServiceFixtureY.getTestDouble(),
528                    timeout(TEST_TIMEOUT))
529                    .setInCallAdapter(
530                            any(IInCallAdapter.class));
531        }
532
533        // Give the InCallService time to respond
534
535        assertTrueWithTimeout(new Predicate<Void>() {
536            @Override
537            public boolean apply(Void v) {
538                return mInCallServiceFixtureX.mInCallAdapter != null;
539            }
540        });
541
542        assertTrueWithTimeout(new Predicate<Void>() {
543            @Override
544            public boolean apply(Void v) {
545                return mInCallServiceFixtureY.mInCallAdapter != null;
546            }
547        });
548
549        verify(
550                mInCallServiceFixtureX.getTestDouble(),
551                timeout(TEST_TIMEOUT))
552                .addCall(
553                        any(ParcelableCall.class));
554        verify(
555                mInCallServiceFixtureY.getTestDouble(),
556                timeout(TEST_TIMEOUT))
557                .addCall(
558                        any(ParcelableCall.class));
559
560        // Give the InCallService time to respond
561
562        assertTrueWithTimeout(new Predicate<Void>() {
563            @Override
564            public boolean apply(Void v) {
565                return startingNumConnections + 1 ==
566                        connectionServiceFixture.mConnectionById.size();
567            }
568        });
569        assertTrueWithTimeout(new Predicate<Void>() {
570            @Override
571            public boolean apply(Void v) {
572                return startingNumCalls + 1 == mInCallServiceFixtureX.mCallById.size();
573            }
574        });
575        assertTrueWithTimeout(new Predicate<Void>() {
576            @Override
577            public boolean apply(Void v) {
578                return startingNumCalls + 1 == mInCallServiceFixtureY.mCallById.size();
579            }
580        });
581
582        assertEquals(
583                mInCallServiceFixtureX.mLatestCallId,
584                mInCallServiceFixtureY.mLatestCallId);
585
586        return new IdPair(
587                connectionServiceFixture.mLatestConnectionId,
588                mInCallServiceFixtureX.mLatestCallId);
589    }
590
591    private void rapidFire(Runnable... tasks) {
592        final CyclicBarrier barrier = new CyclicBarrier(tasks.length);
593        final CountDownLatch latch = new CountDownLatch(tasks.length);
594        for (int i = 0; i < tasks.length; i++) {
595            final Runnable task = tasks[i];
596            new Thread(new Runnable() {
597                @Override
598                public void run() {
599                    try {
600                        barrier.await();
601                        task.run();
602                    } catch (InterruptedException | BrokenBarrierException e){
603                        Log.e(TelecomSystemTest.this, e, "Unexpectedly interrupted");
604                    } finally {
605                        latch.countDown();
606                    }
607                }
608            }).start();
609        }
610        try {
611            latch.await();
612        } catch (InterruptedException e) {
613            Log.e(TelecomSystemTest.this, e, "Unexpectedly interrupted");
614        }
615    }
616
617    // A simple outgoing call, verifying that the appropriate connection service is contacted,
618    // the proper lifecycle is followed, and both In-Call Services are updated correctly.
619    private IdPair startAndMakeActiveOutgoingCall(
620            String number,
621            PhoneAccountHandle phoneAccountHandle,
622            ConnectionServiceFixture connectionServiceFixture) throws Exception {
623        IdPair ids = startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture,
624                Process.myUserHandle());
625
626        connectionServiceFixture.sendSetDialing(ids.mConnectionId);
627        assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
628        assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
629
630        connectionServiceFixture.sendSetActive(ids.mConnectionId);
631        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
632        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
633
634        return ids;
635    }
636
637    public void testBasicConferenceCall() throws Exception {
638        makeConferenceCall();
639    }
640
641    public void testAddCallToConference1() throws Exception {
642        ParcelableCall conferenceCall = makeConferenceCall();
643        IdPair callId3 = startAndMakeActiveOutgoingCall(
644                "650-555-1214",
645                mPhoneAccountA0.getAccountHandle(),
646                mConnectionServiceFixtureA);
647        // testAddCallToConference{1,2} differ in the order of arguments to InCallAdapter#conference
648        mInCallServiceFixtureX.getInCallAdapter().conference(
649                conferenceCall.getId(), callId3.mCallId);
650        Thread.sleep(200);
651
652        ParcelableCall call3 = mInCallServiceFixtureX.getCall(callId3.mCallId);
653        ParcelableCall updatedConference = mInCallServiceFixtureX.getCall(conferenceCall.getId());
654        assertEquals(conferenceCall.getId(), call3.getParentCallId());
655        assertEquals(3, updatedConference.getChildCallIds().size());
656        assertTrue(updatedConference.getChildCallIds().contains(callId3.mCallId));
657    }
658
659    public void testAddCallToConference2() throws Exception {
660        ParcelableCall conferenceCall = makeConferenceCall();
661        IdPair callId3 = startAndMakeActiveOutgoingCall(
662                "650-555-1214",
663                mPhoneAccountA0.getAccountHandle(),
664                mConnectionServiceFixtureA);
665        mInCallServiceFixtureX.getInCallAdapter().conference(
666                callId3.mCallId, conferenceCall.getId());
667        Thread.sleep(200);
668
669        ParcelableCall call3 = mInCallServiceFixtureX.getCall(callId3.mCallId);
670        ParcelableCall updatedConference = mInCallServiceFixtureX.getCall(conferenceCall.getId());
671        assertEquals(conferenceCall.getId(), call3.getParentCallId());
672        assertEquals(3, updatedConference.getChildCallIds().size());
673        assertTrue(updatedConference.getChildCallIds().contains(callId3.mCallId));
674    }
675
676    private ParcelableCall makeConferenceCall() throws Exception {
677        IdPair callId1 = startAndMakeActiveOutgoingCall(
678                "650-555-1212",
679                mPhoneAccountA0.getAccountHandle(),
680                mConnectionServiceFixtureA);
681
682        IdPair callId2 = startAndMakeActiveOutgoingCall(
683                "650-555-1213",
684                mPhoneAccountA0.getAccountHandle(),
685                mConnectionServiceFixtureA);
686
687        IInCallAdapter inCallAdapter = mInCallServiceFixtureX.getInCallAdapter();
688        inCallAdapter.conference(callId1.mCallId, callId2.mCallId);
689        // Wait for wacky non-deterministic behavior
690        Thread.sleep(200);
691        ParcelableCall call1 = mInCallServiceFixtureX.getCall(callId1.mCallId);
692        ParcelableCall call2 = mInCallServiceFixtureX.getCall(callId2.mCallId);
693        // Check that the two calls end up with a parent in the end
694        assertNotNull(call1.getParentCallId());
695        assertNotNull(call2.getParentCallId());
696        assertEquals(call1.getParentCallId(), call2.getParentCallId());
697
698        // Check to make sure that the parent call made it to the in-call service
699        String parentCallId = call1.getParentCallId();
700        ParcelableCall conferenceCall = mInCallServiceFixtureX.getCall(parentCallId);
701        assertEquals(2, conferenceCall.getChildCallIds().size());
702        assertTrue(conferenceCall.getChildCallIds().contains(callId1.mCallId));
703        assertTrue(conferenceCall.getChildCallIds().contains(callId2.mCallId));
704        return conferenceCall;
705    }
706
707    public void testSingleOutgoingCallLocalDisconnect() throws Exception {
708        IdPair ids = startAndMakeActiveOutgoingCall(
709                "650-555-1212",
710                mPhoneAccountA0.getAccountHandle(),
711                mConnectionServiceFixtureA);
712
713        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
714        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
715        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
716
717        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
718        assertEquals(Call.STATE_DISCONNECTED,
719                mInCallServiceFixtureX.getCall(ids.mCallId).getState());
720        assertEquals(Call.STATE_DISCONNECTED,
721                mInCallServiceFixtureY.getCall(ids.mCallId).getState());
722    }
723
724    public void testSingleOutgoingCallRemoteDisconnect() throws Exception {
725        IdPair ids = startAndMakeActiveOutgoingCall(
726                "650-555-1212",
727                mPhoneAccountA0.getAccountHandle(),
728                mConnectionServiceFixtureA);
729
730        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
731        assertEquals(Call.STATE_DISCONNECTED,
732                mInCallServiceFixtureX.getCall(ids.mCallId).getState());
733        assertEquals(Call.STATE_DISCONNECTED,
734                mInCallServiceFixtureY.getCall(ids.mCallId).getState());
735    }
736
737    /**
738     * Tests the {@link TelecomManager#acceptRingingCall()} API.  Tests simple case of an incoming
739     * audio-only call.
740     *
741     * @throws Exception
742     */
743    public void testTelecomManagerAcceptRingingCall() throws Exception {
744        IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(),
745                mConnectionServiceFixtureA);
746
747        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
748        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
749
750        // Use TelecomManager API to answer the ringing call.
751        TelecomManager telecomManager = (TelecomManager) mComponentContextFixture.getTestDouble()
752                .getApplicationContext().getSystemService(Context.TELECOM_SERVICE);
753        telecomManager.acceptRingingCall();
754
755        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
756                .answer(ids.mCallId);
757    }
758
759    /**
760     * Tests the {@link TelecomManager#acceptRingingCall()} API.  Tests simple case of an incoming
761     * video call, which should be answered as video.
762     *
763     * @throws Exception
764     */
765    public void testTelecomManagerAcceptRingingVideoCall() throws Exception {
766        IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(),
767                VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA);
768
769        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
770        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
771
772        // Use TelecomManager API to answer the ringing call; the default expected behavior is to
773        // answer using whatever video state the ringing call requests.
774        TelecomManager telecomManager = (TelecomManager) mComponentContextFixture.getTestDouble()
775                .getApplicationContext().getSystemService(Context.TELECOM_SERVICE);
776        telecomManager.acceptRingingCall();
777
778        // Answer video API should be called
779        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
780                .answerVideo(eq(ids.mCallId), eq(VideoProfile.STATE_BIDIRECTIONAL));
781    }
782
783    /**
784     * Tests the {@link TelecomManager#acceptRingingCall(int)} API.  Tests answering a video call
785     * as an audio call.
786     *
787     * @throws Exception
788     */
789    public void testTelecomManagerAcceptRingingVideoCallAsAudio() throws Exception {
790        IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(),
791                VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA);
792
793        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
794        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
795
796        // Use TelecomManager API to answer the ringing call.
797        TelecomManager telecomManager = (TelecomManager) mComponentContextFixture.getTestDouble()
798                .getApplicationContext().getSystemService(Context.TELECOM_SERVICE);
799        telecomManager.acceptRingingCall(VideoProfile.STATE_AUDIO_ONLY);
800
801        // The generic answer method on the ConnectionService is used to answer audio-only calls.
802        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
803                .answer(eq(ids.mCallId));
804    }
805
806    /**
807     * Tests the {@link TelecomManager#acceptRingingCall()} API.  Tests simple case of an incoming
808     * video call, where an attempt is made to answer with an invalid video state.
809     *
810     * @throws Exception
811     */
812    public void testTelecomManagerAcceptRingingInvalidVideoState() throws Exception {
813        IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(),
814                VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA);
815
816        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
817        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
818
819        // Use TelecomManager API to answer the ringing call; the default expected behavior is to
820        // answer using whatever video state the ringing call requests.
821        TelecomManager telecomManager = (TelecomManager) mComponentContextFixture.getTestDouble()
822                .getApplicationContext().getSystemService(Context.TELECOM_SERVICE);
823        telecomManager.acceptRingingCall(999 /* invalid videostate */);
824
825        // Answer video API should be called
826        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
827                .answerVideo(eq(ids.mCallId), eq(VideoProfile.STATE_BIDIRECTIONAL));
828    }
829
830    // A simple incoming call, similar in scope to the previous test
831    private IdPair startAndMakeActiveIncomingCall(
832            String number,
833            PhoneAccountHandle phoneAccountHandle,
834            ConnectionServiceFixture connectionServiceFixture) throws Exception {
835        IdPair ids = startIncomingPhoneCall(number, phoneAccountHandle, connectionServiceFixture);
836
837        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
838        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
839
840        mInCallServiceFixtureX.mInCallAdapter
841                .answerCall(ids.mCallId, VideoProfile.STATE_AUDIO_ONLY);
842
843        verify(connectionServiceFixture.getTestDouble())
844                .answer(ids.mConnectionId);
845
846        connectionServiceFixture.sendSetActive(ids.mConnectionId);
847        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
848        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
849
850        return ids;
851    }
852
853    public void testSingleIncomingCallLocalDisconnect() throws Exception {
854        IdPair ids = startAndMakeActiveIncomingCall(
855                "650-555-1212",
856                mPhoneAccountA0.getAccountHandle(),
857                mConnectionServiceFixtureA);
858
859        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
860        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
861        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
862
863        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
864        assertEquals(Call.STATE_DISCONNECTED,
865                mInCallServiceFixtureX.getCall(ids.mCallId).getState());
866        assertEquals(Call.STATE_DISCONNECTED,
867                mInCallServiceFixtureY.getCall(ids.mCallId).getState());
868    }
869
870    public void testSingleIncomingCallRemoteDisconnect() throws Exception {
871        IdPair ids = startAndMakeActiveIncomingCall(
872                "650-555-1212",
873                mPhoneAccountA0.getAccountHandle(),
874                mConnectionServiceFixtureA);
875
876        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
877        assertEquals(Call.STATE_DISCONNECTED,
878                mInCallServiceFixtureX.getCall(ids.mCallId).getState());
879        assertEquals(Call.STATE_DISCONNECTED,
880                mInCallServiceFixtureY.getCall(ids.mCallId).getState());
881    }
882
883    public void do_testDeadlockOnOutgoingCall() throws Exception {
884        final IdPair ids = startOutgoingPhoneCall(
885                "650-555-1212",
886                mPhoneAccountA0.getAccountHandle(),
887                mConnectionServiceFixtureA,
888                Process.myUserHandle());
889        rapidFire(
890                new Runnable() {
891                    @Override
892                    public void run() {
893                        while (mCallerInfoAsyncQueryFactoryFixture.mRequests.size() > 0) {
894                            mCallerInfoAsyncQueryFactoryFixture.mRequests.remove(0).reply();
895                        }
896                    }
897                },
898                new Runnable() {
899                    @Override
900                    public void run() {
901                        try {
902                            mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId);
903                        } catch (Exception e) {
904                            Log.e(this, e, "");
905                        }
906                    }
907                });
908    }
909
910    public void testDeadlockOnOutgoingCall() throws Exception {
911        for (int i = 0; i < 100; i++) {
912            TelecomSystemTest test = new TelecomSystemTest();
913            test.setContext(getContext());
914            test.setTestContext(getTestContext());
915            test.setName(getName());
916            test.setUp();
917            test.do_testDeadlockOnOutgoingCall();
918            test.tearDown();
919        }
920    }
921
922    public void testIncomingThenOutgoingCalls() throws Exception {
923        // TODO: We have to use the same PhoneAccount for both; see http://b/18461539
924        IdPair incoming = startAndMakeActiveIncomingCall(
925                "650-555-2323",
926                mPhoneAccountA0.getAccountHandle(),
927                mConnectionServiceFixtureA);
928        IdPair outgoing = startAndMakeActiveOutgoingCall(
929                "650-555-1212",
930                mPhoneAccountA0.getAccountHandle(),
931                mConnectionServiceFixtureA);
932    }
933
934    public void testOutgoingThenIncomingCalls() throws Exception {
935        // TODO: We have to use the same PhoneAccount for both; see http://b/18461539
936        IdPair outgoing = startAndMakeActiveOutgoingCall(
937                "650-555-1212",
938                mPhoneAccountA0.getAccountHandle(),
939                mConnectionServiceFixtureA);
940        IdPair incoming = startAndMakeActiveIncomingCall(
941                "650-555-2323",
942                mPhoneAccountA0.getAccountHandle(),
943                mConnectionServiceFixtureA);
944        verify(mConnectionServiceFixtureA.getTestDouble())
945                .hold(outgoing.mConnectionId);
946        mConnectionServiceFixtureA.mConnectionById.get(outgoing.mConnectionId).state =
947                Connection.STATE_HOLDING;
948        mConnectionServiceFixtureA.sendSetOnHold(outgoing.mConnectionId);
949        assertEquals(
950                Call.STATE_HOLDING,
951                mInCallServiceFixtureX.getCall(outgoing.mCallId).getState());
952        assertEquals(
953                Call.STATE_HOLDING,
954                mInCallServiceFixtureY.getCall(outgoing.mCallId).getState());
955    }
956
957    public void testAnalyticsSingleCall() throws Exception {
958        IdPair testCall = startAndMakeActiveIncomingCall(
959                "650-555-1212",
960                mPhoneAccountA0.getAccountHandle(),
961                mConnectionServiceFixtureA);
962                Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
963
964        assertTrue(analyticsMap.containsKey(testCall.mCallId));
965
966        Analytics.CallInfoImpl callAnalytics = analyticsMap.get(testCall.mCallId);
967        assertTrue(callAnalytics.startTime > 0);
968        assertEquals(0, callAnalytics.endTime);
969        assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics.callDirection);
970        assertFalse(callAnalytics.isInterrupted);
971        assertNull(callAnalytics.callTerminationReason);
972        assertEquals(mConnectionServiceComponentNameA.flattenToShortString(),
973                callAnalytics.connectionService);
974
975        mConnectionServiceFixtureA.
976                sendSetDisconnected(testCall.mConnectionId, DisconnectCause.ERROR);
977
978        analyticsMap = Analytics.cloneData();
979        callAnalytics = analyticsMap.get(testCall.mCallId);
980        assertTrue(callAnalytics.endTime > 0);
981        assertNotNull(callAnalytics.callTerminationReason);
982        assertEquals(DisconnectCause.ERROR, callAnalytics.callTerminationReason.getCode());
983
984        StringWriter sr = new StringWriter();
985        IndentingPrintWriter ip = new IndentingPrintWriter(sr, "    ");
986        Analytics.dump(ip);
987        String dumpResult = sr.toString();
988        String[] expectedFields = {"startTime", "endTime", "direction", "isAdditionalCall",
989                "isInterrupted", "callTechnologies", "callTerminationReason", "connectionServices"};
990        for (String field : expectedFields) {
991            assertTrue(dumpResult.contains(field));
992        }
993    }
994
995    public void testAnalyticsTwoCalls() throws Exception {
996        IdPair testCall1 = startAndMakeActiveIncomingCall(
997                "650-555-1212",
998                mPhoneAccountA0.getAccountHandle(),
999                mConnectionServiceFixtureA);
1000        IdPair testCall2 = startAndMakeActiveOutgoingCall(
1001                "650-555-1213",
1002                mPhoneAccountA0.getAccountHandle(),
1003                mConnectionServiceFixtureA);
1004
1005        Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
1006        assertTrue(analyticsMap.containsKey(testCall1.mCallId));
1007        assertTrue(analyticsMap.containsKey(testCall2.mCallId));
1008
1009        Analytics.CallInfoImpl callAnalytics1 = analyticsMap.get(testCall1.mCallId);
1010        Analytics.CallInfoImpl callAnalytics2 = analyticsMap.get(testCall2.mCallId);
1011        assertTrue(callAnalytics1.startTime > 0);
1012        assertTrue(callAnalytics2.startTime > 0);
1013        assertEquals(0, callAnalytics1.endTime);
1014        assertEquals(0, callAnalytics2.endTime);
1015
1016        assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics1.callDirection);
1017        assertEquals(Analytics.OUTGOING_DIRECTION, callAnalytics2.callDirection);
1018
1019        assertTrue(callAnalytics1.isInterrupted);
1020        assertTrue(callAnalytics2.isAdditionalCall);
1021
1022        assertNull(callAnalytics1.callTerminationReason);
1023        assertNull(callAnalytics2.callTerminationReason);
1024
1025        assertEquals(mConnectionServiceComponentNameA.flattenToShortString(),
1026                callAnalytics1.connectionService);
1027        assertEquals(mConnectionServiceComponentNameA.flattenToShortString(),
1028                callAnalytics1.connectionService);
1029
1030        mConnectionServiceFixtureA.
1031                sendSetDisconnected(testCall2.mConnectionId, DisconnectCause.REMOTE);
1032        mConnectionServiceFixtureA.
1033                sendSetDisconnected(testCall1.mConnectionId, DisconnectCause.ERROR);
1034
1035        analyticsMap = Analytics.cloneData();
1036        callAnalytics1 = analyticsMap.get(testCall1.mCallId);
1037        callAnalytics2 = analyticsMap.get(testCall2.mCallId);
1038        assertTrue(callAnalytics1.endTime > 0);
1039        assertTrue(callAnalytics2.endTime > 0);
1040        assertNotNull(callAnalytics1.callTerminationReason);
1041        assertNotNull(callAnalytics2.callTerminationReason);
1042        assertEquals(DisconnectCause.ERROR, callAnalytics1.callTerminationReason.getCode());
1043        assertEquals(DisconnectCause.REMOTE, callAnalytics2.callTerminationReason.getCode());
1044    }
1045
1046    public void testAudioManagerOperations() throws Exception {
1047        AudioManager audioManager = (AudioManager) mComponentContextFixture.getTestDouble()
1048                .getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
1049
1050        IdPair outgoing = startAndMakeActiveOutgoingCall(
1051                "650-555-1212",
1052                mPhoneAccountA0.getAccountHandle(),
1053                mConnectionServiceFixtureA);
1054
1055        verify(audioManager, timeout(TEST_TIMEOUT))
1056                .requestAudioFocusForCall(anyInt(), anyInt());
1057        verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce())
1058                .setMode(AudioManager.MODE_IN_CALL);
1059
1060        mInCallServiceFixtureX.mInCallAdapter.mute(true);
1061        verify(mAudioService, timeout(TEST_TIMEOUT))
1062                .setMicrophoneMute(eq(true), any(String.class), any(Integer.class));
1063        mInCallServiceFixtureX.mInCallAdapter.mute(false);
1064        verify(mAudioService, timeout(TEST_TIMEOUT))
1065                .setMicrophoneMute(eq(false), any(String.class), any(Integer.class));
1066
1067        mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_SPEAKER);
1068        verify(audioManager, timeout(TEST_TIMEOUT))
1069                .setSpeakerphoneOn(true);
1070        mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_EARPIECE);
1071        verify(audioManager, timeout(TEST_TIMEOUT))
1072                .setSpeakerphoneOn(false);
1073
1074        mConnectionServiceFixtureA.
1075                sendSetDisconnected(outgoing.mConnectionId, DisconnectCause.REMOTE);
1076
1077        verify(audioManager, timeout(TEST_TIMEOUT))
1078                .abandonAudioFocusForCall();
1079        verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce())
1080                .setMode(AudioManager.MODE_NORMAL);
1081    }
1082
1083    protected static void assertTrueWithTimeout(Predicate<Void> predicate) {
1084        int elapsed = 0;
1085        while (elapsed < TEST_TIMEOUT) {
1086            if (predicate.apply(null)) {
1087                return;
1088            } else {
1089                try {
1090                    Thread.sleep(TEST_POLL_INTERVAL);
1091                    elapsed += TEST_POLL_INTERVAL;
1092                } catch (InterruptedException e) {
1093                    fail(e.toString());
1094                }
1095            }
1096        }
1097        fail("Timeout in assertTrueWithTimeout");
1098    }
1099}
1100