1 /* 2 * Copyright (C) 2020 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 17 package com.android.bluetooth.telephony; 18 19 import org.junit.After; 20 import org.junit.Assert; 21 import org.junit.Before; 22 import org.junit.Rule; 23 import org.junit.Test; 24 import org.junit.runner.RunWith; 25 import org.mockito.ArgumentCaptor; 26 import org.mockito.Mock; 27 import org.mockito.MockitoAnnotations; 28 29 import static org.mockito.ArgumentMatchers.any; 30 import static org.mockito.Mockito.*; 31 32 import android.bluetooth.BluetoothAdapter; 33 import android.content.ComponentName; 34 import android.content.Context; 35 import android.content.Intent; 36 import android.content.IntentFilter; 37 import android.net.Uri; 38 import android.os.Binder; 39 import android.os.Bundle; 40 import android.os.IBinder; 41 import android.telecom.BluetoothCallQualityReport; 42 import android.telecom.Call; 43 import android.telecom.Connection; 44 import android.telecom.GatewayInfo; 45 import android.telecom.PhoneAccount; 46 import android.telecom.PhoneAccountHandle; 47 import android.telecom.TelecomManager; 48 import android.telephony.PhoneNumberUtils; 49 import android.telephony.TelephonyManager; 50 import android.util.Log; 51 52 import androidx.test.core.app.ApplicationProvider; 53 import androidx.test.rule.ServiceTestRule; 54 import androidx.test.filters.MediumTest; 55 import androidx.test.runner.AndroidJUnit4; 56 57 import com.android.bluetooth.hfp.BluetoothHeadsetProxy; 58 59 import java.util.ArrayList; 60 import java.util.Arrays; 61 import java.util.List; 62 import java.util.UUID; 63 import java.util.concurrent.TimeUnit; 64 65 /** 66 * Tests for {@link BluetoothInCallService} 67 */ 68 @MediumTest 69 @RunWith(AndroidJUnit4.class) 70 public class BluetoothInCallServiceTest { 71 72 private static final int TEST_DTMF_TONE = 0; 73 private static final String TEST_ACCOUNT_ADDRESS = "//foo.com/"; 74 private static final int TEST_ACCOUNT_INDEX = 0; 75 76 private static final int CALL_STATE_ACTIVE = 0; 77 private static final int CALL_STATE_HELD = 1; 78 private static final int CALL_STATE_DIALING = 2; 79 private static final int CALL_STATE_ALERTING = 3; 80 private static final int CALL_STATE_INCOMING = 4; 81 private static final int CALL_STATE_WAITING = 5; 82 private static final int CALL_STATE_IDLE = 6; 83 private static final int CALL_STATE_DISCONNECTED = 7; 84 // Terminate all held or set UDUB("busy") to a waiting call 85 private static final int CHLD_TYPE_RELEASEHELD = 0; 86 // Terminate all active calls and accepts a waiting/held call 87 private static final int CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD = 1; 88 // Hold all active calls and accepts a waiting/held call 89 private static final int CHLD_TYPE_HOLDACTIVE_ACCEPTHELD = 2; 90 // Add all held calls to a conference 91 private static final int CHLD_TYPE_ADDHELDTOCONF = 3; 92 93 private TestableBluetoothInCallService mBluetoothInCallService; 94 @Rule public final ServiceTestRule mServiceRule 95 = ServiceTestRule.withTimeout(1, TimeUnit.SECONDS); 96 97 @Mock private BluetoothHeadsetProxy mMockBluetoothHeadset; 98 @Mock private BluetoothInCallService.CallInfo mMockCallInfo; 99 @Mock private TelephonyManager mMockTelephonyManager; 100 101 public class TestableBluetoothInCallService extends BluetoothInCallService { 102 @Override onBind(Intent intent)103 public IBinder onBind(Intent intent) { 104 IBinder binder = super.onBind(intent); 105 IntentFilter intentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); 106 registerReceiver(mBluetoothAdapterReceiver, intentFilter); 107 mTelephonyManager = getSystemService(TelephonyManager.class); 108 mTelecomManager = getSystemService(TelecomManager.class); 109 return binder; 110 } 111 @Override enforceModifyPermission()112 protected void enforceModifyPermission() {} 113 } 114 115 @Before setUp()116 public void setUp() throws Exception { 117 MockitoAnnotations.initMocks(this); 118 119 // Create the service Intent. 120 Intent serviceIntent = 121 new Intent(ApplicationProvider.getApplicationContext(), 122 TestableBluetoothInCallService.class); 123 // Bind the service 124 mServiceRule.bindService(serviceIntent); 125 126 // Ensure initialization does not actually try to access any of the CallsManager fields. 127 // This also works to return null if it is not overwritten later in the test. 128 doReturn(null).when(mMockCallInfo).getActiveCall(); 129 doReturn(null).when(mMockCallInfo) 130 .getRingingOrSimulatedRingingCall(); 131 doReturn(null).when(mMockCallInfo).getHeldCall(); 132 doReturn(null).when(mMockCallInfo).getOutgoingCall(); 133 doReturn(0).when(mMockCallInfo).getNumHeldCalls(); 134 doReturn(false).when(mMockCallInfo).hasOnlyDisconnectedCalls(); 135 doReturn(true).when(mMockCallInfo).isNullCall(null); 136 doReturn(false).when(mMockCallInfo).isNullCall(notNull()); 137 138 mBluetoothInCallService = new TestableBluetoothInCallService(); 139 mBluetoothInCallService.setBluetoothHeadset(mMockBluetoothHeadset); 140 mBluetoothInCallService.mCallInfo = mMockCallInfo; 141 } 142 143 @After tearDown()144 public void tearDown() throws Exception { 145 mServiceRule.unbindService(); 146 mBluetoothInCallService = null; 147 } 148 149 @Test testHeadsetAnswerCall()150 public void testHeadsetAnswerCall() throws Exception { 151 BluetoothCall mockCall = createRingingCall(); 152 153 boolean callAnswered = mBluetoothInCallService.answerCall(); 154 verify(mockCall).answer(any(int.class)); 155 156 Assert.assertTrue(callAnswered); 157 } 158 159 @Test testHeadsetAnswerCallNull()160 public void testHeadsetAnswerCallNull() throws Exception { 161 when(mMockCallInfo.getRingingOrSimulatedRingingCall()).thenReturn(null); 162 163 boolean callAnswered = mBluetoothInCallService.answerCall(); 164 Assert.assertFalse(callAnswered); 165 } 166 167 @Test testHeadsetHangupCall()168 public void testHeadsetHangupCall() throws Exception { 169 BluetoothCall mockCall = createForegroundCall(); 170 171 boolean callHungup = mBluetoothInCallService.hangupCall(); 172 173 verify(mockCall).disconnect(); 174 Assert.assertTrue(callHungup); 175 } 176 177 @Test testHeadsetHangupCallNull()178 public void testHeadsetHangupCallNull() throws Exception { 179 when(mMockCallInfo.getForegroundCall()).thenReturn(null); 180 181 boolean callHungup = mBluetoothInCallService.hangupCall(); 182 Assert.assertFalse(callHungup); 183 } 184 185 @Test testHeadsetSendDTMF()186 public void testHeadsetSendDTMF() throws Exception { 187 BluetoothCall mockCall = createForegroundCall(); 188 189 boolean sentDtmf = mBluetoothInCallService.sendDtmf(TEST_DTMF_TONE); 190 191 verify(mockCall).playDtmfTone(eq((char) TEST_DTMF_TONE)); 192 verify(mockCall).stopDtmfTone(); 193 Assert.assertTrue(sentDtmf); 194 } 195 196 @Test testHeadsetSendDTMFNull()197 public void testHeadsetSendDTMFNull() throws Exception { 198 when(mMockCallInfo.getForegroundCall()).thenReturn(null); 199 200 boolean sentDtmf = mBluetoothInCallService.sendDtmf(TEST_DTMF_TONE); 201 Assert.assertFalse(sentDtmf); 202 } 203 204 @Test testGetNetworkOperator()205 public void testGetNetworkOperator() throws Exception { 206 PhoneAccount fakePhoneAccount = makeQuickAccount("id0", TEST_ACCOUNT_INDEX); 207 when(mMockCallInfo.getBestPhoneAccount()).thenReturn(fakePhoneAccount); 208 209 String networkOperator = mBluetoothInCallService.getNetworkOperator(); 210 Assert.assertEquals(networkOperator, "label0"); 211 } 212 213 @Test testGetNetworkOperatorNoPhoneAccount()214 public void testGetNetworkOperatorNoPhoneAccount() throws Exception { 215 when(mMockCallInfo.getForegroundCall()).thenReturn(null); 216 when(mMockTelephonyManager.getNetworkOperatorName()).thenReturn("label1"); 217 mBluetoothInCallService.mTelephonyManager = mMockTelephonyManager; 218 219 String networkOperator = mBluetoothInCallService.getNetworkOperator(); 220 Assert.assertEquals(networkOperator, "label1"); 221 } 222 223 @Test testGetSubscriberNumber()224 public void testGetSubscriberNumber() throws Exception { 225 PhoneAccount fakePhoneAccount = makeQuickAccount("id0", TEST_ACCOUNT_INDEX); 226 when(mMockCallInfo.getBestPhoneAccount()).thenReturn(fakePhoneAccount); 227 228 String subscriberNumber = mBluetoothInCallService.getSubscriberNumber(); 229 Assert.assertEquals(subscriberNumber, TEST_ACCOUNT_ADDRESS + TEST_ACCOUNT_INDEX); 230 } 231 232 @Test testGetSubscriberNumberFallbackToTelephony()233 public void testGetSubscriberNumberFallbackToTelephony() throws Exception { 234 String fakeNumber = "8675309"; 235 when(mMockCallInfo.getBestPhoneAccount()).thenReturn(null); 236 when(mMockTelephonyManager.getLine1Number()) 237 .thenReturn(fakeNumber); 238 mBluetoothInCallService.mTelephonyManager = mMockTelephonyManager; 239 240 String subscriberNumber = mBluetoothInCallService.getSubscriberNumber(); 241 Assert.assertEquals(subscriberNumber, fakeNumber); 242 } 243 244 @Test testListCurrentCallsOneCall()245 public void testListCurrentCallsOneCall() throws Exception { 246 ArrayList<BluetoothCall> calls = new ArrayList<>(); 247 BluetoothCall activeCall = createActiveCall(); 248 when(activeCall.getState()).thenReturn(Call.STATE_ACTIVE); 249 calls.add(activeCall); 250 mBluetoothInCallService.onCallAdded(activeCall); 251 when(activeCall.isConference()).thenReturn(false); 252 when(activeCall.getHandle()).thenReturn(Uri.parse("tel:555-000")); 253 when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); 254 255 clearInvocations(mMockBluetoothHeadset); 256 mBluetoothInCallService.listCurrentCalls(); 257 258 verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(0), eq(0), eq(0), eq(false), 259 eq("555000"), eq(PhoneNumberUtils.TOA_Unknown)); 260 verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0); 261 } 262 263 /** 264 * Verifies bluetooth call quality reports are properly parceled and set as a call event to 265 * Telecom. 266 */ 267 @Test testBluetoothCallQualityReport()268 public void testBluetoothCallQualityReport() { 269 BluetoothCall activeCall = createForegroundCall(); 270 when(activeCall.isCallNull()).thenReturn(false); 271 mBluetoothInCallService.onCallAdded(activeCall); 272 273 mBluetoothInCallService.sendBluetoothCallQualityReport( 274 10, // long timestamp 275 20, // int rssi 276 30, // int snr 277 40, // int retransmissionCount 278 50, // int packetsNotReceiveCount 279 60 // int negativeAcknowledgementCount 280 ); 281 282 ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); 283 verify(activeCall).sendCallEvent( 284 eq(BluetoothCallQualityReport.EVENT_BLUETOOTH_CALL_QUALITY_REPORT), 285 bundleCaptor.capture()); 286 Bundle bundle = bundleCaptor.getValue(); 287 BluetoothCallQualityReport report = (BluetoothCallQualityReport) bundle.get( 288 BluetoothCallQualityReport.EXTRA_BLUETOOTH_CALL_QUALITY_REPORT); 289 Assert.assertEquals(10, report.getSentTimestampMillis()); 290 Assert.assertEquals(20, report.getRssiDbm()); 291 Assert.assertEquals(30, report.getSnrDb()); 292 Assert.assertEquals(40, report.getRetransmittedPacketsCount()); 293 Assert.assertEquals(50, report.getPacketsNotReceivedCount()); 294 Assert.assertEquals(60, report.getNegativeAcknowledgementCount()); 295 } 296 297 @Test testListCurrentCallsSilentRinging()298 public void testListCurrentCallsSilentRinging() throws Exception { 299 ArrayList<BluetoothCall> calls = new ArrayList<>(); 300 BluetoothCall silentRingingCall = createActiveCall(); 301 when(silentRingingCall.getState()).thenReturn(Call.STATE_RINGING); 302 when(silentRingingCall.isSilentRingingRequested()).thenReturn(true); 303 calls.add(silentRingingCall); 304 mBluetoothInCallService.onCallAdded(silentRingingCall); 305 306 when(silentRingingCall.isConference()).thenReturn(false); 307 when(silentRingingCall.getHandle()).thenReturn(Uri.parse("tel:555-000")); 308 when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); 309 when(mMockCallInfo.getRingingOrSimulatedRingingCall()).thenReturn(silentRingingCall); 310 311 clearInvocations(mMockBluetoothHeadset); 312 mBluetoothInCallService.listCurrentCalls(); 313 314 verify(mMockBluetoothHeadset, never()).clccResponse(eq(1), eq(0), eq(0), eq(0), eq(false), 315 eq("555000"), eq(PhoneNumberUtils.TOA_Unknown)); 316 verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0); 317 } 318 319 @Test testConferenceInProgressCDMA()320 public void testConferenceInProgressCDMA() throws Exception { 321 // If two calls are being conferenced and updateHeadsetWithCallState runs while this is 322 // still occurring, it will look like there is an active and held BluetoothCall still while 323 // we are transitioning into a conference. 324 // BluetoothCall has been put into a CDMA "conference" with one BluetoothCall on hold. 325 ArrayList<BluetoothCall> calls = new ArrayList<>(); 326 BluetoothCall parentCall = createActiveCall(); 327 final BluetoothCall confCall1 = getMockCall(); 328 final BluetoothCall confCall2 = createHeldCall(); 329 calls.add(parentCall); 330 calls.add(confCall1); 331 calls.add(confCall2); 332 mBluetoothInCallService.onCallAdded(parentCall); 333 mBluetoothInCallService.onCallAdded(confCall1); 334 mBluetoothInCallService.onCallAdded(confCall2); 335 336 when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); 337 when(confCall1.getState()).thenReturn(Call.STATE_ACTIVE); 338 when(confCall2.getState()).thenReturn(Call.STATE_ACTIVE); 339 when(confCall1.isIncoming()).thenReturn(false); 340 when(confCall2.isIncoming()).thenReturn(true); 341 when(confCall1.getGatewayInfo()).thenReturn( 342 new GatewayInfo(null, null, Uri.parse("tel:555-0000"))); 343 when(confCall2.getGatewayInfo()).thenReturn( 344 new GatewayInfo(null, null, Uri.parse("tel:555-0001"))); 345 addCallCapability(parentCall, Connection.CAPABILITY_MERGE_CONFERENCE); 346 addCallCapability(parentCall, Connection.CAPABILITY_SWAP_CONFERENCE); 347 removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN); 348 String confCall1Id = confCall1.getTelecomCallId(); 349 when(parentCall.getGenericConferenceActiveChildCallId()) 350 .thenReturn(confCall1Id); 351 when(parentCall.isConference()).thenReturn(true); 352 List<String> childrenIds = Arrays.asList(confCall1.getTelecomCallId(), 353 confCall2.getTelecomCallId()); 354 when(parentCall.getChildrenIds()).thenReturn(childrenIds); 355 //Add links from child calls to parent 356 String parentId = parentCall.getTelecomCallId(); 357 when(confCall1.getParentId()).thenReturn(parentId); 358 when(confCall2.getParentId()).thenReturn(parentId); 359 360 clearInvocations(mMockBluetoothHeadset); 361 mBluetoothInCallService.queryPhoneState(); 362 verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(1), eq(CALL_STATE_IDLE), 363 eq(""), eq(128), nullable(String.class)); 364 365 when(parentCall.wasConferencePreviouslyMerged()).thenReturn(true); 366 List<BluetoothCall> children = 367 mBluetoothInCallService.getBluetoothCallsByIds(parentCall.getChildrenIds()); 368 mBluetoothInCallService.getCallback(parentCall) 369 .onChildrenChanged(parentCall, children); 370 verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(0), eq(CALL_STATE_IDLE), 371 eq(""), eq(128), nullable(String.class)); 372 373 when(mMockCallInfo.getHeldCall()).thenReturn(null); 374 // Spurious BluetoothCall to onIsConferencedChanged. 375 mBluetoothInCallService.getCallback(parentCall) 376 .onChildrenChanged(parentCall, children); 377 // Make sure the BluetoothCall has only occurred collectively 2 times (not on the third) 378 verify(mMockBluetoothHeadset, times(2)).phoneStateChanged(any(int.class), 379 any(int.class), any(int.class), nullable(String.class), any(int.class), 380 nullable(String.class)); 381 } 382 383 @Test testListCurrentCallsCdmaHold()384 public void testListCurrentCallsCdmaHold() throws Exception { 385 // BluetoothCall has been put into a CDMA "conference" with one BluetoothCall on hold. 386 List<BluetoothCall> calls = new ArrayList<BluetoothCall>(); 387 BluetoothCall parentCall = createActiveCall(); 388 when(parentCall.getHandle()).thenReturn(Uri.parse("tel:555-0000")); 389 final BluetoothCall foregroundCall = getMockCall(); 390 when(foregroundCall.getHandle()).thenReturn(Uri.parse("tel:555-0001")); 391 final BluetoothCall heldCall = createHeldCall(); 392 when(heldCall.getHandle()).thenReturn(Uri.parse("tel:555-0002")); 393 calls.add(parentCall); 394 calls.add(foregroundCall); 395 calls.add(heldCall); 396 mBluetoothInCallService.onCallAdded(parentCall); 397 mBluetoothInCallService.onCallAdded(foregroundCall); 398 mBluetoothInCallService.onCallAdded(heldCall); 399 400 when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); 401 when(foregroundCall.getState()).thenReturn(Call.STATE_ACTIVE); 402 when(heldCall.getState()).thenReturn(Call.STATE_ACTIVE); 403 when(foregroundCall.isIncoming()).thenReturn(false); 404 when(heldCall.isIncoming()).thenReturn(true); 405 when(foregroundCall.getGatewayInfo()).thenReturn( 406 new GatewayInfo(null, null, Uri.parse("tel:555-0001"))); 407 when(heldCall.getGatewayInfo()).thenReturn( 408 new GatewayInfo(null, null, Uri.parse("tel:555-0002"))); 409 addCallCapability(parentCall, Connection.CAPABILITY_MERGE_CONFERENCE); 410 addCallCapability(parentCall, Connection.CAPABILITY_SWAP_CONFERENCE); 411 removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN); 412 413 String foregroundCallId = foregroundCall.getTelecomCallId(); 414 when(parentCall.getGenericConferenceActiveChildCallId()).thenReturn(foregroundCallId); 415 when(parentCall.isConference()).thenReturn(true); 416 List<String> childrenIds = Arrays.asList(foregroundCall.getTelecomCallId(), 417 heldCall.getTelecomCallId()); 418 when(parentCall.getChildrenIds()).thenReturn(childrenIds); 419 //Add links from child calls to parent 420 String parentId = parentCall.getTelecomCallId(); 421 when(foregroundCall.getParentId()).thenReturn(parentId); 422 when(heldCall.getParentId()).thenReturn(parentId); 423 when(parentCall.hasProperty(Call.Details.PROPERTY_GENERIC_CONFERENCE)).thenReturn(true); 424 425 clearInvocations(mMockBluetoothHeadset); 426 mBluetoothInCallService.listCurrentCalls(); 427 428 verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(0), eq(CALL_STATE_ACTIVE), eq(0), 429 eq(false), eq("5550001"), eq(PhoneNumberUtils.TOA_Unknown)); 430 verify(mMockBluetoothHeadset).clccResponse(eq(2), eq(1), eq(CALL_STATE_HELD), eq(0), 431 eq(false), eq("5550002"), eq(PhoneNumberUtils.TOA_Unknown)); 432 verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0); 433 } 434 435 @Test testListCurrentCallsCdmaConference()436 public void testListCurrentCallsCdmaConference() throws Exception { 437 // BluetoothCall is in a true CDMA conference 438 ArrayList<BluetoothCall> calls = new ArrayList<>(); 439 BluetoothCall parentCall = createActiveCall(); 440 final BluetoothCall confCall1 = getMockCall(); 441 final BluetoothCall confCall2 = createHeldCall(); 442 when(parentCall.getHandle()).thenReturn(Uri.parse("tel:555-0000")); 443 when(confCall1.getHandle()).thenReturn(Uri.parse("tel:555-0001")); 444 when(confCall2.getHandle()).thenReturn(Uri.parse("tel:555-0002")); 445 calls.add(parentCall); 446 calls.add(confCall1); 447 calls.add(confCall2); 448 mBluetoothInCallService.onCallAdded(parentCall); 449 mBluetoothInCallService.onCallAdded(confCall1); 450 mBluetoothInCallService.onCallAdded(confCall2); 451 452 when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); 453 when(confCall1.getState()).thenReturn(Call.STATE_ACTIVE); 454 when(confCall2.getState()).thenReturn(Call.STATE_ACTIVE); 455 when(confCall1.isIncoming()).thenReturn(false); 456 when(confCall2.isIncoming()).thenReturn(true); 457 when(confCall1.getGatewayInfo()).thenReturn( 458 new GatewayInfo(null, null, Uri.parse("tel:555-0000"))); 459 when(confCall2.getGatewayInfo()).thenReturn( 460 new GatewayInfo(null, null, Uri.parse("tel:555-0001"))); 461 removeCallCapability(parentCall, Connection.CAPABILITY_MERGE_CONFERENCE); 462 removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN); 463 when(parentCall.wasConferencePreviouslyMerged()).thenReturn(true); 464 //when(parentCall.getConferenceLevelActiveCall()).thenReturn(confCall1); 465 when(parentCall.isConference()).thenReturn(true); 466 List<String> childrenIds = Arrays.asList(confCall1.getTelecomCallId(), 467 confCall2.getTelecomCallId()); 468 when(parentCall.getChildrenIds()).thenReturn(childrenIds); 469 //Add links from child calls to parent 470 String parentId = parentCall.getTelecomCallId(); 471 when(confCall1.getParentId()).thenReturn(parentId); 472 when(confCall2.getParentId()).thenReturn(parentId); 473 when(parentCall.hasProperty(Call.Details.PROPERTY_GENERIC_CONFERENCE)).thenReturn(true); 474 475 clearInvocations(mMockBluetoothHeadset); 476 mBluetoothInCallService.listCurrentCalls(); 477 478 verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(0), eq(CALL_STATE_ACTIVE), eq(0), 479 eq(true), eq("5550000"), eq(PhoneNumberUtils.TOA_Unknown)); 480 verify(mMockBluetoothHeadset).clccResponse(eq(2), eq(1), eq(CALL_STATE_ACTIVE), eq(0), 481 eq(true), eq("5550001"), eq(PhoneNumberUtils.TOA_Unknown)); 482 verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0); 483 } 484 485 @Test testWaitingCallClccResponse()486 public void testWaitingCallClccResponse() throws Exception { 487 ArrayList<BluetoothCall> calls = new ArrayList<>(); 488 when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); 489 // This test does not define a value for getForegroundCall(), so this ringing 490 // BluetoothCall will be treated as if it is a waiting BluetoothCall 491 // when listCurrentCalls() is invoked. 492 BluetoothCall waitingCall = createRingingCall(); 493 calls.add(waitingCall); 494 mBluetoothInCallService.onCallAdded(waitingCall); 495 496 when(waitingCall.isIncoming()).thenReturn(true); 497 when(waitingCall.getGatewayInfo()).thenReturn( 498 new GatewayInfo(null, null, Uri.parse("tel:555-0000"))); 499 when(waitingCall.getState()).thenReturn(Call.STATE_RINGING); 500 when(waitingCall.isConference()).thenReturn(false); 501 when(waitingCall.getHandle()).thenReturn(Uri.parse("tel:555-0000")); 502 503 clearInvocations(mMockBluetoothHeadset); 504 mBluetoothInCallService.listCurrentCalls(); 505 verify(mMockBluetoothHeadset).clccResponse(1, 1, CALL_STATE_WAITING, 0, false, 506 "5550000", PhoneNumberUtils.TOA_Unknown); 507 verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0); 508 verify(mMockBluetoothHeadset, times(2)).clccResponse(anyInt(), 509 anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class), anyInt()); 510 } 511 512 @Test testNewCallClccResponse()513 public void testNewCallClccResponse() throws Exception { 514 ArrayList<BluetoothCall> calls = new ArrayList<>(); 515 when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); 516 BluetoothCall newCall = createForegroundCall(); 517 calls.add(newCall); 518 mBluetoothInCallService.onCallAdded(newCall); 519 520 when(newCall.getState()).thenReturn(Call.STATE_NEW); 521 when(newCall.isConference()).thenReturn(false); 522 523 clearInvocations(mMockBluetoothHeadset); 524 mBluetoothInCallService.listCurrentCalls(); 525 verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0); 526 verify(mMockBluetoothHeadset, times(1)).clccResponse(anyInt(), 527 anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class), anyInt()); 528 } 529 530 @Test testRingingCallClccResponse()531 public void testRingingCallClccResponse() throws Exception { 532 ArrayList<BluetoothCall> calls = new ArrayList<>(); 533 when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); 534 BluetoothCall ringingCall = createForegroundCall(); 535 calls.add(ringingCall); 536 mBluetoothInCallService.onCallAdded(ringingCall); 537 538 when(ringingCall.getState()).thenReturn(Call.STATE_RINGING); 539 when(ringingCall.isIncoming()).thenReturn(true); 540 when(ringingCall.isConference()).thenReturn(false); 541 when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555-0000")); 542 when(ringingCall.getGatewayInfo()).thenReturn( 543 new GatewayInfo(null, null, Uri.parse("tel:555-0000"))); 544 545 clearInvocations(mMockBluetoothHeadset); 546 mBluetoothInCallService.listCurrentCalls(); 547 verify(mMockBluetoothHeadset).clccResponse(1, 1, CALL_STATE_INCOMING, 0, false, 548 "5550000", PhoneNumberUtils.TOA_Unknown); 549 verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0); 550 verify(mMockBluetoothHeadset, times(2)).clccResponse(anyInt(), 551 anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class), anyInt()); 552 } 553 554 @Test testCallClccCache()555 public void testCallClccCache() throws Exception { 556 ArrayList<BluetoothCall> calls = new ArrayList<>(); 557 when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); 558 BluetoothCall ringingCall = createForegroundCall(); 559 calls.add(ringingCall); 560 mBluetoothInCallService.onCallAdded(ringingCall); 561 562 when(ringingCall.getState()).thenReturn(Call.STATE_RINGING); 563 when(ringingCall.isIncoming()).thenReturn(true); 564 when(ringingCall.isConference()).thenReturn(false); 565 when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:5550000")); 566 when(ringingCall.getGatewayInfo()).thenReturn( 567 new GatewayInfo(null, null, Uri.parse("tel:5550000"))); 568 569 clearInvocations(mMockBluetoothHeadset); 570 mBluetoothInCallService.listCurrentCalls(); 571 verify(mMockBluetoothHeadset).clccResponse(1, 1, CALL_STATE_INCOMING, 0, false, 572 "5550000", PhoneNumberUtils.TOA_Unknown); 573 574 // Test Caching of old BluetoothCall indices in clcc 575 when(ringingCall.getState()).thenReturn(Call.STATE_ACTIVE); 576 BluetoothCall newHoldingCall = createHeldCall(); 577 calls.add(0, newHoldingCall); 578 mBluetoothInCallService.onCallAdded(newHoldingCall); 579 580 when(newHoldingCall.getState()).thenReturn(Call.STATE_HOLDING); 581 when(newHoldingCall.isIncoming()).thenReturn(true); 582 when(newHoldingCall.isConference()).thenReturn(false); 583 when(newHoldingCall.getHandle()).thenReturn(Uri.parse("tel:555-0001")); 584 when(newHoldingCall.getGatewayInfo()).thenReturn( 585 new GatewayInfo(null, null, Uri.parse("tel:555-0001"))); 586 587 mBluetoothInCallService.listCurrentCalls(); 588 verify(mMockBluetoothHeadset).clccResponse(1, 1, CALL_STATE_ACTIVE, 0, false, 589 "5550000", PhoneNumberUtils.TOA_Unknown); 590 verify(mMockBluetoothHeadset).clccResponse(2, 1, CALL_STATE_HELD, 0, false, 591 "5550001", PhoneNumberUtils.TOA_Unknown); 592 verify(mMockBluetoothHeadset, times(2)).clccResponse(0, 0, 0, 0, false, null, 0); 593 } 594 595 @Test testAlertingCallClccResponse()596 public void testAlertingCallClccResponse() throws Exception { 597 ArrayList<BluetoothCall> calls = new ArrayList<>(); 598 when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); 599 BluetoothCall dialingCall = createForegroundCall(); 600 calls.add(dialingCall); 601 mBluetoothInCallService.onCallAdded(dialingCall); 602 603 when(dialingCall.getState()).thenReturn(Call.STATE_DIALING); 604 when(dialingCall.isIncoming()).thenReturn(false); 605 when(dialingCall.isConference()).thenReturn(false); 606 when(dialingCall.getHandle()).thenReturn(Uri.parse("tel:555-0000")); 607 when(dialingCall.getGatewayInfo()).thenReturn( 608 new GatewayInfo(null, null, Uri.parse("tel:555-0000"))); 609 610 clearInvocations(mMockBluetoothHeadset); 611 mBluetoothInCallService.listCurrentCalls(); 612 verify(mMockBluetoothHeadset).clccResponse(1, 0, CALL_STATE_ALERTING, 0, false, 613 "5550000", PhoneNumberUtils.TOA_Unknown); 614 verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0); 615 verify(mMockBluetoothHeadset, times(2)).clccResponse(anyInt(), 616 anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class), anyInt()); 617 } 618 619 @Test testHoldingCallClccResponse()620 public void testHoldingCallClccResponse() throws Exception { 621 ArrayList<BluetoothCall> calls = new ArrayList<>(); 622 when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); 623 BluetoothCall dialingCall = createForegroundCall(); 624 calls.add(dialingCall); 625 mBluetoothInCallService.onCallAdded(dialingCall); 626 627 when(dialingCall.getState()).thenReturn(Call.STATE_DIALING); 628 when(dialingCall.isIncoming()).thenReturn(false); 629 when(dialingCall.isConference()).thenReturn(false); 630 when(dialingCall.getHandle()).thenReturn(Uri.parse("tel:555-0000")); 631 when(dialingCall.getGatewayInfo()).thenReturn( 632 new GatewayInfo(null, null, Uri.parse("tel:555-0000"))); 633 BluetoothCall holdingCall = createHeldCall(); 634 calls.add(holdingCall); 635 mBluetoothInCallService.onCallAdded(holdingCall); 636 637 when(holdingCall.getState()).thenReturn(Call.STATE_HOLDING); 638 when(holdingCall.isIncoming()).thenReturn(true); 639 when(holdingCall.isConference()).thenReturn(false); 640 when(holdingCall.getHandle()).thenReturn(Uri.parse("tel:555-0001")); 641 when(holdingCall.getGatewayInfo()).thenReturn( 642 new GatewayInfo(null, null, Uri.parse("tel:555-0001"))); 643 644 clearInvocations(mMockBluetoothHeadset); 645 mBluetoothInCallService.listCurrentCalls(); 646 verify(mMockBluetoothHeadset).clccResponse(1, 0, CALL_STATE_ALERTING, 0, false, 647 "5550000", PhoneNumberUtils.TOA_Unknown); 648 verify(mMockBluetoothHeadset).clccResponse(2, 1, CALL_STATE_HELD, 0, false, 649 "5550001", PhoneNumberUtils.TOA_Unknown); 650 verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0); 651 verify(mMockBluetoothHeadset, times(3)).clccResponse(anyInt(), 652 anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class), anyInt()); 653 } 654 655 @Test testListCurrentCallsImsConference()656 public void testListCurrentCallsImsConference() throws Exception { 657 ArrayList<BluetoothCall> calls = new ArrayList<>(); 658 BluetoothCall parentCall = createActiveCall(); 659 calls.add(parentCall); 660 mBluetoothInCallService.onCallAdded(parentCall); 661 662 addCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN); 663 when(parentCall.isConference()).thenReturn(true); 664 when(parentCall.getState()).thenReturn(Call.STATE_ACTIVE); 665 when(parentCall.isIncoming()).thenReturn(true); 666 when(parentCall.getHandle()).thenReturn(Uri.parse("tel:555-0000")); 667 when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); 668 669 clearInvocations(mMockBluetoothHeadset); 670 mBluetoothInCallService.listCurrentCalls(); 671 672 verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(1), eq(CALL_STATE_ACTIVE), eq(0), 673 eq(true), eq("5550000"), eq(129)); 674 verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0); 675 } 676 677 @Test testListCurrentCallsHeldImsCepConference()678 public void testListCurrentCallsHeldImsCepConference() throws Exception { 679 ArrayList<BluetoothCall> calls = new ArrayList<>(); 680 BluetoothCall parentCall = createHeldCall(); 681 BluetoothCall childCall1 = createActiveCall(); 682 BluetoothCall childCall2 = createActiveCall(); 683 when(parentCall.getHandle()).thenReturn(Uri.parse("tel:555-0000")); 684 when(childCall1.getHandle()).thenReturn(Uri.parse("tel:555-0001")); 685 when(childCall2.getHandle()).thenReturn(Uri.parse("tel:555-0002")); 686 687 calls.add(parentCall); 688 calls.add(childCall1); 689 calls.add(childCall2); 690 mBluetoothInCallService.onCallAdded(parentCall); 691 mBluetoothInCallService.onCallAdded(childCall1); 692 mBluetoothInCallService.onCallAdded(childCall2); 693 694 addCallCapability(parentCall, Connection.CAPABILITY_MANAGE_CONFERENCE); 695 String parentId = parentCall.getTelecomCallId(); 696 when(childCall1.getParentId()).thenReturn(parentId); 697 when(childCall2.getParentId()).thenReturn(parentId); 698 699 when(parentCall.isConference()).thenReturn(true); 700 when(parentCall.getState()).thenReturn(Call.STATE_HOLDING); 701 when(childCall1.getState()).thenReturn(Call.STATE_ACTIVE); 702 when(childCall2.getState()).thenReturn(Call.STATE_ACTIVE); 703 when(parentCall.hasProperty(Call.Details.PROPERTY_GENERIC_CONFERENCE)).thenReturn(true); 704 705 when(parentCall.isIncoming()).thenReturn(true); 706 when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); 707 708 clearInvocations(mMockBluetoothHeadset); 709 mBluetoothInCallService.listCurrentCalls(); 710 711 verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(0), eq(CALL_STATE_HELD), eq(0), 712 eq(true), eq("5550001"), eq(PhoneNumberUtils.TOA_Unknown)); 713 verify(mMockBluetoothHeadset).clccResponse(eq(2), eq(0), eq(CALL_STATE_HELD), eq(0), 714 eq(true), eq("5550002"), eq(PhoneNumberUtils.TOA_Unknown)); 715 verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0); 716 } 717 718 @Test testQueryPhoneState()719 public void testQueryPhoneState() throws Exception { 720 BluetoothCall ringingCall = createRingingCall(); 721 when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:5550000")); 722 723 clearInvocations(mMockBluetoothHeadset); 724 mBluetoothInCallService.queryPhoneState(); 725 726 verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING), 727 eq("5550000"), eq(PhoneNumberUtils.TOA_Unknown), nullable(String.class)); 728 } 729 730 @Test testCDMAConferenceQueryState()731 public void testCDMAConferenceQueryState() throws Exception { 732 BluetoothCall parentConfCall = createActiveCall(); 733 final BluetoothCall confCall1 = getMockCall(); 734 final BluetoothCall confCall2 = getMockCall(); 735 mBluetoothInCallService.onCallAdded(confCall1); 736 mBluetoothInCallService.onCallAdded(confCall2); 737 when(parentConfCall.getHandle()).thenReturn(Uri.parse("tel:555-0000")); 738 addCallCapability(parentConfCall, Connection.CAPABILITY_SWAP_CONFERENCE); 739 removeCallCapability(parentConfCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN); 740 when(parentConfCall.wasConferencePreviouslyMerged()).thenReturn(true); 741 when(parentConfCall.isConference()).thenReturn(true); 742 List<String> childrenIds = Arrays.asList(confCall1.getTelecomCallId(), 743 confCall2.getTelecomCallId()); 744 when(parentConfCall.getChildrenIds()).thenReturn(childrenIds); 745 746 clearInvocations(mMockBluetoothHeadset); 747 mBluetoothInCallService.queryPhoneState(); 748 verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(0), eq(CALL_STATE_IDLE), 749 eq(""), eq(128), nullable(String.class)); 750 } 751 752 @Test testProcessChldTypeReleaseHeldRinging()753 public void testProcessChldTypeReleaseHeldRinging() throws Exception { 754 BluetoothCall ringingCall = createRingingCall(); 755 Log.i("BluetoothInCallService", "asdf start " + Integer.toString(ringingCall.hashCode())); 756 757 boolean didProcess = mBluetoothInCallService.processChld(CHLD_TYPE_RELEASEHELD); 758 759 verify(ringingCall).reject(eq(false), nullable(String.class)); 760 Assert.assertTrue(didProcess); 761 } 762 763 @Test testProcessChldTypeReleaseHeldHold()764 public void testProcessChldTypeReleaseHeldHold() throws Exception { 765 BluetoothCall onHoldCall = createHeldCall(); 766 boolean didProcess = mBluetoothInCallService.processChld(CHLD_TYPE_RELEASEHELD); 767 768 verify(onHoldCall).disconnect(); 769 Assert.assertTrue(didProcess); 770 } 771 772 @Test testProcessChldReleaseActiveRinging()773 public void testProcessChldReleaseActiveRinging() throws Exception { 774 BluetoothCall activeCall = createActiveCall(); 775 BluetoothCall ringingCall = createRingingCall(); 776 777 boolean didProcess = mBluetoothInCallService.processChld( 778 CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD); 779 780 verify(activeCall).disconnect(); 781 verify(ringingCall).answer(any(int.class)); 782 Assert.assertTrue(didProcess); 783 } 784 785 @Test testProcessChldReleaseActiveHold()786 public void testProcessChldReleaseActiveHold() throws Exception { 787 BluetoothCall activeCall = createActiveCall(); 788 BluetoothCall heldCall = createHeldCall(); 789 790 boolean didProcess = mBluetoothInCallService.processChld( 791 CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD); 792 793 verify(activeCall).disconnect(); 794 // BluetoothCall unhold will occur as part of CallsManager auto-unholding 795 // the background BluetoothCall on its own. 796 Assert.assertTrue(didProcess); 797 } 798 799 @Test testProcessChldHoldActiveRinging()800 public void testProcessChldHoldActiveRinging() throws Exception { 801 BluetoothCall ringingCall = createRingingCall(); 802 803 boolean didProcess = mBluetoothInCallService.processChld( 804 CHLD_TYPE_HOLDACTIVE_ACCEPTHELD); 805 806 verify(ringingCall).answer(any(int.class)); 807 Assert.assertTrue(didProcess); 808 } 809 810 @Test testProcessChldHoldActiveUnhold()811 public void testProcessChldHoldActiveUnhold() throws Exception { 812 BluetoothCall heldCall = createHeldCall(); 813 814 boolean didProcess = mBluetoothInCallService.processChld( 815 CHLD_TYPE_HOLDACTIVE_ACCEPTHELD); 816 817 verify(heldCall).unhold(); 818 Assert.assertTrue(didProcess); 819 } 820 821 @Test testProcessChldHoldActiveHold()822 public void testProcessChldHoldActiveHold() throws Exception { 823 BluetoothCall activeCall = createActiveCall(); 824 addCallCapability(activeCall, Connection.CAPABILITY_HOLD); 825 826 boolean didProcess = mBluetoothInCallService.processChld( 827 CHLD_TYPE_HOLDACTIVE_ACCEPTHELD); 828 829 verify(activeCall).hold(); 830 Assert.assertTrue(didProcess); 831 } 832 833 @Test testProcessChldAddHeldToConfHolding()834 public void testProcessChldAddHeldToConfHolding() throws Exception { 835 BluetoothCall activeCall = createActiveCall(); 836 addCallCapability(activeCall, Connection.CAPABILITY_MERGE_CONFERENCE); 837 838 boolean didProcess = mBluetoothInCallService.processChld(CHLD_TYPE_ADDHELDTOCONF); 839 840 verify(activeCall).mergeConference(); 841 Assert.assertTrue(didProcess); 842 } 843 844 @Test testProcessChldAddHeldToConf()845 public void testProcessChldAddHeldToConf() throws Exception { 846 BluetoothCall activeCall = createActiveCall(); 847 removeCallCapability(activeCall, Connection.CAPABILITY_MERGE_CONFERENCE); 848 BluetoothCall conferenceableCall = getMockCall(); 849 ArrayList<String> conferenceableCalls = new ArrayList<>(); 850 conferenceableCalls.add(conferenceableCall.getTelecomCallId()); 851 mBluetoothInCallService.onCallAdded(conferenceableCall); 852 853 when(activeCall.getConferenceableCalls()).thenReturn(conferenceableCalls); 854 855 boolean didProcess = mBluetoothInCallService.processChld(CHLD_TYPE_ADDHELDTOCONF); 856 857 verify(activeCall).conference(conferenceableCall); 858 Assert.assertTrue(didProcess); 859 } 860 861 @Test testProcessChldHoldActiveSwapConference()862 public void testProcessChldHoldActiveSwapConference() throws Exception { 863 // Create an active CDMA BluetoothCall with a BluetoothCall on hold 864 // and simulate a swapConference(). 865 BluetoothCall parentCall = createActiveCall(); 866 final BluetoothCall foregroundCall = getMockCall(); 867 when(foregroundCall.getHandle()).thenReturn(Uri.parse("tel:555-0001")); 868 final BluetoothCall heldCall = createHeldCall(); 869 when(heldCall.getHandle()).thenReturn(Uri.parse("tel:555-0002")); 870 addCallCapability(parentCall, Connection.CAPABILITY_SWAP_CONFERENCE); 871 removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN); 872 when(parentCall.isConference()).thenReturn(true); 873 when(parentCall.wasConferencePreviouslyMerged()).thenReturn(false); 874 when(heldCall.getHandle()).thenReturn(Uri.parse("tel:555-0000")); 875 List<String> childrenIds = Arrays.asList(foregroundCall.getTelecomCallId(), 876 heldCall.getTelecomCallId()); 877 when(parentCall.getChildrenIds()).thenReturn(childrenIds); 878 879 clearInvocations(mMockBluetoothHeadset); 880 boolean didProcess = mBluetoothInCallService.processChld( 881 CHLD_TYPE_HOLDACTIVE_ACCEPTHELD); 882 883 verify(parentCall).swapConference(); 884 verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(1), eq(CALL_STATE_IDLE), eq(""), 885 eq(128), nullable(String.class)); 886 Assert.assertTrue(didProcess); 887 } 888 889 // Testing the CallsManager Listener Functionality on Bluetooth 890 @Test testOnCallAddedRinging()891 public void testOnCallAddedRinging() throws Exception { 892 BluetoothCall ringingCall = createRingingCall(); 893 when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555000")); 894 895 mBluetoothInCallService.onCallAdded(ringingCall); 896 897 verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING), 898 eq("555000"), eq(PhoneNumberUtils.TOA_Unknown), nullable(String.class)); 899 } 900 901 @Test testSilentRingingCallState()902 public void testSilentRingingCallState() throws Exception { 903 BluetoothCall ringingCall = createRingingCall(); 904 when(ringingCall.isSilentRingingRequested()).thenReturn(true); 905 when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555000")); 906 907 mBluetoothInCallService.onCallAdded(ringingCall); 908 909 verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(), 910 anyString(), anyInt(), nullable(String.class)); 911 } 912 913 @Test testOnCallAddedCdmaActiveHold()914 public void testOnCallAddedCdmaActiveHold() throws Exception { 915 // BluetoothCall has been put into a CDMA "conference" with one BluetoothCall on hold. 916 BluetoothCall parentCall = createActiveCall(); 917 final BluetoothCall foregroundCall = getMockCall(); 918 final BluetoothCall heldCall = createHeldCall(); 919 when(foregroundCall.getHandle()).thenReturn(Uri.parse("tel:555-0001")); 920 when(heldCall.getHandle()).thenReturn(Uri.parse("tel:555-0002")); 921 addCallCapability(parentCall, Connection.CAPABILITY_MERGE_CONFERENCE); 922 removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN); 923 when(parentCall.isConference()).thenReturn(true); 924 List<String> childrenIds = Arrays.asList(foregroundCall.getTelecomCallId(), 925 heldCall.getTelecomCallId()); 926 when(parentCall.getChildrenIds()).thenReturn(childrenIds); 927 928 mBluetoothInCallService.onCallAdded(parentCall); 929 930 verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(1), eq(CALL_STATE_IDLE), 931 eq(""), eq(128), nullable(String.class)); 932 } 933 934 @Test testOnCallRemoved()935 public void testOnCallRemoved() throws Exception { 936 BluetoothCall activeCall = createActiveCall(); 937 mBluetoothInCallService.onCallAdded(activeCall); 938 doReturn(null).when(mMockCallInfo).getActiveCall(); 939 when(activeCall.getHandle()).thenReturn(Uri.parse("tel:555-0001")); 940 mBluetoothInCallService.onCallRemoved(activeCall); 941 942 verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_IDLE), 943 eq(""), eq(128), nullable(String.class)); 944 } 945 946 @Test testOnCallStateChangedConnectingCall()947 public void testOnCallStateChangedConnectingCall() throws Exception { 948 BluetoothCall activeCall = getMockCall(); 949 BluetoothCall connectingCall = getMockCall(); 950 when(connectingCall.getState()).thenReturn(Call.STATE_CONNECTING); 951 ArrayList<BluetoothCall> calls = new ArrayList<>(); 952 calls.add(connectingCall); 953 calls.add(activeCall); 954 mBluetoothInCallService.onCallAdded(connectingCall); 955 mBluetoothInCallService.onCallAdded(activeCall); 956 when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); 957 958 mBluetoothInCallService.getCallback(activeCall) 959 .onStateChanged(activeCall, Call.STATE_HOLDING); 960 961 verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(), 962 anyString(), anyInt(), nullable(String.class)); 963 } 964 965 @Test testOnCallAddedAudioProcessing()966 public void testOnCallAddedAudioProcessing() throws Exception { 967 BluetoothCall call = getMockCall(); 968 when(call.getState()).thenReturn(Call.STATE_AUDIO_PROCESSING); 969 mBluetoothInCallService.onCallAdded(call); 970 971 verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(), 972 anyString(), anyInt(), nullable(String.class)); 973 } 974 975 @Test testOnCallStateChangedRingingToAudioProcessing()976 public void testOnCallStateChangedRingingToAudioProcessing() throws Exception { 977 BluetoothCall ringingCall = createRingingCall(); 978 when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555000")); 979 980 mBluetoothInCallService.onCallAdded(ringingCall); 981 982 verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING), 983 eq("555000"), eq(PhoneNumberUtils.TOA_Unknown), nullable(String.class)); 984 985 when(ringingCall.getState()).thenReturn(Call.STATE_AUDIO_PROCESSING); 986 when(mMockCallInfo.getRingingOrSimulatedRingingCall()).thenReturn(null); 987 988 mBluetoothInCallService.getCallback(ringingCall) 989 .onStateChanged(ringingCall, Call.STATE_AUDIO_PROCESSING); 990 991 verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_IDLE), 992 eq(""), eq(128), nullable(String.class)); 993 } 994 995 @Test testOnCallStateChangedAudioProcessingToSimulatedRinging()996 public void testOnCallStateChangedAudioProcessingToSimulatedRinging() throws Exception { 997 BluetoothCall ringingCall = createRingingCall(); 998 when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555-0000")); 999 mBluetoothInCallService.onCallAdded(ringingCall); 1000 mBluetoothInCallService.getCallback(ringingCall) 1001 .onStateChanged(ringingCall, Call.STATE_SIMULATED_RINGING); 1002 1003 verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING), 1004 eq("555-0000"), eq(PhoneNumberUtils.TOA_Unknown), nullable(String.class)); 1005 } 1006 1007 @Test testOnCallStateChangedAudioProcessingToActive()1008 public void testOnCallStateChangedAudioProcessingToActive() throws Exception { 1009 BluetoothCall activeCall = createActiveCall(); 1010 when(activeCall.getState()).thenReturn(Call.STATE_ACTIVE); 1011 mBluetoothInCallService.onCallAdded(activeCall); 1012 mBluetoothInCallService.getCallback(activeCall) 1013 .onStateChanged(activeCall, Call.STATE_ACTIVE); 1014 1015 verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(0), eq(CALL_STATE_IDLE), 1016 eq(""), eq(128), nullable(String.class)); 1017 } 1018 1019 @Test testOnCallStateChangedDialing()1020 public void testOnCallStateChangedDialing() throws Exception { 1021 BluetoothCall activeCall = createActiveCall(); 1022 1023 // make "mLastState" STATE_CONNECTING 1024 BluetoothInCallService.CallStateCallback callback = 1025 mBluetoothInCallService.new CallStateCallback(Call.STATE_CONNECTING); 1026 mBluetoothInCallService.mCallbacks.put( 1027 activeCall.getTelecomCallId(), callback); 1028 1029 mBluetoothInCallService.mCallbacks.get(activeCall.getTelecomCallId()) 1030 .onStateChanged(activeCall, Call.STATE_DIALING); 1031 1032 verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(), 1033 anyString(), anyInt(), nullable(String.class)); 1034 } 1035 1036 @Test testOnCallStateChangedAlerting()1037 public void testOnCallStateChangedAlerting() throws Exception { 1038 BluetoothCall outgoingCall = createOutgoingCall(); 1039 mBluetoothInCallService.onCallAdded(outgoingCall); 1040 mBluetoothInCallService.getCallback(outgoingCall) 1041 .onStateChanged(outgoingCall, Call.STATE_DIALING); 1042 1043 verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_DIALING), 1044 eq(""), eq(128), nullable(String.class)); 1045 verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_ALERTING), 1046 eq(""), eq(128), nullable(String.class)); 1047 } 1048 1049 @Test testOnCallStateChangedDisconnected()1050 public void testOnCallStateChangedDisconnected() throws Exception { 1051 BluetoothCall disconnectedCall = createDisconnectedCall(); 1052 doReturn(true).when(mMockCallInfo).hasOnlyDisconnectedCalls(); 1053 mBluetoothInCallService.onCallAdded(disconnectedCall); 1054 mBluetoothInCallService.getCallback(disconnectedCall) 1055 .onStateChanged(disconnectedCall, Call.STATE_DISCONNECTED); 1056 verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_DISCONNECTED), 1057 eq(""), eq(128), nullable(String.class)); 1058 } 1059 1060 @Test testOnCallStateChanged()1061 public void testOnCallStateChanged() throws Exception { 1062 BluetoothCall ringingCall = createRingingCall(); 1063 when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555-0000")); 1064 mBluetoothInCallService.onCallAdded(ringingCall); 1065 1066 verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING), 1067 eq("555-0000"), eq(PhoneNumberUtils.TOA_Unknown), nullable(String.class)); 1068 1069 //Switch to active 1070 doReturn(null).when(mMockCallInfo).getRingingOrSimulatedRingingCall(); 1071 when(mMockCallInfo.getActiveCall()).thenReturn(ringingCall); 1072 1073 mBluetoothInCallService.getCallback(ringingCall) 1074 .onStateChanged(ringingCall, Call.STATE_ACTIVE); 1075 1076 verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(0), eq(CALL_STATE_IDLE), 1077 eq(""), eq(128), nullable(String.class)); 1078 } 1079 1080 @Test testOnCallStateChangedGSMSwap()1081 public void testOnCallStateChangedGSMSwap() throws Exception { 1082 BluetoothCall heldCall = createHeldCall(); 1083 when(heldCall.getHandle()).thenReturn(Uri.parse("tel:555-0000")); 1084 mBluetoothInCallService.onCallAdded(heldCall); 1085 doReturn(2).when(mMockCallInfo).getNumHeldCalls(); 1086 1087 clearInvocations(mMockBluetoothHeadset); 1088 mBluetoothInCallService.getCallback(heldCall) 1089 .onStateChanged(heldCall, Call.STATE_HOLDING); 1090 1091 verify(mMockBluetoothHeadset, never()).phoneStateChanged(eq(0), eq(2), eq(CALL_STATE_HELD), 1092 eq("5550000"), eq(PhoneNumberUtils.TOA_Unknown), nullable(String.class)); 1093 } 1094 1095 @Test testOnParentOnChildrenChanged()1096 public void testOnParentOnChildrenChanged() throws Exception { 1097 // Start with two calls that are being merged into a CDMA conference call. The 1098 // onIsConferencedChanged method will be called multiple times during the call. Make sure 1099 // that the bluetooth phone state is updated properly. 1100 BluetoothCall parentCall = createActiveCall(); 1101 BluetoothCall activeCall = getMockCall(); 1102 BluetoothCall heldCall = createHeldCall(); 1103 mBluetoothInCallService.onCallAdded(parentCall); 1104 mBluetoothInCallService.onCallAdded(activeCall); 1105 mBluetoothInCallService.onCallAdded(heldCall); 1106 String parentId = parentCall.getTelecomCallId(); 1107 when(activeCall.getParentId()).thenReturn(parentId); 1108 when(heldCall.getParentId()).thenReturn(parentId); 1109 1110 ArrayList<String> calls = new ArrayList<>(); 1111 calls.add(activeCall.getTelecomCallId()); 1112 1113 when(parentCall.getChildrenIds()).thenReturn(calls); 1114 when(parentCall.isConference()).thenReturn(true); 1115 1116 removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN); 1117 addCallCapability(parentCall, Connection.CAPABILITY_SWAP_CONFERENCE); 1118 when(parentCall.wasConferencePreviouslyMerged()).thenReturn(false); 1119 1120 clearInvocations(mMockBluetoothHeadset); 1121 // Be sure that onIsConferencedChanged rejects spurious changes during set up of 1122 // CDMA "conference" 1123 mBluetoothInCallService.getCallback(activeCall).onParentChanged(activeCall); 1124 verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(), 1125 anyString(), anyInt(), nullable(String.class)); 1126 1127 mBluetoothInCallService.getCallback(heldCall).onParentChanged(heldCall); 1128 verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(), 1129 anyString(), anyInt(), nullable(String.class)); 1130 1131 mBluetoothInCallService.getCallback(parentCall) 1132 .onChildrenChanged( 1133 parentCall, 1134 mBluetoothInCallService.getBluetoothCallsByIds(calls)); 1135 verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(), 1136 anyString(), anyInt(), nullable(String.class)); 1137 1138 calls.add(heldCall.getTelecomCallId()); 1139 mBluetoothInCallService.onCallAdded(heldCall); 1140 mBluetoothInCallService.getCallback(parentCall) 1141 .onChildrenChanged( 1142 parentCall, 1143 mBluetoothInCallService.getBluetoothCallsByIds(calls)); 1144 verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(1), eq(CALL_STATE_IDLE), 1145 eq(""), eq(128), nullable(String.class)); 1146 } 1147 1148 @Test testBluetoothAdapterReceiver()1149 public void testBluetoothAdapterReceiver() throws Exception { 1150 BluetoothCall ringingCall = createRingingCall(); 1151 when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:5550000")); 1152 1153 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 1154 intent.putExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_ON); 1155 clearInvocations(mMockBluetoothHeadset); 1156 mBluetoothInCallService.mBluetoothAdapterReceiver 1157 = mBluetoothInCallService.new BluetoothAdapterReceiver(); 1158 mBluetoothInCallService.mBluetoothAdapterReceiver 1159 .onReceive(mBluetoothInCallService, intent); 1160 1161 verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING), 1162 eq("5550000"), eq(PhoneNumberUtils.TOA_Unknown), nullable(String.class)); 1163 } 1164 addCallCapability(BluetoothCall call, int capability)1165 private void addCallCapability(BluetoothCall call, int capability) { 1166 when(call.can(capability)).thenReturn(true); 1167 } 1168 removeCallCapability(BluetoothCall call, int capability)1169 private void removeCallCapability(BluetoothCall call, int capability) { 1170 when(call.can(capability)).thenReturn(false); 1171 } 1172 createActiveCall()1173 private BluetoothCall createActiveCall() { 1174 BluetoothCall call = getMockCall(); 1175 when(mMockCallInfo.getActiveCall()).thenReturn(call); 1176 return call; 1177 } 1178 createRingingCall()1179 private BluetoothCall createRingingCall() { 1180 BluetoothCall call = getMockCall(); 1181 Log.i("BluetoothInCallService", "asdf creaete " + Integer.toString(call.hashCode())); 1182 when(mMockCallInfo.getRingingOrSimulatedRingingCall()).thenReturn(call); 1183 return call; 1184 } 1185 createHeldCall()1186 private BluetoothCall createHeldCall() { 1187 BluetoothCall call = getMockCall(); 1188 when(mMockCallInfo.getHeldCall()).thenReturn(call); 1189 return call; 1190 } 1191 createOutgoingCall()1192 private BluetoothCall createOutgoingCall() { 1193 BluetoothCall call = getMockCall(); 1194 when(mMockCallInfo.getOutgoingCall()).thenReturn(call); 1195 return call; 1196 } 1197 createDisconnectedCall()1198 private BluetoothCall createDisconnectedCall() { 1199 BluetoothCall call = getMockCall(); 1200 when(mMockCallInfo.getCallByState(Call.STATE_DISCONNECTED)).thenReturn(call); 1201 return call; 1202 } 1203 createForegroundCall()1204 private BluetoothCall createForegroundCall() { 1205 BluetoothCall call = getMockCall(); 1206 when(mMockCallInfo.getForegroundCall()).thenReturn(call); 1207 return call; 1208 } 1209 makeQuickConnectionServiceComponentName()1210 private static ComponentName makeQuickConnectionServiceComponentName() { 1211 return new ComponentName("com.android.server.telecom.tests", 1212 "com.android.server.telecom.tests.MockConnectionService"); 1213 } 1214 makeQuickAccountHandle(String id)1215 private static PhoneAccountHandle makeQuickAccountHandle(String id) { 1216 return new PhoneAccountHandle(makeQuickConnectionServiceComponentName(), id, 1217 Binder.getCallingUserHandle()); 1218 } 1219 makeQuickAccountBuilder(String id, int idx)1220 private PhoneAccount.Builder makeQuickAccountBuilder(String id, int idx) { 1221 return new PhoneAccount.Builder(makeQuickAccountHandle(id), "label" + idx); 1222 } 1223 makeQuickAccount(String id, int idx)1224 private PhoneAccount makeQuickAccount(String id, int idx) { 1225 return makeQuickAccountBuilder(id, idx) 1226 .setAddress(Uri.parse(TEST_ACCOUNT_ADDRESS + idx)) 1227 .setSubscriptionAddress(Uri.parse("tel:555-000" + idx)) 1228 .setCapabilities(idx) 1229 .setShortDescription("desc" + idx) 1230 .setIsEnabled(true) 1231 .build(); 1232 } 1233 getMockCall()1234 private BluetoothCall getMockCall() { 1235 BluetoothCall call = mock(com.android.bluetooth.telephony.BluetoothCall.class); 1236 String uuid = UUID.randomUUID().toString(); 1237 when(call.getTelecomCallId()).thenReturn(uuid); 1238 return call; 1239 } 1240 } 1241