/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.car.bluetooth; import static android.car.settings.CarSettings.Secure.KEY_BLUETOOTH_DEVICES; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothStatusCodes; import android.bluetooth.BluetoothUuid; import android.content.Context; import android.content.Intent; import android.os.Handler; import android.os.Looper; import android.os.ParcelUuid; import android.provider.Settings; import android.text.TextUtils; import androidx.test.InstrumentationRegistry; import androidx.test.filters.RequiresDevice; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.invocation.InvocationOnMock; import org.mockito.junit.MockitoJUnitRunner; import org.mockito.stubbing.Answer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * Unit tests for {@link BluetoothDeviceManager} * * Run: * atest BluetoothDeviceManagerTest */ @RequiresDevice @RunWith(MockitoJUnitRunner.class) public class BluetoothDeviceManagerTest extends AbstractExtendedMockitoBluetoothTestCase { private static final int CONNECT_LATENCY_MS = 100; private static final int CONNECT_TIMEOUT_MS = 8000; private static final int ADAPTER_STATE_ANY = 0; private static final int ADAPTER_STATE_OFF = 1; private static final int ADAPTER_STATE_OFF_NOT_PERSISTED = 2; private static final int ADAPTER_STATE_ON = 3; private static final List EMPTY_DEVICE_LIST = Arrays.asList(); private static final List SINGLE_DEVICE_LIST = Arrays.asList("DE:AD:BE:EF:00:00"); private static final List SMALL_DEVICE_LIST = Arrays.asList( "DE:AD:BE:EF:00:00", "DE:AD:BE:EF:00:01", "DE:AD:BE:EF:00:02"); private static final List LARGE_DEVICE_LIST = Arrays.asList( "DE:AD:BE:EF:00:00", "DE:AD:BE:EF:00:01", "DE:AD:BE:EF:00:02", "DE:AD:BE:EF:00:03", "DE:AD:BE:EF:00:04", "DE:AD:BE:EF:00:05", "DE:AD:BE:EF:00:06", "DE:AD:BE:EF:00:07"); private static final String EMPTY_SETTINGS_STRING = ""; private static final String SINGLE_SETTINGS_STRING = makeSettingsString(SINGLE_DEVICE_LIST); private static final String SMALL_SETTINGS_STRING = makeSettingsString(SMALL_DEVICE_LIST); private static final String LARGE_SETTINGS_STRING = makeSettingsString(LARGE_DEVICE_LIST); private final String mSettingsKey = KEY_BLUETOOTH_DEVICES; private List mDeviceList; BluetoothDeviceManager mDeviceManager; // Tests assume the auto connecting devices only support MAP private final String mConnectionAction = "android.bluetooth.mapmce.profile.action.CONNECTION_STATE_CHANGED"; private ParcelUuid[] mUuids = new ParcelUuid[] { BluetoothUuid.MAS}; private Handler mHandler; private static final Object HANDLER_TOKEN = new Object(); private Context mTargetContext; private MockContext mMockContext; @Mock private BluetoothAdapter mMockBluetoothAdapter; @Mock private BluetoothManager mMockBluetoothManager; //--------------------------------------------------------------------------------------------// // Setup/TearDown // //--------------------------------------------------------------------------------------------// @Before public void setUp() { mTargetContext = InstrumentationRegistry.getTargetContext(); mMockContext = new MockContext(mTargetContext); setSettingsDeviceList(""); assertSettingsContains(""); mMockContext.addMockedSystemService(BluetoothManager.class, mMockBluetoothManager); when(mMockBluetoothManager.getAdapter()).thenReturn(mMockBluetoothAdapter); /** * Mocks {@link BluetoothAdapter#getRemoteDevice(boolean)} */ doAnswer(new Answer() { @Override public BluetoothDevice answer(InvocationOnMock invocation) throws Throwable { String bdAddr = ""; Object[] arguments = invocation.getArguments(); if (arguments != null && arguments.length == 1 && arguments[0] != null) { bdAddr = (String) arguments[0]; } return createDevice(bdAddr); } }).when(mMockBluetoothAdapter).getRemoteDevice(anyString()); mHandler = new Handler(Looper.getMainLooper()); mDeviceManager = BluetoothDeviceManager.create(mMockContext); Assert.assertTrue(mDeviceManager != null); mDeviceList = new ArrayList(); } @After public void tearDown() { mDeviceList = null; if (mDeviceManager != null) { mDeviceManager.stop(); mDeviceManager = null; } if (mHandler != null) { mHandler.removeCallbacksAndMessages(HANDLER_TOKEN); mHandler = null; } if (mMockContext != null) { mMockContext.release(); mMockContext = null; } } //--------------------------------------------------------------------------------------------// // Utilities // //--------------------------------------------------------------------------------------------// private void setSettingsDeviceList(String devicesStr) { Settings.Secure.putString(mMockContext.getContentResolver(), mSettingsKey, devicesStr); } private String getSettingsDeviceList() { String devices = Settings.Secure.getString(mMockContext.getContentResolver(), mSettingsKey); if (devices == null) devices = ""; return devices; } private ArrayList makeDeviceList(List addresses) { ArrayList devices = new ArrayList<>(); for (String address : addresses) { BluetoothDevice device = createDevice(address, mUuids); if (device == null) continue; devices.add(device); } return devices; } private static String makeSettingsString(List addresses) { return TextUtils.join(",", addresses); } private void setPreconditionsAndStart(int adapterState, String settings, List devices) { switch (adapterState) { case ADAPTER_STATE_ON: when(mMockBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_ON); Settings.Global.putInt(mMockContext.getContentResolver(), Settings.Global.BLUETOOTH_ON, 1); break; case ADAPTER_STATE_OFF: when(mMockBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_OFF); Settings.Global.putInt(mMockContext.getContentResolver(), Settings.Global.BLUETOOTH_ON, 0); break; case ADAPTER_STATE_OFF_NOT_PERSISTED: when(mMockBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_OFF); break; case ADAPTER_STATE_ANY: break; default: break; } setSettingsDeviceList(settings); mDeviceList = makeDeviceList(devices); mDeviceManager.start(); for (BluetoothDevice device : mDeviceList) { mDeviceManager.addDevice(device); } } private void sendAdapterStateChanged(int newState) { Assert.assertTrue(mMockContext != null); Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); mMockContext.sendBroadcast(intent); } private void sendBondStateChanged(BluetoothDevice device, int newState) { Assert.assertTrue(mMockContext != null); Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, newState); mMockContext.sendBroadcast(intent); } private void sendDeviceUuids(BluetoothDevice device, ParcelUuid[] uuids) { Assert.assertTrue(mMockContext != null); Intent intent = new Intent(BluetoothDevice.ACTION_UUID); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.putExtra(BluetoothDevice.EXTRA_UUID, uuids); mMockContext.sendBroadcast(intent); } private void sendConnectionStateChanged(BluetoothDevice device, int newState) { Assert.assertTrue(mMockContext != null); Intent intent = new Intent(mConnectionAction); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.putExtra(BluetoothProfile.EXTRA_STATE, newState); mMockContext.sendBroadcast(intent); } private synchronized void assertSettingsContains(String expected) { Assert.assertTrue(expected != null); String settings = getSettingsDeviceList(); if (settings == null) settings = ""; Assert.assertEquals(expected, settings); } private void assertDeviceList(List expected) { List devices = mDeviceManager.getDeviceListSnapshot(); ArrayList expectedDevices = makeDeviceList(expected); Assert.assertTrue(devices != null); Assert.assertEquals(expectedDevices.size(), devices.size()); for (int i = 0; i < expectedDevices.size(); i++) { BluetoothDevice expectedDevice = expectedDevices.get(i); BluetoothDevice device = devices.get(i); Assert.assertEquals(expectedDevice.getAddress(), device.getAddress()); } } private BluetoothDevice createDevice(String bdAddr) { return createDevice(bdAddr, null); } private BluetoothDevice createDevice(String bdAddr, ParcelUuid[] uuids) { BluetoothDevice device = mock(BluetoothDevice.class); when(device.getAddress()).thenReturn(bdAddr); when(device.getName()).thenReturn(bdAddr); when(device.getUuids()).thenReturn(uuids); when(device.connect()).thenReturn(BluetoothStatusCodes.SUCCESS); when(device.disconnect()).thenReturn(BluetoothStatusCodes.SUCCESS); return device; } //--------------------------------------------------------------------------------------------// // Load from persistent memory tests // //--------------------------------------------------------------------------------------------// /** * Preconditions: * - Settings contains no devices * * Actions: * - Initialize the device manager * * Outcome: * - device manager should initialize */ @Test public void testEmptySettingsString_loadNoDevices() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST); assertDeviceList(EMPTY_DEVICE_LIST); } /** * Preconditions: * - Settings contains a single device * * Actions: * - Initialize the device manager * * Outcome: * - The single device is now located in the device manager's device list */ @Test public void testSingleDeviceSettingsString_loadSingleDevice() { setPreconditionsAndStart(ADAPTER_STATE_ANY, SINGLE_SETTINGS_STRING, EMPTY_DEVICE_LIST); assertDeviceList(SINGLE_DEVICE_LIST); } /** * Preconditions: * - Settings contains several devices * * Actions: * - Initialize the device manager * * Outcome: * - All devices are now in the device manager's list, all in the proper order. */ @Test public void testSeveralDevicesSettingsString_loadAllDevices() { setPreconditionsAndStart(ADAPTER_STATE_ANY, LARGE_SETTINGS_STRING, EMPTY_DEVICE_LIST); assertDeviceList(LARGE_DEVICE_LIST); } //--------------------------------------------------------------------------------------------// // Commit to persistent memory tests // //--------------------------------------------------------------------------------------------// /** * Preconditions: * - The device manager is initialized and the list contains no devices * * Actions: * - An event forces the device manager to commit it's list * * Outcome: * - The empty list should be written to Settings.Secure as an empty string, "" */ @Test public void testNoDevicesCommit_commitEmptyDeviceString() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST); sendAdapterStateChanged(BluetoothAdapter.STATE_OFF); assertSettingsContains(EMPTY_SETTINGS_STRING); } /** * Preconditions: * - The device manager contains several devices * * Actions: * - An event forces the device manager to commit it's list * * Outcome: * - The ordered device list should be written to Settings.Secure as a comma separated list */ @Test public void testSeveralDevicesCommit_commitAllDeviceString() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, LARGE_DEVICE_LIST); sendAdapterStateChanged(BluetoothAdapter.STATE_OFF); assertSettingsContains(LARGE_SETTINGS_STRING); } //--------------------------------------------------------------------------------------------// // Add Device tests // //--------------------------------------------------------------------------------------------// /** * Preconditions: * - The device manager is initialized and contains no devices. * * Actions: * - Add a single device * * Outcome: * - The device manager priority list contains the single device */ @Test public void testAddSingleDevice_devicesAppearInPriorityList() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SINGLE_DEVICE_LIST); assertDeviceList(SINGLE_DEVICE_LIST); } /** * Preconditions: * - The device manager is initialized and contains no devices. * * Actions: * - Add several devices * * Outcome: * - The device manager priority list contains all devices, ordered properly */ @Test public void testAddMultipleDevices_devicesAppearInPriorityList() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, LARGE_DEVICE_LIST); assertDeviceList(LARGE_DEVICE_LIST); } /** * Preconditions: * - The device manager is initialized and contains one device * * Actions: * - Add the device that is already in the list * * Outcome: * - The device manager's list remains unchanged with only one device in it */ @Test public void testAddDeviceAlreadyInList_priorityListUnchanged() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SINGLE_DEVICE_LIST); BluetoothDevice device = mDeviceList.get(0); mDeviceManager.addDevice(device); assertDeviceList(SINGLE_DEVICE_LIST); } //--------------------------------------------------------------------------------------------// // Remove Device tests // //--------------------------------------------------------------------------------------------// /** * Preconditions: * - The device manager is initialized and contains no devices. * * Actions: * - Remove a device from the list * * Outcome: * - The device manager does not error out and continues to have an empty list */ @Test public void testRemoveDeviceFromEmptyList_priorityListUnchanged() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST); mDeviceManager.removeDevice(createDevice("DE:AD:BE:EF:00:00")); assertDeviceList(EMPTY_DEVICE_LIST); } /** * Preconditions: * - The device manager is initialized and contains several devices. * * Actions: * - Remove the device with the highest priority (front of list) * * Outcome: * - The device manager removes the leading device. The other devices have been shifted down. */ @Test public void testRemoveDeviceFront_deviceNoLongerInPriorityList() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST); BluetoothDevice device = mDeviceList.get(0); mDeviceManager.removeDevice(device); ArrayList expected = new ArrayList(SMALL_DEVICE_LIST); expected.remove(0); assertDeviceList(expected); } /** * Preconditions: * - The device manager is initialized and contains several devices. * * Actions: * - Remove a device from the middle of the list * * Outcome: * - The device manager removes the device. The other devices with larger priorities have been * shifted down. */ @Test public void testRemoveDeviceMiddle_deviceNoLongerInPriorityList() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST); BluetoothDevice device = mDeviceList.get(1); mDeviceManager.removeDevice(device); ArrayList expected = new ArrayList(SMALL_DEVICE_LIST); expected.remove(1); assertDeviceList(expected); } /** * Preconditions: * - The device manager is initialized and contains several devices. * * Actions: * - Remove the device from the end of the list * * Outcome: * - The device manager removes the device. The other devices remain in their places, unchanged */ @Test public void testRemoveDeviceEnd_deviceNoLongerInPriorityList() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST); BluetoothDevice device = mDeviceList.get(2); mDeviceManager.removeDevice(device); ArrayList expected = new ArrayList(SMALL_DEVICE_LIST); expected.remove(2); // 00, 01 assertDeviceList(expected); } /** * Preconditions: * - The device manager is initialized and contains several devices. * * Actions: * - Remove a device thats not in the list * * Outcome: * - The device manager's list remains unchanged. */ @Test public void testRemoveDeviceNotInList_priorityListUnchanged() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST); BluetoothDevice device = createDevice("10:20:30:40:50:60"); mDeviceManager.removeDevice(device); assertDeviceList(SMALL_DEVICE_LIST); } //--------------------------------------------------------------------------------------------// // GetDeviceConnectionPriority() tests // //--------------------------------------------------------------------------------------------// /** * Preconditions: * - The device manager is initialized and contains several devices. * * Actions: * - Get the priority of each device in the list * * Outcome: * - The device manager returns the proper priority for each device */ @Test public void testGetConnectionPriority_prioritiesReturned() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST); ArrayList devices = makeDeviceList(SMALL_DEVICE_LIST); for (int i = 0; i < mDeviceList.size(); i++) { BluetoothDevice device = mDeviceList.get(i); int priority = mDeviceManager.getDeviceConnectionPriority(device); Assert.assertEquals(i, priority); } } /** * Preconditions: * - The device manager is initialized and contains several devices. * * Actions: * - Get the priority of a device that is not in the list * * Outcome: * - The device manager returns a -1 */ @Test public void testGetConnectionPriorityDeviceNotInList_negativeOneReturned() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST); BluetoothDevice deviceNotPresent = createDevice("10:20:30:40:50:60"); int priority = mDeviceManager.getDeviceConnectionPriority(deviceNotPresent); Assert.assertEquals(-1, priority); } //--------------------------------------------------------------------------------------------// // setDeviceConnectionPriority() tests // //--------------------------------------------------------------------------------------------// /** * Preconditions: * - The device manager is initialized and contains several devices. * * Actions: * - Set the priority of several devices in the list, testing the following moves: * Mid priority -> higher priority * Mid priority -> lower priority * Highest priority -> lower priority * Lowest priority -> higher priority * Any priority -> same priority * * Outcome: * - Increased prioritied shuffle devices to proper lower priorities, decreased priorities * shuffle devices to proper high priorities, and a request to set the same priority yields no * change. */ @Test public void testSetConnectionPriority_listOrderedCorrectly() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST); // move middle device to front BluetoothDevice device = mDeviceList.get(1); mDeviceManager.setDeviceConnectionPriority(device, 0); Assert.assertEquals(0, mDeviceManager.getDeviceConnectionPriority(device)); ArrayList expected = new ArrayList(SMALL_DEVICE_LIST); Collections.swap(expected, 1, 0); // expected: 00, [01], 02 -> [01], 00, 02 assertDeviceList(expected); // move front device to the end mDeviceManager.setDeviceConnectionPriority(device, 2); Assert.assertEquals(2, mDeviceManager.getDeviceConnectionPriority(device)); Collections.swap(expected, 0, 2); // expected: [01], 00, 02 -> 00, 02, [01] Collections.swap(expected, 0, 1); assertDeviceList(expected); // move end device to middle mDeviceManager.setDeviceConnectionPriority(device, 1); Assert.assertEquals(1, mDeviceManager.getDeviceConnectionPriority(device)); Collections.swap(expected, 2, 1); // expected: 00, 02, [01] -> 00, [01], 02 assertDeviceList(expected); // move middle to end mDeviceManager.setDeviceConnectionPriority(device, 2); Assert.assertEquals(2, mDeviceManager.getDeviceConnectionPriority(device)); Collections.swap(expected, 1, 2); // expected: 00, [01], 02 -> 00, 02, [01] assertDeviceList(expected); // move end to front mDeviceManager.setDeviceConnectionPriority(device, 0); Assert.assertEquals(0, mDeviceManager.getDeviceConnectionPriority(device)); Collections.swap(expected, 2, 0); // expected: 00, 02, [01] -> [01], 00, 02 Collections.swap(expected, 1, 2); assertDeviceList(expected); // move front to middle mDeviceManager.setDeviceConnectionPriority(device, 1); Assert.assertEquals(1, mDeviceManager.getDeviceConnectionPriority(device)); Collections.swap(expected, 0, 1); // expected: [01], 00, 02 -> 00, [01], 02 assertDeviceList(expected); // move middle to middle (i.e same to same) mDeviceManager.setDeviceConnectionPriority(device, 1); Assert.assertEquals(1, mDeviceManager.getDeviceConnectionPriority(device)); assertDeviceList(expected); // expected: 00, [01], 02 -> 00, [01], 02 } /** * Preconditions: * - The device manager is initialized and contains several devices. * * Actions: * - Set the priority of a device that is not currently in the list * * Outcome: * - Device is added to the list in the requested spot. Devices with lower priorities have had * their priorities adjusted accordingly. */ @Test public void testSetConnectionPriorityNewDevice_listOrderedCorrectly() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST); // add new device to the middle BluetoothDevice device = createDevice("10:20:30:40:50:60"); mDeviceManager.setDeviceConnectionPriority(device, 1); Assert.assertEquals(1, mDeviceManager.getDeviceConnectionPriority(device)); ArrayList expected = new ArrayList(SMALL_DEVICE_LIST); expected.add(1, "10:20:30:40:50:60"); // 00, 60, 01, 02 assertDeviceList(expected); // add new device to the front device = createDevice("10:20:30:40:50:61"); mDeviceManager.setDeviceConnectionPriority(device, 0); Assert.assertEquals(0, mDeviceManager.getDeviceConnectionPriority(device)); expected.add(0, "10:20:30:40:50:61"); // 61, 00, 60, 01, 02 assertDeviceList(expected); // add new device to the end device = createDevice("10:20:30:40:50:62"); mDeviceManager.setDeviceConnectionPriority(device, 5); Assert.assertEquals(5, mDeviceManager.getDeviceConnectionPriority(device)); expected.add(5, "10:20:30:40:50:62"); // 61, 00, 60, 01, 02, 62 assertDeviceList(expected); } /** * Preconditions: * - The device manager is initialized and contains several devices. * * Actions: * - Request to set a priority that exceeds the bounds of the list (upper) * * Outcome: * - No operation is taken */ @Test public void testSetConnectionPriorityLargerThanSize_priorityListUnchanged() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST); // Attempt to move middle device to end with huge end priority BluetoothDevice device = mDeviceList.get(1); mDeviceManager.setDeviceConnectionPriority(device, 100000); Assert.assertEquals(1, mDeviceManager.getDeviceConnectionPriority(device)); assertDeviceList(SMALL_DEVICE_LIST); } /** * Preconditions: * - The device manager is initialized and contains several devices. * * Actions: * - Request to set a priority that exceeds the bounds of the list (lower) * * Outcome: * - No operation is taken */ @Test public void testSetConnectionPriorityNegative_priorityListUnchanged() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST); // Attempt to move middle device to negative priority BluetoothDevice device = mDeviceList.get(1); mDeviceManager.setDeviceConnectionPriority(device, -1); assertDeviceList(SMALL_DEVICE_LIST); } /** * Preconditions: * - The device manager is initialized and contains several devices. * * Actions: * - Request to set a priority for a null device * * Outcome: * - No operation is taken */ @Test public void testSetConnectionPriorityNullDevice_priorityListUnchanged() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST); mDeviceManager.setDeviceConnectionPriority(null, 1); assertDeviceList(SMALL_DEVICE_LIST); } //--------------------------------------------------------------------------------------------// // beginAutoConnecting() tests // //--------------------------------------------------------------------------------------------// /** * Preconditions: * - The Bluetooth adapter is ON, the device manager is initialized and no devices are in the * list. * * Actions: * - Initiate an auto connection * * Outcome: * - Auto connect returns immediately with no connection attempts made. */ @Test public void testAutoConnectNoDevices_returnsImmediately() throws Exception { setPreconditionsAndStart(ADAPTER_STATE_ON, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST); mDeviceManager.beginAutoConnecting(); for (BluetoothDevice device : mDeviceList) { verify(device, never()).connect(); } Assert.assertFalse(mDeviceManager.isAutoConnecting()); } /** * Preconditions: * - The Bluetooth adapter is OFF, the device manager is initialized and there are several * devices are in the list. * * Actions: * - Initiate an auto connection * * Outcome: * - Auto connect returns immediately with no connection attempts made. */ @Test public void testAutoConnectAdapterOff_returnsImmediately() throws Exception { setPreconditionsAndStart(ADAPTER_STATE_OFF, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST); mDeviceManager.beginAutoConnecting(); for (BluetoothDevice device : mDeviceList) { verify(device, never()).connect(); } Assert.assertFalse(mDeviceManager.isAutoConnecting()); } /** * Preconditions: * - The Bluetooth adapter is ON, the device manager is initialized and there are several * devices are in the list. * * Actions: * - Initiate an auto connection * * Outcome: * - Auto connect attempts to connect each device in the list, in order of priority. */ @Test public void testAutoConnectSeveralDevices_attemptsToConnectEachDevice() throws Exception { setPreconditionsAndStart(ADAPTER_STATE_ON, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST); mDeviceManager.beginAutoConnecting(); sendConnectionStateChanged(mDeviceList.get(0), BluetoothProfile.STATE_CONNECTED); verify(mDeviceList.get(0), timeout(CONNECT_TIMEOUT_MS).times(1)).connect(); sendConnectionStateChanged(mDeviceList.get(1), BluetoothProfile.STATE_CONNECTED); verify(mDeviceList.get(1), timeout(CONNECT_TIMEOUT_MS).times(1)).connect(); sendConnectionStateChanged(mDeviceList.get(2), BluetoothProfile.STATE_CONNECTED); verify(mDeviceList.get(2), timeout(CONNECT_TIMEOUT_MS).times(1)).connect(); } //--------------------------------------------------------------------------------------------// // Bluetooth stack device connection status changed event tests // //--------------------------------------------------------------------------------------------// /** * Preconditions: * - The device manager is initialized, there are no devices in the list. * * Actions: * - A connection action comes in for a profile and the device's priority is * CONNECTION_POLICY_ALLOWED. * * Outcome: * - The device is added to the list. Related/configured trigger profiles are connected. */ @Test public void testReceiveDeviceConnection_deviceAdded() throws Exception { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST); BluetoothDevice device = createDevice(SINGLE_DEVICE_LIST.get(0)); sendConnectionStateChanged(device, BluetoothProfile.STATE_CONNECTED); assertDeviceList(SINGLE_DEVICE_LIST); verify(device, times(1)).connect(); } /** * Preconditions: * - The device manager is initialized, there are is one device in the list. * * Actions: * - A disconnection action comes in for the profile we're tracking and the device's priority is * CONNECTION_POLICY_ALLOWED. * * Outcome: * - The device list is unchanged. */ @Test public void testReceiveDeviceDisconnection_listUnchanged() throws Exception { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SINGLE_DEVICE_LIST); BluetoothDevice device = mDeviceList.get(0); sendConnectionStateChanged(device, BluetoothProfile.STATE_DISCONNECTED); assertDeviceList(SINGLE_DEVICE_LIST); } //--------------------------------------------------------------------------------------------// // Bluetooth stack device bond status changed event tests // //--------------------------------------------------------------------------------------------// /** * Preconditions: * - The device manager is initialized, there is one device in the list. * * Actions: * - A device from the list has unbonded * * Outcome: * - The device is removed from the list. */ @Test public void testReceiveDeviceUnbonded_deviceRemoved() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SINGLE_DEVICE_LIST); BluetoothDevice device = mDeviceList.get(0); sendBondStateChanged(device, BluetoothDevice.BOND_NONE); assertDeviceList(EMPTY_DEVICE_LIST); } /** * Preconditions: * - The device manager is initialized, there are no devices in the list. * * Actions: * - A device has bonded. * * Outcome: * - Successful bonds don't impact the list, only device connections. The list is unchanged. */ @Test public void testReceiveDeviceBonded_deviceListNotChanged() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST); BluetoothDevice device = createDevice(SINGLE_DEVICE_LIST.get(0)); sendBondStateChanged(device, BluetoothDevice.BOND_BONDED); assertDeviceList(EMPTY_DEVICE_LIST); } /** * Preconditions: * - The device manager is initialized, there are no devices in the list. * * Actions: * - A device is bonding. * * Outcome: * - A mid-bond event don't impact the list, only device connections. The list is unchanged. */ @Test public void testReceiveDeviceBonding_deviceListNotChanged() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST); BluetoothDevice device = createDevice(SINGLE_DEVICE_LIST.get(0)); sendBondStateChanged(device, BluetoothDevice.BOND_BONDING); assertDeviceList(EMPTY_DEVICE_LIST); } //--------------------------------------------------------------------------------------------// // Bluetooth stack adapter status changed event tests // //--------------------------------------------------------------------------------------------// /** * Preconditions: * - The device manager is initialized, there are several devices in the list. The adapter is on * and we are currently connecting devices. * * Actions: * - The adapter is turning off * * Outcome: * - Auto-connecting is cancelled */ @Test public void testReceiveAdapterTurningOff_cancel() { setPreconditionsAndStart(ADAPTER_STATE_ON, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST); mDeviceManager.beginAutoConnecting(); Assert.assertTrue(mDeviceManager.isAutoConnecting()); // We have 24 seconds of auto connecting time while we force it to quit sendAdapterStateChanged(BluetoothAdapter.STATE_TURNING_OFF); Assert.assertFalse(mDeviceManager.isAutoConnecting()); } /** * Preconditions: * - The device manager is initialized, there are several devices in the list. The adapter is on * and we are currently connecting devices. * * Actions: * - The adapter becomes off * * Outcome: * - Auto-connecting is cancelled. The device list is committed */ @Test public void testReceiveAdapterOff_cancelAndCommit() { setPreconditionsAndStart(ADAPTER_STATE_ON, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST); mDeviceManager.beginAutoConnecting(); Assert.assertTrue(mDeviceManager.isAutoConnecting()); // We have 24 seconds of auto connecting time while we force it to quit sendAdapterStateChanged(BluetoothAdapter.STATE_OFF); Assert.assertFalse(mDeviceManager.isAutoConnecting()); assertSettingsContains(SMALL_SETTINGS_STRING); } /** * Preconditions: * - The device manager is initialized, there are several devices in the list. The adapter is on * and we are currently connecting devices. * * Actions: * - The adapter sends a turning on. (This can happen in weird cases in the stack where the * adapter is ON but the intent is sent away. Additionally, being ON and sending the intent is * a great way to make sure we called cancel) * * Outcome: * - Auto-connecting is cancelled */ @Test public void testReceiveAdapterTurningOn_cancel() { setPreconditionsAndStart(ADAPTER_STATE_ON, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST); mDeviceManager.beginAutoConnecting(); Assert.assertTrue(mDeviceManager.isAutoConnecting()); sendAdapterStateChanged(BluetoothAdapter.STATE_TURNING_ON); Assert.assertFalse(mDeviceManager.isAutoConnecting()); } /** * Preconditions: * - The device manager is initialized, there are several devices in the list. * * Actions: * - The adapter becomes on * * Outcome: * - No connection actions are taken */ @Test public void testReceiveAdapterOn_doNothing() { setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST); sendAdapterStateChanged(BluetoothAdapter.STATE_ON); for (BluetoothDevice device : mDeviceList) { verify(device, never()).connect(); } } }