BasicCallTests.java revision 874c0f8fa95a5da5a82e67c1fe39697883d753eb
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.ParcelableCall;
45import android.telecom.PhoneAccount;
46import android.telecom.PhoneAccountHandle;
47import android.telecom.TelecomManager;
48import android.telecom.VideoProfile;
49import android.test.suitebuilder.annotation.LargeTest;
50import android.test.suitebuilder.annotation.MediumTest;
51
52import com.android.internal.telecom.IInCallAdapter;
53import com.android.internal.telephony.CallerInfo;
54import com.android.server.telecom.Log;
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(ids.mCallId);
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.mCallId), eq(VideoProfile.STATE_BIDIRECTIONAL));
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.mCallId));
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.mCallId), eq(VideoProfile.STATE_BIDIRECTIONAL));
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 testOutgoingCallAndSelectPhoneAccount() throws Exception {
242        // Remove default PhoneAccount so that the Call moves into the correct
243        // SELECT_PHONE_ACCOUNT state.
244        mTelecomSystem.getPhoneAccountRegistrar().setUserSelectedOutgoingPhoneAccount(
245                null, Process.myUserHandle());
246        int startingNumConnections = mConnectionServiceFixtureA.mConnectionById.size();
247        int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
248        String callId = startOutgoingPhoneCallWithNoPhoneAccount("650-555-1212",
249                mConnectionServiceFixtureA);
250        assertEquals(Call.STATE_SELECT_PHONE_ACCOUNT,
251                mInCallServiceFixtureX.getCall(callId).getState());
252        assertEquals(Call.STATE_SELECT_PHONE_ACCOUNT,
253                mInCallServiceFixtureY.getCall(callId).getState());
254        mInCallServiceFixtureX.mInCallAdapter.phoneAccountSelected(callId,
255                mPhoneAccountA0.getAccountHandle(), false);
256
257        IdPair ids = outgoingCallPhoneAccountSelected(mPhoneAccountA0.getAccountHandle(),
258                startingNumConnections, startingNumCalls, mConnectionServiceFixtureA);
259
260        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
261        assertEquals(Call.STATE_DISCONNECTED,
262                mInCallServiceFixtureX.getCall(ids.mCallId).getState());
263        assertEquals(Call.STATE_DISCONNECTED,
264                mInCallServiceFixtureY.getCall(ids.mCallId).getState());
265    }
266
267    @LargeTest
268    public void testIncomingCallFromContactWithSendToVoicemailIsRejected() throws Exception {
269        Bundle extras = new Bundle();
270        extras.putParcelable(
271                TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
272                Uri.fromParts(PhoneAccount.SCHEME_TEL, "650-555-1212", null));
273        mTelecomSystem.getTelecomServiceImpl().getBinder()
274                .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras);
275
276        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
277        verify(mConnectionServiceFixtureA.getTestDouble())
278                .createConnection(any(PhoneAccountHandle.class), anyString(),
279                        any(ConnectionRequest.class), eq(true), eq(false));
280
281        assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size());
282        for (CallerInfoAsyncQueryFactoryFixture.Request request :
283                mCallerInfoAsyncQueryFactoryFixture.mRequests) {
284            CallerInfo sendToVoicemailCallerInfo = new CallerInfo();
285            sendToVoicemailCallerInfo.shouldSendToVoicemail = true;
286            request.replyWithCallerInfo(sendToVoicemailCallerInfo);
287        }
288
289        assertTrueWithTimeout(new Predicate<Void>() {
290            @Override
291            public boolean apply(Void aVoid) {
292                return mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size() == 1;
293            }
294        });
295        assertTrueWithTimeout(new Predicate<Void>() {
296            @Override
297            public boolean apply(Void aVoid) {
298                return mMissedCallNotifier.missedCallsNotified.size() == 1;
299            }
300        });
301
302        verify(mInCallServiceFixtureX.getTestDouble(), never())
303                .setInCallAdapter(any(IInCallAdapter.class));
304        verify(mInCallServiceFixtureY.getTestDouble(), never())
305                .setInCallAdapter(any(IInCallAdapter.class));
306    }
307
308    @LargeTest
309    public void testIncomingCallCallerInfoLookupTimesOutIsAllowed() throws Exception {
310        Bundle extras = new Bundle();
311        extras.putParcelable(
312                TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
313                Uri.fromParts(PhoneAccount.SCHEME_TEL, "650-555-1212", null));
314        mTelecomSystem.getTelecomServiceImpl().getBinder()
315                .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras);
316
317        verify(mConnectionServiceFixtureA.getTestDouble())
318                .createConnection(any(PhoneAccountHandle.class), anyString(),
319                        any(ConnectionRequest.class), eq(true), eq(false));
320
321        // Never reply to the caller info lookup.
322        assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size());
323
324        verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
325                .setInCallAdapter(any(IInCallAdapter.class));
326        verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT))
327                .setInCallAdapter(any(IInCallAdapter.class));
328
329        assertEquals(0, mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size());
330        assertEquals(0, mMissedCallNotifier.missedCallsNotified.size());
331
332        assertTrueWithTimeout(new Predicate<Void>() {
333            @Override
334            public boolean apply(Void v) {
335                return mInCallServiceFixtureX.mInCallAdapter != null;
336            }
337        });
338
339        verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
340                .addCall(any(ParcelableCall.class));
341        verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT))
342                .addCall(any(ParcelableCall.class));
343
344        disconnectCall(mInCallServiceFixtureX.mLatestCallId,
345                mConnectionServiceFixtureA.mLatestConnectionId);
346    }
347
348    @LargeTest
349    public void testIncomingCallFromBlockedNumberIsRejected() throws Exception {
350        String phoneNumber = "650-555-1212";
351        blockNumber(phoneNumber);
352
353        Bundle extras = new Bundle();
354        extras.putParcelable(
355                TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
356                Uri.fromParts(PhoneAccount.SCHEME_TEL, phoneNumber, null));
357        mTelecomSystem.getTelecomServiceImpl().getBinder()
358                .addNewIncomingCall(mPhoneAccountA0.getAccountHandle(), extras);
359
360        verify(mConnectionServiceFixtureA.getTestDouble())
361                .createConnection(any(PhoneAccountHandle.class), anyString(),
362                        any(ConnectionRequest.class), eq(true), eq(false));
363
364        assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size());
365        for (CallerInfoAsyncQueryFactoryFixture.Request request :
366                mCallerInfoAsyncQueryFactoryFixture.mRequests) {
367            request.reply();
368        }
369
370        assertTrueWithTimeout(new Predicate<Void>() {
371            @Override
372            public boolean apply(Void aVoid) {
373                return mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size() == 1;
374            }
375        });
376        assertEquals(0, mMissedCallNotifier.missedCallsNotified.size());
377
378        verify(mInCallServiceFixtureX.getTestDouble(), never())
379                .setInCallAdapter(any(IInCallAdapter.class));
380        verify(mInCallServiceFixtureY.getTestDouble(), never())
381                .setInCallAdapter(any(IInCallAdapter.class));
382    }
383
384    @LargeTest
385    public void testIncomingCallBlockCheckTimesoutIsAllowed() throws Exception {
386        final CountDownLatch latch = new CountDownLatch(1);
387        String phoneNumber = "650-555-1212";
388        blockNumberWithAnswer(phoneNumber, new Answer<Bundle>() {
389            @Override
390            public Bundle answer(InvocationOnMock invocation) throws Throwable {
391                latch.await(TEST_TIMEOUT * 2, TimeUnit.MILLISECONDS);
392                Bundle bundle = new Bundle();
393                bundle.putBoolean(BlockedNumberContract.RES_NUMBER_IS_BLOCKED, true);
394                return bundle;
395            }
396        });
397
398        IdPair ids = startAndMakeActiveIncomingCall(
399                phoneNumber, mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
400        latch.countDown();
401
402        assertEquals(0, mConnectionServiceFixtureA.mConnectionService.rejectedCallIds.size());
403        assertEquals(0, mMissedCallNotifier.missedCallsNotified.size());
404        disconnectCall(ids.mCallId, ids.mConnectionId);
405    }
406
407    public void do_testDeadlockOnOutgoingCall() throws Exception {
408        final IdPair ids = startOutgoingPhoneCall("650-555-1212",
409                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA,
410                Process.myUserHandle());
411        rapidFire(
412                new Runnable() {
413                    @Override
414                    public void run() {
415                        while (mCallerInfoAsyncQueryFactoryFixture.mRequests.size() > 0) {
416                            mCallerInfoAsyncQueryFactoryFixture.mRequests.remove(0).reply();
417                        }
418                    }
419                },
420                new Runnable() {
421                    @Override
422                    public void run() {
423                        try {
424                            mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId);
425                        } catch (Exception e) {
426                            Log.e(this, e, "");
427                        }
428                    }
429                });
430    }
431
432    @MediumTest
433    public void testDeadlockOnOutgoingCall() throws Exception {
434        for (int i = 0; i < 100; i++) {
435            BasicCallTests test = new BasicCallTests();
436            test.setContext(getContext());
437            test.setTestContext(getTestContext());
438            test.setName(getName());
439            test.setUp();
440            test.do_testDeadlockOnOutgoingCall();
441            test.tearDown();
442        }
443    }
444
445    @LargeTest
446    public void testIncomingThenOutgoingCalls() throws Exception {
447        // TODO: We have to use the same PhoneAccount for both; see http://b/18461539
448        IdPair incoming = startAndMakeActiveIncomingCall("650-555-2323",
449                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
450        IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1212",
451                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
452
453        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(incoming.mCallId);
454        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(outgoing.mCallId);
455    }
456
457    @LargeTest
458    public void testOutgoingThenIncomingCalls() throws Exception {
459        // TODO: We have to use the same PhoneAccount for both; see http://b/18461539
460        IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1212",
461                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
462        IdPair incoming = startAndMakeActiveIncomingCall("650-555-2323",
463                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
464        verify(mConnectionServiceFixtureA.getTestDouble())
465                .hold(outgoing.mConnectionId);
466        mConnectionServiceFixtureA.mConnectionById.get(outgoing.mConnectionId).state =
467                Connection.STATE_HOLDING;
468        mConnectionServiceFixtureA.sendSetOnHold(outgoing.mConnectionId);
469        assertEquals(Call.STATE_HOLDING,
470                mInCallServiceFixtureX.getCall(outgoing.mCallId).getState());
471        assertEquals(Call.STATE_HOLDING,
472                mInCallServiceFixtureY.getCall(outgoing.mCallId).getState());
473
474        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(incoming.mCallId);
475        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(outgoing.mCallId);
476    }
477
478    @LargeTest
479    public void testAudioManagerOperations() throws Exception {
480        AudioManager audioManager = (AudioManager) mComponentContextFixture.getTestDouble()
481                .getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
482
483        IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1212",
484                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
485
486        verify(audioManager, timeout(TEST_TIMEOUT)).requestAudioFocusForCall(anyInt(), anyInt());
487        verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce())
488                .setMode(AudioManager.MODE_IN_CALL);
489
490        mInCallServiceFixtureX.mInCallAdapter.mute(true);
491        verify(mAudioService, timeout(TEST_TIMEOUT))
492                .setMicrophoneMute(eq(true), any(String.class), any(Integer.class));
493        mInCallServiceFixtureX.mInCallAdapter.mute(false);
494        verify(mAudioService, timeout(TEST_TIMEOUT))
495                .setMicrophoneMute(eq(false), any(String.class), any(Integer.class));
496
497        mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_SPEAKER);
498        verify(audioManager, timeout(TEST_TIMEOUT))
499                .setSpeakerphoneOn(true);
500        mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_EARPIECE);
501        verify(audioManager, timeout(TEST_TIMEOUT))
502                .setSpeakerphoneOn(false);
503
504        mConnectionServiceFixtureA.
505                sendSetDisconnected(outgoing.mConnectionId, DisconnectCause.REMOTE);
506
507        verify(audioManager, timeout(TEST_TIMEOUT))
508                .abandonAudioFocusForCall();
509        verify(audioManager, timeout(TEST_TIMEOUT).atLeastOnce())
510                .setMode(AudioManager.MODE_NORMAL);
511    }
512
513    private void rapidFire(Runnable... tasks) {
514        final CyclicBarrier barrier = new CyclicBarrier(tasks.length);
515        final CountDownLatch latch = new CountDownLatch(tasks.length);
516        for (int i = 0; i < tasks.length; i++) {
517            final Runnable task = tasks[i];
518            new Thread(new Runnable() {
519                @Override
520                public void run() {
521                    try {
522                        barrier.await();
523                        task.run();
524                    } catch (InterruptedException | BrokenBarrierException e){
525                        Log.e(BasicCallTests.this, e, "Unexpectedly interrupted");
526                    } finally {
527                        latch.countDown();
528                    }
529                }
530            }).start();
531        }
532        try {
533            latch.await();
534        } catch (InterruptedException e) {
535            Log.e(BasicCallTests.this, e, "Unexpectedly interrupted");
536        }
537    }
538
539    @MediumTest
540    public void testBasicConferenceCall() throws Exception {
541        makeConferenceCall();
542    }
543
544    @MediumTest
545    public void testAddCallToConference1() throws Exception {
546        ParcelableCall conferenceCall = makeConferenceCall();
547        IdPair callId3 = startAndMakeActiveOutgoingCall("650-555-1214",
548                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
549        // testAddCallToConference{1,2} differ in the order of arguments to InCallAdapter#conference
550        mInCallServiceFixtureX.getInCallAdapter().conference(
551                conferenceCall.getId(), callId3.mCallId);
552        Thread.sleep(200);
553
554        ParcelableCall call3 = mInCallServiceFixtureX.getCall(callId3.mCallId);
555        ParcelableCall updatedConference = mInCallServiceFixtureX.getCall(conferenceCall.getId());
556        assertEquals(conferenceCall.getId(), call3.getParentCallId());
557        assertEquals(3, updatedConference.getChildCallIds().size());
558        assertTrue(updatedConference.getChildCallIds().contains(callId3.mCallId));
559    }
560
561    @MediumTest
562    public void testAddCallToConference2() throws Exception {
563        ParcelableCall conferenceCall = makeConferenceCall();
564        IdPair callId3 = startAndMakeActiveOutgoingCall("650-555-1214",
565                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
566        mInCallServiceFixtureX.getInCallAdapter()
567                .conference(callId3.mCallId, conferenceCall.getId());
568        Thread.sleep(200);
569
570        ParcelableCall call3 = mInCallServiceFixtureX.getCall(callId3.mCallId);
571        ParcelableCall updatedConference = mInCallServiceFixtureX.getCall(conferenceCall.getId());
572        assertEquals(conferenceCall.getId(), call3.getParentCallId());
573        assertEquals(3, updatedConference.getChildCallIds().size());
574        assertTrue(updatedConference.getChildCallIds().contains(callId3.mCallId));
575    }
576
577    /**
578     * Tests the {@link Call#pullExternalCall()} API.  Verifies that if a call is not an external
579     * call, no pull call request is made to the connection service.
580     *
581     * @throws Exception
582     */
583    @MediumTest
584    public void testPullNonExternalCall() throws Exception {
585        // TODO: Revisit this unit test once telecom support for filtering external calls from
586        // InCall services is implemented.
587        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
588                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
589        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
590
591        // Attempt to pull the call and verify the API call makes it through
592        mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId);
593        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT).never())
594                .pullExternalCall(ids.mCallId);
595    }
596
597    /**
598     * Tests the {@link Connection#sendConnectionEvent(String)} API.
599     *
600     * @throws Exception
601     */
602    @MediumTest
603    public void testSendConnectionEventNull() throws Exception {
604        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
605                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
606        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
607        mConnectionServiceFixtureA.sendConnectionEvent(ids.mConnectionId, TEST_EVENT, null);
608        verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
609                .onConnectionEvent(ids.mCallId, TEST_EVENT, null);
610    }
611
612    /**
613     * Tests the {@link Connection#sendConnectionEvent(String)} API.
614     *
615     * @throws Exception
616     */
617    @MediumTest
618    public void testSendConnectionEventNotNull() throws Exception {
619        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
620                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
621        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
622
623        Bundle testBundle = new Bundle();
624        testBundle.putString(TEST_BUNDLE_KEY, "TEST");
625
626        ArgumentCaptor<Bundle> bundleArgumentCaptor = ArgumentCaptor.forClass(Bundle.class);
627        mConnectionServiceFixtureA.sendConnectionEvent(ids.mConnectionId, TEST_EVENT, testBundle);
628        verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
629                .onConnectionEvent(eq(ids.mCallId), eq(TEST_EVENT), bundleArgumentCaptor.capture());
630        assert (bundleArgumentCaptor.getValue().containsKey(TEST_BUNDLE_KEY));
631    }
632
633    /**
634     * Tests the {@link Call#sendCallEvent(String, Bundle)} API.
635     *
636     * @throws Exception
637     */
638    @MediumTest
639    public void testSendCallEventNull() throws Exception {
640        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
641                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
642        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
643
644        mInCallServiceFixtureX.mInCallAdapter.sendCallEvent(ids.mCallId, TEST_EVENT, null);
645        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
646                .sendCallEvent(ids.mCallId, TEST_EVENT, null);
647    }
648
649    /**
650     * Tests the {@link Call#sendCallEvent(String, Bundle)} API.
651     *
652     * @throws Exception
653     */
654    @MediumTest
655    public void testSendCallEventNonNull() throws Exception {
656        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
657                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
658        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
659
660        Bundle testBundle = new Bundle();
661        testBundle.putString(TEST_BUNDLE_KEY, "TEST");
662
663        ArgumentCaptor<Bundle> bundleArgumentCaptor = ArgumentCaptor.forClass(Bundle.class);
664        mInCallServiceFixtureX.mInCallAdapter.sendCallEvent(ids.mCallId, TEST_EVENT,
665                testBundle);
666        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
667                .sendCallEvent(eq(ids.mCallId), eq(TEST_EVENT),
668                        bundleArgumentCaptor.capture());
669        assert (bundleArgumentCaptor.getValue().containsKey(TEST_BUNDLE_KEY));
670    }
671
672    private void blockNumber(String phoneNumber) throws Exception {
673        blockNumberWithAnswer(phoneNumber, new Answer<Bundle>() {
674            @Override
675            public Bundle answer(InvocationOnMock invocation) throws Throwable {
676                Bundle bundle = new Bundle();
677                bundle.putBoolean(BlockedNumberContract.RES_NUMBER_IS_BLOCKED, true);
678                return bundle;
679            }
680        });
681    }
682
683    private void blockNumberWithAnswer(String phoneNumber, Answer answer) throws Exception {
684        when(getBlockedNumberProvider().call(
685                anyString(),
686                eq(BlockedNumberContract.SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER),
687                eq(phoneNumber),
688                isNull(Bundle.class))).thenAnswer(answer);
689    }
690
691    private void verifyNoBlockChecks() {
692        verifyZeroInteractions(getBlockedNumberProvider());
693    }
694
695    private IContentProvider getBlockedNumberProvider() {
696        return mSpyContext.getContentResolver().acquireProvider(BlockedNumberContract.AUTHORITY);
697    }
698
699    private void disconnectCall(String callId, String connectionId) throws Exception {
700        mConnectionServiceFixtureA.sendSetDisconnected(connectionId, DisconnectCause.LOCAL);
701        assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureX.getCall(callId).getState());
702        assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureY.getCall(callId).getState());
703    }
704
705    /**
706     * Tests to make sure that the Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY property is set on a
707     * Call that is based on a Connection with the Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY
708     * property set.
709     */
710    @MediumTest
711    public void testCdmaEnhancedPrivacyVoiceCall() throws Exception {
712        mConnectionServiceFixtureA.mConnectionServiceDelegate.mProperties =
713                Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY;
714
715        IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
716                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
717        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
718
719        assertTrue(Call.Details.hasProperty(
720                mInCallServiceFixtureX.getCall(ids.mCallId).getProperties(),
721                Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY));
722    }
723
724    /**
725     * Tests to make sure that Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY is dropped
726     * when the Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY property is removed from the Connection.
727     */
728    @MediumTest
729    public void testDropCdmaEnhancedPrivacyVoiceCall() throws Exception {
730        mConnectionServiceFixtureA.mConnectionServiceDelegate.mProperties =
731                Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY;
732
733        IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
734                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
735        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
736        mConnectionServiceFixtureA.mLatestConnection.setConnectionProperties(0);
737
738        assertFalse(Call.Details.hasProperty(
739                mInCallServiceFixtureX.getCall(ids.mCallId).getProperties(),
740                Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY));
741    }
742
743    /**
744     * Tests the {@link Call#pullExternalCall()} API.  Ensures that an external call which is
745     * pullable can be pulled.
746     *
747     * @throws Exception
748     */
749    @LargeTest
750    public void testPullExternalCall() throws Exception {
751        // TODO: Revisit this unit test once telecom support for filtering external calls from
752        // InCall services is implemented.
753        mConnectionServiceFixtureA.mConnectionServiceDelegate.mCapabilities =
754                Connection.CAPABILITY_CAN_PULL_CALL;
755        mConnectionServiceFixtureA.mConnectionServiceDelegate.mProperties =
756                Connection.PROPERTY_IS_EXTERNAL_CALL;
757
758        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
759                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
760        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
761
762        // Attempt to pull the call and verify the API call makes it through
763        mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId);
764        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
765                .pullExternalCall(ids.mCallId);
766    }
767
768    /**
769     * Tests the {@link Call#pullExternalCall()} API.  Verifies that if an external call is not
770     * marked as pullable that the connection service does not get an API call to pull the external
771     * call.
772     *
773     * @throws Exception
774     */
775    @LargeTest
776    public void testPullNonPullableExternalCall() throws Exception {
777        // TODO: Revisit this unit test once telecom support for filtering external calls from
778        // InCall services is implemented.
779        mConnectionServiceFixtureA.mConnectionServiceDelegate.mProperties =
780                Connection.PROPERTY_IS_EXTERNAL_CALL;
781
782        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
783                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
784        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
785
786        // Attempt to pull the call and verify the API call makes it through
787        mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId);
788        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT).never())
789                .pullExternalCall(ids.mCallId);
790    }
791
792    public void testMergeFailedAndNotifyInCallUi() throws Exception {
793        IdPair testCall1 = startAndMakeActiveOutgoingCall(
794                "650-555-1212",
795                mPhoneAccountA0.getAccountHandle(),
796                mConnectionServiceFixtureA);
797        IdPair testCall2 = startAndMakeActiveOutgoingCall(
798                "650-555-1213",
799                mPhoneAccountA0.getAccountHandle(),
800                mConnectionServiceFixtureA);
801
802        assertEquals(Call.STATE_ACTIVE,
803                mInCallServiceFixtureX.getCall(testCall1.mCallId).getState());
804        assertEquals(Call.STATE_ACTIVE,
805                mInCallServiceFixtureX.getCall(testCall2.mCallId).getState());
806        assertEquals(Call.STATE_ACTIVE,
807                mInCallServiceFixtureY.getCall(testCall1.mCallId).getState());
808        assertEquals(Call.STATE_ACTIVE,
809                mInCallServiceFixtureY.getCall(testCall2.mCallId).getState());
810
811        // Conference will not occur and instead will send setConferenceMergeFailed
812        ((ConnectionServiceFixture.FakeConnection)
813                mConnectionServiceFixtureA.mLatestConnection).setIsConferenceCreated(false);
814        mInCallServiceFixtureX.getInCallAdapter().conference(testCall2.mCallId, testCall1.mCallId);
815
816        verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT)).onConnectionEvent(
817                eq(testCall2.mCallId), eq(Connection.EVENT_CALL_MERGE_FAILED), any(Bundle.class));
818        verify(mInCallServiceFixtureY.getTestDouble(), timeout(TEST_TIMEOUT)).onConnectionEvent(
819                eq(testCall2.mCallId), eq(Connection.EVENT_CALL_MERGE_FAILED), any(Bundle.class));
820    }
821}
822