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