BluetoothPhoneServiceTest.java revision a35090657297f5f0f20c2bb31cdf1eb7d6da6419
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 android.bluetooth.BluetoothAdapter;
20import android.content.ComponentName;
21import android.content.Intent;
22import android.graphics.drawable.Icon;
23import android.net.Uri;
24import android.os.Binder;
25import android.os.Debug;
26import android.telecom.Connection;
27import android.telecom.GatewayInfo;
28import android.telecom.PhoneAccount;
29import android.telecom.PhoneAccountHandle;
30import android.telecom.TelecomManager;
31import android.telephony.PhoneNumberUtils;
32import android.telephony.TelephonyManager;
33import android.test.suitebuilder.annotation.MediumTest;
34import android.test.suitebuilder.annotation.SmallTest;
35
36import com.android.server.telecom.BluetoothHeadsetProxy;
37import com.android.server.telecom.BluetoothPhoneServiceImpl;
38import com.android.server.telecom.Call;
39import com.android.server.telecom.CallState;
40import com.android.server.telecom.CallsManager;
41import com.android.server.telecom.PhoneAccountRegistrar;
42import com.android.server.telecom.TelecomSystem;
43
44import org.mockito.Mock;
45import org.mockito.MockitoAnnotations;
46
47import java.util.ArrayList;
48import java.util.LinkedList;
49
50import static org.mockito.Matchers.any;
51import static org.mockito.Matchers.anyBoolean;
52import static org.mockito.Matchers.anyChar;
53import static org.mockito.Matchers.anyInt;
54import static org.mockito.Matchers.anyString;
55import static org.mockito.Matchers.eq;
56import static org.mockito.Matchers.isNull;
57import static org.mockito.Mockito.doNothing;
58import static org.mockito.Mockito.doReturn;
59import static org.mockito.Mockito.mock;
60import static org.mockito.Mockito.never;
61import static org.mockito.Mockito.times;
62import static org.mockito.Mockito.when;
63import static org.mockito.Mockito.verify;
64
65public class BluetoothPhoneServiceTest extends TelecomTestCase {
66
67    private static final int TEST_DTMF_TONE = 0;
68    private static final String TEST_ACCOUNT_ADDRESS = "//foo.com/";
69    private static final int TEST_ACCOUNT_INDEX = 0;
70
71    // match up with BluetoothPhoneServiceImpl
72    private static final int CALL_STATE_ACTIVE = 0;
73    private static final int CALL_STATE_HELD = 1;
74    private static final int CALL_STATE_DIALING = 2;
75    private static final int CALL_STATE_ALERTING = 3;
76    private static final int CALL_STATE_INCOMING = 4;
77    private static final int CALL_STATE_WAITING = 5;
78    private static final int CALL_STATE_IDLE = 6;
79    // Terminate all held or set UDUB("busy") to a waiting call
80    private static final int CHLD_TYPE_RELEASEHELD = 0;
81    // Terminate all active calls and accepts a waiting/held call
82    private static final int CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD = 1;
83    // Hold all active calls and accepts a waiting/held call
84    private static final int CHLD_TYPE_HOLDACTIVE_ACCEPTHELD = 2;
85    // Add all held calls to a conference
86    private static final int CHLD_TYPE_ADDHELDTOCONF = 3;
87
88    private BluetoothPhoneServiceImpl mBluetoothPhoneService;
89    private final TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() {
90    };
91
92    @Mock CallsManager mMockCallsManager;
93    @Mock PhoneAccountRegistrar mMockPhoneAccountRegistrar;
94    @Mock BluetoothHeadsetProxy mMockBluetoothHeadset;
95
96    @Override
97    public void setUp() throws Exception {
98        super.setUp();
99        MockitoAnnotations.initMocks(this);
100        mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
101
102        // Ensure initialization does not actually try to access any of the CallsManager fields.
103        // This also works to return null if it is not overwritten later in the test.
104        doNothing().when(mMockCallsManager).addListener(any(
105                CallsManager.CallsManagerListener.class));
106        doReturn(null).when(mMockCallsManager).getActiveCall();
107        doReturn(null).when(mMockCallsManager).getRingingCall();
108        doReturn(null).when(mMockCallsManager).getHeldCall();
109        doReturn(null).when(mMockCallsManager).getOutgoingCall();
110        doReturn(0).when(mMockCallsManager).getNumHeldCalls();
111        mBluetoothPhoneService = new BluetoothPhoneServiceImpl(mContext, mLock, mMockCallsManager,
112                mMockPhoneAccountRegistrar);
113
114        // Bring in test Bluetooth Headset
115        mBluetoothPhoneService.setBluetoothHeadset(mMockBluetoothHeadset);
116    }
117
118    @Override
119    public void tearDown() throws Exception {
120
121        mBluetoothPhoneService = null;
122        super.tearDown();
123    }
124
125    @SmallTest
126    public void testHeadsetAnswerCall() throws Exception {
127        Call mockCall = createRingingCall();
128
129        boolean callAnswered = mBluetoothPhoneService.mBinder.answerCall();
130
131        verify(mMockCallsManager).answerCall(eq(mockCall), any(int.class));
132        assertEquals(callAnswered, true);
133    }
134
135    @SmallTest
136    public void testHeadsetAnswerCallNull() throws Exception {
137        when(mMockCallsManager.getRingingCall()).thenReturn(null);
138
139        boolean callAnswered = mBluetoothPhoneService.mBinder.answerCall();
140
141        verify(mMockCallsManager,never()).answerCall(any(Call.class), any(int.class));
142        assertEquals(callAnswered, false);
143    }
144
145    @SmallTest
146    public void testHeadsetHangupCall() throws Exception {
147        Call mockCall = createForegroundCall();
148
149        boolean callHungup = mBluetoothPhoneService.mBinder.hangupCall();
150
151        verify(mMockCallsManager).disconnectCall(eq(mockCall));
152        assertEquals(callHungup, true);
153    }
154
155    @SmallTest
156    public void testHeadsetHangupCallNull() throws Exception {
157        when(mMockCallsManager.getForegroundCall()).thenReturn(null);
158
159        boolean callHungup = mBluetoothPhoneService.mBinder.hangupCall();
160
161        verify(mMockCallsManager,never()).disconnectCall(any(Call.class));
162        assertEquals(callHungup, false);
163    }
164
165    @SmallTest
166    public void testHeadsetSendDTMF() throws Exception {
167        Call mockCall = createForegroundCall();
168
169        boolean sentDtmf = mBluetoothPhoneService.mBinder.sendDtmf(TEST_DTMF_TONE);
170
171        verify(mMockCallsManager).playDtmfTone(eq(mockCall), eq((char) TEST_DTMF_TONE));
172        verify(mMockCallsManager).stopDtmfTone(eq(mockCall));
173        assertEquals(sentDtmf, true);
174    }
175
176    @SmallTest
177    public void testHeadsetSendDTMFNull() throws Exception {
178        when(mMockCallsManager.getForegroundCall()).thenReturn(null);
179
180        boolean sentDtmf = mBluetoothPhoneService.mBinder.sendDtmf(TEST_DTMF_TONE);
181
182        verify(mMockCallsManager,never()).playDtmfTone(any(Call.class), anyChar());
183        verify(mMockCallsManager,never()).stopDtmfTone(any(Call.class));
184        assertEquals(sentDtmf, false);
185    }
186
187    @SmallTest
188    public void testGetNetworkOperator() throws Exception {
189        Call mockCall = createForegroundCall();
190        PhoneAccount fakePhoneAccount = makeQuickAccount("id0", TEST_ACCOUNT_INDEX);
191        when(mMockPhoneAccountRegistrar.getPhoneAccountOfCurrentUser(
192                any(PhoneAccountHandle.class))).thenReturn(fakePhoneAccount);
193
194        String networkOperator = mBluetoothPhoneService.mBinder.getNetworkOperator();
195
196        assertEquals(networkOperator, "label0");
197    }
198
199    @SmallTest
200    public void testGetNetworkOperatorNoPhoneAccount() throws Exception {
201        when(mMockCallsManager.getForegroundCall()).thenReturn(null);
202
203        String networkOperator = mBluetoothPhoneService.mBinder.getNetworkOperator();
204
205        assertEquals(networkOperator, "label1");
206    }
207
208    @SmallTest
209    public void testGetSubscriberNumber() throws Exception {
210        Call mockCall = createForegroundCall();
211        PhoneAccount fakePhoneAccount = makeQuickAccount("id0", TEST_ACCOUNT_INDEX);
212        when(mMockPhoneAccountRegistrar.getPhoneAccountOfCurrentUser(
213                any(PhoneAccountHandle.class))).thenReturn(fakePhoneAccount);
214
215        String subscriberNumber = mBluetoothPhoneService.mBinder.getSubscriberNumber();
216
217        assertEquals(subscriberNumber, TEST_ACCOUNT_ADDRESS + TEST_ACCOUNT_INDEX);
218    }
219
220    @SmallTest
221    public void testGetSubscriberNumberFallbackToTelephony() throws Exception {
222        Call mockCall = createForegroundCall();
223        String fakeNumber = "8675309";
224        when(mMockPhoneAccountRegistrar.getPhoneAccountOfCurrentUser(
225                any(PhoneAccountHandle.class))).thenReturn(null);
226        when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(
227                any(PhoneAccountHandle.class))).thenReturn(null);
228        when(TelephonyManager.from(mContext).getLine1Number()).thenReturn(fakeNumber);
229
230        String subscriberNumber = mBluetoothPhoneService.mBinder.getSubscriberNumber();
231
232        assertEquals(subscriberNumber, fakeNumber);
233    }
234
235    @MediumTest
236    public void testListCurrentCallsOneCall() throws Exception {
237        ArrayList<Call> calls = new ArrayList<>();
238        Call activeCall = createActiveCall();
239        when(activeCall.getState()).thenReturn(CallState.ACTIVE);
240        calls.add(activeCall);
241        when(activeCall.isConference()).thenReturn(false);
242        when(activeCall.getHandle()).thenReturn(Uri.parse("tel:555-000"));
243        when(mMockCallsManager.getCalls()).thenReturn(calls);
244
245        mBluetoothPhoneService.mBinder.listCurrentCalls();
246
247        verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(0), eq(0), eq(0), eq(false),
248                eq("555-000"), eq(PhoneNumberUtils.TOA_Unknown));
249        verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
250    }
251
252    @MediumTest
253    public void testConferenceInProgressCDMA() throws Exception {
254        // If two calls are being conferenced and updateHeadsetWithCallState runs while this is
255        // still occuring, it will look like there is an active and held call still while we are
256        // transitioning into a conference.
257        // Call has been put into a CDMA "conference" with one call on hold.
258        ArrayList<Call> calls = new ArrayList<>();
259        Call parentCall = createActiveCall();
260        final Call confCall1 = mock(Call.class);
261        final Call confCall2 = createHeldCall();
262        calls.add(parentCall);
263        calls.add(confCall1);
264        calls.add(confCall2);
265        when(mMockCallsManager.getCalls()).thenReturn(calls);
266        when(confCall1.getState()).thenReturn(CallState.ACTIVE);
267        when(confCall2.getState()).thenReturn(CallState.ACTIVE);
268        when(confCall1.isIncoming()).thenReturn(false);
269        when(confCall2.isIncoming()).thenReturn(true);
270        when(confCall1.getGatewayInfo()).thenReturn(new GatewayInfo(null, null,
271                Uri.parse("tel:555-0000")));
272        when(confCall2.getGatewayInfo()).thenReturn(new GatewayInfo(null, null,
273                Uri.parse("tel:555-0001")));
274        addCallCapability(parentCall, Connection.CAPABILITY_MERGE_CONFERENCE);
275        addCallCapability(parentCall, Connection.CAPABILITY_SWAP_CONFERENCE);
276        removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
277        when(parentCall.getConferenceLevelActiveCall()).thenReturn(confCall1);
278        when(parentCall.isConference()).thenReturn(true);
279        when(parentCall.getChildCalls()).thenReturn(new LinkedList<Call>() {{
280            add(confCall1);
281            add(confCall2);
282        }});
283        //Add links from child calls to parent
284        when(confCall1.getParentCall()).thenReturn(parentCall);
285        when(confCall2.getParentCall()).thenReturn(parentCall);
286
287        mBluetoothPhoneService.mBinder.queryPhoneState();
288        verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(1), eq(CALL_STATE_IDLE),
289                eq(""), eq(128));
290        when(parentCall.wasConferencePreviouslyMerged()).thenReturn(true);
291        mBluetoothPhoneService.mCallsManagerListener.onIsConferencedChanged(parentCall);
292        verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(0), eq(CALL_STATE_IDLE),
293                eq(""), eq(128));
294        when(mMockCallsManager.getHeldCall()).thenReturn(null);
295        // Spurious call to onIsConferencedChanged.
296        mBluetoothPhoneService.mCallsManagerListener.onIsConferencedChanged(parentCall);
297        // Make sure the call has only occurred collectively 2 times (not on the third)
298        verify(mMockBluetoothHeadset, times(2)).phoneStateChanged(any(int.class),
299                any(int.class), any(int.class), any(String.class), any(int.class));
300    }
301
302    @MediumTest
303    public void testListCurrentCallsCdmaHold() throws Exception {
304        // Call has been put into a CDMA "conference" with one call on hold.
305        ArrayList<Call> calls = new ArrayList<>();
306        Call parentCall = createActiveCall();
307        final Call foregroundCall = mock(Call.class);
308        final Call heldCall = createHeldCall();
309        calls.add(parentCall);
310        calls.add(foregroundCall);
311        calls.add(heldCall);
312        when(mMockCallsManager.getCalls()).thenReturn(calls);
313        when(foregroundCall.getState()).thenReturn(CallState.ACTIVE);
314        when(heldCall.getState()).thenReturn(CallState.ACTIVE);
315        when(foregroundCall.isIncoming()).thenReturn(false);
316        when(heldCall.isIncoming()).thenReturn(true);
317        when(foregroundCall.getGatewayInfo()).thenReturn(new GatewayInfo(null, null,
318                Uri.parse("tel:555-0000")));
319        when(heldCall.getGatewayInfo()).thenReturn(new GatewayInfo(null, null,
320                Uri.parse("tel:555-0001")));
321        addCallCapability(parentCall, Connection.CAPABILITY_MERGE_CONFERENCE);
322        addCallCapability(parentCall, Connection.CAPABILITY_SWAP_CONFERENCE);
323        removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
324        when(parentCall.getConferenceLevelActiveCall()).thenReturn(foregroundCall);
325        when(parentCall.isConference()).thenReturn(true);
326        when(parentCall.getChildCalls()).thenReturn(new LinkedList<Call>() {{
327            add(foregroundCall);
328            add(heldCall);
329        }});
330        //Add links from child calls to parent
331        when(foregroundCall.getParentCall()).thenReturn(parentCall);
332        when(heldCall.getParentCall()).thenReturn(parentCall);
333
334        mBluetoothPhoneService.mBinder.listCurrentCalls();
335
336        verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(0), eq(CALL_STATE_ACTIVE), eq(0),
337                eq(false), eq("555-0000"), eq(PhoneNumberUtils.TOA_Unknown));
338        verify(mMockBluetoothHeadset).clccResponse(eq(2), eq(1), eq(CALL_STATE_HELD), eq(0),
339                eq(false), eq("555-0001"), eq(PhoneNumberUtils.TOA_Unknown));
340        verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
341    }
342
343    @MediumTest
344    public void testListCurrentCallsCdmaConference() throws Exception {
345        // Call is in a true CDMA conference
346        ArrayList<Call> calls = new ArrayList<>();
347        Call parentCall = createActiveCall();
348        final Call confCall1 = mock(Call.class);
349        final Call confCall2 = createHeldCall();
350        calls.add(parentCall);
351        calls.add(confCall1);
352        calls.add(confCall2);
353        when(mMockCallsManager.getCalls()).thenReturn(calls);
354        when(confCall1.getState()).thenReturn(CallState.ACTIVE);
355        when(confCall2.getState()).thenReturn(CallState.ACTIVE);
356        when(confCall1.isIncoming()).thenReturn(false);
357        when(confCall2.isIncoming()).thenReturn(true);
358        when(confCall1.getGatewayInfo()).thenReturn(new GatewayInfo(null, null,
359                Uri.parse("tel:555-0000")));
360        when(confCall2.getGatewayInfo()).thenReturn(new GatewayInfo(null, null,
361                Uri.parse("tel:555-0001")));
362        removeCallCapability(parentCall, Connection.CAPABILITY_MERGE_CONFERENCE);
363        removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
364        when(parentCall.wasConferencePreviouslyMerged()).thenReturn(true);
365        when(parentCall.getConferenceLevelActiveCall()).thenReturn(confCall1);
366        when(parentCall.isConference()).thenReturn(true);
367        when(parentCall.getChildCalls()).thenReturn(new LinkedList<Call>() {{
368            add(confCall1);
369            add(confCall2);
370        }});
371        //Add links from child calls to parent
372        when(confCall1.getParentCall()).thenReturn(parentCall);
373        when(confCall2.getParentCall()).thenReturn(parentCall);
374
375        mBluetoothPhoneService.mBinder.listCurrentCalls();
376
377        verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(0), eq(CALL_STATE_ACTIVE), eq(0),
378                eq(true), eq("555-0000"), eq(PhoneNumberUtils.TOA_Unknown));
379        verify(mMockBluetoothHeadset).clccResponse(eq(2), eq(1), eq(CALL_STATE_ACTIVE), eq(0),
380                eq(true), eq("555-0001"), eq(PhoneNumberUtils.TOA_Unknown));
381        verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
382    }
383
384    @MediumTest
385    public void testWaitingCallClccResponse() throws Exception {
386        ArrayList<Call> calls = new ArrayList<>();
387        when(mMockCallsManager.getCalls()).thenReturn(calls);
388        // This test does not define a value for getForegroundCall(), so this ringing call will
389        // be treated as if it is a waiting call when listCurrentCalls() is invoked.
390        Call waitingCall = createRingingCall();
391        calls.add(waitingCall);
392        when(waitingCall.isIncoming()).thenReturn(true);
393        when(waitingCall.getGatewayInfo()).thenReturn(new GatewayInfo(null, null,
394                Uri.parse("tel:555-0000")));
395        when(waitingCall.getState()).thenReturn(CallState.RINGING);
396        when(waitingCall.isConference()).thenReturn(false);
397
398        mBluetoothPhoneService.mBinder.listCurrentCalls();
399        verify(mMockBluetoothHeadset).clccResponse(1, 1, CALL_STATE_WAITING, 0, false,
400                "555-0000", PhoneNumberUtils.TOA_Unknown);
401        verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
402        verify(mMockBluetoothHeadset, times(2)).clccResponse(anyInt(),
403                anyInt(), anyInt(), anyInt(), anyBoolean(), anyString(), anyInt());
404    }
405
406    @MediumTest
407    public void testNewCallClccResponse() throws Exception {
408        ArrayList<Call> calls = new ArrayList<>();
409        when(mMockCallsManager.getCalls()).thenReturn(calls);
410        Call newCall = createForegroundCall();
411        calls.add(newCall);
412        when(newCall.getState()).thenReturn(CallState.NEW);
413        when(newCall.isConference()).thenReturn(false);
414
415        mBluetoothPhoneService.mBinder.listCurrentCalls();
416        verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
417        verify(mMockBluetoothHeadset, times(1)).clccResponse(anyInt(),
418                anyInt(), anyInt(), anyInt(), anyBoolean(), anyString(), anyInt());
419    }
420
421    @MediumTest
422    public void testRingingCallClccResponse() throws Exception {
423        ArrayList<Call> calls = new ArrayList<>();
424        when(mMockCallsManager.getCalls()).thenReturn(calls);
425        Call ringingCall = createForegroundCall();
426        calls.add(ringingCall);
427        when(ringingCall.getState()).thenReturn(CallState.RINGING);
428        when(ringingCall.isIncoming()).thenReturn(true);
429        when(ringingCall.isConference()).thenReturn(false);
430        when(ringingCall.getGatewayInfo()).thenReturn(new GatewayInfo(null, null,
431                Uri.parse("tel:555-0000")));
432
433        mBluetoothPhoneService.mBinder.listCurrentCalls();
434        verify(mMockBluetoothHeadset).clccResponse(1, 1, CALL_STATE_INCOMING, 0, false,
435                "555-0000", PhoneNumberUtils.TOA_Unknown);
436        verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
437        verify(mMockBluetoothHeadset, times(2)).clccResponse(anyInt(),
438                anyInt(), anyInt(), anyInt(), anyBoolean(), anyString(), anyInt());
439    }
440
441    @MediumTest
442    public void testCallClccCache() throws Exception {
443        ArrayList<Call> calls = new ArrayList<>();
444        when(mMockCallsManager.getCalls()).thenReturn(calls);
445        Call ringingCall = createForegroundCall();
446        calls.add(ringingCall);
447        when(ringingCall.getState()).thenReturn(CallState.RINGING);
448        when(ringingCall.isIncoming()).thenReturn(true);
449        when(ringingCall.isConference()).thenReturn(false);
450        when(ringingCall.getGatewayInfo()).thenReturn(new GatewayInfo(null, null,
451                Uri.parse("tel:555-0000")));
452
453        mBluetoothPhoneService.mBinder.listCurrentCalls();
454        verify(mMockBluetoothHeadset).clccResponse(1, 1, CALL_STATE_INCOMING, 0, false,
455                "555-0000", PhoneNumberUtils.TOA_Unknown);
456
457        // Test Caching of old call indicies in clcc
458        when(ringingCall.getState()).thenReturn(CallState.ACTIVE);
459        Call newHoldingCall = createHeldCall();
460        calls.add(0, newHoldingCall);
461        when(newHoldingCall.getState()).thenReturn(CallState.ON_HOLD);
462        when(newHoldingCall.isIncoming()).thenReturn(true);
463        when(newHoldingCall.isConference()).thenReturn(false);
464        when(newHoldingCall.getGatewayInfo()).thenReturn(new GatewayInfo(null, null,
465                Uri.parse("tel:555-0001")));
466
467        mBluetoothPhoneService.mBinder.listCurrentCalls();
468        verify(mMockBluetoothHeadset).clccResponse(1, 1, CALL_STATE_ACTIVE, 0, false,
469                "555-0000", PhoneNumberUtils.TOA_Unknown);
470        verify(mMockBluetoothHeadset).clccResponse(2, 1, CALL_STATE_HELD, 0, false,
471                "555-0001", PhoneNumberUtils.TOA_Unknown);
472        verify(mMockBluetoothHeadset, times(2)).clccResponse(0, 0, 0, 0, false, null, 0);
473    }
474
475    @MediumTest
476    public void testAlertingCallClccResponse() throws Exception {
477        ArrayList<Call> calls = new ArrayList<>();
478        when(mMockCallsManager.getCalls()).thenReturn(calls);
479        Call dialingCall = createForegroundCall();
480        calls.add(dialingCall);
481        when(dialingCall.getState()).thenReturn(CallState.DIALING);
482        when(dialingCall.isIncoming()).thenReturn(false);
483        when(dialingCall.isConference()).thenReturn(false);
484        when(dialingCall.getGatewayInfo()).thenReturn(new GatewayInfo(null, null,
485                Uri.parse("tel:555-0000")));
486
487        mBluetoothPhoneService.mBinder.listCurrentCalls();
488        verify(mMockBluetoothHeadset).clccResponse(1, 0, CALL_STATE_ALERTING, 0, false,
489                "555-0000", PhoneNumberUtils.TOA_Unknown);
490        verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
491        verify(mMockBluetoothHeadset, times(2)).clccResponse(anyInt(),
492                anyInt(), anyInt(), anyInt(), anyBoolean(), anyString(), anyInt());
493    }
494
495    @MediumTest
496    public void testHoldingCallClccResponse() throws Exception {
497        ArrayList<Call> calls = new ArrayList<>();
498        when(mMockCallsManager.getCalls()).thenReturn(calls);
499        Call dialingCall = createForegroundCall();
500        calls.add(dialingCall);
501        when(dialingCall.getState()).thenReturn(CallState.DIALING);
502        when(dialingCall.isIncoming()).thenReturn(false);
503        when(dialingCall.isConference()).thenReturn(false);
504        when(dialingCall.getGatewayInfo()).thenReturn(new GatewayInfo(null, null,
505                Uri.parse("tel:555-0000")));
506        Call holdingCall = createHeldCall();
507        calls.add(holdingCall);
508        when(holdingCall.getState()).thenReturn(CallState.ON_HOLD);
509        when(holdingCall.isIncoming()).thenReturn(true);
510        when(holdingCall.isConference()).thenReturn(false);
511        when(holdingCall.getGatewayInfo()).thenReturn(new GatewayInfo(null, null,
512                Uri.parse("tel:555-0001")));
513
514        mBluetoothPhoneService.mBinder.listCurrentCalls();
515        verify(mMockBluetoothHeadset).clccResponse(1, 0, CALL_STATE_ALERTING, 0, false,
516                "555-0000", PhoneNumberUtils.TOA_Unknown);
517        verify(mMockBluetoothHeadset).clccResponse(2, 1, CALL_STATE_HELD, 0, false,
518                "555-0001", PhoneNumberUtils.TOA_Unknown);
519        verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
520        verify(mMockBluetoothHeadset, times(3)).clccResponse(anyInt(),
521                anyInt(), anyInt(), anyInt(), anyBoolean(), anyString(), anyInt());
522    }
523
524    @MediumTest
525    public void testListCurrentCallsImsConference() throws Exception {
526        ArrayList<Call> calls = new ArrayList<>();
527        Call parentCall = createActiveCall();
528        calls.add(parentCall);
529        addCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
530        when(parentCall.isConference()).thenReturn(true);
531        when(parentCall.getState()).thenReturn(CallState.ACTIVE);
532        when(parentCall.isIncoming()).thenReturn(true);
533        when(mMockCallsManager.getCalls()).thenReturn(calls);
534
535        mBluetoothPhoneService.mBinder.listCurrentCalls();
536
537        verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(1), eq(CALL_STATE_ACTIVE), eq(0),
538                eq(true), (String) isNull(), eq(-1));
539        verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
540    }
541
542    @MediumTest
543    public void testQueryPhoneState() throws Exception {
544        Call ringingCall = createRingingCall();
545        when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555-0000"));
546
547        mBluetoothPhoneService.mBinder.queryPhoneState();
548
549        verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING),
550                eq("555-0000"), eq(PhoneNumberUtils.TOA_Unknown));
551    }
552
553    @MediumTest
554    public void testCDMAConferenceQueryState() throws Exception {
555        Call parentConfCall = createActiveCall();
556        final Call confCall1 = mock(Call.class);
557        final Call confCall2 = mock(Call.class);
558        when(parentConfCall.getHandle()).thenReturn(Uri.parse("tel:555-0000"));
559        addCallCapability(parentConfCall, Connection.CAPABILITY_SWAP_CONFERENCE);
560        removeCallCapability(parentConfCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
561        when(parentConfCall.wasConferencePreviouslyMerged()).thenReturn(true);
562        when(parentConfCall.isConference()).thenReturn(true);
563        when(parentConfCall.getChildCalls()).thenReturn(new LinkedList<Call>() {{
564            add(confCall1);
565            add(confCall2);
566        }});
567
568        mBluetoothPhoneService.mBinder.queryPhoneState();
569        verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(0), eq(CALL_STATE_IDLE),
570                eq(""), eq(128));
571    }
572
573    @MediumTest
574    public void testProcessChldTypeReleaseHeldRinging() throws Exception {
575        Call ringingCall = createRingingCall();
576
577        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(CHLD_TYPE_RELEASEHELD);
578
579        verify(mMockCallsManager).rejectCall(eq(ringingCall), eq(false), any(String.class));
580        assertEquals(didProcess, true);
581    }
582
583    @MediumTest
584    public void testProcessChldTypeReleaseHeldHold() throws Exception {
585        Call onHoldCall = createHeldCall();
586
587        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(CHLD_TYPE_RELEASEHELD);
588
589        verify(mMockCallsManager).disconnectCall(eq(onHoldCall));
590        assertEquals(didProcess, true);
591    }
592
593    @MediumTest
594    public void testProcessChldReleaseActiveRinging() throws Exception {
595        Call activeCall = createActiveCall();
596        Call ringingCall = createRingingCall();
597
598        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(
599                CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD);
600
601        verify(mMockCallsManager).disconnectCall(eq(activeCall));
602        verify(mMockCallsManager).answerCall(eq(ringingCall), any(int.class));
603        assertEquals(didProcess, true);
604    }
605
606    @MediumTest
607    public void testProcessChldReleaseActiveHold() throws Exception {
608        Call activeCall = createActiveCall();
609        Call heldCall = createHeldCall();
610
611        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(
612                CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD);
613
614        verify(mMockCallsManager).disconnectCall(eq(activeCall));
615        verify(mMockCallsManager).unholdCall(eq(heldCall));
616        assertEquals(didProcess, true);
617    }
618
619    @MediumTest
620    public void testProcessChldHoldActiveRinging() throws Exception {
621        Call ringingCall = createRingingCall();
622
623        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(
624                CHLD_TYPE_HOLDACTIVE_ACCEPTHELD);
625
626        verify(mMockCallsManager).answerCall(eq(ringingCall), any(int.class));
627        assertEquals(didProcess, true);
628    }
629
630    @MediumTest
631    public void testProcessChldHoldActiveUnhold() throws Exception {
632        Call heldCall = createHeldCall();
633
634        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(
635                CHLD_TYPE_HOLDACTIVE_ACCEPTHELD);
636
637        verify(mMockCallsManager).unholdCall(eq(heldCall));
638        assertEquals(didProcess, true);
639    }
640
641    @MediumTest
642    public void testProcessChldHoldActiveHold() throws Exception {
643        Call activeCall = createActiveCall();
644        addCallCapability(activeCall, Connection.CAPABILITY_HOLD);
645
646        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(
647                CHLD_TYPE_HOLDACTIVE_ACCEPTHELD);
648
649        verify(mMockCallsManager).holdCall(eq(activeCall));
650        assertEquals(didProcess, true);
651    }
652
653    @MediumTest
654    public void testProcessChldAddHeldToConfHolding() throws Exception {
655        Call activeCall = createActiveCall();
656        addCallCapability(activeCall, Connection.CAPABILITY_MERGE_CONFERENCE);
657
658        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(CHLD_TYPE_ADDHELDTOCONF);
659
660        verify(activeCall).mergeConference();
661        assertEquals(didProcess, true);
662    }
663
664    @MediumTest
665    public void testProcessChldAddHeldToConf() throws Exception {
666        Call activeCall = createActiveCall();
667        removeCallCapability(activeCall, Connection.CAPABILITY_MERGE_CONFERENCE);
668        Call conferenceableCall = mock(Call.class);
669        ArrayList<Call> conferenceableCalls = new ArrayList<>();
670        conferenceableCalls.add(conferenceableCall);
671        when(activeCall.getConferenceableCalls()).thenReturn(conferenceableCalls);
672
673        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(CHLD_TYPE_ADDHELDTOCONF);
674
675        verify(mMockCallsManager).conference(activeCall, conferenceableCall);
676        assertEquals(didProcess, true);
677    }
678
679    @MediumTest
680    public void testProcessChldHoldActiveSwapConference() throws Exception {
681        // Create an active CDMA Call with a call on hold and simulate a swapConference().
682        Call parentCall = createActiveCall();
683        final Call foregroundCall = mock(Call.class);
684        final Call heldCall = createHeldCall();
685        addCallCapability(parentCall, Connection.CAPABILITY_SWAP_CONFERENCE);
686        removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
687        when(parentCall.isConference()).thenReturn(true);
688        when(parentCall.wasConferencePreviouslyMerged()).thenReturn(false);
689        when(parentCall.getChildCalls()).thenReturn(new LinkedList<Call>() {{
690            add(foregroundCall);
691            add(heldCall);
692        }});
693
694        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(
695                CHLD_TYPE_HOLDACTIVE_ACCEPTHELD);
696
697        verify(parentCall).swapConference();
698        verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(1), eq(CALL_STATE_IDLE), eq(""),
699                eq(128));
700        assertEquals(didProcess, true);
701    }
702
703    // Testing the CallsManager Listener Functionality on Bluetooth
704    @MediumTest
705    public void testOnCallAddedRinging() throws Exception {
706        Call ringingCall = createRingingCall();
707        when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555-000"));
708
709        mBluetoothPhoneService.mCallsManagerListener.onCallAdded(ringingCall);
710
711        verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING),
712                eq("555-000"), eq(PhoneNumberUtils.TOA_Unknown));
713
714    }
715
716    @MediumTest
717    public void testOnCallAddedCdmaActiveHold() throws Exception {
718        // Call has been put into a CDMA "conference" with one call on hold.
719        Call parentCall = createActiveCall();
720        final Call foregroundCall = mock(Call.class);
721        final Call heldCall = createHeldCall();
722        addCallCapability(parentCall, Connection.CAPABILITY_MERGE_CONFERENCE);
723        removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
724        when(parentCall.isConference()).thenReturn(true);
725        when(parentCall.getChildCalls()).thenReturn(new LinkedList<Call>() {{
726            add(foregroundCall);
727            add(heldCall);
728        }});
729
730        mBluetoothPhoneService.mCallsManagerListener.onCallAdded(parentCall);
731
732        verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(1), eq(CALL_STATE_IDLE),
733                eq(""), eq(128));
734
735    }
736
737    @MediumTest
738    public void testOnCallRemoved() throws Exception {
739        Call activeCall = createActiveCall();
740        mBluetoothPhoneService.mCallsManagerListener.onCallAdded(activeCall);
741        doReturn(null).when(mMockCallsManager).getActiveCall();
742        mBluetoothPhoneService.mCallsManagerListener.onCallRemoved(activeCall);
743
744        verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_IDLE),
745                eq(""), eq(128));
746    }
747
748    @MediumTest
749    public void testOnCallStateChangedConnectingCall() throws Exception {
750        Call activeCall = mock(Call.class);
751        Call connectingCall = mock(Call.class);
752        when(connectingCall.getState()).thenReturn(CallState.CONNECTING);
753        ArrayList<Call> calls = new ArrayList<>();
754        calls.add(connectingCall);
755        calls.add(activeCall);
756        when(mMockCallsManager.getCalls()).thenReturn(calls);
757
758        mBluetoothPhoneService.mCallsManagerListener.onCallStateChanged(activeCall,
759                CallState.ACTIVE, CallState.ON_HOLD);
760
761        verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(),
762                anyString(), anyInt());
763    }
764
765    @MediumTest
766    public void testOnCallStateChangedDialing() throws Exception {
767        Call activeCall = createActiveCall();
768
769        mBluetoothPhoneService.mCallsManagerListener.onCallStateChanged(activeCall,
770                CallState.CONNECTING, CallState.DIALING);
771
772        verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(),
773                anyString(), anyInt());
774    }
775
776    @MediumTest
777    public void testOnCallStateChangedAlerting() throws Exception {
778        Call outgoingCall = createOutgoingCall();
779
780        mBluetoothPhoneService.mCallsManagerListener.onCallStateChanged(outgoingCall,
781                CallState.NEW, CallState.DIALING);
782
783        verify(mMockBluetoothHeadset).phoneStateChanged(0, 0, CALL_STATE_DIALING, "", 128);
784        verify(mMockBluetoothHeadset).phoneStateChanged(0, 0, CALL_STATE_ALERTING, "", 128);
785    }
786
787    @MediumTest
788    public void testOnCallStateChanged() throws Exception {
789        Call ringingCall = createRingingCall();
790        when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555-0000"));
791        mBluetoothPhoneService.mCallsManagerListener.onCallAdded(ringingCall);
792
793        verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING),
794                eq("555-0000"), eq(PhoneNumberUtils.TOA_Unknown));
795
796        //Switch to active
797        doReturn(null).when(mMockCallsManager).getRingingCall();
798        when(mMockCallsManager.getActiveCall()).thenReturn(ringingCall);
799
800        mBluetoothPhoneService.mCallsManagerListener.onCallStateChanged(ringingCall,
801                CallState.RINGING, CallState.ACTIVE);
802
803        verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(0), eq(CALL_STATE_IDLE),
804                eq(""), eq(128));
805    }
806
807    @MediumTest
808    public void testOnCallStateChangedGSMSwap() throws Exception {
809        Call heldCall = createHeldCall();
810        when(heldCall.getHandle()).thenReturn(Uri.parse("tel:555-0000"));
811        doReturn(2).when(mMockCallsManager).getNumHeldCalls();
812        mBluetoothPhoneService.mCallsManagerListener.onCallStateChanged(heldCall,
813                CallState.ACTIVE, CallState.ON_HOLD);
814
815        verify(mMockBluetoothHeadset, never()).phoneStateChanged(eq(0), eq(2), eq(CALL_STATE_HELD),
816                eq("555-0000"), eq(PhoneNumberUtils.TOA_Unknown));
817    }
818
819    @MediumTest
820    public void testOnIsConferencedChanged() throws Exception {
821        // Start with two calls that are being merged into a CDMA conference call. The
822        // onIsConferencedChanged method will be called multiple times during the call. Make sure
823        // that the bluetooth phone state is updated properly.
824        Call parentCall = createActiveCall();
825        Call activeCall = mock(Call.class);
826        Call heldCall = createHeldCall();
827        when(activeCall.getParentCall()).thenReturn(parentCall);
828        when(heldCall.getParentCall()).thenReturn(parentCall);
829        ArrayList<Call> calls = new ArrayList<>();
830        calls.add(activeCall);
831        when(parentCall.getChildCalls()).thenReturn(calls);
832        when(parentCall.isConference()).thenReturn(true);
833        removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
834        addCallCapability(parentCall, Connection.CAPABILITY_SWAP_CONFERENCE);
835        when(parentCall.wasConferencePreviouslyMerged()).thenReturn(false);
836
837        // Be sure that onIsConferencedChanged rejects spurious changes during set up of
838        // CDMA "conference"
839        mBluetoothPhoneService.mCallsManagerListener.onIsConferencedChanged(activeCall);
840        verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(),
841                anyString(), anyInt());
842        mBluetoothPhoneService.mCallsManagerListener.onIsConferencedChanged(heldCall);
843        verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(),
844                anyString(), anyInt());
845        mBluetoothPhoneService.mCallsManagerListener.onIsConferencedChanged(parentCall);
846        verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(),
847                anyString(), anyInt());
848
849        calls.add(heldCall);
850        mBluetoothPhoneService.mCallsManagerListener.onIsConferencedChanged(parentCall);
851        verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(1), eq(CALL_STATE_IDLE),
852                eq(""), eq(128));
853    }
854
855    @MediumTest
856    public void testBluetoothAdapterReceiver() throws Exception {
857        Call ringingCall = createRingingCall();
858        when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555-0000"));
859
860        Intent intent = new Intent();
861        intent.putExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_ON);
862        mBluetoothPhoneService.mBluetoothAdapterReceiver.onReceive(mContext, intent);
863
864        verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING),
865                eq("555-0000"), eq(PhoneNumberUtils.TOA_Unknown));
866    }
867
868    private void addCallCapability(Call call, int capability) {
869        when(call.can(capability)).thenReturn(true);
870    }
871
872    private void removeCallCapability(Call call, int capability) {
873        when(call.can(capability)).thenReturn(false);
874    }
875
876    private Call createActiveCall() {
877        Call call = mock(Call.class);
878        when(mMockCallsManager.getActiveCall()).thenReturn(call);
879        return call;
880    }
881
882    private Call createRingingCall() {
883        Call call = mock(Call.class);
884        when(mMockCallsManager.getRingingCall()).thenReturn(call);
885        return call;
886    }
887
888    private Call createHeldCall() {
889        Call call = mock(Call.class);
890        when(mMockCallsManager.getHeldCall()).thenReturn(call);
891        return call;
892    }
893
894    private Call createOutgoingCall() {
895        Call call = mock(Call.class);
896        when(mMockCallsManager.getOutgoingCall()).thenReturn(call);
897        return call;
898    }
899
900    private Call createForegroundCall() {
901        Call call = mock(Call.class);
902        when(mMockCallsManager.getForegroundCall()).thenReturn(call);
903        return call;
904    }
905
906    private static ComponentName makeQuickConnectionServiceComponentName() {
907        return new ComponentName("com.android.server.telecom.tests",
908                "com.android.server.telecom.tests.MockConnectionService");
909    }
910
911    private static PhoneAccountHandle makeQuickAccountHandle(String id) {
912        return new PhoneAccountHandle(makeQuickConnectionServiceComponentName(), id,
913                Binder.getCallingUserHandle());
914    }
915
916    private PhoneAccount.Builder makeQuickAccountBuilder(String id, int idx) {
917        return new PhoneAccount.Builder(makeQuickAccountHandle(id), "label" + idx);
918    }
919
920    private PhoneAccount makeQuickAccount(String id, int idx) {
921        return makeQuickAccountBuilder(id, idx)
922                .setAddress(Uri.parse(TEST_ACCOUNT_ADDRESS + idx))
923                .setSubscriptionAddress(Uri.parse("tel:555-000" + idx))
924                .setCapabilities(idx)
925                .setIcon(Icon.createWithResource(
926                        "com.android.server.telecom.tests", R.drawable.stat_sys_phone_call))
927                .setShortDescription("desc" + idx)
928                .setIsEnabled(true)
929                .build();
930    }
931}
932