Loading src/com/android/server/telecom/Call.java +58 −5 Original line number Diff line number Diff line Loading @@ -506,6 +506,15 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, */ private boolean mIsVideoCallingSupportedByPhoneAccount = false; /** * Indicates whether or not this call can be pulled if it is an external call. If true, respect * the Connection Capability set by the ConnectionService. If false, override the capability * set and always remove the ability to pull this external call. * * See {@link #setIsPullExternalCallSupported(boolean)} */ private boolean mIsPullExternalCallSupported = true; private PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter; /** Loading Loading @@ -1450,6 +1459,26 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, setConnectionCapabilities(getConnectionCapabilities(), true /* force */); } /** * Determines if pulling this external call is supported. If it is supported, we will allow the * {@link Connection#CAPABILITY_CAN_PULL_CALL} capability to be added to this call's * capabilities. If it is not supported, we will strip this capability before sending this * call's capabilities to the InCallService. * @param isPullExternalCallSupported true, if pulling this external call is supported, false * otherwise. */ public void setIsPullExternalCallSupported(boolean isPullExternalCallSupported) { if (!isExternalCall()) return; if (isPullExternalCallSupported == mIsPullExternalCallSupported) return; Log.i(this, "setCanPullExternalCall: canPull=%b", isPullExternalCallSupported); mIsPullExternalCallSupported = isPullExternalCallSupported; // Use mConnectionCapabilities here to get the unstripped capabilities. setConnectionCapabilities(mConnectionCapabilities, true /* force */); } /** * @return {@code true} if the {@link Call} locally supports video. */ Loading Loading @@ -1656,7 +1685,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, } public int getConnectionCapabilities() { return mConnectionCapabilities; return stripUnsupportedCapabilities(mConnectionCapabilities); } int getConnectionProperties() { Loading @@ -1677,15 +1706,33 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, l.onConnectionCapabilitiesChanged(this); } int xorCaps = previousCapabilities ^ mConnectionCapabilities; int strippedCaps = getConnectionCapabilities(); int xorCaps = previousCapabilities ^ strippedCaps; Log.addEvent(this, LogUtils.Events.CAPABILITY_CHANGE, "Current: [%s], Removed [%s], Added [%s]", Connection.capabilitiesToStringShort(mConnectionCapabilities), Connection.capabilitiesToStringShort(strippedCaps), Connection.capabilitiesToStringShort(previousCapabilities & xorCaps), Connection.capabilitiesToStringShort(mConnectionCapabilities & xorCaps)); Connection.capabilitiesToStringShort(strippedCaps & xorCaps)); } } /** * For some states of Telecom, we need to modify this connection's capabilities: * - A user should not be able to pull an external call during an emergency call, so * CAPABILITY_CAN_PULL_CALL should be removed until the emergency call ends. * @param capabilities The original capabilities. * @return The stripped capabilities. */ private int stripUnsupportedCapabilities(int capabilities) { if (!mIsPullExternalCallSupported) { if ((capabilities |= Connection.CAPABILITY_CAN_PULL_CALL) > 0) { capabilities &= ~Connection.CAPABILITY_CAN_PULL_CALL; Log.i(this, "stripCapabilitiesBasedOnState: CAPABILITY_CAN_PULL_CALL removed."); } } return capabilities; } public void setConnectionProperties(int connectionProperties) { Log.v(this, "setConnectionProperties: %s", Connection.propertiesToString( connectionProperties)); Loading Loading @@ -1731,6 +1778,12 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, Log.v(this, "setConnectionProperties: external call changed isExternal = %b", isExternal); Log.addEvent(this, LogUtils.Events.IS_EXTERNAL, isExternal); if (isExternal) { // If there is an ongoing emergency call, remove the ability for this call to // be pulled. boolean isInEmergencyCall = mCallsManager.isInEmergencyCall(); setIsPullExternalCallSupported(!isInEmergencyCall); } for (Listener l : mListeners) { l.onExternalCallChanged(this, isExternal); } Loading Loading @@ -2829,7 +2882,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, @VisibleForTesting public boolean can(int capability) { return (mConnectionCapabilities & capability) == capability; return (getConnectionCapabilities() & capability) == capability; } @VisibleForTesting Loading src/com/android/server/telecom/CallsManager.java +16 −2 Original line number Diff line number Diff line Loading @@ -3433,6 +3433,7 @@ public class CallsManager extends Call.ListenerBase updateCanAddCall(); updateHasActiveRttCall(); updateExternalCallCanPullSupport(); // onCallAdded for calls which immediately take the foreground (like the first call). for (CallsManagerListener listener : mListeners) { if (LogUtils.SYSTRACE_DEBUG) { Loading @@ -3446,7 +3447,8 @@ public class CallsManager extends Call.ListenerBase Trace.endSection(); } private void removeCall(Call call) { @VisibleForTesting public void removeCall(Call call) { Trace.beginSection("removeCall"); Log.v(this, "removeCall(%s)", call); Loading @@ -3462,7 +3464,7 @@ public class CallsManager extends Call.ListenerBase } call.destroy(); updateExternalCallCanPullSupport(); // Only broadcast changes for calls that are being tracked. if (shouldNotify) { updateCanAddCall(); Loading Loading @@ -5115,6 +5117,18 @@ public class CallsManager extends Call.ListenerBase || c.isNetworkIdentifiedEmergencyCall()) && !c.isDisconnected()).count() > 0; } /** * Trigger a recalculation of support for CAPABILITY_CAN_PULL_CALL for external calls due to * a possible emergency call being added/removed. */ private void updateExternalCallCanPullSupport() { boolean isInEmergencyCall = isInEmergencyCall(); // Remove the capability to pull an external call in the case that we are in an emergency // call. mCalls.stream().filter(Call::isExternalCall).forEach( c->c.setIsPullExternalCallSupported(!isInEmergencyCall)); } /** * Trigger display of an error message to the user; we do this outside of dialer for calls which * fail to be created and added to Dialer. Loading tests/src/com/android/server/telecom/tests/CallTest.java +48 −0 Original line number Diff line number Diff line Loading @@ -223,6 +223,54 @@ public class CallTest extends TelecomTestCase { assertEquals(DisconnectCause.REJECTED, call.getDisconnectCause().getCode()); } @Test @SmallTest public void testCanPullCallRemovedDuringEmergencyCall() { Call call = new Call( "1", /* callId */ mContext, mMockCallsManager, mLock, null /* ConnectionServiceRepository */, mMockPhoneNumberUtilsAdapter, TEST_ADDRESS, null /* GatewayInfo */, null /* connectionManagerPhoneAccountHandle */, SIM_1_HANDLE, Call.CALL_DIRECTION_INCOMING, false /* shouldAttachToExistingConnection*/, false /* isConference */, mMockClockProxy, mMockToastProxy); boolean[] hasCalledConnectionCapabilitiesChanged = new boolean[1]; call.addListener(new Call.ListenerBase() { @Override public void onConnectionCapabilitiesChanged(Call call) { hasCalledConnectionCapabilitiesChanged[0] = true; } }); call.setConnectionService(mMockConnectionService); call.setConnectionProperties(Connection.PROPERTY_IS_EXTERNAL_CALL); call.setConnectionCapabilities(Connection.CAPABILITY_CAN_PULL_CALL); call.setState(CallState.ACTIVE, ""); assertTrue(hasCalledConnectionCapabilitiesChanged[0]); // Capability should be present assertTrue((call.getConnectionCapabilities() | Connection.CAPABILITY_CAN_PULL_CALL) > 0); hasCalledConnectionCapabilitiesChanged[0] = false; // Emergency call in progress call.setIsPullExternalCallSupported(false /*isPullCallSupported*/); assertTrue(hasCalledConnectionCapabilitiesChanged[0]); // Capability should not be present assertEquals(0, call.getConnectionCapabilities() & Connection.CAPABILITY_CAN_PULL_CALL); hasCalledConnectionCapabilitiesChanged[0] = false; // Emergency call complete call.setIsPullExternalCallSupported(true /*isPullCallSupported*/); assertTrue(hasCalledConnectionCapabilitiesChanged[0]); // Capability should be present assertEquals(Connection.CAPABILITY_CAN_PULL_CALL, call.getConnectionCapabilities() & Connection.CAPABILITY_CAN_PULL_CALL); } @Test @SmallTest public void testCanNotPullCallDuringEmergencyCall() { Loading tests/src/com/android/server/telecom/tests/CallsManagerTest.java +60 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.telecom.tests; import static junit.framework.Assert.assertNotNull; import static junit.framework.TestCase.fail; import static org.junit.Assert.assertEquals; Loading Loading @@ -1201,6 +1202,41 @@ public class CallsManagerTest extends TelecomTestCase { assertTrue(ongoingCall.isVideoCallingSupportedByPhoneAccount()); } /** * Verifies that adding and removing a call triggers external calls to have capabilities * recalculated. */ @SmallTest @Test public void testExternalCallCapabilitiesUpdated() throws InterruptedException { Call externalCall = addSpyCall(SIM_2_HANDLE, null, CallState.ACTIVE, Connection.CAPABILITY_CAN_PULL_CALL, Connection.PROPERTY_IS_EXTERNAL_CALL); LinkedBlockingQueue<Integer> capabilitiesQueue = new LinkedBlockingQueue<>(1); externalCall.addListener(new Call.ListenerBase() { @Override public void onConnectionCapabilitiesChanged(Call call) { try { capabilitiesQueue.put(call.getConnectionCapabilities()); } catch (InterruptedException e) { fail(); } } }); Call call = createSpyCall(SIM_2_HANDLE, CallState.DIALING); doReturn(true).when(call).isEmergencyCall(); mCallsManager.addCall(call); Integer result = capabilitiesQueue.poll(TEST_TIMEOUT, TimeUnit.MILLISECONDS); assertNotNull(result); assertEquals(0, Connection.CAPABILITY_CAN_PULL_CALL & result); mCallsManager.removeCall(call); result = capabilitiesQueue.poll(TEST_TIMEOUT, TimeUnit.MILLISECONDS); assertNotNull(result); assertEquals(Connection.CAPABILITY_CAN_PULL_CALL, Connection.CAPABILITY_CAN_PULL_CALL & result); } /** * Verifies that speakers is disabled when there's no video capabilities, even if a video call * tried to place. Loading Loading @@ -1342,12 +1378,21 @@ public class CallsManagerTest extends TelecomTestCase { } private Call addSpyCall(PhoneAccountHandle targetPhoneAccount, int initialState) { return addSpyCall(targetPhoneAccount, null, initialState); return addSpyCall(targetPhoneAccount, null, initialState, 0 /*caps*/, 0 /*props*/); } private Call addSpyCall(PhoneAccountHandle targetPhoneAccount, PhoneAccountHandle connectionMgrAcct, int initialState) { return addSpyCall(targetPhoneAccount, connectionMgrAcct, initialState, 0 /*caps*/, 0 /*props*/); } private Call addSpyCall(PhoneAccountHandle targetPhoneAccount, PhoneAccountHandle connectionMgrAcct, int initialState, int connectionCapabilities, int connectionProperties) { Call ongoingCall = createCall(targetPhoneAccount, connectionMgrAcct, initialState); ongoingCall.setConnectionProperties(connectionProperties); ongoingCall.setConnectionCapabilities(connectionCapabilities); Call callSpy = Mockito.spy(ongoingCall); // Mocks some methods to not call the real method. Loading @@ -1361,6 +1406,20 @@ public class CallsManagerTest extends TelecomTestCase { return callSpy; } private Call createSpyCall(PhoneAccountHandle handle, int initialState) { Call ongoingCall = createCall(handle, initialState); Call callSpy = Mockito.spy(ongoingCall); // Mocks some methods to not call the real method. doNothing().when(callSpy).unhold(); doNothing().when(callSpy).hold(); doNothing().when(callSpy).disconnect(); doNothing().when(callSpy).answer(Matchers.anyInt()); doNothing().when(callSpy).setStartWithSpeakerphoneOn(Matchers.anyBoolean()); return callSpy; } private Call createCall(PhoneAccountHandle targetPhoneAccount, int initialState) { return createCall(targetPhoneAccount, null /* connectionManager */, initialState); } Loading Loading
src/com/android/server/telecom/Call.java +58 −5 Original line number Diff line number Diff line Loading @@ -506,6 +506,15 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, */ private boolean mIsVideoCallingSupportedByPhoneAccount = false; /** * Indicates whether or not this call can be pulled if it is an external call. If true, respect * the Connection Capability set by the ConnectionService. If false, override the capability * set and always remove the ability to pull this external call. * * See {@link #setIsPullExternalCallSupported(boolean)} */ private boolean mIsPullExternalCallSupported = true; private PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter; /** Loading Loading @@ -1450,6 +1459,26 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, setConnectionCapabilities(getConnectionCapabilities(), true /* force */); } /** * Determines if pulling this external call is supported. If it is supported, we will allow the * {@link Connection#CAPABILITY_CAN_PULL_CALL} capability to be added to this call's * capabilities. If it is not supported, we will strip this capability before sending this * call's capabilities to the InCallService. * @param isPullExternalCallSupported true, if pulling this external call is supported, false * otherwise. */ public void setIsPullExternalCallSupported(boolean isPullExternalCallSupported) { if (!isExternalCall()) return; if (isPullExternalCallSupported == mIsPullExternalCallSupported) return; Log.i(this, "setCanPullExternalCall: canPull=%b", isPullExternalCallSupported); mIsPullExternalCallSupported = isPullExternalCallSupported; // Use mConnectionCapabilities here to get the unstripped capabilities. setConnectionCapabilities(mConnectionCapabilities, true /* force */); } /** * @return {@code true} if the {@link Call} locally supports video. */ Loading Loading @@ -1656,7 +1685,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, } public int getConnectionCapabilities() { return mConnectionCapabilities; return stripUnsupportedCapabilities(mConnectionCapabilities); } int getConnectionProperties() { Loading @@ -1677,15 +1706,33 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, l.onConnectionCapabilitiesChanged(this); } int xorCaps = previousCapabilities ^ mConnectionCapabilities; int strippedCaps = getConnectionCapabilities(); int xorCaps = previousCapabilities ^ strippedCaps; Log.addEvent(this, LogUtils.Events.CAPABILITY_CHANGE, "Current: [%s], Removed [%s], Added [%s]", Connection.capabilitiesToStringShort(mConnectionCapabilities), Connection.capabilitiesToStringShort(strippedCaps), Connection.capabilitiesToStringShort(previousCapabilities & xorCaps), Connection.capabilitiesToStringShort(mConnectionCapabilities & xorCaps)); Connection.capabilitiesToStringShort(strippedCaps & xorCaps)); } } /** * For some states of Telecom, we need to modify this connection's capabilities: * - A user should not be able to pull an external call during an emergency call, so * CAPABILITY_CAN_PULL_CALL should be removed until the emergency call ends. * @param capabilities The original capabilities. * @return The stripped capabilities. */ private int stripUnsupportedCapabilities(int capabilities) { if (!mIsPullExternalCallSupported) { if ((capabilities |= Connection.CAPABILITY_CAN_PULL_CALL) > 0) { capabilities &= ~Connection.CAPABILITY_CAN_PULL_CALL; Log.i(this, "stripCapabilitiesBasedOnState: CAPABILITY_CAN_PULL_CALL removed."); } } return capabilities; } public void setConnectionProperties(int connectionProperties) { Log.v(this, "setConnectionProperties: %s", Connection.propertiesToString( connectionProperties)); Loading Loading @@ -1731,6 +1778,12 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, Log.v(this, "setConnectionProperties: external call changed isExternal = %b", isExternal); Log.addEvent(this, LogUtils.Events.IS_EXTERNAL, isExternal); if (isExternal) { // If there is an ongoing emergency call, remove the ability for this call to // be pulled. boolean isInEmergencyCall = mCallsManager.isInEmergencyCall(); setIsPullExternalCallSupported(!isInEmergencyCall); } for (Listener l : mListeners) { l.onExternalCallChanged(this, isExternal); } Loading Loading @@ -2829,7 +2882,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, @VisibleForTesting public boolean can(int capability) { return (mConnectionCapabilities & capability) == capability; return (getConnectionCapabilities() & capability) == capability; } @VisibleForTesting Loading
src/com/android/server/telecom/CallsManager.java +16 −2 Original line number Diff line number Diff line Loading @@ -3433,6 +3433,7 @@ public class CallsManager extends Call.ListenerBase updateCanAddCall(); updateHasActiveRttCall(); updateExternalCallCanPullSupport(); // onCallAdded for calls which immediately take the foreground (like the first call). for (CallsManagerListener listener : mListeners) { if (LogUtils.SYSTRACE_DEBUG) { Loading @@ -3446,7 +3447,8 @@ public class CallsManager extends Call.ListenerBase Trace.endSection(); } private void removeCall(Call call) { @VisibleForTesting public void removeCall(Call call) { Trace.beginSection("removeCall"); Log.v(this, "removeCall(%s)", call); Loading @@ -3462,7 +3464,7 @@ public class CallsManager extends Call.ListenerBase } call.destroy(); updateExternalCallCanPullSupport(); // Only broadcast changes for calls that are being tracked. if (shouldNotify) { updateCanAddCall(); Loading Loading @@ -5115,6 +5117,18 @@ public class CallsManager extends Call.ListenerBase || c.isNetworkIdentifiedEmergencyCall()) && !c.isDisconnected()).count() > 0; } /** * Trigger a recalculation of support for CAPABILITY_CAN_PULL_CALL for external calls due to * a possible emergency call being added/removed. */ private void updateExternalCallCanPullSupport() { boolean isInEmergencyCall = isInEmergencyCall(); // Remove the capability to pull an external call in the case that we are in an emergency // call. mCalls.stream().filter(Call::isExternalCall).forEach( c->c.setIsPullExternalCallSupported(!isInEmergencyCall)); } /** * Trigger display of an error message to the user; we do this outside of dialer for calls which * fail to be created and added to Dialer. Loading
tests/src/com/android/server/telecom/tests/CallTest.java +48 −0 Original line number Diff line number Diff line Loading @@ -223,6 +223,54 @@ public class CallTest extends TelecomTestCase { assertEquals(DisconnectCause.REJECTED, call.getDisconnectCause().getCode()); } @Test @SmallTest public void testCanPullCallRemovedDuringEmergencyCall() { Call call = new Call( "1", /* callId */ mContext, mMockCallsManager, mLock, null /* ConnectionServiceRepository */, mMockPhoneNumberUtilsAdapter, TEST_ADDRESS, null /* GatewayInfo */, null /* connectionManagerPhoneAccountHandle */, SIM_1_HANDLE, Call.CALL_DIRECTION_INCOMING, false /* shouldAttachToExistingConnection*/, false /* isConference */, mMockClockProxy, mMockToastProxy); boolean[] hasCalledConnectionCapabilitiesChanged = new boolean[1]; call.addListener(new Call.ListenerBase() { @Override public void onConnectionCapabilitiesChanged(Call call) { hasCalledConnectionCapabilitiesChanged[0] = true; } }); call.setConnectionService(mMockConnectionService); call.setConnectionProperties(Connection.PROPERTY_IS_EXTERNAL_CALL); call.setConnectionCapabilities(Connection.CAPABILITY_CAN_PULL_CALL); call.setState(CallState.ACTIVE, ""); assertTrue(hasCalledConnectionCapabilitiesChanged[0]); // Capability should be present assertTrue((call.getConnectionCapabilities() | Connection.CAPABILITY_CAN_PULL_CALL) > 0); hasCalledConnectionCapabilitiesChanged[0] = false; // Emergency call in progress call.setIsPullExternalCallSupported(false /*isPullCallSupported*/); assertTrue(hasCalledConnectionCapabilitiesChanged[0]); // Capability should not be present assertEquals(0, call.getConnectionCapabilities() & Connection.CAPABILITY_CAN_PULL_CALL); hasCalledConnectionCapabilitiesChanged[0] = false; // Emergency call complete call.setIsPullExternalCallSupported(true /*isPullCallSupported*/); assertTrue(hasCalledConnectionCapabilitiesChanged[0]); // Capability should be present assertEquals(Connection.CAPABILITY_CAN_PULL_CALL, call.getConnectionCapabilities() & Connection.CAPABILITY_CAN_PULL_CALL); } @Test @SmallTest public void testCanNotPullCallDuringEmergencyCall() { Loading
tests/src/com/android/server/telecom/tests/CallsManagerTest.java +60 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.telecom.tests; import static junit.framework.Assert.assertNotNull; import static junit.framework.TestCase.fail; import static org.junit.Assert.assertEquals; Loading Loading @@ -1201,6 +1202,41 @@ public class CallsManagerTest extends TelecomTestCase { assertTrue(ongoingCall.isVideoCallingSupportedByPhoneAccount()); } /** * Verifies that adding and removing a call triggers external calls to have capabilities * recalculated. */ @SmallTest @Test public void testExternalCallCapabilitiesUpdated() throws InterruptedException { Call externalCall = addSpyCall(SIM_2_HANDLE, null, CallState.ACTIVE, Connection.CAPABILITY_CAN_PULL_CALL, Connection.PROPERTY_IS_EXTERNAL_CALL); LinkedBlockingQueue<Integer> capabilitiesQueue = new LinkedBlockingQueue<>(1); externalCall.addListener(new Call.ListenerBase() { @Override public void onConnectionCapabilitiesChanged(Call call) { try { capabilitiesQueue.put(call.getConnectionCapabilities()); } catch (InterruptedException e) { fail(); } } }); Call call = createSpyCall(SIM_2_HANDLE, CallState.DIALING); doReturn(true).when(call).isEmergencyCall(); mCallsManager.addCall(call); Integer result = capabilitiesQueue.poll(TEST_TIMEOUT, TimeUnit.MILLISECONDS); assertNotNull(result); assertEquals(0, Connection.CAPABILITY_CAN_PULL_CALL & result); mCallsManager.removeCall(call); result = capabilitiesQueue.poll(TEST_TIMEOUT, TimeUnit.MILLISECONDS); assertNotNull(result); assertEquals(Connection.CAPABILITY_CAN_PULL_CALL, Connection.CAPABILITY_CAN_PULL_CALL & result); } /** * Verifies that speakers is disabled when there's no video capabilities, even if a video call * tried to place. Loading Loading @@ -1342,12 +1378,21 @@ public class CallsManagerTest extends TelecomTestCase { } private Call addSpyCall(PhoneAccountHandle targetPhoneAccount, int initialState) { return addSpyCall(targetPhoneAccount, null, initialState); return addSpyCall(targetPhoneAccount, null, initialState, 0 /*caps*/, 0 /*props*/); } private Call addSpyCall(PhoneAccountHandle targetPhoneAccount, PhoneAccountHandle connectionMgrAcct, int initialState) { return addSpyCall(targetPhoneAccount, connectionMgrAcct, initialState, 0 /*caps*/, 0 /*props*/); } private Call addSpyCall(PhoneAccountHandle targetPhoneAccount, PhoneAccountHandle connectionMgrAcct, int initialState, int connectionCapabilities, int connectionProperties) { Call ongoingCall = createCall(targetPhoneAccount, connectionMgrAcct, initialState); ongoingCall.setConnectionProperties(connectionProperties); ongoingCall.setConnectionCapabilities(connectionCapabilities); Call callSpy = Mockito.spy(ongoingCall); // Mocks some methods to not call the real method. Loading @@ -1361,6 +1406,20 @@ public class CallsManagerTest extends TelecomTestCase { return callSpy; } private Call createSpyCall(PhoneAccountHandle handle, int initialState) { Call ongoingCall = createCall(handle, initialState); Call callSpy = Mockito.spy(ongoingCall); // Mocks some methods to not call the real method. doNothing().when(callSpy).unhold(); doNothing().when(callSpy).hold(); doNothing().when(callSpy).disconnect(); doNothing().when(callSpy).answer(Matchers.anyInt()); doNothing().when(callSpy).setStartWithSpeakerphoneOn(Matchers.anyBoolean()); return callSpy; } private Call createCall(PhoneAccountHandle targetPhoneAccount, int initialState) { return createCall(targetPhoneAccount, null /* connectionManager */, initialState); } Loading