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