BluetoothPhoneServiceTest.java revision 240656f19c078b4f703d0502ce29114de0d45a50
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.content.ComponentName;
20import android.graphics.drawable.Icon;
21import android.net.Uri;
22import android.os.Binder;
23import android.telecom.Connection;
24import android.telecom.GatewayInfo;
25import android.telecom.PhoneAccount;
26import android.telecom.PhoneAccountHandle;
27import android.telephony.PhoneNumberUtils;
28
29import com.android.server.telecom.BluetoothHeadsetProxy;
30import com.android.server.telecom.BluetoothPhoneServiceImpl;
31import com.android.server.telecom.Call;
32import com.android.server.telecom.CallState;
33import com.android.server.telecom.CallsManager;
34import com.android.server.telecom.PhoneAccountRegistrar;
35import com.android.server.telecom.TelecomSystem;
36
37import org.mockito.Mock;
38import org.mockito.MockitoAnnotations;
39
40import java.util.ArrayList;
41import java.util.LinkedList;
42
43import static org.mockito.Matchers.any;
44import static org.mockito.Matchers.anyInt;
45import static org.mockito.Matchers.anyString;
46import static org.mockito.Matchers.eq;
47import static org.mockito.Matchers.isNull;
48import static org.mockito.Mockito.doNothing;
49import static org.mockito.Mockito.doReturn;
50import static org.mockito.Mockito.mock;
51import static org.mockito.Mockito.never;
52import static org.mockito.Mockito.when;
53import static org.mockito.Mockito.verify;
54
55public class BluetoothPhoneServiceTest extends TelecomTestCase {
56
57    private static final int TEST_DTMF_TONE = 0;
58    private static final String TEST_ACCOUNT_ADDRESS = "//foo.com/";
59    private static final int TEST_ACCOUNT_INDEX = 0;
60
61    // match up with BluetoothPhoneServiceImpl
62    private static final int CALL_STATE_ACTIVE = 0;
63    private static final int CALL_STATE_HELD = 1;
64    private static final int CALL_STATE_DIALING = 2;
65    private static final int CALL_STATE_ALERTING = 3;
66    private static final int CALL_STATE_INCOMING = 4;
67    private static final int CALL_STATE_WAITING = 5;
68    private static final int CALL_STATE_IDLE = 6;
69    // Terminate all held or set UDUB("busy") to a waiting call
70    private static final int CHLD_TYPE_RELEASEHELD = 0;
71    // Terminate all active calls and accepts a waiting/held call
72    private static final int CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD = 1;
73    // Hold all active calls and accepts a waiting/held call
74    private static final int CHLD_TYPE_HOLDACTIVE_ACCEPTHELD = 2;
75    // Add all held calls to a conference
76    private static final int CHLD_TYPE_ADDHELDTOCONF = 3;
77
78    private BluetoothPhoneServiceImpl mBluetoothPhoneService;
79    private final TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() {
80    };
81
82    @Mock
83    CallsManager mMockCallsManager;
84    @Mock
85    PhoneAccountRegistrar mMockPhoneAccountRegistrar;
86    @Mock
87    BluetoothHeadsetProxy mMockBluetoothHeadset;
88
89    @Override
90    public void setUp() throws Exception {
91        super.setUp();
92        MockitoAnnotations.initMocks(this);
93        mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
94
95        // Ensure initialization does not actually try to access any of the CallsManager fields.
96        // This also works to return null if it is not overwritten later in the test.
97        doNothing().when(mMockCallsManager).addListener(any(CallsManager.CallsManagerListener.class));
98        doReturn(null).when(mMockCallsManager).getActiveCall();
99        doReturn(null).when(mMockCallsManager).getRingingCall();
100        doReturn(null).when(mMockCallsManager).getHeldCall();
101        doReturn(null).when(mMockCallsManager).getOutgoingCall();
102        doReturn(0).when(mMockCallsManager).getNumHeldCalls();
103        mBluetoothPhoneService = new BluetoothPhoneServiceImpl(mContext, mLock, mMockCallsManager,
104                mMockPhoneAccountRegistrar);
105
106        // Bring in test Bluetooth Headset
107        mBluetoothPhoneService.setBluetoothHeadset(mMockBluetoothHeadset);
108    }
109
110    @Override
111    public void tearDown() throws Exception {
112
113        mBluetoothPhoneService = null;
114        super.tearDown();
115    }
116
117    // Testing the headset binder interface
118    public void testHeadsetAnswerCall() throws Exception {
119        Call mockCall = createRingingCall();
120
121        boolean callAnswered = mBluetoothPhoneService.mBinder.answerCall();
122
123        verify(mMockCallsManager).answerCall(eq(mockCall), any(int.class));
124        assertEquals(callAnswered, true);
125    }
126
127    public void testHeadsetHangupCall() throws Exception {
128        Call mockCall = createForegroundCall();
129
130        boolean callHungup = mBluetoothPhoneService.mBinder.hangupCall();
131
132        verify(mMockCallsManager).disconnectCall(eq(mockCall));
133        assertEquals(callHungup, true);
134    }
135
136    public void testHeadsetSendDTMF() throws Exception {
137        Call mockCall = createForegroundCall();
138
139        boolean sentDtmf = mBluetoothPhoneService.mBinder.sendDtmf(TEST_DTMF_TONE);
140
141        verify(mMockCallsManager).playDtmfTone(eq(mockCall), eq((char) TEST_DTMF_TONE));
142        verify(mMockCallsManager).stopDtmfTone(eq(mockCall));
143        assertEquals(sentDtmf, true);
144    }
145
146    public void testGetNetworkOperator() throws Exception {
147        Call mockCall = createForegroundCall();
148        PhoneAccount fakePhoneAccount = makeQuickAccount("id0", TEST_ACCOUNT_INDEX);
149        when(mMockPhoneAccountRegistrar.getPhoneAccountOfCurrentUser(
150                any(PhoneAccountHandle.class))).thenReturn(fakePhoneAccount);
151
152        String networkOperator = mBluetoothPhoneService.mBinder.getNetworkOperator();
153
154        assertEquals(networkOperator, "label0");
155    }
156
157    public void testGetNetworkOperatorNoPhoneAccount() throws Exception {
158        when(mMockCallsManager.getForegroundCall()).thenReturn(null);
159
160        String networkOperator = mBluetoothPhoneService.mBinder.getNetworkOperator();
161
162        assertEquals(networkOperator, "label1");
163    }
164
165    public void testGetSubscriberNumber() throws Exception {
166        Call mockCall = createForegroundCall();
167        PhoneAccount fakePhoneAccount = makeQuickAccount("id0", TEST_ACCOUNT_INDEX);
168        when(mMockPhoneAccountRegistrar.getPhoneAccountOfCurrentUser(
169                any(PhoneAccountHandle.class))).thenReturn(fakePhoneAccount);
170
171        String subscriberNumber = mBluetoothPhoneService.mBinder.getSubscriberNumber();
172
173        assertEquals(subscriberNumber, TEST_ACCOUNT_ADDRESS + TEST_ACCOUNT_INDEX);
174    }
175
176    public void testListCurrentCallsOneCall() throws Exception {
177        ArrayList<Call> calls = new ArrayList<>();
178        Call activeCall = createActiveCall();
179        when(activeCall.getState()).thenReturn(CallState.ACTIVE);
180        calls.add(activeCall);
181        when(activeCall.isConference()).thenReturn(false);
182        when(activeCall.getHandle()).thenReturn(Uri.parse("tel:555-000"));
183        when(mMockCallsManager.getCalls()).thenReturn(calls);
184
185        mBluetoothPhoneService.mBinder.listCurrentCalls();
186
187        verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(0), eq(0), eq(0), eq(false),
188                eq("555-000"), eq(PhoneNumberUtils.TOA_Unknown));
189        verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
190    }
191
192    public void testListCurrentCallsCdmaHold() throws Exception {
193        // Call has been put into a CDMA "conference" with one call on hold.
194        ArrayList<Call> calls = new ArrayList<>();
195        Call parentCall = createActiveCall();
196        final Call foregroundCall = mock(Call.class);
197        final Call heldCall = createHeldCall();
198        calls.add(parentCall);
199        calls.add(foregroundCall);
200        calls.add(heldCall);
201        when(mMockCallsManager.getCalls()).thenReturn(calls);
202        when(foregroundCall.getState()).thenReturn(CallState.ACTIVE);
203        when(heldCall.getState()).thenReturn(CallState.ACTIVE);
204        when(foregroundCall.isIncoming()).thenReturn(false);
205        when(heldCall.isIncoming()).thenReturn(true);
206        when(foregroundCall.getGatewayInfo()).thenReturn(new GatewayInfo(null, null,
207                Uri.parse("tel:555-0000")));
208        when(heldCall.getGatewayInfo()).thenReturn(new GatewayInfo(null, null,
209                Uri.parse("tel:555-0001")));
210        addCallCapability(parentCall, Connection.CAPABILITY_MERGE_CONFERENCE);
211        addCallCapability(parentCall, Connection.CAPABILITY_SWAP_CONFERENCE);
212        removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
213        when(parentCall.getConferenceLevelActiveCall()).thenReturn(foregroundCall);
214        when(parentCall.isConference()).thenReturn(true);
215        when(parentCall.getChildCalls()).thenReturn(new LinkedList<Call>() {{
216            add(foregroundCall);
217            add(heldCall);
218        }});
219        //Add links from child calls to parent
220        when(foregroundCall.getParentCall()).thenReturn(parentCall);
221        when(heldCall.getParentCall()).thenReturn(parentCall);
222
223        mBluetoothPhoneService.mBinder.listCurrentCalls();
224
225        verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(0), eq(CALL_STATE_ACTIVE), eq(0),
226                eq(false), eq("555-0000"), eq(PhoneNumberUtils.TOA_Unknown));
227        verify(mMockBluetoothHeadset).clccResponse(eq(2), eq(1), eq(CALL_STATE_HELD), eq(0),
228                eq(false), eq("555-0001"), eq(PhoneNumberUtils.TOA_Unknown));
229        verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
230    }
231
232    public void testListCurrentCallsCdmaConference() throws Exception {
233        // Call is in a true CDMA conference
234        ArrayList<Call> calls = new ArrayList<>();
235        Call parentCall = createActiveCall();
236        final Call confCall1 = mock(Call.class);
237        final Call confCall2 = createHeldCall();
238        calls.add(parentCall);
239        calls.add(confCall1);
240        calls.add(confCall2);
241        when(mMockCallsManager.getCalls()).thenReturn(calls);
242        when(confCall1.getState()).thenReturn(CallState.ACTIVE);
243        when(confCall2.getState()).thenReturn(CallState.ACTIVE);
244        when(confCall1.isIncoming()).thenReturn(false);
245        when(confCall2.isIncoming()).thenReturn(true);
246        when(confCall1.getGatewayInfo()).thenReturn(new GatewayInfo(null, null,
247                Uri.parse("tel:555-0000")));
248        when(confCall2.getGatewayInfo()).thenReturn(new GatewayInfo(null, null,
249                Uri.parse("tel:555-0001")));
250        removeCallCapability(parentCall, Connection.CAPABILITY_MERGE_CONFERENCE);
251        removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
252        when(parentCall.wasConferencePreviouslyMerged()).thenReturn(true);
253        when(parentCall.getConferenceLevelActiveCall()).thenReturn(confCall1);
254        when(parentCall.isConference()).thenReturn(true);
255        when(parentCall.getChildCalls()).thenReturn(new LinkedList<Call>() {{
256            add(confCall1);
257            add(confCall2);
258        }});
259        //Add links from child calls to parent
260        when(confCall1.getParentCall()).thenReturn(parentCall);
261        when(confCall2.getParentCall()).thenReturn(parentCall);
262
263        mBluetoothPhoneService.mBinder.listCurrentCalls();
264
265        verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(0), eq(CALL_STATE_ACTIVE), eq(0),
266                eq(true), eq("555-0000"), eq(PhoneNumberUtils.TOA_Unknown));
267        verify(mMockBluetoothHeadset).clccResponse(eq(2), eq(1), eq(CALL_STATE_ACTIVE), eq(0),
268                eq(true), eq("555-0001"), eq(PhoneNumberUtils.TOA_Unknown));
269        verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
270    }
271
272    public void testListCurrentCallsImsConference() throws Exception {
273        ArrayList<Call> calls = new ArrayList<>();
274        Call parentCall = createActiveCall();
275        calls.add(parentCall);
276        addCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
277        when(parentCall.isConference()).thenReturn(true);
278        when(parentCall.getState()).thenReturn(CallState.ACTIVE);
279        when(parentCall.isIncoming()).thenReturn(true);
280        when(mMockCallsManager.getCalls()).thenReturn(calls);
281
282        mBluetoothPhoneService.mBinder.listCurrentCalls();
283
284        verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(1), eq(CALL_STATE_ACTIVE), eq(0),
285                eq(true), (String) isNull(), eq(-1));
286        verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
287    }
288
289    public void testQueryPhoneState() throws Exception {
290        Call ringingCall = createRingingCall();
291        when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555-0000"));
292
293        mBluetoothPhoneService.mBinder.queryPhoneState();
294
295        verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING),
296                eq("555-0000"), eq(PhoneNumberUtils.TOA_Unknown));
297    }
298
299    public void testProcessChldTypeReleaseHeldRinging() throws Exception {
300        Call ringingCall = createRingingCall();
301
302        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(CHLD_TYPE_RELEASEHELD);
303
304        verify(mMockCallsManager).rejectCall(eq(ringingCall), eq(false), any(String.class));
305        assertEquals(didProcess, true);
306    }
307
308    public void testProcessChldTypeReleaseHeldHold() throws Exception {
309        Call onHoldCall = createHeldCall();
310
311        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(CHLD_TYPE_RELEASEHELD);
312
313        verify(mMockCallsManager).disconnectCall(eq(onHoldCall));
314        assertEquals(didProcess, true);
315    }
316
317    public void testProcessChldReleaseActiveRinging() throws Exception {
318        Call activeCall = createActiveCall();
319        Call ringingCall = createRingingCall();
320
321        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(
322                CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD);
323
324        verify(mMockCallsManager).disconnectCall(eq(activeCall));
325        verify(mMockCallsManager).answerCall(eq(ringingCall), any(int.class));
326        assertEquals(didProcess, true);
327    }
328
329    public void testProcessChldReleaseActiveHold() throws Exception {
330        Call activeCall = createActiveCall();
331        Call heldCall = createHeldCall();
332
333        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(
334                CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD);
335
336        verify(mMockCallsManager).disconnectCall(eq(activeCall));
337        verify(mMockCallsManager).unholdCall(eq(heldCall));
338        assertEquals(didProcess, true);
339    }
340
341    public void testProcessChldHoldActiveRinging() throws Exception {
342        Call ringingCall = createRingingCall();
343
344        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(
345                CHLD_TYPE_HOLDACTIVE_ACCEPTHELD);
346
347        verify(mMockCallsManager).answerCall(eq(ringingCall), any(int.class));
348        assertEquals(didProcess, true);
349    }
350
351    public void testProcessChldHoldActiveUnhold() throws Exception {
352        Call heldCall = createHeldCall();
353
354        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(
355                CHLD_TYPE_HOLDACTIVE_ACCEPTHELD);
356
357        verify(mMockCallsManager).unholdCall(eq(heldCall));
358        assertEquals(didProcess, true);
359    }
360
361    public void testProcessChldHoldActiveHold() throws Exception {
362        Call activeCall = createActiveCall();
363        addCallCapability(activeCall, Connection.CAPABILITY_HOLD);
364
365        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(
366                CHLD_TYPE_HOLDACTIVE_ACCEPTHELD);
367
368        verify(mMockCallsManager).holdCall(eq(activeCall));
369        assertEquals(didProcess, true);
370    }
371
372    public void testProcessChldAddHeldToConfHolding() throws Exception {
373        Call activeCall = createActiveCall();
374        addCallCapability(activeCall, Connection.CAPABILITY_MERGE_CONFERENCE);
375
376        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(CHLD_TYPE_ADDHELDTOCONF);
377
378        verify(activeCall).mergeConference();
379        assertEquals(didProcess, true);
380    }
381
382    public void testProcessChldAddHeldToConf() throws Exception {
383        Call activeCall = createActiveCall();
384        removeCallCapability(activeCall, Connection.CAPABILITY_MERGE_CONFERENCE);
385        Call conferenceableCall = mock(Call.class);
386        ArrayList<Call> conferenceableCalls = new ArrayList<>();
387        conferenceableCalls.add(conferenceableCall);
388        when(activeCall.getConferenceableCalls()).thenReturn(conferenceableCalls);
389
390        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(CHLD_TYPE_ADDHELDTOCONF);
391
392        verify(mMockCallsManager).conference(activeCall, conferenceableCall);
393        assertEquals(didProcess, true);
394    }
395
396    public void testProcessChldHoldActiveSwapConference() throws Exception {
397        // Create an active CDMA Call with a call on hold and simulate a swapConference().
398        Call parentCall = createActiveCall();
399        final Call foregroundCall = mock(Call.class);
400        final Call heldCall = createHeldCall();
401        addCallCapability(parentCall, Connection.CAPABILITY_SWAP_CONFERENCE);
402        removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
403        when(parentCall.isConference()).thenReturn(true);
404        when(parentCall.wasConferencePreviouslyMerged()).thenReturn(false);
405        when(parentCall.getChildCalls()).thenReturn(new LinkedList<Call>() {{
406            add(foregroundCall);
407            add(heldCall);
408        }});
409
410        boolean didProcess = mBluetoothPhoneService.mBinder.processChld(
411                CHLD_TYPE_HOLDACTIVE_ACCEPTHELD);
412
413        verify(parentCall).swapConference();
414        verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(1), eq(CALL_STATE_IDLE), eq(""),
415                eq(128));
416        assertEquals(didProcess, true);
417    }
418
419    // Testing the CallsManager Listener Functionality on Bluetooth
420    public void testOnCallAddedRinging() throws Exception {
421        Call ringingCall = createRingingCall();
422        when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555-000"));
423
424        mBluetoothPhoneService.mCallsManagerListener.onCallAdded(ringingCall);
425
426        verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING),
427                eq("555-000"), eq(PhoneNumberUtils.TOA_Unknown));
428
429    }
430
431    public void testOnCallAddedCdmaActiveHold() throws Exception {
432        // Call has been put into a CDMA "conference" with one call on hold.
433        Call parentCall = createActiveCall();
434        final Call foregroundCall = mock(Call.class);
435        final Call heldCall = createHeldCall();
436        addCallCapability(parentCall, Connection.CAPABILITY_MERGE_CONFERENCE);
437        removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
438        when(parentCall.isConference()).thenReturn(true);
439        when(parentCall.getChildCalls()).thenReturn(new LinkedList<Call>() {{
440            add(foregroundCall);
441            add(heldCall);
442        }});
443
444        mBluetoothPhoneService.mCallsManagerListener.onCallAdded(parentCall);
445
446        verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(1), eq(CALL_STATE_IDLE),
447                eq(""), eq(128));
448
449    }
450
451    public void testOnCallRemoved() throws Exception {
452        Call activeCall = createActiveCall();
453        mBluetoothPhoneService.mCallsManagerListener.onCallAdded(activeCall);
454        doReturn(null).when(mMockCallsManager).getActiveCall();
455        mBluetoothPhoneService.mCallsManagerListener.onCallRemoved(activeCall);
456
457        verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_IDLE),
458                eq(""), eq(128));
459    }
460
461    public void testOnCallStateChangedConnectingCall() throws Exception {
462        Call activeCall = mock(Call.class);
463        Call connectingCall = mock(Call.class);
464        when(connectingCall.getState()).thenReturn(CallState.CONNECTING);
465        ArrayList<Call> calls = new ArrayList<>();
466        calls.add(connectingCall);
467        calls.add(activeCall);
468        when(mMockCallsManager.getCalls()).thenReturn(calls);
469
470        mBluetoothPhoneService.mCallsManagerListener.onCallStateChanged(activeCall,
471                CallState.ACTIVE, CallState.ON_HOLD);
472
473        verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(),
474                anyString(), anyInt());
475    }
476
477    public void testOnCallStateChangedDialing() throws Exception {
478        Call activeCall = createActiveCall();
479
480        mBluetoothPhoneService.mCallsManagerListener.onCallStateChanged(activeCall,
481                CallState.CONNECTING, CallState.DIALING);
482
483        verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(),
484                anyString(), anyInt());
485    }
486
487    public void testOnCallStateChanged() throws Exception {
488        Call ringingCall = createRingingCall();
489        when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555-0000"));
490        mBluetoothPhoneService.mCallsManagerListener.onCallAdded(ringingCall);
491
492        verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING),
493                eq("555-0000"), eq(PhoneNumberUtils.TOA_Unknown));
494
495        //Switch to active
496        doReturn(null).when(mMockCallsManager).getRingingCall();
497        when(mMockCallsManager.getActiveCall()).thenReturn(ringingCall);
498
499        mBluetoothPhoneService.mCallsManagerListener.onCallStateChanged(ringingCall,
500                CallState.RINGING, CallState.ACTIVE);
501
502        verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(0), eq(CALL_STATE_IDLE),
503                eq(""), eq(128));
504    }
505
506    public void testOnIsConferencedChanged() throws Exception {
507        // Start with two calls that are being merged into a CDMA conference call. The
508        // onIsConferencedChanged method will be called multiple times during the call. Make sure
509        // that the bluetooth phone state is updated properly.
510        Call parentCall = createActiveCall();
511        Call activeCall = mock(Call.class);
512        Call heldCall = createHeldCall();
513        when(activeCall.getParentCall()).thenReturn(parentCall);
514        when(heldCall.getParentCall()).thenReturn(parentCall);
515        ArrayList<Call> calls = new ArrayList<>();
516        calls.add(activeCall);
517        when(parentCall.getChildCalls()).thenReturn(calls);
518        when(parentCall.isConference()).thenReturn(true);
519        removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
520        addCallCapability(parentCall, Connection.CAPABILITY_SWAP_CONFERENCE);
521        when(parentCall.wasConferencePreviouslyMerged()).thenReturn(false);
522
523        // Be sure that onIsConferencedChanged rejects spurious changes during set up of
524        // CDMA "conference"
525        mBluetoothPhoneService.mCallsManagerListener.onIsConferencedChanged(activeCall);
526        verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(),
527                anyString(), anyInt());
528        mBluetoothPhoneService.mCallsManagerListener.onIsConferencedChanged(heldCall);
529        verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(),
530                anyString(), anyInt());
531        mBluetoothPhoneService.mCallsManagerListener.onIsConferencedChanged(parentCall);
532        verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(),
533                anyString(), anyInt());
534
535        calls.add(heldCall);
536        mBluetoothPhoneService.mCallsManagerListener.onIsConferencedChanged(parentCall);
537        verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(1), eq(CALL_STATE_IDLE),
538                eq(""), eq(128));
539    }
540
541    private void addCallCapability(Call call, int capability) {
542        when(call.can(capability)).thenReturn(true);
543    }
544
545    private void removeCallCapability(Call call, int capability) {
546        when(call.can(capability)).thenReturn(false);
547    }
548
549    private Call createActiveCall() {
550        Call call = mock(Call.class);
551        when(mMockCallsManager.getActiveCall()).thenReturn(call);
552        return call;
553    }
554
555    private Call createRingingCall() {
556        Call call = mock(Call.class);
557        when(mMockCallsManager.getRingingCall()).thenReturn(call);
558        return call;
559    }
560
561    private Call createHeldCall() {
562        Call call = mock(Call.class);
563        when(mMockCallsManager.getHeldCall()).thenReturn(call);
564        return call;
565    }
566
567    private Call createOutgoingCall() {
568        Call call = mock(Call.class);
569        when(mMockCallsManager.getOutgoingCall()).thenReturn(call);
570        return call;
571    }
572
573    private Call createForegroundCall() {
574        Call call = mock(Call.class);
575        when(mMockCallsManager.getForegroundCall()).thenReturn(call);
576        return call;
577    }
578
579    private static ComponentName makeQuickConnectionServiceComponentName() {
580        return new ComponentName("com.android.server.telecom.tests",
581                "com.android.server.telecom.tests.MockConnectionService");
582    }
583
584    private static PhoneAccountHandle makeQuickAccountHandle(String id) {
585        return new PhoneAccountHandle(makeQuickConnectionServiceComponentName(), id,
586                Binder.getCallingUserHandle());
587    }
588
589    private PhoneAccount.Builder makeQuickAccountBuilder(String id, int idx) {
590        return new PhoneAccount.Builder(makeQuickAccountHandle(id), "label" + idx);
591    }
592
593    private PhoneAccount makeQuickAccount(String id, int idx) {
594        return makeQuickAccountBuilder(id, idx)
595                .setAddress(Uri.parse(TEST_ACCOUNT_ADDRESS + idx))
596                .setSubscriptionAddress(Uri.parse("tel:555-000" + idx))
597                .setCapabilities(idx)
598                .setIcon(Icon.createWithResource(
599                        "com.android.server.telecom.tests", R.drawable.stat_sys_phone_call))
600                .setShortDescription("desc" + idx)
601                .setIsEnabled(true)
602                .build();
603    }
604}
605