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