BasicCallTests.java revision a2b067eacbd9ee7210cb0887a6b26068990d82ff
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.anyInt;
21import static org.mockito.Matchers.anyString;
22import static org.mockito.Matchers.eq;
23import static org.mockito.Matchers.isNull;
24import static org.mockito.Mockito.never;
25import static org.mockito.Mockito.timeout;
26import static org.mockito.Mockito.verify;
27import static org.mockito.Mockito.verifyZeroInteractions;
28import static org.mockito.Mockito.when;
29
30import android.content.Context;
31import android.content.IContentProvider;
32import android.media.AudioManager;
33import android.net.Uri;
34import android.os.Bundle;
35import android.os.Handler;
36import android.os.Looper;
37import android.os.Process;
38import android.provider.BlockedNumberContract;
39import android.telecom.Call;
40import android.telecom.CallAudioState;
41import android.telecom.Connection;
42import android.telecom.ConnectionRequest;
43import android.telecom.DisconnectCause;
44import android.telecom.Log;
45import android.telecom.ParcelableCall;
46import android.telecom.PhoneAccount;
47import android.telecom.PhoneAccountHandle;
48import android.telecom.TelecomManager;
49import android.telecom.VideoProfile;
50import android.test.suitebuilder.annotation.LargeTest;
51import android.test.suitebuilder.annotation.MediumTest;
52
53import com.android.internal.telecom.IInCallAdapter;
54import com.android.internal.telephony.CallerInfo;
55
56import com.google.common.base.Predicate;
57
58import org.mockito.invocation.InvocationOnMock;
59import org.mockito.stubbing.Answer;
60
61import java.util.concurrent.BrokenBarrierException;
62import java.util.concurrent.CountDownLatch;
63import java.util.concurrent.CyclicBarrier;
64import java.util.concurrent.TimeUnit;
65
66import org.mockito.ArgumentCaptor;
67
68/**
69 * Performs various basic call tests in Telecom.
70 */
71public class BasicCallTests extends TelecomSystemTest {
72    private static final String TEST_BUNDLE_KEY = "android.telecom.extra.TEST";
73    private static final String TEST_EVENT = "android.telecom.event.TEST";
74
75    @LargeTest
76    public void testSingleOutgoingCallLocalDisconnect() throws Exception {
77        IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
78                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
79
80        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
81        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
82        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
83
84        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
85        assertEquals(Call.STATE_DISCONNECTED,
86                mInCallServiceFixtureX.getCall(ids.mCallId).getState());
87        assertEquals(Call.STATE_DISCONNECTED,
88                mInCallServiceFixtureY.getCall(ids.mCallId).getState());
89        verifyNoBlockChecks();
90    }
91
92    @LargeTest
93    public void testSingleOutgoingCallRemoteDisconnect() throws Exception {
94        IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
95                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
96
97        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
98        assertEquals(Call.STATE_DISCONNECTED,
99                mInCallServiceFixtureX.getCall(ids.mCallId).getState());
100        assertEquals(Call.STATE_DISCONNECTED,
101                mInCallServiceFixtureY.getCall(ids.mCallId).getState());
102        verifyNoBlockChecks();
103    }
104
105    /**
106     * Tests the {@link TelecomManager#acceptRingingCall()} API.  Tests simple case of an incoming
107     * audio-only call.
108     *
109     * @throws Exception
110     */
111    @LargeTest
112    public void testTelecomManagerAcceptRingingCall() throws Exception {
113        IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(),
114                mConnectionServiceFixtureA);
115
116        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
117        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
118
119        // Use TelecomManager API to answer the ringing call.
120        TelecomManager telecomManager = (TelecomManager) mComponentContextFixture.getTestDouble()
121                .getApplicationContext().getSystemService(Context.TELECOM_SERVICE);
122        telecomManager.acceptRingingCall();
123
124        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
125                .answer(eq(ids.mConnectionId), any());
126        mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId);
127
128        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
129    }
130
131    /**
132     * Tests the {@link TelecomManager#acceptRingingCall()} API.  Tests simple case of an incoming
133     * video call, which should be answered as video.
134     *
135     * @throws Exception
136     */
137    @LargeTest
138    public void testTelecomManagerAcceptRingingVideoCall() throws Exception {
139        IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(),
140                VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA);
141
142        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
143        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
144
145        // Use TelecomManager API to answer the ringing call; the default expected behavior is to
146        // answer using whatever video state the ringing call requests.
147        TelecomManager telecomManager = (TelecomManager) mComponentContextFixture.getTestDouble()
148                .getApplicationContext().getSystemService(Context.TELECOM_SERVICE);
149        telecomManager.acceptRingingCall();
150
151        // Answer video API should be called
152        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
153                .answerVideo(eq(ids.mConnectionId), eq(VideoProfile.STATE_BIDIRECTIONAL), any());
154        mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId);
155
156        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
157    }
158
159    /**
160     * Tests the {@link TelecomManager#acceptRingingCall(int)} API.  Tests answering a video call
161     * as an audio call.
162     *
163     * @throws Exception
164     */
165    @LargeTest
166    public void testTelecomManagerAcceptRingingVideoCallAsAudio() throws Exception {
167        IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(),
168                VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA);
169
170        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
171        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
172
173        // Use TelecomManager API to answer the ringing call.
174        TelecomManager telecomManager = (TelecomManager) mComponentContextFixture.getTestDouble()
175                .getApplicationContext().getSystemService(Context.TELECOM_SERVICE);
176        telecomManager.acceptRingingCall(VideoProfile.STATE_AUDIO_ONLY);
177
178        // The generic answer method on the ConnectionService is used to answer audio-only calls.
179        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
180                .answer(eq(ids.mConnectionId), any());
181        mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId);
182
183        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
184    }
185
186    /**
187     * Tests the {@link TelecomManager#acceptRingingCall()} API.  Tests simple case of an incoming
188     * video call, where an attempt is made to answer with an invalid video state.
189     *
190     * @throws Exception
191     */
192    @LargeTest
193    public void testTelecomManagerAcceptRingingInvalidVideoState() throws Exception {
194        IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(),
195                VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA);
196
197        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
198        assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
199
200        // Use TelecomManager API to answer the ringing call; the default expected behavior is to
201        // answer using whatever video state the ringing call requests.
202        TelecomManager telecomManager = (TelecomManager) mComponentContextFixture.getTestDouble()
203                .getApplicationContext().getSystemService(Context.TELECOM_SERVICE);
204        telecomManager.acceptRingingCall(999 /* invalid videostate */);
205
206        // Answer video API should be called
207        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
208                .answerVideo(eq(ids.mConnectionId), eq(VideoProfile.STATE_BIDIRECTIONAL), any());
209        mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId);
210        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
211    }
212
213    @LargeTest
214    public void testSingleIncomingCallLocalDisconnect() throws Exception {
215        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
216                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
217        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
218        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
219        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
220
221        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
222        assertEquals(Call.STATE_DISCONNECTED,
223                mInCallServiceFixtureX.getCall(ids.mCallId).getState());
224        assertEquals(Call.STATE_DISCONNECTED,
225                mInCallServiceFixtureY.getCall(ids.mCallId).getState());
226    }
227
228    @LargeTest
229    public void testSingleIncomingCallRemoteDisconnect() throws Exception {
230        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
231                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
232
233        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
234        assertEquals(Call.STATE_DISCONNECTED,
235                mInCallServiceFixtureX.getCall(ids.mCallId).getState());
236        assertEquals(Call.STATE_DISCONNECTED,
237                mInCallServiceFixtureY.getCall(ids.mCallId).getState());
238    }
239
240    @LargeTest
241    public void testIncomingEmergencyCallback() throws Exception {
242        // Make an outgoing emergency call
243        String phoneNumber = "650-555-1212";
244        IdPair ids = startAndMakeDialingEmergencyCall(phoneNumber,
245                mPhoneAccountE0.getAccountHandle(), mConnectionServiceFixtureA);
246        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(ids.mCallId);
247        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
248
249        // Incoming call should be marked as a potential emergency callback
250        Bundle extras = new Bundle();
251        extras.putParcelable(
252                TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
253                Uri.fromParts(PhoneAccount.SCHEME_TEL, phoneNumber, null));
254        mTelecomSystem.getTelecomServiceImpl().getBinder()
255                .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras);
256
257        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
258        ArgumentCaptor<ConnectionRequest> connectionRequestCaptor
259            = ArgumentCaptor.forClass(ConnectionRequest.class);
260        verify(mConnectionServiceFixtureA.getTestDouble())
261                .createConnection(any(PhoneAccountHandle.class), anyString(),
262                        connectionRequestCaptor.capture(), eq(true), eq(false), any());
263
264        assert(connectionRequestCaptor.getValue().getExtras().containsKey(
265            android.telecom.Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS));
266        assertTrue(connectionRequestCaptor.getValue().getExtras().getLong(
267            android.telecom.Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0) > 0);
268        assert(connectionRequestCaptor.getValue().getExtras().containsKey(
269            TelecomManager.EXTRA_INCOMING_CALL_ADDRESS));
270    }
271
272    @LargeTest
273    public void testOutgoingCallAndSelectPhoneAccount() throws Exception {
274        // Remove default PhoneAccount so that the Call moves into the correct
275        // SELECT_PHONE_ACCOUNT state.
276        mTelecomSystem.getPhoneAccountRegistrar().setUserSelectedOutgoingPhoneAccount(
277                null, Process.myUserHandle());
278        int startingNumConnections = mConnectionServiceFixtureA.mConnectionById.size();
279        int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
280        String callId = startOutgoingPhoneCallWithNoPhoneAccount("650-555-1212",
281                mConnectionServiceFixtureA);
282        assertEquals(Call.STATE_SELECT_PHONE_ACCOUNT,
283                mInCallServiceFixtureX.getCall(callId).getState());
284        assertEquals(Call.STATE_SELECT_PHONE_ACCOUNT,
285                mInCallServiceFixtureY.getCall(callId).getState());
286        mInCallServiceFixtureX.mInCallAdapter.phoneAccountSelected(callId,
287                mPhoneAccountA0.getAccountHandle(), false);
288
289        IdPair ids = outgoingCallPhoneAccountSelected(mPhoneAccountA0.getAccountHandle(),
290                startingNumConnections, startingNumCalls, mConnectionServiceFixtureA);
291
292        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
293        assertEquals(Call.STATE_DISCONNECTED,
294                mInCallServiceFixtureX.getCall(ids.mCallId).getState());
295        assertEquals(Call.STATE_DISCONNECTED,
296                mInCallServiceFixtureY.getCall(ids.mCallId).getState());
297    }
298
299    @LargeTest
300    public void testIncomingCallFromContactWithSendToVoicemailIsRejected() throws Exception {
301        Bundle extras = new Bundle();
302        extras.putParcelable(
303                TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
304                Uri.fromParts(PhoneAccount.SCHEME_TEL, "650-555-1212", null));
305        mTelecomSystem.getTelecomServiceImpl().getBinder()
306                .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras);
307
308        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
309        verify(mConnectionServiceFixtureA.getTestDouble())
310                .createConnection(any(PhoneAccountHandle.class), anyString(),
311                        any(ConnectionRequest.class), eq(true), eq(false), any());
312
313        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
314        assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size());
315        for (CallerInfoAsyncQueryFactoryFixture.Request request :
316                mCallerInfoAsyncQueryFactoryFixture.mRequests) {
317            CallerInfo sendToVoicemailCallerInfo = new CallerInfo();
318            sendToVoicemailCallerInfo.shouldSendToVoicemail = true;
319            request.replyWithCallerInfo(sendToVoicemailCallerInfo);
320        }
321
322        assertTrueWithTimeout(new Predicate<Void>() {
323            @Override
324            public boolean apply(Void aVoid) {
325                return mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size() == 1;
326            }
327        });
328        assertTrueWithTimeout(new Predicate<Void>() {
329            @Override
330            public boolean apply(Void aVoid) {
331                return mMissedCallNotifier.missedCallsNotified.size() == 1;
332            }
333        });
334
335        verify(mInCallServiceFixtureX.getTestDouble(), never())
336                .setInCallAdapter(any(IInCallAdapter.class));
337        verify(mInCallServiceFixtureY.getTestDouble(), never())
338                .setInCallAdapter(any(IInCallAdapter.class));
339    }
340
341    @LargeTest
342    public void testIncomingCallCallerInfoLookupTimesOutIsAllowed() throws Exception {
343        Bundle extras = new Bundle();
344        extras.putParcelable(
345                TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
346                Uri.fromParts(PhoneAccount.SCHEME_TEL, "650-555-1212", null));
347        mTelecomSystem.getTelecomServiceImpl().getBinder()
348                .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras);
349
350        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
351        verify(mConnectionServiceFixtureA.getTestDouble())
352                .createConnection(any(PhoneAccountHandle.class), anyString(),
353                        any(ConnectionRequest.class), eq(true), eq(false), any());
354
355        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
356        // Never reply to the caller info lookup.
357        assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size());
358
359        verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
360                .setInCallAdapter(any(IInCallAdapter.class));
361        verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT))
362                .setInCallAdapter(any(IInCallAdapter.class));
363
364        assertEquals(0, mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size());
365        assertEquals(0, mMissedCallNotifier.missedCallsNotified.size());
366
367        assertTrueWithTimeout(new Predicate<Void>() {
368            @Override
369            public boolean apply(Void v) {
370                return mInCallServiceFixtureX.mInCallAdapter != null;
371            }
372        });
373
374        verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
375                .addCall(any(ParcelableCall.class));
376        verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT))
377                .addCall(any(ParcelableCall.class));
378
379        disconnectCall(mInCallServiceFixtureX.mLatestCallId,
380                mConnectionServiceFixtureA.mLatestConnectionId);
381    }
382
383    @LargeTest
384    public void testIncomingCallFromBlockedNumberIsRejected() throws Exception {
385        String phoneNumber = "650-555-1212";
386        blockNumber(phoneNumber);
387
388        Bundle extras = new Bundle();
389        extras.putParcelable(
390                TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
391                Uri.fromParts(PhoneAccount.SCHEME_TEL, phoneNumber, null));
392        mTelecomSystem.getTelecomServiceImpl().getBinder()
393                .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras);
394
395        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
396        verify(mConnectionServiceFixtureA.getTestDouble())
397                .createConnection(any(PhoneAccountHandle.class), anyString(),
398                        any(ConnectionRequest.class), eq(true), eq(false), any());
399
400        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
401        assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size());
402        for (CallerInfoAsyncQueryFactoryFixture.Request request :
403                mCallerInfoAsyncQueryFactoryFixture.mRequests) {
404            request.reply();
405        }
406
407        assertTrueWithTimeout(new Predicate<Void>() {
408            @Override
409            public boolean apply(Void aVoid) {
410                return mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size() == 1;
411            }
412        });
413        assertEquals(0, mMissedCallNotifier.missedCallsNotified.size());
414
415        verify(mInCallServiceFixtureX.getTestDouble(), never())
416                .setInCallAdapter(any(IInCallAdapter.class));
417        verify(mInCallServiceFixtureY.getTestDouble(), never())
418                .setInCallAdapter(any(IInCallAdapter.class));
419    }
420
421    @LargeTest
422    public void testIncomingCallBlockCheckTimesoutIsAllowed() throws Exception {
423        final CountDownLatch latch = new CountDownLatch(1);
424        String phoneNumber = "650-555-1212";
425        blockNumberWithAnswer(phoneNumber, new Answer<Bundle>() {
426            @Override
427            public Bundle answer(InvocationOnMock invocation) throws Throwable {
428                latch.await(TEST_TIMEOUT * 2, TimeUnit.MILLISECONDS);
429                Bundle bundle = new Bundle();
430                bundle.putBoolean(BlockedNumberContract.RES_NUMBER_IS_BLOCKED, true);
431                return bundle;
432            }
433        });
434
435        IdPair ids = startAndMakeActiveIncomingCall(
436                phoneNumber, mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
437        latch.countDown();
438
439        assertEquals(0, mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size());
440        assertEquals(0, mMissedCallNotifier.missedCallsNotified.size());
441        disconnectCall(ids.mCallId, ids.mConnectionId);
442    }
443
444    public void do_testDeadlockOnOutgoingCall() throws Exception {
445        final IdPair ids = startOutgoingPhoneCall("650-555-1212",
446                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA,
447                Process.myUserHandle());
448        rapidFire(
449                new Runnable() {
450                    @Override
451                    public void run() {
452                        while (mCallerInfoAsyncQueryFactoryFixture.mRequests.size() > 0) {
453                            mCallerInfoAsyncQueryFactoryFixture.mRequests.remove(0).reply();
454                        }
455                    }
456                },
457                new Runnable() {
458                    @Override
459                    public void run() {
460                        try {
461                            mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId);
462                        } catch (Exception e) {
463                            Log.e(this, e, "");
464                        }
465                    }
466                });
467    }
468
469    @MediumTest
470    public void testDeadlockOnOutgoingCall() throws Exception {
471        for (int i = 0; i < 100; i++) {
472            BasicCallTests test = new BasicCallTests();
473            test.setContext(getContext());
474            test.setTestContext(getTestContext());
475            test.setName(getName());
476            test.setUp();
477            test.do_testDeadlockOnOutgoingCall();
478            test.tearDown();
479        }
480    }
481
482    @LargeTest
483    public void testIncomingThenOutgoingCalls() throws Exception {
484        // TODO: We have to use the same PhoneAccount for both; see http://b/18461539
485        IdPair incoming = startAndMakeActiveIncomingCall("650-555-2323",
486                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
487        IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1212",
488                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
489
490        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(incoming.mCallId);
491        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(outgoing.mCallId);
492    }
493
494    @LargeTest
495    public void testOutgoingThenIncomingCalls() throws Exception {
496        // TODO: We have to use the same PhoneAccount for both; see http://b/18461539
497        IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1212",
498                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
499        IdPair incoming = startAndMakeActiveIncomingCall("650-555-2323",
500                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
501        verify(mConnectionServiceFixtureA.getTestDouble())
502                .hold(eq(outgoing.mConnectionId), any());
503        mConnectionServiceFixtureA.mConnectionById.get(outgoing.mConnectionId).state =
504                Connection.STATE_HOLDING;
505        mConnectionServiceFixtureA.sendSetOnHold(outgoing.mConnectionId);
506        assertEquals(Call.STATE_HOLDING,
507                mInCallServiceFixtureX.getCall(outgoing.mCallId).getState());
508        assertEquals(Call.STATE_HOLDING,
509                mInCallServiceFixtureY.getCall(outgoing.mCallId).getState());
510
511        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(incoming.mCallId);
512        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(outgoing.mCallId);
513    }
514
515    @LargeTest
516    public void testAudioManagerOperations() throws Exception {
517        AudioManager audioManager = (AudioManager) mComponentContextFixture.getTestDouble()
518                .getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
519
520        IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1212",
521                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
522
523        verify(audioManager, timeout(TEST_TIMEOUT)).requestAudioFocusForCall(anyInt(), anyInt());
524        verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce())
525                .setMode(AudioManager.MODE_IN_CALL);
526
527        mInCallServiceFixtureX.mInCallAdapter.mute(true);
528        verify(mAudioService, timeout(TEST_TIMEOUT))
529                .setMicrophoneMute(eq(true), any(String.class), any(Integer.class));
530        mInCallServiceFixtureX.mInCallAdapter.mute(false);
531        verify(mAudioService, timeout(TEST_TIMEOUT))
532                .setMicrophoneMute(eq(false), any(String.class), any(Integer.class));
533
534        mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_SPEAKER);
535        verify(audioManager, timeout(TEST_TIMEOUT))
536                .setSpeakerphoneOn(true);
537        mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_EARPIECE);
538        verify(audioManager, timeout(TEST_TIMEOUT))
539                .setSpeakerphoneOn(false);
540
541        mConnectionServiceFixtureA.
542                sendSetDisconnected(outgoing.mConnectionId, DisconnectCause.REMOTE);
543
544        verify(audioManager, timeout(TEST_TIMEOUT))
545                .abandonAudioFocusForCall();
546        verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce())
547                .setMode(AudioManager.MODE_NORMAL);
548    }
549
550    private void rapidFire(Runnable... tasks) {
551        final CyclicBarrier barrier = new CyclicBarrier(tasks.length);
552        final CountDownLatch latch = new CountDownLatch(tasks.length);
553        for (int i = 0; i < tasks.length; i++) {
554            final Runnable task = tasks[i];
555            new Thread(new Runnable() {
556                @Override
557                public void run() {
558                    try {
559                        barrier.await();
560                        task.run();
561                    } catch (InterruptedException | BrokenBarrierException e){
562                        Log.e(BasicCallTests.this, e, "Unexpectedly interrupted");
563                    } finally {
564                        latch.countDown();
565                    }
566                }
567            }).start();
568        }
569        try {
570            latch.await();
571        } catch (InterruptedException e) {
572            Log.e(BasicCallTests.this, e, "Unexpectedly interrupted");
573        }
574    }
575
576    @MediumTest
577    public void testBasicConferenceCall() throws Exception {
578        makeConferenceCall();
579    }
580
581    @MediumTest
582    public void testAddCallToConference1() throws Exception {
583        ParcelableCall conferenceCall = makeConferenceCall();
584        IdPair callId3 = startAndMakeActiveOutgoingCall("650-555-1214",
585                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
586        // testAddCallToConference{1,2} differ in the order of arguments to InCallAdapter#conference
587        mInCallServiceFixtureX.getInCallAdapter().conference(
588                conferenceCall.getId(), callId3.mCallId);
589        Thread.sleep(200);
590
591        ParcelableCall call3 = mInCallServiceFixtureX.getCall(callId3.mCallId);
592        ParcelableCall updatedConference = mInCallServiceFixtureX.getCall(conferenceCall.getId());
593        assertEquals(conferenceCall.getId(), call3.getParentCallId());
594        assertEquals(3, updatedConference.getChildCallIds().size());
595        assertTrue(updatedConference.getChildCallIds().contains(callId3.mCallId));
596    }
597
598    @MediumTest
599    public void testAddCallToConference2() throws Exception {
600        ParcelableCall conferenceCall = makeConferenceCall();
601        IdPair callId3 = startAndMakeActiveOutgoingCall("650-555-1214",
602                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
603        mInCallServiceFixtureX.getInCallAdapter()
604                .conference(callId3.mCallId, conferenceCall.getId());
605        Thread.sleep(200);
606
607        ParcelableCall call3 = mInCallServiceFixtureX.getCall(callId3.mCallId);
608        ParcelableCall updatedConference = mInCallServiceFixtureX.getCall(conferenceCall.getId());
609        assertEquals(conferenceCall.getId(), call3.getParentCallId());
610        assertEquals(3, updatedConference.getChildCallIds().size());
611        assertTrue(updatedConference.getChildCallIds().contains(callId3.mCallId));
612    }
613
614    /**
615     * Tests the {@link Call#pullExternalCall()} API.  Verifies that if a call is not an external
616     * call, no pull call request is made to the connection service.
617     *
618     * @throws Exception
619     */
620    @MediumTest
621    public void testPullNonExternalCall() throws Exception {
622        // TODO: Revisit this unit test once telecom support for filtering external calls from
623        // InCall services is implemented.
624        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
625                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
626        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
627
628        // Attempt to pull the call and verify the API call makes it through
629        mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId);
630        Thread.sleep(TEST_TIMEOUT);
631        verify(mConnectionServiceFixtureA.getTestDouble(), never())
632                .pullExternalCall(eq(ids.mCallId), any());
633    }
634
635    /**
636     * Tests the {@link Connection#sendConnectionEvent(String, Bundle)} API.
637     *
638     * @throws Exception
639     */
640    @MediumTest
641    public void testSendConnectionEventNull() throws Exception {
642        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
643                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
644        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
645        mConnectionServiceFixtureA.sendConnectionEvent(ids.mConnectionId, TEST_EVENT, null);
646        verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
647                .onConnectionEvent(ids.mCallId, TEST_EVENT, null);
648    }
649
650    /**
651     * Tests the {@link Connection#sendConnectionEvent(String, Bundle)} API.
652     *
653     * @throws Exception
654     */
655    @MediumTest
656    public void testSendConnectionEventNotNull() throws Exception {
657        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
658                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
659        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
660
661        Bundle testBundle = new Bundle();
662        testBundle.putString(TEST_BUNDLE_KEY, "TEST");
663
664        ArgumentCaptor<Bundle> bundleArgumentCaptor = ArgumentCaptor.forClass(Bundle.class);
665        mConnectionServiceFixtureA.sendConnectionEvent(ids.mConnectionId, TEST_EVENT, testBundle);
666        verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
667                .onConnectionEvent(eq(ids.mCallId), eq(TEST_EVENT), bundleArgumentCaptor.capture());
668        assert (bundleArgumentCaptor.getValue().containsKey(TEST_BUNDLE_KEY));
669    }
670
671    /**
672     * Tests the {@link Call#sendCallEvent(String, Bundle)} API.
673     *
674     * @throws Exception
675     */
676    @MediumTest
677    public void testSendCallEventNull() throws Exception {
678        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
679                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
680        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
681
682        mInCallServiceFixtureX.mInCallAdapter.sendCallEvent(ids.mCallId, TEST_EVENT, null);
683        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
684                .sendCallEvent(eq(ids.mConnectionId), eq(TEST_EVENT), isNull(Bundle.class), any());
685    }
686
687    /**
688     * Tests the {@link Call#sendCallEvent(String, Bundle)} API.
689     *
690     * @throws Exception
691     */
692    @MediumTest
693    public void testSendCallEventNonNull() throws Exception {
694        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
695                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
696        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
697
698        Bundle testBundle = new Bundle();
699        testBundle.putString(TEST_BUNDLE_KEY, "TEST");
700
701        ArgumentCaptor<Bundle> bundleArgumentCaptor = ArgumentCaptor.forClass(Bundle.class);
702        mInCallServiceFixtureX.mInCallAdapter.sendCallEvent(ids.mCallId, TEST_EVENT,
703                testBundle);
704        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
705                .sendCallEvent(eq(ids.mConnectionId), eq(TEST_EVENT),
706                        bundleArgumentCaptor.capture(), any());
707        assert (bundleArgumentCaptor.getValue().containsKey(TEST_BUNDLE_KEY));
708    }
709
710    private void blockNumber(String phoneNumber) throws Exception {
711        blockNumberWithAnswer(phoneNumber, new Answer<Bundle>() {
712            @Override
713            public Bundle answer(InvocationOnMock invocation) throws Throwable {
714                Bundle bundle = new Bundle();
715                bundle.putBoolean(BlockedNumberContract.RES_NUMBER_IS_BLOCKED, true);
716                return bundle;
717            }
718        });
719    }
720
721    private void blockNumberWithAnswer(String phoneNumber, Answer answer) throws Exception {
722        when(getBlockedNumberProvider().call(
723                anyString(),
724                eq(BlockedNumberContract.SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER),
725                eq(phoneNumber),
726                isNull(Bundle.class))).thenAnswer(answer);
727    }
728
729    private void verifyNoBlockChecks() {
730        verifyZeroInteractions(getBlockedNumberProvider());
731    }
732
733    private IContentProvider getBlockedNumberProvider() {
734        return mSpyContext.getContentResolver().acquireProvider(BlockedNumberContract.AUTHORITY);
735    }
736
737    private void disconnectCall(String callId, String connectionId) throws Exception {
738        mConnectionServiceFixtureA.sendSetDisconnected(connectionId, DisconnectCause.LOCAL);
739        assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureX.getCall(callId).getState());
740        assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureY.getCall(callId).getState());
741    }
742
743    /**
744     * Tests to make sure that the Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY property is set on a
745     * Call that is based on a Connection with the Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY
746     * property set.
747     */
748    @MediumTest
749    public void testCdmaEnhancedPrivacyVoiceCall() throws Exception {
750        mConnectionServiceFixtureA.mConnectionServiceDelegate.mProperties =
751                Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY;
752
753        IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
754                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
755        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
756
757        assertTrue(Call.Details.hasProperty(
758                mInCallServiceFixtureX.getCall(ids.mCallId).getProperties(),
759                Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY));
760    }
761
762    /**
763     * Tests to make sure that Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY is dropped
764     * when the Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY property is removed from the Connection.
765     */
766    @MediumTest
767    public void testDropCdmaEnhancedPrivacyVoiceCall() throws Exception {
768        mConnectionServiceFixtureA.mConnectionServiceDelegate.mProperties =
769                Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY;
770
771        IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
772                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
773        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
774        mConnectionServiceFixtureA.mLatestConnection.setConnectionProperties(0);
775
776        assertFalse(Call.Details.hasProperty(
777                mInCallServiceFixtureX.getCall(ids.mCallId).getProperties(),
778                Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY));
779    }
780
781    /**
782     * Tests the {@link Call#pullExternalCall()} API.  Ensures that an external call which is
783     * pullable can be pulled.
784     *
785     * @throws Exception
786     */
787    @LargeTest
788    public void testPullExternalCall() throws Exception {
789        // TODO: Revisit this unit test once telecom support for filtering external calls from
790        // InCall services is implemented.
791        mConnectionServiceFixtureA.mConnectionServiceDelegate.mCapabilities =
792                Connection.CAPABILITY_CAN_PULL_CALL;
793        mConnectionServiceFixtureA.mConnectionServiceDelegate.mProperties =
794                Connection.PROPERTY_IS_EXTERNAL_CALL;
795
796        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
797                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
798        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
799
800        // Attempt to pull the call and verify the API call makes it through
801        mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId);
802        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
803                .pullExternalCall(eq(ids.mConnectionId), any());
804    }
805
806    /**
807     * Tests the {@link Call#pullExternalCall()} API.  Verifies that if an external call is not
808     * marked as pullable that the connection service does not get an API call to pull the external
809     * call.
810     *
811     * @throws Exception
812     */
813    @LargeTest
814    public void testPullNonPullableExternalCall() throws Exception {
815        // TODO: Revisit this unit test once telecom support for filtering external calls from
816        // InCall services is implemented.
817        mConnectionServiceFixtureA.mConnectionServiceDelegate.mProperties =
818                Connection.PROPERTY_IS_EXTERNAL_CALL;
819
820        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
821                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
822        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
823
824        // Attempt to pull the call and verify the API call makes it through
825        mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId);
826        Thread.sleep(TEST_TIMEOUT);
827        verify(mConnectionServiceFixtureA.getTestDouble(), never())
828                .pullExternalCall(eq(ids.mConnectionId), any());
829    }
830
831    @LargeTest
832    public void testEmergencyCallFailMoveToSecondSim() throws Exception {
833        IdPair ids = startAndMakeDialingEmergencyCall("650-555-1212",
834                mPhoneAccountE0.getAccountHandle(), mConnectionServiceFixtureA);
835        assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
836        assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
837
838        // The Emergency Call has failed on the default SIM with an ERROR Disconnect Cause. Retry
839        // with the other SIM PhoneAccount
840        IdPair newIds = triggerEmergencyRedial(mPhoneAccountE1.getAccountHandle(),
841                mConnectionServiceFixtureA, ids);
842
843        // Call should be active on the E1 PhoneAccount
844        mConnectionServiceFixtureA.sendSetActive(newIds.mConnectionId);
845        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(newIds.mCallId).getState());
846        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(newIds.mCallId).getState());
847        assertEquals(mInCallServiceFixtureX.getCall(ids.mCallId).getAccountHandle(),
848                mPhoneAccountE1.getAccountHandle());
849    }
850
851    /**
852     * Test scenario where the user starts an outgoing video call with no selected PhoneAccount, and
853     * then subsequently selects a PhoneAccount which supports video calling.
854     * @throws Exception
855     */
856    @LargeTest
857    public void testOutgoingCallSelectPhoneAccountVideo() throws Exception {
858        startOutgoingPhoneCallPendingCreateConnection("650-555-1212",
859                null, mConnectionServiceFixtureA,
860                Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL);
861        com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls()
862                .iterator().next();
863        assert(call.isVideoCallingSupported());
864        assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState());
865
866        // Change the phone account to one which supports video calling.
867        call.setTargetPhoneAccount(mPhoneAccountA1.getAccountHandle());
868        assert(call.isVideoCallingSupported());
869        assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState());
870    }
871
872    /**
873     * Test scenario where the user starts an outgoing video call with no selected PhoneAccount, and
874     * then subsequently selects a PhoneAccount which does not support video calling.
875     * @throws Exception
876     */
877    @LargeTest
878    public void testOutgoingCallSelectPhoneAccountNoVideo() throws Exception {
879        startOutgoingPhoneCallPendingCreateConnection("650-555-1212",
880                null, mConnectionServiceFixtureA,
881                Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL);
882        com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls()
883                .iterator().next();
884        assert(call.isVideoCallingSupported());
885        assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState());
886
887        // Change the phone account to one which does not support video calling.
888        call.setTargetPhoneAccount(mPhoneAccountA2.getAccountHandle());
889        assert(!call.isVideoCallingSupported());
890        assertEquals(VideoProfile.STATE_AUDIO_ONLY, call.getVideoState());
891    }
892}
893