TelecomSystemTest.java revision b60f00673149da9a96d9369f4e1c4458e9a9cf53
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
19import static org.mockito.Matchers.any;
20import static org.mockito.Matchers.anyBoolean;
21import static org.mockito.Matchers.anyInt;
22import static org.mockito.Matchers.anyString;
23import static org.mockito.Matchers.eq;
24import static org.mockito.Mockito.atLeastOnce;
25import static org.mockito.Mockito.mock;
26import static org.mockito.Mockito.reset;
27import static org.mockito.Mockito.timeout;
28import static org.mockito.Mockito.verify;
29import static org.mockito.Mockito.when;
30
31import android.content.BroadcastReceiver;
32import android.content.ComponentName;
33import android.content.Context;
34import android.content.Intent;
35import android.media.AudioManager;
36import android.net.Uri;
37import android.os.Bundle;
38import android.os.Handler;
39import android.os.UserHandle;
40import android.telecom.Call;
41import android.telecom.CallAudioState;
42import android.telecom.ConnectionRequest;
43import android.telecom.DisconnectCause;
44import android.telecom.ParcelableCall;
45import android.telecom.PhoneAccount;
46import android.telecom.PhoneAccountHandle;
47import android.telecom.TelecomManager;
48import android.telephony.TelephonyManager;
49
50import com.android.internal.telecom.IInCallAdapter;
51import com.android.server.telecom.CallsManager;
52import com.android.server.telecom.HeadsetMediaButton;
53import com.android.server.telecom.HeadsetMediaButtonFactory;
54import com.android.server.telecom.InCallWakeLockController;
55import com.android.server.telecom.InCallWakeLockControllerFactory;
56import com.android.server.telecom.Log;
57import com.android.server.telecom.MissedCallNotifier;
58import com.android.server.telecom.ProximitySensorManager;
59import com.android.server.telecom.ProximitySensorManagerFactory;
60import com.android.server.telecom.TelecomSystem;
61
62import org.mockito.ArgumentCaptor;
63import org.mockito.Mock;
64import org.mockito.internal.verification.VerificationModeFactory;
65
66import java.util.concurrent.BrokenBarrierException;
67import java.util.concurrent.CountDownLatch;
68import java.util.concurrent.CyclicBarrier;
69
70public class TelecomSystemTest extends TelecomTestCase {
71
72    static final int TEST_TIMEOUT = 1000;  // milliseconds
73
74    @Mock MissedCallNotifier mMissedCallNotifier;
75    @Mock HeadsetMediaButton mHeadsetMediaButton;
76    @Mock ProximitySensorManager mProximitySensorManager;
77    @Mock InCallWakeLockController mInCallWakeLockController;
78
79    final ComponentName mInCallServiceComponentNameX =
80            new ComponentName(
81                    "incall-service-package-X",
82                    "incall-service-class-X");
83    final ComponentName mInCallServiceComponentNameY =
84            new ComponentName(
85                    "incall-service-package-Y",
86                    "incall-service-class-Y");
87
88    InCallServiceFixture mInCallServiceFixtureX;
89    InCallServiceFixture mInCallServiceFixtureY;
90
91    final ComponentName mConnectionServiceComponentNameA =
92            new ComponentName(
93                    "connection-service-package-A",
94                    "connection-service-class-A");
95    final ComponentName mConnectionServiceComponentNameB =
96            new ComponentName(
97                    "connection-service-package-B",
98                    "connection-service-class-B");
99
100    final PhoneAccount mPhoneAccountA0 =
101            PhoneAccount.builder(
102                    new PhoneAccountHandle(
103                            mConnectionServiceComponentNameA,
104                            "id A 0"),
105                    "Phone account service A ID 0")
106                    .addSupportedUriScheme("tel")
107                    .setCapabilities(
108                            PhoneAccount.CAPABILITY_CALL_PROVIDER |
109                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
110                    .build();
111    final PhoneAccount mPhoneAccountA1 =
112            PhoneAccount.builder(
113                    new PhoneAccountHandle(
114                            mConnectionServiceComponentNameA,
115                            "id A 1"),
116                    "Phone account service A ID 1")
117                    .addSupportedUriScheme("tel")
118                    .setCapabilities(
119                            PhoneAccount.CAPABILITY_CALL_PROVIDER |
120                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
121                    .build();
122    final PhoneAccount mPhoneAccountB0 =
123            PhoneAccount.builder(
124                    new PhoneAccountHandle(
125                            mConnectionServiceComponentNameB,
126                            "id B 0"),
127                    "Phone account service B ID 0")
128                    .addSupportedUriScheme("tel")
129                    .setCapabilities(
130                            PhoneAccount.CAPABILITY_CALL_PROVIDER |
131                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
132                    .build();
133
134    ConnectionServiceFixture mConnectionServiceFixtureA;
135    ConnectionServiceFixture mConnectionServiceFixtureB;
136
137    CallerInfoAsyncQueryFactoryFixture mCallerInfoAsyncQueryFactoryFixture;
138
139    TelecomSystem mTelecomSystem;
140
141    class IdPair {
142        final String mConnectionId;
143        final String mCallId;
144
145        public IdPair(String connectionId, String callId) {
146            this.mConnectionId = connectionId;
147            this.mCallId = callId;
148        }
149    }
150
151    @Override
152    public void setUp() throws Exception {
153        super.setUp();
154
155        // First set up information about the In-Call services in the mock Context, since
156        // Telecom will search for these as soon as it is instantiated
157        setupInCallServices();
158
159        // Next, create the TelecomSystem, our system under test
160        setupTelecomSystem();
161
162        // Finally, register the ConnectionServices with the PhoneAccountRegistrar of the
163        // now-running TelecomSystem
164        setupConnectionServices();
165    }
166
167    @Override
168    public void tearDown() throws Exception {
169        mTelecomSystem = null;
170        super.tearDown();
171    }
172
173    private void setupTelecomSystem() throws Exception {
174        HeadsetMediaButtonFactory headsetMediaButtonFactory =
175                mock(HeadsetMediaButtonFactory.class);
176        ProximitySensorManagerFactory proximitySensorManagerFactory =
177                mock(ProximitySensorManagerFactory.class);
178        InCallWakeLockControllerFactory inCallWakeLockControllerFactory =
179                mock(InCallWakeLockControllerFactory.class);
180
181        mCallerInfoAsyncQueryFactoryFixture = new CallerInfoAsyncQueryFactoryFixture();
182
183        when(headsetMediaButtonFactory.create(
184                any(Context.class),
185                any(CallsManager.class),
186                any(TelecomSystem.SyncRoot.class)))
187                .thenReturn(mHeadsetMediaButton);
188        when(proximitySensorManagerFactory.create(
189                any(Context.class),
190                any(CallsManager.class)))
191                .thenReturn(mProximitySensorManager);
192        when(inCallWakeLockControllerFactory.create(
193                any(Context.class),
194                any(CallsManager.class)))
195                .thenReturn(mInCallWakeLockController);
196
197        mTelecomSystem = new TelecomSystem(
198                mComponentContextFixture.getTestDouble(),
199                mMissedCallNotifier,
200                mCallerInfoAsyncQueryFactoryFixture.getTestDouble(),
201                headsetMediaButtonFactory,
202                proximitySensorManagerFactory,
203                inCallWakeLockControllerFactory);
204
205        verify(headsetMediaButtonFactory).create(
206                eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
207                any(CallsManager.class),
208                any(TelecomSystem.SyncRoot.class));
209        verify(proximitySensorManagerFactory).create(
210                eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
211                any(CallsManager.class));
212        verify(inCallWakeLockControllerFactory).create(
213                eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
214                any(CallsManager.class));
215    }
216
217    private void setupConnectionServices() throws Exception {
218        mConnectionServiceFixtureA = new ConnectionServiceFixture();
219        mConnectionServiceFixtureB = new ConnectionServiceFixture();
220
221        mComponentContextFixture.addConnectionService(
222                mConnectionServiceComponentNameA,
223                mConnectionServiceFixtureA.getTestDouble());
224        mComponentContextFixture.addConnectionService(
225                mConnectionServiceComponentNameB,
226                mConnectionServiceFixtureB.getTestDouble());
227
228        mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA0);
229        mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA1);
230        mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountB0);
231
232        mTelecomSystem.getPhoneAccountRegistrar().setUserSelectedOutgoingPhoneAccount(
233                mPhoneAccountA0.getAccountHandle());
234    }
235
236    private void setupInCallServices() throws Exception {
237        mComponentContextFixture.putResource(
238                com.android.server.telecom.R.string.ui_default_package,
239                mInCallServiceComponentNameX.getPackageName());
240        mComponentContextFixture.putResource(
241                com.android.server.telecom.R.string.incall_default_class,
242                mInCallServiceComponentNameX.getClassName());
243
244        mInCallServiceFixtureX = new InCallServiceFixture();
245        mInCallServiceFixtureY = new InCallServiceFixture();
246
247        mComponentContextFixture.addInCallService(
248                mInCallServiceComponentNameX,
249                mInCallServiceFixtureX.getTestDouble());
250        mComponentContextFixture.addInCallService(
251                mInCallServiceComponentNameY,
252                mInCallServiceFixtureY.getTestDouble());
253    }
254
255    private IdPair startOutgoingPhoneCall(
256            String number,
257            PhoneAccountHandle phoneAccountHandle,
258            ConnectionServiceFixture connectionServiceFixture) throws Exception {
259        reset(
260                connectionServiceFixture.getTestDouble(),
261                mInCallServiceFixtureX.getTestDouble(),
262                mInCallServiceFixtureY.getTestDouble());
263
264        assertEquals(
265                mInCallServiceFixtureX.mCallById.size(),
266                mInCallServiceFixtureY.mCallById.size());
267        assertEquals(
268                (mInCallServiceFixtureX.mInCallAdapter != null),
269                (mInCallServiceFixtureY.mInCallAdapter != null));
270
271        int startingNumConnections = connectionServiceFixture.mConnectionById.size();
272        int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
273        boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null;
274
275        Intent actionCallIntent = new Intent();
276        actionCallIntent.setData(Uri.parse("tel:" + number));
277        actionCallIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
278        actionCallIntent.setAction(Intent.ACTION_CALL);
279        if (phoneAccountHandle != null) {
280            actionCallIntent.putExtra(
281                    TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
282                    phoneAccountHandle);
283        }
284
285        mTelecomSystem.getCallIntentProcessor().processIntent(actionCallIntent);
286
287        if (!hasInCallAdapter) {
288            verify(mInCallServiceFixtureX.getTestDouble())
289                    .setInCallAdapter(
290                            any(IInCallAdapter.class));
291            verify(mInCallServiceFixtureY.getTestDouble())
292                    .setInCallAdapter(
293                            any(IInCallAdapter.class));
294        }
295
296        ArgumentCaptor<Intent> newOutgoingCallIntent =
297                ArgumentCaptor.forClass(Intent.class);
298        ArgumentCaptor<BroadcastReceiver> newOutgoingCallReceiver =
299                ArgumentCaptor.forClass(BroadcastReceiver.class);
300
301        verify(mComponentContextFixture.getTestDouble().getApplicationContext())
302                .sendOrderedBroadcastAsUser(
303                        newOutgoingCallIntent.capture(),
304                        any(UserHandle.class),
305                        anyString(),
306                        anyInt(),
307                        newOutgoingCallReceiver.capture(),
308                        any(Handler.class),
309                        anyInt(),
310                        anyString(),
311                        any(Bundle.class));
312
313        assertNotNull(mInCallServiceFixtureX.mInCallAdapter);
314        assertNotNull(mInCallServiceFixtureY.mInCallAdapter);
315
316        // Pass on the new outgoing call Intent
317        // Set a dummy PendingResult so the BroadcastReceiver agrees to accept onReceive()
318        newOutgoingCallReceiver.getValue().setPendingResult(
319                new BroadcastReceiver.PendingResult(0, "", null, 0, true, false, null, 0, 0));
320        newOutgoingCallReceiver.getValue().setResultData(
321                newOutgoingCallIntent.getValue().getStringExtra(Intent.EXTRA_PHONE_NUMBER));
322        newOutgoingCallReceiver.getValue().onReceive(
323                mComponentContextFixture.getTestDouble(),
324                newOutgoingCallIntent.getValue());
325
326        assertEquals(startingNumConnections + 1, connectionServiceFixture.mConnectionById.size());
327
328        verify(connectionServiceFixture.getTestDouble()).createConnection(
329                eq(phoneAccountHandle),
330                anyString(),
331                any(ConnectionRequest.class),
332                anyBoolean(),
333                anyBoolean());
334
335        connectionServiceFixture.sendHandleCreateConnectionComplete(
336                connectionServiceFixture.mLatestConnectionId);
337
338        assertEquals(startingNumCalls + 1, mInCallServiceFixtureX.mCallById.size());
339        assertEquals(startingNumCalls + 1, mInCallServiceFixtureY.mCallById.size());
340
341        assertEquals(
342                mInCallServiceFixtureX.mLatestCallId,
343                mInCallServiceFixtureY.mLatestCallId);
344
345        return new IdPair(
346                connectionServiceFixture.mLatestConnectionId,
347                mInCallServiceFixtureX.mLatestCallId);
348    }
349
350    private IdPair startIncomingPhoneCall(
351            String number,
352            PhoneAccountHandle phoneAccountHandle,
353            ConnectionServiceFixture connectionServiceFixture) throws Exception {
354        reset(
355                connectionServiceFixture.getTestDouble(),
356                mInCallServiceFixtureX.getTestDouble(),
357                mInCallServiceFixtureY.getTestDouble());
358
359        assertEquals(
360                mInCallServiceFixtureX.mCallById.size(),
361                mInCallServiceFixtureY.mCallById.size());
362        assertEquals(
363                (mInCallServiceFixtureX.mInCallAdapter != null),
364                (mInCallServiceFixtureY.mInCallAdapter != null));
365
366        int startingNumConnections = connectionServiceFixture.mConnectionById.size();
367        int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
368        boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null;
369
370        Bundle extras = new Bundle();
371        extras.putParcelable(
372                TelephonyManager.EXTRA_INCOMING_NUMBER,
373                Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null));
374        mTelecomSystem.getTelecomServiceImpl().getBinder()
375                .addNewIncomingCall(phoneAccountHandle, extras);
376
377        verify(connectionServiceFixture.getTestDouble()).createConnection(
378                any(PhoneAccountHandle.class),
379                anyString(),
380                any(ConnectionRequest.class),
381                eq(true),
382                eq(false));
383
384        connectionServiceFixture.sendHandleCreateConnectionComplete(
385                connectionServiceFixture.mLatestConnectionId);
386        connectionServiceFixture.sendSetRinging(
387                connectionServiceFixture.mLatestConnectionId);
388
389        // For the case of incoming calls, Telecom connecting the InCall services and adding the
390        // Call is triggered by the async completion of the CallerInfoAsyncQuery. Once the Call
391        // is added, future interactions as triggered by the ConnectionService, through the various
392        // test fixtures, will be synchronous.
393
394        if (!hasInCallAdapter) {
395            verify(
396                    mInCallServiceFixtureX.getTestDouble(),
397                    timeout(TEST_TIMEOUT))
398                    .setInCallAdapter(
399                            any(IInCallAdapter.class));
400            verify(
401                    mInCallServiceFixtureY.getTestDouble(),
402                    timeout(TEST_TIMEOUT))
403                    .setInCallAdapter(
404                            any(IInCallAdapter.class));
405        }
406
407        // Give the InCallService time to respond
408        pause();
409
410        assertNotNull(mInCallServiceFixtureX.mInCallAdapter);
411        assertNotNull(mInCallServiceFixtureY.mInCallAdapter);
412
413        verify(
414                mInCallServiceFixtureX.getTestDouble(),
415                timeout(TEST_TIMEOUT))
416                .addCall(
417                        any(ParcelableCall.class));
418        verify(
419                mInCallServiceFixtureY.getTestDouble(),
420                timeout(TEST_TIMEOUT))
421                .addCall(
422                        any(ParcelableCall.class));
423
424        // Give the InCallService time to respond
425        pause();
426
427        assertEquals(startingNumConnections + 1, connectionServiceFixture.mConnectionById.size());
428        assertEquals(startingNumCalls + 1, mInCallServiceFixtureX.mCallById.size());
429        assertEquals(startingNumCalls + 1, mInCallServiceFixtureY.mCallById.size());
430
431        assertEquals(
432                mInCallServiceFixtureX.mLatestCallId,
433                mInCallServiceFixtureY.mLatestCallId);
434
435        return new IdPair(
436                connectionServiceFixture.mLatestConnectionId,
437                mInCallServiceFixtureX.mLatestCallId);
438    }
439
440    private void rapidFire(Runnable... tasks) {
441        final CyclicBarrier barrier = new CyclicBarrier(tasks.length);
442        final CountDownLatch latch = new CountDownLatch(tasks.length);
443        for (int i = 0; i < tasks.length; i++) {
444            final Runnable task = tasks[i];
445            new Thread(new Runnable() {
446                @Override
447                public void run() {
448                    try {
449                        barrier.await();
450                        task.run();
451                    } catch (InterruptedException | BrokenBarrierException e){
452                        Log.e(TelecomSystemTest.this, e, "Unexpectedly interrupted");
453                    } finally {
454                        latch.countDown();
455                    }
456                }
457            }).start();
458        }
459        try {
460            latch.await();
461        } catch (InterruptedException e) {
462            Log.e(TelecomSystemTest.this, e, "Unexpectedly interrupted");
463        }
464    }
465
466    // A simple outgoing call, verifying that the appropriate connection service is contacted,
467    // the proper lifecycle is followed, and both In-Call Services are updated correctly.
468    private IdPair startAndMakeActiveOutgoingCall(
469            String number,
470            PhoneAccountHandle phoneAccountHandle,
471            ConnectionServiceFixture connectionServiceFixture) throws Exception {
472        IdPair ids = startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture);
473
474        connectionServiceFixture.sendSetDialing(ids.mConnectionId);
475
476        assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
477        assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
478
479        connectionServiceFixture.sendSetActive(ids.mConnectionId);
480        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
481        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
482
483        return ids;
484    }
485
486    public void testSingleOutgoingCallLocalDisconnect() throws Exception {
487        IdPair ids = startAndMakeActiveOutgoingCall(
488                "650-555-1212",
489                mPhoneAccountA0.getAccountHandle(),
490                mConnectionServiceFixtureA);
491
492        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
493        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
494        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
495
496        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
497        assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
498        assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
499    }
500
501    public void testSingleOutgoingCallRemoteDisconnect() throws Exception {
502        IdPair ids = startAndMakeActiveOutgoingCall(
503                "650-555-1212",
504                mPhoneAccountA0.getAccountHandle(),
505                mConnectionServiceFixtureA);
506
507        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
508        assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
509        assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
510    }
511
512    // A simple incoming call, similar in scope to the previous test
513    private IdPair startAndMakeActiveIncomingCall(
514            String number,
515            PhoneAccountHandle phoneAccountHandle,
516            ConnectionServiceFixture connectionServiceFixture) throws Exception {
517        IdPair ids = startIncomingPhoneCall(number, phoneAccountHandle, connectionServiceFixture);
518
519        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
520        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
521
522        connectionServiceFixture.sendSetActive(ids.mConnectionId);
523        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
524        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
525
526        return ids;
527    }
528
529    public void testSingleIncomingCallLocalDisconnect() throws Exception {
530        IdPair ids = startAndMakeActiveIncomingCall(
531                "650-555-1212",
532                mPhoneAccountA0.getAccountHandle(),
533                mConnectionServiceFixtureA);
534
535        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
536        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
537        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
538
539        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
540        assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
541        assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
542    }
543
544    public void testSingleIncomingCallRemoteDisconnect() throws Exception {
545        IdPair ids = startAndMakeActiveIncomingCall(
546                "650-555-1212",
547                mPhoneAccountA0.getAccountHandle(),
548                mConnectionServiceFixtureA);
549
550        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
551        assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
552        assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
553    }
554
555    public void do_testDeadlockOnOutgoingCall() throws Exception {
556        final IdPair ids = startOutgoingPhoneCall(
557                "650-555-1212",
558                mPhoneAccountA0.getAccountHandle(),
559                mConnectionServiceFixtureA);
560        rapidFire(
561                new Runnable() {
562                    @Override
563                    public void run() {
564                        while (mCallerInfoAsyncQueryFactoryFixture.mRequests.size() > 0) {
565                            mCallerInfoAsyncQueryFactoryFixture.mRequests.remove(0).reply();
566                        }
567                    }
568                },
569                new Runnable() {
570                    @Override
571                    public void run() {
572                        try {
573                            mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId);
574                        } catch (Exception e) {
575                            Log.e(this, e, "");
576                        }
577                    }
578                });
579    }
580
581    public void testDeadlockOnOutgoingCall() throws Exception {
582        for (int i = 0; i < 100; i++) {
583            TelecomSystemTest test = new TelecomSystemTest();
584            test.setContext(getContext());
585            test.setTestContext(getTestContext());
586            test.setName(getName());
587            test.setUp();
588            test.do_testDeadlockOnOutgoingCall();
589            test.tearDown();
590        }
591    }
592
593    public void testIncomingThenOutgoingCalls() throws Exception {
594        // TODO: We have to use the same PhoneAccount for both; see http://b/18461539
595        IdPair incoming = startAndMakeActiveIncomingCall(
596                "650-555-2323",
597                mPhoneAccountA0.getAccountHandle(),
598                mConnectionServiceFixtureA);
599        IdPair outgoing = startAndMakeActiveOutgoingCall(
600                "650-555-1212",
601                mPhoneAccountA0.getAccountHandle(),
602                mConnectionServiceFixtureA);
603    }
604
605    public void testOutgoingThenIncomingCalls() throws Exception {
606        // TODO: We have to use the same PhoneAccount for both; see http://b/18461539
607        IdPair outgoing = startAndMakeActiveOutgoingCall(
608                "650-555-1212",
609                mPhoneAccountA0.getAccountHandle(),
610                mConnectionServiceFixtureA);
611        IdPair incoming = startAndMakeActiveIncomingCall(
612                "650-555-2323",
613                mPhoneAccountA0.getAccountHandle(),
614                mConnectionServiceFixtureA);
615    }
616
617    public void testAudioManagerOperations() throws Exception {
618        AudioManager audioManager = (AudioManager) mComponentContextFixture.getTestDouble()
619                .getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
620
621        IdPair outgoing = startAndMakeActiveOutgoingCall(
622                "650-555-1212",
623                mPhoneAccountA0.getAccountHandle(),
624                mConnectionServiceFixtureA);
625
626        verify(audioManager, timeout(TEST_TIMEOUT))
627                .requestAudioFocusForCall(anyInt(), anyInt());
628        verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce())
629                .setMode(AudioManager.MODE_IN_CALL);
630
631        mInCallServiceFixtureX.mInCallAdapter.mute(true);
632        verify(audioManager, timeout(TEST_TIMEOUT))
633                .setMicrophoneMute(true);
634        mInCallServiceFixtureX.mInCallAdapter.mute(false);
635        verify(audioManager, timeout(TEST_TIMEOUT))
636                .setMicrophoneMute(false);
637
638        mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_SPEAKER);
639        verify(audioManager, timeout(TEST_TIMEOUT))
640                .setSpeakerphoneOn(true);
641        mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_EARPIECE);
642        verify(audioManager, timeout(TEST_TIMEOUT))
643                .setSpeakerphoneOn(false);
644
645        mConnectionServiceFixtureA.
646                sendSetDisconnected(outgoing.mConnectionId, DisconnectCause.REMOTE);
647
648        verify(audioManager, timeout(TEST_TIMEOUT))
649                .abandonAudioFocusForCall();
650        verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce())
651                .setMode(AudioManager.MODE_NORMAL);
652    }
653
654    protected static void pause() {
655        try {
656            Thread.sleep(TEST_TIMEOUT);
657        } catch (InterruptedException e) {
658            fail(e.toString());
659        }
660    }
661}
662