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