Loading android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java +53 −78 Original line number Diff line number Diff line Loading @@ -96,6 +96,7 @@ final class A2dpStateMachine extends StateMachine { A2dpStateMachine(BluetoothDevice device, A2dpService a2dpService, A2dpNativeInterface a2dpNativeInterface, Looper looper) { super(TAG, looper); setDbg(DBG); mDevice = device; mA2dpService = a2dpService; mA2dpNativeInterface = a2dpNativeInterface; Loading @@ -115,9 +116,7 @@ final class A2dpStateMachine extends StateMachine { static A2dpStateMachine make(BluetoothDevice device, A2dpService a2dpService, A2dpNativeInterface a2dpNativeInterface, Looper looper) { if (DBG) { Log.d(TAG, "make for device " + device); } Log.i(TAG, "make for device " + device); A2dpStateMachine a2dpSm = new A2dpStateMachine(device, a2dpService, a2dpNativeInterface, looper); a2dpSm.start(); Loading @@ -125,29 +124,24 @@ final class A2dpStateMachine extends StateMachine { } public void doQuit() { if (DBG) { Log.d(TAG, "doQuit for device " + mDevice); } log("doQuit for device " + mDevice); quitNow(); } public void cleanup() { if (DBG) { Log.d(TAG, "cleanup for device " + mDevice); } log("cleanup for device " + mDevice); } @VisibleForTesting class Disconnected extends State { @Override public void enter() { Log.i(TAG, "Enter Disconnected(" + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); Message currentMessage = getCurrentMessage(); Log.i(TAG, "Enter Disconnected(" + mDevice + "): " + (currentMessage == null ? "null" : messageWhatToString(currentMessage.what))); mConnectionState = BluetoothProfile.STATE_DISCONNECTED; removeDeferredMessages(DISCONNECT); // Remove Timeout messages when moved to stable state removeMessages(CONNECT_TIMEOUT); if (mLastConnectionState != -1) { // Don't broadcast during startup Loading @@ -164,19 +158,16 @@ final class A2dpStateMachine extends StateMachine { @Override public void exit() { if (DBG) { Log.d(TAG, "Exit Disconnected(" + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); } Message currentMessage = getCurrentMessage(); log("Exit Disconnected(" + mDevice + "): " + (currentMessage == null ? "null" : messageWhatToString(currentMessage.what))); mLastConnectionState = BluetoothProfile.STATE_DISCONNECTED; } @Override public boolean processMessage(Message message) { if (DBG) { Log.d(TAG, "Disconnected process message(" + mDevice + "): " log("Disconnected process message(" + mDevice + "): " + messageWhatToString(message.what)); } switch (message.what) { case CONNECT: Loading @@ -187,7 +178,6 @@ final class A2dpStateMachine extends StateMachine { } if (mA2dpService.okToConnect(mDevice)) { transitionTo(mConnecting); sendMessageDelayed(CONNECT_TIMEOUT, sConnectTimeoutMs); } else { // Reject the request and stay in Disconnected state Log.w(TAG, "Outgoing A2DP Connecting request rejected: " + mDevice); Loading @@ -198,9 +188,7 @@ final class A2dpStateMachine extends StateMachine { break; case STACK_EVENT: A2dpStackEvent event = (A2dpStackEvent) message.obj; if (DBG) { Log.d(TAG, "Disconnected: stack event: " + event); } log("Disconnected: stack event: " + event); if (!mDevice.equals(event.device)) { Log.wtfStack(TAG, "Device(" + mDevice + "): event mismatch: " + event); } Loading Loading @@ -263,27 +251,27 @@ final class A2dpStateMachine extends StateMachine { class Connecting extends State { @Override public void enter() { Log.i(TAG, "Enter Connecting(" + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); Message currentMessage = getCurrentMessage(); Log.i(TAG, "Enter Connecting(" + mDevice + "): " + (currentMessage == null ? "null" : messageWhatToString(currentMessage.what))); sendMessageDelayed(CONNECT_TIMEOUT, sConnectTimeoutMs); mConnectionState = BluetoothProfile.STATE_CONNECTING; broadcastConnectionState(mConnectionState, mLastConnectionState); } @Override public void exit() { if (DBG) { Log.d(TAG, "Exit Connecting(" + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); } Message currentMessage = getCurrentMessage(); log("Exit Connecting(" + mDevice + "): " + (currentMessage == null ? "null" : messageWhatToString(currentMessage.what))); mLastConnectionState = BluetoothProfile.STATE_CONNECTING; removeMessages(CONNECT_TIMEOUT); } @Override public boolean processMessage(Message message) { if (DBG) { Log.d(TAG, "Connecting process message(" + mDevice + "): " log("Connecting process message(" + mDevice + "): " + messageWhatToString(message.what)); } switch (message.what) { case CONNECT: Loading @@ -307,9 +295,7 @@ final class A2dpStateMachine extends StateMachine { break; case STACK_EVENT: A2dpStackEvent event = (A2dpStackEvent) message.obj; if (DBG) { Log.d(TAG, "Connecting: stack event: " + event); } log("Connecting: stack event: " + event); if (!mDevice.equals(event.device)) { Log.wtfStack(TAG, "Device(" + mDevice + "): event mismatch: " + event); } Loading Loading @@ -360,27 +346,27 @@ final class A2dpStateMachine extends StateMachine { class Disconnecting extends State { @Override public void enter() { Log.i(TAG, "Enter Disconnecting(" + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); Message currentMessage = getCurrentMessage(); Log.i(TAG, "Enter Disconnecting(" + mDevice + "): " + (currentMessage == null ? "null" : messageWhatToString(currentMessage.what))); sendMessageDelayed(CONNECT_TIMEOUT, sConnectTimeoutMs); mConnectionState = BluetoothProfile.STATE_DISCONNECTING; broadcastConnectionState(mConnectionState, mLastConnectionState); } @Override public void exit() { if (DBG) { Log.d(TAG, "Exit Disconnecting(" + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); } Message currentMessage = getCurrentMessage(); log("Exit Disconnecting(" + mDevice + "): " + (currentMessage == null ? "null" : messageWhatToString(currentMessage.what))); mLastConnectionState = BluetoothProfile.STATE_DISCONNECTING; removeMessages(CONNECT_TIMEOUT); } @Override public boolean processMessage(Message message) { if (DBG) { Log.d(TAG, "Disconnecting process message(" + mDevice + "): " log("Disconnecting process message(" + mDevice + "): " + messageWhatToString(message.what)); } switch (message.what) { case CONNECT: Loading @@ -401,9 +387,7 @@ final class A2dpStateMachine extends StateMachine { break; case STACK_EVENT: A2dpStackEvent event = (A2dpStackEvent) message.obj; if (DBG) { Log.d(TAG, "Disconnecting: stack event: " + event); } log("Disconnecting: stack event: " + event); if (!mDevice.equals(event.device)) { Log.wtfStack(TAG, "Device(" + mDevice + "): event mismatch: " + event); } Loading Loading @@ -467,13 +451,12 @@ final class A2dpStateMachine extends StateMachine { class Connected extends State { @Override public void enter() { Log.i(TAG, "Enter Connected(" + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); Message currentMessage = getCurrentMessage(); Log.i(TAG, "Enter Connected(" + mDevice + "): " + (currentMessage == null ? "null" : messageWhatToString(currentMessage.what))); mConnectionState = BluetoothProfile.STATE_CONNECTED; removeDeferredMessages(CONNECT); // Remove Timeout messages when moved to stable state removeMessages(CONNECT_TIMEOUT); broadcastConnectionState(mConnectionState, mLastConnectionState); // Upon connected, the audio starts out as stopped Loading @@ -483,19 +466,15 @@ final class A2dpStateMachine extends StateMachine { @Override public void exit() { if (DBG) { Log.d(TAG, "Exit Connected(" + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); } Message currentMessage = getCurrentMessage(); log("Exit Connected(" + mDevice + "): " + (currentMessage == null ? "null" : messageWhatToString(currentMessage.what))); mLastConnectionState = BluetoothProfile.STATE_CONNECTED; } @Override public boolean processMessage(Message message) { if (DBG) { Log.d(TAG, "Connected process message(" + mDevice + "): " + messageWhatToString(message.what)); } log("Connected process message(" + mDevice + "): " + messageWhatToString(message.what)); switch (message.what) { case CONNECT: Loading @@ -512,15 +491,9 @@ final class A2dpStateMachine extends StateMachine { transitionTo(mDisconnecting); } break; case CONNECT_TIMEOUT: // Ignore - nothing to timeout. We are already connected. Log.w(TAG, "Connected: CONNECT_TIMEOUT ignored: " + mDevice); break; case STACK_EVENT: A2dpStackEvent event = (A2dpStackEvent) message.obj; if (DBG) { Log.d(TAG, "Connected: stack event: " + event); } log("Connected: stack event: " + event); if (!mDevice.equals(event.device)) { Log.wtfStack(TAG, "Device(" + mDevice + "): event mismatch: " + event); } Loading Loading @@ -657,10 +630,8 @@ final class A2dpStateMachine extends StateMachine { // This method does not check for error conditon (newState == prevState) private void broadcastConnectionState(int newState, int prevState) { if (DBG) { Log.d(TAG, "Connection state " + mDevice + ": " + profileStateToString(prevState) log("Connection state " + mDevice + ": " + profileStateToString(prevState) + "->" + profileStateToString(newState)); } Intent intent = new Intent(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); Loading @@ -672,11 +643,8 @@ final class A2dpStateMachine extends StateMachine { } private void broadcastAudioState(int newState, int prevState) { if (DBG) { Log.d(TAG, "A2DP Playing state : device: " + mDevice + " State:" + audioStateToString(prevState) + "->" + audioStateToString(newState)); } log("A2DP Playing state : device: " + mDevice + " State:" + audioStateToString(prevState) + "->" + audioStateToString(newState)); Intent intent = new Intent(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); Loading Loading @@ -768,4 +736,11 @@ final class A2dpStateMachine extends StateMachine { } scanner.close(); } @Override protected void log(String msg) { if (DBG) { super.log(msg); } } } android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpStateMachineTest.java +39 −0 Original line number Diff line number Diff line Loading @@ -215,4 +215,43 @@ public class A2dpStateMachineTest { Assert.assertThat(mA2dpStateMachine.getCurrentState(), IsInstanceOf.instanceOf(A2dpStateMachine.Disconnected.class)); } /** * Test that an incoming connection times out */ @Test public void testIncomingTimeout() { allowConnection(true); doReturn(true).when(mA2dpNativeInterface).connectA2dp(any(BluetoothDevice.class)); doReturn(true).when(mA2dpNativeInterface).disconnectA2dp(any(BluetoothDevice.class)); // Inject an event for when incoming connection is requested A2dpStackEvent connStCh = new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connStCh.device = mTestDevice; connStCh.valueInt = A2dpStackEvent.CONNECTION_STATE_CONNECTING; mA2dpStateMachine.sendMessage(A2dpStateMachine.STACK_EVENT, connStCh); // Verify that one connection state broadcast is executed ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class); verify(mA2dpService, timeout(TIMEOUT_MS).times(1)).sendBroadcast(intentArgument1.capture(), anyString()); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, intentArgument1.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); // Check that we are in Connecting state Assert.assertThat(mA2dpStateMachine.getCurrentState(), IsInstanceOf.instanceOf(A2dpStateMachine.Connecting.class)); // Verify that one connection state broadcast is executed ArgumentCaptor<Intent> intentArgument2 = ArgumentCaptor.forClass(Intent.class); verify(mA2dpService, timeout(A2dpStateMachine.sConnectTimeoutMs * 2).times( 2)).sendBroadcast(intentArgument2.capture(), anyString()); Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, intentArgument2.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); // Check that we are in Disconnected state Assert.assertThat(mA2dpStateMachine.getCurrentState(), IsInstanceOf.instanceOf(A2dpStateMachine.Disconnected.class)); } } Loading
android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java +53 −78 Original line number Diff line number Diff line Loading @@ -96,6 +96,7 @@ final class A2dpStateMachine extends StateMachine { A2dpStateMachine(BluetoothDevice device, A2dpService a2dpService, A2dpNativeInterface a2dpNativeInterface, Looper looper) { super(TAG, looper); setDbg(DBG); mDevice = device; mA2dpService = a2dpService; mA2dpNativeInterface = a2dpNativeInterface; Loading @@ -115,9 +116,7 @@ final class A2dpStateMachine extends StateMachine { static A2dpStateMachine make(BluetoothDevice device, A2dpService a2dpService, A2dpNativeInterface a2dpNativeInterface, Looper looper) { if (DBG) { Log.d(TAG, "make for device " + device); } Log.i(TAG, "make for device " + device); A2dpStateMachine a2dpSm = new A2dpStateMachine(device, a2dpService, a2dpNativeInterface, looper); a2dpSm.start(); Loading @@ -125,29 +124,24 @@ final class A2dpStateMachine extends StateMachine { } public void doQuit() { if (DBG) { Log.d(TAG, "doQuit for device " + mDevice); } log("doQuit for device " + mDevice); quitNow(); } public void cleanup() { if (DBG) { Log.d(TAG, "cleanup for device " + mDevice); } log("cleanup for device " + mDevice); } @VisibleForTesting class Disconnected extends State { @Override public void enter() { Log.i(TAG, "Enter Disconnected(" + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); Message currentMessage = getCurrentMessage(); Log.i(TAG, "Enter Disconnected(" + mDevice + "): " + (currentMessage == null ? "null" : messageWhatToString(currentMessage.what))); mConnectionState = BluetoothProfile.STATE_DISCONNECTED; removeDeferredMessages(DISCONNECT); // Remove Timeout messages when moved to stable state removeMessages(CONNECT_TIMEOUT); if (mLastConnectionState != -1) { // Don't broadcast during startup Loading @@ -164,19 +158,16 @@ final class A2dpStateMachine extends StateMachine { @Override public void exit() { if (DBG) { Log.d(TAG, "Exit Disconnected(" + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); } Message currentMessage = getCurrentMessage(); log("Exit Disconnected(" + mDevice + "): " + (currentMessage == null ? "null" : messageWhatToString(currentMessage.what))); mLastConnectionState = BluetoothProfile.STATE_DISCONNECTED; } @Override public boolean processMessage(Message message) { if (DBG) { Log.d(TAG, "Disconnected process message(" + mDevice + "): " log("Disconnected process message(" + mDevice + "): " + messageWhatToString(message.what)); } switch (message.what) { case CONNECT: Loading @@ -187,7 +178,6 @@ final class A2dpStateMachine extends StateMachine { } if (mA2dpService.okToConnect(mDevice)) { transitionTo(mConnecting); sendMessageDelayed(CONNECT_TIMEOUT, sConnectTimeoutMs); } else { // Reject the request and stay in Disconnected state Log.w(TAG, "Outgoing A2DP Connecting request rejected: " + mDevice); Loading @@ -198,9 +188,7 @@ final class A2dpStateMachine extends StateMachine { break; case STACK_EVENT: A2dpStackEvent event = (A2dpStackEvent) message.obj; if (DBG) { Log.d(TAG, "Disconnected: stack event: " + event); } log("Disconnected: stack event: " + event); if (!mDevice.equals(event.device)) { Log.wtfStack(TAG, "Device(" + mDevice + "): event mismatch: " + event); } Loading Loading @@ -263,27 +251,27 @@ final class A2dpStateMachine extends StateMachine { class Connecting extends State { @Override public void enter() { Log.i(TAG, "Enter Connecting(" + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); Message currentMessage = getCurrentMessage(); Log.i(TAG, "Enter Connecting(" + mDevice + "): " + (currentMessage == null ? "null" : messageWhatToString(currentMessage.what))); sendMessageDelayed(CONNECT_TIMEOUT, sConnectTimeoutMs); mConnectionState = BluetoothProfile.STATE_CONNECTING; broadcastConnectionState(mConnectionState, mLastConnectionState); } @Override public void exit() { if (DBG) { Log.d(TAG, "Exit Connecting(" + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); } Message currentMessage = getCurrentMessage(); log("Exit Connecting(" + mDevice + "): " + (currentMessage == null ? "null" : messageWhatToString(currentMessage.what))); mLastConnectionState = BluetoothProfile.STATE_CONNECTING; removeMessages(CONNECT_TIMEOUT); } @Override public boolean processMessage(Message message) { if (DBG) { Log.d(TAG, "Connecting process message(" + mDevice + "): " log("Connecting process message(" + mDevice + "): " + messageWhatToString(message.what)); } switch (message.what) { case CONNECT: Loading @@ -307,9 +295,7 @@ final class A2dpStateMachine extends StateMachine { break; case STACK_EVENT: A2dpStackEvent event = (A2dpStackEvent) message.obj; if (DBG) { Log.d(TAG, "Connecting: stack event: " + event); } log("Connecting: stack event: " + event); if (!mDevice.equals(event.device)) { Log.wtfStack(TAG, "Device(" + mDevice + "): event mismatch: " + event); } Loading Loading @@ -360,27 +346,27 @@ final class A2dpStateMachine extends StateMachine { class Disconnecting extends State { @Override public void enter() { Log.i(TAG, "Enter Disconnecting(" + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); Message currentMessage = getCurrentMessage(); Log.i(TAG, "Enter Disconnecting(" + mDevice + "): " + (currentMessage == null ? "null" : messageWhatToString(currentMessage.what))); sendMessageDelayed(CONNECT_TIMEOUT, sConnectTimeoutMs); mConnectionState = BluetoothProfile.STATE_DISCONNECTING; broadcastConnectionState(mConnectionState, mLastConnectionState); } @Override public void exit() { if (DBG) { Log.d(TAG, "Exit Disconnecting(" + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); } Message currentMessage = getCurrentMessage(); log("Exit Disconnecting(" + mDevice + "): " + (currentMessage == null ? "null" : messageWhatToString(currentMessage.what))); mLastConnectionState = BluetoothProfile.STATE_DISCONNECTING; removeMessages(CONNECT_TIMEOUT); } @Override public boolean processMessage(Message message) { if (DBG) { Log.d(TAG, "Disconnecting process message(" + mDevice + "): " log("Disconnecting process message(" + mDevice + "): " + messageWhatToString(message.what)); } switch (message.what) { case CONNECT: Loading @@ -401,9 +387,7 @@ final class A2dpStateMachine extends StateMachine { break; case STACK_EVENT: A2dpStackEvent event = (A2dpStackEvent) message.obj; if (DBG) { Log.d(TAG, "Disconnecting: stack event: " + event); } log("Disconnecting: stack event: " + event); if (!mDevice.equals(event.device)) { Log.wtfStack(TAG, "Device(" + mDevice + "): event mismatch: " + event); } Loading Loading @@ -467,13 +451,12 @@ final class A2dpStateMachine extends StateMachine { class Connected extends State { @Override public void enter() { Log.i(TAG, "Enter Connected(" + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); Message currentMessage = getCurrentMessage(); Log.i(TAG, "Enter Connected(" + mDevice + "): " + (currentMessage == null ? "null" : messageWhatToString(currentMessage.what))); mConnectionState = BluetoothProfile.STATE_CONNECTED; removeDeferredMessages(CONNECT); // Remove Timeout messages when moved to stable state removeMessages(CONNECT_TIMEOUT); broadcastConnectionState(mConnectionState, mLastConnectionState); // Upon connected, the audio starts out as stopped Loading @@ -483,19 +466,15 @@ final class A2dpStateMachine extends StateMachine { @Override public void exit() { if (DBG) { Log.d(TAG, "Exit Connected(" + mDevice + "): " + messageWhatToString(getCurrentMessage().what)); } Message currentMessage = getCurrentMessage(); log("Exit Connected(" + mDevice + "): " + (currentMessage == null ? "null" : messageWhatToString(currentMessage.what))); mLastConnectionState = BluetoothProfile.STATE_CONNECTED; } @Override public boolean processMessage(Message message) { if (DBG) { Log.d(TAG, "Connected process message(" + mDevice + "): " + messageWhatToString(message.what)); } log("Connected process message(" + mDevice + "): " + messageWhatToString(message.what)); switch (message.what) { case CONNECT: Loading @@ -512,15 +491,9 @@ final class A2dpStateMachine extends StateMachine { transitionTo(mDisconnecting); } break; case CONNECT_TIMEOUT: // Ignore - nothing to timeout. We are already connected. Log.w(TAG, "Connected: CONNECT_TIMEOUT ignored: " + mDevice); break; case STACK_EVENT: A2dpStackEvent event = (A2dpStackEvent) message.obj; if (DBG) { Log.d(TAG, "Connected: stack event: " + event); } log("Connected: stack event: " + event); if (!mDevice.equals(event.device)) { Log.wtfStack(TAG, "Device(" + mDevice + "): event mismatch: " + event); } Loading Loading @@ -657,10 +630,8 @@ final class A2dpStateMachine extends StateMachine { // This method does not check for error conditon (newState == prevState) private void broadcastConnectionState(int newState, int prevState) { if (DBG) { Log.d(TAG, "Connection state " + mDevice + ": " + profileStateToString(prevState) log("Connection state " + mDevice + ": " + profileStateToString(prevState) + "->" + profileStateToString(newState)); } Intent intent = new Intent(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); Loading @@ -672,11 +643,8 @@ final class A2dpStateMachine extends StateMachine { } private void broadcastAudioState(int newState, int prevState) { if (DBG) { Log.d(TAG, "A2DP Playing state : device: " + mDevice + " State:" + audioStateToString(prevState) + "->" + audioStateToString(newState)); } log("A2DP Playing state : device: " + mDevice + " State:" + audioStateToString(prevState) + "->" + audioStateToString(newState)); Intent intent = new Intent(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); Loading Loading @@ -768,4 +736,11 @@ final class A2dpStateMachine extends StateMachine { } scanner.close(); } @Override protected void log(String msg) { if (DBG) { super.log(msg); } } }
android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpStateMachineTest.java +39 −0 Original line number Diff line number Diff line Loading @@ -215,4 +215,43 @@ public class A2dpStateMachineTest { Assert.assertThat(mA2dpStateMachine.getCurrentState(), IsInstanceOf.instanceOf(A2dpStateMachine.Disconnected.class)); } /** * Test that an incoming connection times out */ @Test public void testIncomingTimeout() { allowConnection(true); doReturn(true).when(mA2dpNativeInterface).connectA2dp(any(BluetoothDevice.class)); doReturn(true).when(mA2dpNativeInterface).disconnectA2dp(any(BluetoothDevice.class)); // Inject an event for when incoming connection is requested A2dpStackEvent connStCh = new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connStCh.device = mTestDevice; connStCh.valueInt = A2dpStackEvent.CONNECTION_STATE_CONNECTING; mA2dpStateMachine.sendMessage(A2dpStateMachine.STACK_EVENT, connStCh); // Verify that one connection state broadcast is executed ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class); verify(mA2dpService, timeout(TIMEOUT_MS).times(1)).sendBroadcast(intentArgument1.capture(), anyString()); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, intentArgument1.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); // Check that we are in Connecting state Assert.assertThat(mA2dpStateMachine.getCurrentState(), IsInstanceOf.instanceOf(A2dpStateMachine.Connecting.class)); // Verify that one connection state broadcast is executed ArgumentCaptor<Intent> intentArgument2 = ArgumentCaptor.forClass(Intent.class); verify(mA2dpService, timeout(A2dpStateMachine.sConnectTimeoutMs * 2).times( 2)).sendBroadcast(intentArgument2.capture(), anyString()); Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, intentArgument2.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); // Check that we are in Disconnected state Assert.assertThat(mA2dpStateMachine.getCurrentState(), IsInstanceOf.instanceOf(A2dpStateMachine.Disconnected.class)); } }