Loading android/app/src/com/android/bluetooth/btservice/AdapterService.java +2 −1 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.ParcelUuid; Loading Loading @@ -394,7 +395,7 @@ public class AdapterService extends Service { public void onCreate() { super.onCreate(); debugLog("onCreate()"); mRemoteDevices = new RemoteDevices(this); mRemoteDevices = new RemoteDevices(this, Looper.getMainLooper()); mRemoteDevices.init(); mBinder = new AdapterServiceBinder(this); mAdapterProperties = new AdapterProperties(this); Loading android/app/src/com/android/bluetooth/btservice/RemoteDevices.java +27 −15 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.ParcelUuid; import android.support.annotation.VisibleForTesting; Loading Loading @@ -59,6 +60,30 @@ final class RemoteDevices { private final HashMap<String, DeviceProperties> mDevices; private Queue<String> mDeviceQueue; private final Handler mHandler; private class RemoteDevicesHandler extends Handler { /** * Handler must be created from an explicit looper to avoid threading ambiguity * @param looper The looper that this handler should be executed on */ RemoteDevicesHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_UUID_INTENT: BluetoothDevice device = (BluetoothDevice) msg.obj; if (device != null) { sendUuidIntent(device); } break; } } } private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading @@ -80,12 +105,13 @@ final class RemoteDevices { } }; RemoteDevices(AdapterService service) { RemoteDevices(AdapterService service, Looper looper) { sAdapter = BluetoothAdapter.getDefaultAdapter(); sAdapterService = service; sSdpTracker = new ArrayList<BluetoothDevice>(); mDevices = new HashMap<String, DeviceProperties>(); mDeviceQueue = new LinkedList<String>(); mHandler = new RemoteDevicesHandler(looper); } /** Loading Loading @@ -782,20 +808,6 @@ final class RemoteDevices { return batteryLevel * 100 / numberOfLevels; } private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_UUID_INTENT: BluetoothDevice device = (BluetoothDevice) msg.obj; if (device != null) { sendUuidIntent(device); } break; } } }; private static void errorLog(String msg) { Log.e(TAG, msg); } Loading android/app/tests/src/com/android/bluetooth/btservice/RemoteDevicesTest.java +27 −24 Original line number Diff line number Diff line Loading @@ -8,13 +8,17 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothProfile; import android.content.Intent; import android.os.Looper; import android.os.HandlerThread; import android.os.Message; import android.os.TestLooperManager; import android.support.test.InstrumentationRegistry; import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; import com.android.bluetooth.Utils; import com.android.bluetooth.hfp.HeadsetHalConstants; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; Loading @@ -34,26 +38,39 @@ public class RemoteDevicesTest { private ArgumentCaptor<String> mStringArgument = ArgumentCaptor.forClass(String.class); private BluetoothDevice mDevice1; private RemoteDevices mRemoteDevices; private HandlerThread mHandlerThread; private TestLooperManager mTestLooperManager; @Mock private AdapterService mAdapterService; @Before public void setUp() { MockitoAnnotations.initMocks(this); if (Looper.myLooper() == null) { Looper.prepare(); } mDevice1 = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(TEST_BT_ADDR_1); mRemoteDevices = new RemoteDevices(mAdapterService); mHandlerThread = new HandlerThread("RemoteDevicesTestHandlerThread"); mHandlerThread.start(); mTestLooperManager = InstrumentationRegistry.getInstrumentation() .acquireLooperManager(mHandlerThread.getLooper()); mRemoteDevices = new RemoteDevices(mAdapterService, mHandlerThread.getLooper()); } @After public void tearDown() { mTestLooperManager.release(); mHandlerThread.quit(); } @Test public void testSendUuidIntent() { MyAdapterSvc m = new MyAdapterSvc(); RemoteDevices instance = new RemoteDevices(m); instance.updateUuids(mDevice1); Looper.loop(); Assert.assertTrue(m.isRecvd()); // Verify that a handler message is sent by the method call mRemoteDevices.updateUuids(mDevice1); Message msg = mTestLooperManager.next(); Assert.assertNotNull(msg); // Verify that executing that message results in a broadcast intent mTestLooperManager.execute(msg); verify(mAdapterService).sendBroadcast(any(), anyString()); verifyNoMoreInteractions(mAdapterService); } @Test Loading Loading @@ -462,18 +479,4 @@ public class RemoteDevicesTest { list.add(0); return list.toArray(); } public class MyAdapterSvc extends AdapterService { private boolean recvd = false; @Override public void sendBroadcast(Intent intent, String receiverPermission) { recvd = (intent.getAction() == BluetoothDevice.ACTION_UUID); if (recvd || Looper.myQueue().isIdle()) Looper.myLooper().quitSafely(); } boolean isRecvd() { return recvd; } } } android/app/tests/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java +73 −88 Original line number Diff line number Diff line Loading @@ -8,30 +8,57 @@ import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.Intent; import android.media.AudioManager; import android.support.test.InstrumentationRegistry; import android.os.HandlerThread; import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; import com.android.bluetooth.btservice.AdapterService; import org.hamcrest.core.IsInstanceOf; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @MediumTest @RunWith(AndroidJUnit4.class) public class HeadsetClientStateMachineTest { private BluetoothAdapter mAdapter = null; private Context mTargetContext; private BluetoothAdapter mAdapter; private HandlerThread mHandlerThread; private HeadsetClientStateMachine mHeadsetClientStateMachine; private BluetoothDevice mTestDevice; @Mock private HeadsetClientService mHeadsetClientService; @Mock private AudioManager mAudioManager; @Before public void setUp() throws Exception { mTargetContext = InstrumentationRegistry.getTargetContext(); AdapterService inst = mock(AdapterService.class); Assert.assertTrue(inst != null); public void setUp() { // Setup mocks and test assets MockitoAnnotations.initMocks(this); // Set a valid volume when(mAudioManager.getStreamVolume(anyInt())).thenReturn(2); when(mAudioManager.getStreamMaxVolume(anyInt())).thenReturn(10); when(mAudioManager.getStreamMinVolume(anyInt())).thenReturn(1); when(mHeadsetClientService.getSystemService(Context.AUDIO_SERVICE)).thenReturn( mAudioManager); // This line must be called to make sure relevant objects are initialized properly mAdapter = BluetoothAdapter.getDefaultAdapter(); // Get a device for testing mTestDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05"); // Setup thread and looper mHandlerThread = new HandlerThread("HeadsetClientStateMachineTestHandlerThread"); mHandlerThread.start(); // Manage looper execution in main test thread explicitly to guarantee timing consistency mHeadsetClientStateMachine = new HeadsetClientStateMachine(mHeadsetClientService, mHandlerThread.getLooper()); } @After public void tearDown() { mHandlerThread.quit(); } /** Loading @@ -39,14 +66,7 @@ public class HeadsetClientStateMachineTest { */ @Test public void testDefaultDisconnectedState() { HeadsetClientService mockService = mock(HeadsetClientService.class); AudioManager mockAudioManager = mock(AudioManager.class); when(mockService.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mockAudioManager); HeadsetClientStateMachine mockSM = new HeadsetClientStateMachine(mockService, mTargetContext.getMainLooper()); Assert.assertEquals(mockSM.getConnectionState((BluetoothDevice) null), Assert.assertEquals(mHeadsetClientStateMachine.getConnectionState(null), BluetoothProfile.STATE_DISCONNECTED); } Loading @@ -55,33 +75,23 @@ public class HeadsetClientStateMachineTest { */ @Test public void testIncomingPriorityReject() { HeadsetClientService mockService = mock(HeadsetClientService.class); AudioManager mockAudioManager = mock(AudioManager.class); BluetoothDevice device = mAdapter.getRemoteDevice("00:01:02:03:04:05"); when(mockService.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mockAudioManager); HeadsetClientStateMachine mockSM = new HeadsetClientStateMachine(mockService, mTargetContext.getMainLooper()); mockSM.start(); mHeadsetClientStateMachine.start(); // Return false for priority. when(mockService.getPriority(any(BluetoothDevice.class))).thenReturn( when(mHeadsetClientService.getPriority(any(BluetoothDevice.class))).thenReturn( BluetoothProfile.PRIORITY_OFF); // Inject an event for when incoming connection is requested StackEvent connStCh = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connStCh.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED; connStCh.valueInt2 = 0; connStCh.valueInt3 = 0; connStCh.device = device; mockSM.sendMessage(StackEvent.STACK_EVENT, connStCh); connStCh.device = mTestDevice; mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, connStCh); // Verify that no connection state broadcast is executed verify(mockService, never()).sendBroadcast(any(Intent.class), anyString()); verify(mHeadsetClientService, never()).sendBroadcast(any(Intent.class), anyString()); // Check we are in disconnected state still. Assert.assertTrue( mockSM.getCurrentState() instanceof HeadsetClientStateMachine.Disconnected); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Disconnected.class)); } /** Loading @@ -89,58 +99,45 @@ public class HeadsetClientStateMachineTest { */ @Test public void testIncomingPriorityAccept() { HeadsetClientService mockService = mock(HeadsetClientService.class); AudioManager mockAudioManager = mock(AudioManager.class); BluetoothDevice device = mAdapter.getRemoteDevice("00:01:02:03:04:05"); when(mockService.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mockAudioManager); // Set a valid volume when(mockAudioManager.getStreamVolume(anyInt())).thenReturn(2); when(mockAudioManager.getStreamMaxVolume(anyInt())).thenReturn(10); when(mockAudioManager.getStreamMinVolume(anyInt())).thenReturn(1); mHeadsetClientStateMachine.start(); HeadsetClientStateMachine mockSM = new HeadsetClientStateMachine(mockService, mTargetContext.getMainLooper()); mockSM.start(); // Return false for priority. when(mockService.getPriority(any(BluetoothDevice.class))).thenReturn( // Return true for priority. when(mHeadsetClientService.getPriority(any(BluetoothDevice.class))).thenReturn( BluetoothProfile.PRIORITY_ON); // Inject an event for when incoming connection is requested StackEvent connStCh = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connStCh.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED; connStCh.valueInt2 = 0; connStCh.valueInt3 = 0; connStCh.device = device; mockSM.sendMessage(StackEvent.STACK_EVENT, connStCh); connStCh.device = mTestDevice; mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, connStCh); // Verify that one connection state broadcast is executed ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class); verify(mockService, timeout(1000)).sendBroadcast(intentArgument1.capture(), anyString()); verify(mHeadsetClientService, timeout(1000)).sendBroadcast(intentArgument1.capture(), anyString()); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, intentArgument1.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); // Check we are in connecting state now. Assert.assertTrue(mockSM.getCurrentState() instanceof HeadsetClientStateMachine.Connecting); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connecting.class)); // Send a message to trigger SLC connection StackEvent slcEvent = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); slcEvent.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_SLC_CONNECTED; slcEvent.valueInt2 = HeadsetClientHalConstants.PEER_FEAT_ECS; slcEvent.valueInt3 = 0; slcEvent.device = device; mockSM.sendMessage(StackEvent.STACK_EVENT, slcEvent); slcEvent.device = mTestDevice; mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, slcEvent); // Verify that one connection state broadcast is executed ArgumentCaptor<Intent> intentArgument2 = ArgumentCaptor.forClass(Intent.class); verify(mockService, timeout(1000).times(2)).sendBroadcast(intentArgument2.capture(), anyString()); verify(mHeadsetClientService, timeout(1000).times(2)).sendBroadcast( intentArgument2.capture(), anyString()); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, intentArgument2.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); // Check we are in connecting state now. Assert.assertTrue(mockSM.getCurrentState() instanceof HeadsetClientStateMachine.Connected); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class)); } /** Loading @@ -148,51 +145,39 @@ public class HeadsetClientStateMachineTest { */ @Test public void testIncomingTimeout() { HeadsetClientService mockService = mock(HeadsetClientService.class); AudioManager mockAudioManager = mock(AudioManager.class); BluetoothDevice device = mAdapter.getRemoteDevice("00:01:02:03:04:05"); mHeadsetClientStateMachine.start(); when(mockService.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mockAudioManager); // Set a valid volume when(mockAudioManager.getStreamVolume(anyInt())).thenReturn(2); when(mockAudioManager.getStreamMaxVolume(anyInt())).thenReturn(10); when(mockAudioManager.getStreamMinVolume(anyInt())).thenReturn(1); HeadsetClientStateMachine mockSM = new HeadsetClientStateMachine(mockService, mTargetContext.getMainLooper()); mockSM.start(); // Return false for priority. when(mockService.getPriority(any(BluetoothDevice.class))).thenReturn( // Return true for priority. when(mHeadsetClientService.getPriority(any(BluetoothDevice.class))).thenReturn( BluetoothProfile.PRIORITY_ON); // Inject an event for when incoming connection is requested StackEvent connStCh = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connStCh.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED; connStCh.valueInt2 = 0; connStCh.valueInt3 = 0; connStCh.device = device; mockSM.sendMessage(StackEvent.STACK_EVENT, connStCh); connStCh.device = mTestDevice; mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, connStCh); // Verify that one connection state broadcast is executed ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class); verify(mockService, timeout(1000)).sendBroadcast(intentArgument1.capture(), anyString()); verify(mHeadsetClientService, timeout(1000)).sendBroadcast(intentArgument1.capture(), anyString()); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, intentArgument1.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); // Check we are in connecting state now. Assert.assertTrue(mockSM.getCurrentState() instanceof HeadsetClientStateMachine.Connecting); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connecting.class)); // Verify that one connection state broadcast is executed ArgumentCaptor<Intent> intentArgument2 = ArgumentCaptor.forClass(Intent.class); verify(mockService, timeout(HeadsetClientStateMachine.CONNECTING_TIMEOUT_MS * 2).times( verify(mHeadsetClientService, timeout(HeadsetClientStateMachine.CONNECTING_TIMEOUT_MS * 2).times( 2)).sendBroadcast(intentArgument2.capture(), anyString()); Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, intentArgument2.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); // Check we are in connecting state now. Assert.assertTrue( mockSM.getCurrentState() instanceof HeadsetClientStateMachine.Disconnected); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Disconnected.class)); } } Loading
android/app/src/com/android/bluetooth/btservice/AdapterService.java +2 −1 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.ParcelUuid; Loading Loading @@ -394,7 +395,7 @@ public class AdapterService extends Service { public void onCreate() { super.onCreate(); debugLog("onCreate()"); mRemoteDevices = new RemoteDevices(this); mRemoteDevices = new RemoteDevices(this, Looper.getMainLooper()); mRemoteDevices.init(); mBinder = new AdapterServiceBinder(this); mAdapterProperties = new AdapterProperties(this); Loading
android/app/src/com/android/bluetooth/btservice/RemoteDevices.java +27 −15 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.ParcelUuid; import android.support.annotation.VisibleForTesting; Loading Loading @@ -59,6 +60,30 @@ final class RemoteDevices { private final HashMap<String, DeviceProperties> mDevices; private Queue<String> mDeviceQueue; private final Handler mHandler; private class RemoteDevicesHandler extends Handler { /** * Handler must be created from an explicit looper to avoid threading ambiguity * @param looper The looper that this handler should be executed on */ RemoteDevicesHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_UUID_INTENT: BluetoothDevice device = (BluetoothDevice) msg.obj; if (device != null) { sendUuidIntent(device); } break; } } } private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading @@ -80,12 +105,13 @@ final class RemoteDevices { } }; RemoteDevices(AdapterService service) { RemoteDevices(AdapterService service, Looper looper) { sAdapter = BluetoothAdapter.getDefaultAdapter(); sAdapterService = service; sSdpTracker = new ArrayList<BluetoothDevice>(); mDevices = new HashMap<String, DeviceProperties>(); mDeviceQueue = new LinkedList<String>(); mHandler = new RemoteDevicesHandler(looper); } /** Loading Loading @@ -782,20 +808,6 @@ final class RemoteDevices { return batteryLevel * 100 / numberOfLevels; } private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_UUID_INTENT: BluetoothDevice device = (BluetoothDevice) msg.obj; if (device != null) { sendUuidIntent(device); } break; } } }; private static void errorLog(String msg) { Log.e(TAG, msg); } Loading
android/app/tests/src/com/android/bluetooth/btservice/RemoteDevicesTest.java +27 −24 Original line number Diff line number Diff line Loading @@ -8,13 +8,17 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothProfile; import android.content.Intent; import android.os.Looper; import android.os.HandlerThread; import android.os.Message; import android.os.TestLooperManager; import android.support.test.InstrumentationRegistry; import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; import com.android.bluetooth.Utils; import com.android.bluetooth.hfp.HeadsetHalConstants; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; Loading @@ -34,26 +38,39 @@ public class RemoteDevicesTest { private ArgumentCaptor<String> mStringArgument = ArgumentCaptor.forClass(String.class); private BluetoothDevice mDevice1; private RemoteDevices mRemoteDevices; private HandlerThread mHandlerThread; private TestLooperManager mTestLooperManager; @Mock private AdapterService mAdapterService; @Before public void setUp() { MockitoAnnotations.initMocks(this); if (Looper.myLooper() == null) { Looper.prepare(); } mDevice1 = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(TEST_BT_ADDR_1); mRemoteDevices = new RemoteDevices(mAdapterService); mHandlerThread = new HandlerThread("RemoteDevicesTestHandlerThread"); mHandlerThread.start(); mTestLooperManager = InstrumentationRegistry.getInstrumentation() .acquireLooperManager(mHandlerThread.getLooper()); mRemoteDevices = new RemoteDevices(mAdapterService, mHandlerThread.getLooper()); } @After public void tearDown() { mTestLooperManager.release(); mHandlerThread.quit(); } @Test public void testSendUuidIntent() { MyAdapterSvc m = new MyAdapterSvc(); RemoteDevices instance = new RemoteDevices(m); instance.updateUuids(mDevice1); Looper.loop(); Assert.assertTrue(m.isRecvd()); // Verify that a handler message is sent by the method call mRemoteDevices.updateUuids(mDevice1); Message msg = mTestLooperManager.next(); Assert.assertNotNull(msg); // Verify that executing that message results in a broadcast intent mTestLooperManager.execute(msg); verify(mAdapterService).sendBroadcast(any(), anyString()); verifyNoMoreInteractions(mAdapterService); } @Test Loading Loading @@ -462,18 +479,4 @@ public class RemoteDevicesTest { list.add(0); return list.toArray(); } public class MyAdapterSvc extends AdapterService { private boolean recvd = false; @Override public void sendBroadcast(Intent intent, String receiverPermission) { recvd = (intent.getAction() == BluetoothDevice.ACTION_UUID); if (recvd || Looper.myQueue().isIdle()) Looper.myLooper().quitSafely(); } boolean isRecvd() { return recvd; } } }
android/app/tests/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java +73 −88 Original line number Diff line number Diff line Loading @@ -8,30 +8,57 @@ import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.Intent; import android.media.AudioManager; import android.support.test.InstrumentationRegistry; import android.os.HandlerThread; import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; import com.android.bluetooth.btservice.AdapterService; import org.hamcrest.core.IsInstanceOf; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @MediumTest @RunWith(AndroidJUnit4.class) public class HeadsetClientStateMachineTest { private BluetoothAdapter mAdapter = null; private Context mTargetContext; private BluetoothAdapter mAdapter; private HandlerThread mHandlerThread; private HeadsetClientStateMachine mHeadsetClientStateMachine; private BluetoothDevice mTestDevice; @Mock private HeadsetClientService mHeadsetClientService; @Mock private AudioManager mAudioManager; @Before public void setUp() throws Exception { mTargetContext = InstrumentationRegistry.getTargetContext(); AdapterService inst = mock(AdapterService.class); Assert.assertTrue(inst != null); public void setUp() { // Setup mocks and test assets MockitoAnnotations.initMocks(this); // Set a valid volume when(mAudioManager.getStreamVolume(anyInt())).thenReturn(2); when(mAudioManager.getStreamMaxVolume(anyInt())).thenReturn(10); when(mAudioManager.getStreamMinVolume(anyInt())).thenReturn(1); when(mHeadsetClientService.getSystemService(Context.AUDIO_SERVICE)).thenReturn( mAudioManager); // This line must be called to make sure relevant objects are initialized properly mAdapter = BluetoothAdapter.getDefaultAdapter(); // Get a device for testing mTestDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05"); // Setup thread and looper mHandlerThread = new HandlerThread("HeadsetClientStateMachineTestHandlerThread"); mHandlerThread.start(); // Manage looper execution in main test thread explicitly to guarantee timing consistency mHeadsetClientStateMachine = new HeadsetClientStateMachine(mHeadsetClientService, mHandlerThread.getLooper()); } @After public void tearDown() { mHandlerThread.quit(); } /** Loading @@ -39,14 +66,7 @@ public class HeadsetClientStateMachineTest { */ @Test public void testDefaultDisconnectedState() { HeadsetClientService mockService = mock(HeadsetClientService.class); AudioManager mockAudioManager = mock(AudioManager.class); when(mockService.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mockAudioManager); HeadsetClientStateMachine mockSM = new HeadsetClientStateMachine(mockService, mTargetContext.getMainLooper()); Assert.assertEquals(mockSM.getConnectionState((BluetoothDevice) null), Assert.assertEquals(mHeadsetClientStateMachine.getConnectionState(null), BluetoothProfile.STATE_DISCONNECTED); } Loading @@ -55,33 +75,23 @@ public class HeadsetClientStateMachineTest { */ @Test public void testIncomingPriorityReject() { HeadsetClientService mockService = mock(HeadsetClientService.class); AudioManager mockAudioManager = mock(AudioManager.class); BluetoothDevice device = mAdapter.getRemoteDevice("00:01:02:03:04:05"); when(mockService.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mockAudioManager); HeadsetClientStateMachine mockSM = new HeadsetClientStateMachine(mockService, mTargetContext.getMainLooper()); mockSM.start(); mHeadsetClientStateMachine.start(); // Return false for priority. when(mockService.getPriority(any(BluetoothDevice.class))).thenReturn( when(mHeadsetClientService.getPriority(any(BluetoothDevice.class))).thenReturn( BluetoothProfile.PRIORITY_OFF); // Inject an event for when incoming connection is requested StackEvent connStCh = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connStCh.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED; connStCh.valueInt2 = 0; connStCh.valueInt3 = 0; connStCh.device = device; mockSM.sendMessage(StackEvent.STACK_EVENT, connStCh); connStCh.device = mTestDevice; mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, connStCh); // Verify that no connection state broadcast is executed verify(mockService, never()).sendBroadcast(any(Intent.class), anyString()); verify(mHeadsetClientService, never()).sendBroadcast(any(Intent.class), anyString()); // Check we are in disconnected state still. Assert.assertTrue( mockSM.getCurrentState() instanceof HeadsetClientStateMachine.Disconnected); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Disconnected.class)); } /** Loading @@ -89,58 +99,45 @@ public class HeadsetClientStateMachineTest { */ @Test public void testIncomingPriorityAccept() { HeadsetClientService mockService = mock(HeadsetClientService.class); AudioManager mockAudioManager = mock(AudioManager.class); BluetoothDevice device = mAdapter.getRemoteDevice("00:01:02:03:04:05"); when(mockService.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mockAudioManager); // Set a valid volume when(mockAudioManager.getStreamVolume(anyInt())).thenReturn(2); when(mockAudioManager.getStreamMaxVolume(anyInt())).thenReturn(10); when(mockAudioManager.getStreamMinVolume(anyInt())).thenReturn(1); mHeadsetClientStateMachine.start(); HeadsetClientStateMachine mockSM = new HeadsetClientStateMachine(mockService, mTargetContext.getMainLooper()); mockSM.start(); // Return false for priority. when(mockService.getPriority(any(BluetoothDevice.class))).thenReturn( // Return true for priority. when(mHeadsetClientService.getPriority(any(BluetoothDevice.class))).thenReturn( BluetoothProfile.PRIORITY_ON); // Inject an event for when incoming connection is requested StackEvent connStCh = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connStCh.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED; connStCh.valueInt2 = 0; connStCh.valueInt3 = 0; connStCh.device = device; mockSM.sendMessage(StackEvent.STACK_EVENT, connStCh); connStCh.device = mTestDevice; mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, connStCh); // Verify that one connection state broadcast is executed ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class); verify(mockService, timeout(1000)).sendBroadcast(intentArgument1.capture(), anyString()); verify(mHeadsetClientService, timeout(1000)).sendBroadcast(intentArgument1.capture(), anyString()); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, intentArgument1.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); // Check we are in connecting state now. Assert.assertTrue(mockSM.getCurrentState() instanceof HeadsetClientStateMachine.Connecting); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connecting.class)); // Send a message to trigger SLC connection StackEvent slcEvent = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); slcEvent.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_SLC_CONNECTED; slcEvent.valueInt2 = HeadsetClientHalConstants.PEER_FEAT_ECS; slcEvent.valueInt3 = 0; slcEvent.device = device; mockSM.sendMessage(StackEvent.STACK_EVENT, slcEvent); slcEvent.device = mTestDevice; mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, slcEvent); // Verify that one connection state broadcast is executed ArgumentCaptor<Intent> intentArgument2 = ArgumentCaptor.forClass(Intent.class); verify(mockService, timeout(1000).times(2)).sendBroadcast(intentArgument2.capture(), anyString()); verify(mHeadsetClientService, timeout(1000).times(2)).sendBroadcast( intentArgument2.capture(), anyString()); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, intentArgument2.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); // Check we are in connecting state now. Assert.assertTrue(mockSM.getCurrentState() instanceof HeadsetClientStateMachine.Connected); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class)); } /** Loading @@ -148,51 +145,39 @@ public class HeadsetClientStateMachineTest { */ @Test public void testIncomingTimeout() { HeadsetClientService mockService = mock(HeadsetClientService.class); AudioManager mockAudioManager = mock(AudioManager.class); BluetoothDevice device = mAdapter.getRemoteDevice("00:01:02:03:04:05"); mHeadsetClientStateMachine.start(); when(mockService.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mockAudioManager); // Set a valid volume when(mockAudioManager.getStreamVolume(anyInt())).thenReturn(2); when(mockAudioManager.getStreamMaxVolume(anyInt())).thenReturn(10); when(mockAudioManager.getStreamMinVolume(anyInt())).thenReturn(1); HeadsetClientStateMachine mockSM = new HeadsetClientStateMachine(mockService, mTargetContext.getMainLooper()); mockSM.start(); // Return false for priority. when(mockService.getPriority(any(BluetoothDevice.class))).thenReturn( // Return true for priority. when(mHeadsetClientService.getPriority(any(BluetoothDevice.class))).thenReturn( BluetoothProfile.PRIORITY_ON); // Inject an event for when incoming connection is requested StackEvent connStCh = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connStCh.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED; connStCh.valueInt2 = 0; connStCh.valueInt3 = 0; connStCh.device = device; mockSM.sendMessage(StackEvent.STACK_EVENT, connStCh); connStCh.device = mTestDevice; mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, connStCh); // Verify that one connection state broadcast is executed ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class); verify(mockService, timeout(1000)).sendBroadcast(intentArgument1.capture(), anyString()); verify(mHeadsetClientService, timeout(1000)).sendBroadcast(intentArgument1.capture(), anyString()); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, intentArgument1.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); // Check we are in connecting state now. Assert.assertTrue(mockSM.getCurrentState() instanceof HeadsetClientStateMachine.Connecting); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connecting.class)); // Verify that one connection state broadcast is executed ArgumentCaptor<Intent> intentArgument2 = ArgumentCaptor.forClass(Intent.class); verify(mockService, timeout(HeadsetClientStateMachine.CONNECTING_TIMEOUT_MS * 2).times( verify(mHeadsetClientService, timeout(HeadsetClientStateMachine.CONNECTING_TIMEOUT_MS * 2).times( 2)).sendBroadcast(intentArgument2.capture(), anyString()); Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, intentArgument2.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); // Check we are in connecting state now. Assert.assertTrue( mockSM.getCurrentState() instanceof HeadsetClientStateMachine.Disconnected); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Disconnected.class)); } }