blob: 29585ff0997e06fe4e15a6dcfae4c9463b37959b [file] [log] [blame]
/*
* Copyright 2018 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.bluetooth.btservice;
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
import android.os.HandlerThread;
import android.os.ParcelUuid;
import android.os.UserHandle;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import com.android.bluetooth.TestUtils;
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 BondStateMachineTest {
private static final int TEST_BOND_REASON = 0;
private static final byte[] TEST_BT_ADDR_BYTES = {00, 11, 22, 33, 44, 55};
private static final ParcelUuid[] TEST_UUIDS =
{ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB")};
private static final int BOND_NONE = BluetoothDevice.BOND_NONE;
private static final int BOND_BONDING = BluetoothDevice.BOND_BONDING;
private static final int BOND_BONDED = BluetoothDevice.BOND_BONDED;
private AdapterProperties mAdapterProperties;
private BluetoothDevice mDevice;
private Context mTargetContext;
private RemoteDevices mRemoteDevices;
private BondStateMachine mBondStateMachine;
private HandlerThread mHandlerThread;
private RemoteDevices.DeviceProperties mDeviceProperties;
private int mVerifyCount = 0;
@Mock private AdapterService mAdapterService;
@Before
public void setUp() throws Exception {
mTargetContext = InstrumentationRegistry.getTargetContext();
MockitoAnnotations.initMocks(this);
TestUtils.setAdapterService(mAdapterService);
mHandlerThread = new HandlerThread("BondStateMachineTestHandlerThread");
mHandlerThread.start();
mRemoteDevices = new RemoteDevices(mAdapterService, mHandlerThread.getLooper());
mRemoteDevices.reset();
when(mAdapterService.getResources()).thenReturn(
mTargetContext.getResources());
mAdapterProperties = new AdapterProperties(mAdapterService);
mAdapterProperties.init(mRemoteDevices);
mBondStateMachine = BondStateMachine.make(mAdapterService, mAdapterProperties,
mRemoteDevices);
}
@After
public void tearDown() throws Exception {
mHandlerThread.quit();
TestUtils.clearAdapterService(mAdapterService);
}
@Test
public void testSendIntent() {
int badBondState = 42;
mVerifyCount = 0;
// Reset mRemoteDevices for the test.
mRemoteDevices.reset();
mDeviceProperties = mRemoteDevices.addDeviceProperties(TEST_BT_ADDR_BYTES);
mDevice = mDeviceProperties.getDevice();
Assert.assertNotNull(mDevice);
/* Classic / Dualmode test cases*/
// Uuid not available, mPendingBondedDevice is empty.
testSendIntentNoPendingDevice(BOND_NONE, BOND_NONE, BOND_NONE,
false, BOND_NONE, BOND_NONE);
testSendIntentNoPendingDevice(BOND_NONE, BOND_BONDING, BOND_BONDING,
true, BOND_NONE, BOND_BONDING);
testSendIntentNoPendingDevice(BOND_NONE, BOND_BONDED, BOND_BONDED,
true, BOND_NONE, BOND_BONDING);
testSendIntentNoPendingDevice(BOND_NONE, badBondState, BOND_NONE,
false, BOND_NONE, BOND_NONE);
testSendIntentNoPendingDevice(BOND_BONDING, BOND_NONE, BOND_NONE,
true, BOND_BONDING, BOND_NONE);
testSendIntentNoPendingDevice(BOND_BONDING, BOND_BONDING, BOND_BONDING,
false, BOND_NONE, BOND_NONE);
testSendIntentNoPendingDevice(BOND_BONDING, BOND_BONDED, BOND_BONDED,
false, BOND_NONE, BOND_NONE);
testSendIntentNoPendingDevice(BOND_BONDING, badBondState, BOND_BONDING,
false, BOND_NONE, BOND_NONE);
testSendIntentNoPendingDevice(BOND_BONDED, BOND_NONE, BOND_NONE,
true, BOND_BONDED, BOND_NONE);
testSendIntentNoPendingDevice(BOND_BONDED, BOND_BONDING, BOND_BONDING,
true, BOND_BONDED, BOND_BONDING);
testSendIntentNoPendingDevice(BOND_BONDED, BOND_BONDED, BOND_BONDED,
false, BOND_NONE, BOND_NONE);
testSendIntentNoPendingDevice(BOND_BONDED, badBondState, BOND_BONDED,
false, BOND_NONE, BOND_NONE);
// Uuid not available, mPendingBondedDevice contains a remote device.
testSendIntentPendingDevice(BOND_NONE, BOND_NONE, BOND_NONE,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDevice(BOND_NONE, BOND_BONDING, BOND_NONE,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDevice(BOND_NONE, BOND_BONDED, BOND_NONE,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDevice(BOND_NONE, badBondState, BOND_NONE,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDevice(BOND_BONDING, BOND_NONE, BOND_BONDING,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDevice(BOND_BONDING, BOND_BONDING, BOND_BONDING,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDevice(BOND_BONDING, BOND_BONDED, BOND_BONDING,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDevice(BOND_BONDING, badBondState, BOND_BONDING,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDevice(BOND_BONDED, BOND_NONE, BOND_NONE,
true, BOND_BONDING, BOND_NONE);
testSendIntentPendingDevice(BOND_BONDED, BOND_BONDING, BOND_BONDING,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDevice(BOND_BONDED, BOND_BONDED, BOND_BONDED,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDevice(BOND_BONDED, badBondState, BOND_BONDED,
false, BOND_NONE, BOND_NONE);
// Uuid available, mPendingBondedDevice is empty.
testSendIntentNoPendingDeviceWithUuid(BOND_NONE, BOND_NONE, BOND_NONE,
false, BOND_NONE, BOND_NONE);
testSendIntentNoPendingDeviceWithUuid(BOND_NONE, BOND_BONDING, BOND_BONDING,
true, BOND_NONE, BOND_BONDING);
testSendIntentNoPendingDeviceWithUuid(BOND_NONE, BOND_BONDED, BOND_BONDED,
true, BOND_NONE, BOND_BONDED);
testSendIntentNoPendingDeviceWithUuid(BOND_NONE, badBondState, BOND_NONE,
false, BOND_NONE, BOND_NONE);
testSendIntentNoPendingDeviceWithUuid(BOND_BONDING, BOND_NONE, BOND_NONE,
true, BOND_BONDING, BOND_NONE);
testSendIntentNoPendingDeviceWithUuid(BOND_BONDING, BOND_BONDING, BOND_BONDING,
false, BOND_NONE, BOND_NONE);
testSendIntentNoPendingDeviceWithUuid(BOND_BONDING, BOND_BONDED, BOND_BONDED,
true, BOND_BONDING, BOND_BONDED);
testSendIntentNoPendingDeviceWithUuid(BOND_BONDING, badBondState, BOND_BONDING,
false, BOND_NONE, BOND_NONE);
testSendIntentNoPendingDeviceWithUuid(BOND_BONDED, BOND_NONE, BOND_NONE,
true, BOND_BONDED, BOND_NONE);
testSendIntentNoPendingDeviceWithUuid(BOND_BONDED, BOND_BONDING, BOND_BONDING,
true, BOND_BONDED, BOND_BONDING);
testSendIntentNoPendingDeviceWithUuid(BOND_BONDED, BOND_BONDED, BOND_BONDED,
false, BOND_NONE, BOND_NONE);
testSendIntentNoPendingDeviceWithUuid(BOND_BONDED, badBondState, BOND_BONDED,
false, BOND_NONE, BOND_NONE);
// Uuid available, mPendingBondedDevice contains a remote device.
testSendIntentPendingDeviceWithUuid(BOND_NONE, BOND_NONE, BOND_NONE,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDeviceWithUuid(BOND_NONE, BOND_BONDING, BOND_NONE,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDeviceWithUuid(BOND_NONE, BOND_BONDED, BOND_NONE,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDeviceWithUuid(BOND_NONE, badBondState, BOND_NONE,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDeviceWithUuid(BOND_BONDING, BOND_NONE, BOND_BONDING,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDeviceWithUuid(BOND_BONDING, BOND_BONDING, BOND_BONDING,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDeviceWithUuid(BOND_BONDING, BOND_BONDED, BOND_BONDING,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDeviceWithUuid(BOND_BONDING, badBondState, BOND_BONDING,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDeviceWithUuid(BOND_BONDED, BOND_NONE, BOND_NONE,
true, BOND_BONDING, BOND_NONE);
testSendIntentPendingDeviceWithUuid(BOND_BONDED, BOND_BONDING, BOND_BONDING,
false, BOND_NONE, BOND_NONE);
testSendIntentPendingDeviceWithUuid(BOND_BONDED, BOND_BONDED, BOND_BONDED,
true, BOND_BONDING, BOND_BONDED);
testSendIntentPendingDeviceWithUuid(BOND_BONDED, badBondState, BOND_BONDED,
false, BOND_NONE, BOND_NONE);
/* Low energy test cases */
testSendIntentBle(BOND_NONE, BOND_NONE, BOND_NONE);
testSendIntentBle(BOND_NONE, BOND_BONDING, BOND_BONDING);
testSendIntentBle(BOND_NONE, BOND_BONDED, BOND_BONDED);
testSendIntentBle(BOND_BONDING, BOND_NONE, BOND_NONE);
testSendIntentBle(BOND_BONDING, BOND_BONDING, BOND_BONDING);
testSendIntentBle(BOND_BONDING, BOND_BONDED, BOND_BONDED);
testSendIntentBle(BOND_BONDED, BOND_NONE, BOND_NONE);
testSendIntentBle(BOND_BONDED, BOND_BONDING, BOND_BONDING);
testSendIntentBle(BOND_BONDED, BOND_BONDED, BOND_BONDED);
}
private void testSendIntentCase(int oldState, int newState, int expectedNewState,
boolean shouldBroadcast, int broadcastOldState, int broadcastNewState) {
ArgumentCaptor<Intent> intentArgument = ArgumentCaptor.forClass(Intent.class);
// Setup old state before start test.
mDeviceProperties.mBondState = oldState;
try {
mBondStateMachine.sendIntent(mDevice, newState, TEST_BOND_REASON);
} catch (IllegalArgumentException e) {
// Do nothing.
}
Assert.assertEquals(expectedNewState, mDeviceProperties.getBondState());
// Check for bond state Intent status.
if (shouldBroadcast) {
verify(mAdapterService, times(++mVerifyCount)).sendBroadcastAsUser(
intentArgument.capture(), eq(UserHandle.ALL),
eq(AdapterService.BLUETOOTH_PERM));
verifyBondStateChangeIntent(broadcastOldState, broadcastNewState,
intentArgument.getValue());
} else {
verify(mAdapterService, times(mVerifyCount)).sendBroadcastAsUser(any(Intent.class),
any(UserHandle.class), anyString());
}
}
private void testSendIntentNoPendingDeviceWithUuid(int oldState, int newState,
int expectedNewState, boolean shouldBroadcast, int broadcastOldState,
int broadcastNewState) {
// Add dummy UUID for the device.
mDeviceProperties.mUuids = TEST_UUIDS;
testSendIntentNoPendingDevice(oldState, newState, expectedNewState, shouldBroadcast,
broadcastOldState, broadcastNewState);
}
private void testSendIntentPendingDeviceWithUuid(int oldState, int newState,
int expectedNewState, boolean shouldBroadcast, int broadcastOldState,
int broadcastNewState) {
// Add dummy UUID for the device.
mDeviceProperties.mUuids = TEST_UUIDS;
testSendIntentPendingDevice(oldState, newState, expectedNewState, shouldBroadcast,
broadcastOldState, broadcastNewState);
}
private void testSendIntentPendingDevice(int oldState, int newState, int expectedNewState,
boolean shouldBroadcast, int broadcastOldState, int broadcastNewState) {
// Test for classic remote device.
mDeviceProperties.mDeviceType = BluetoothDevice.DEVICE_TYPE_CLASSIC;
mBondStateMachine.mPendingBondedDevices.clear();
mBondStateMachine.mPendingBondedDevices.add(mDevice);
testSendIntentCase(oldState, newState, expectedNewState, shouldBroadcast,
broadcastOldState, broadcastNewState);
// Test for dual-mode remote device.
mDeviceProperties.mDeviceType = BluetoothDevice.DEVICE_TYPE_DUAL;
mBondStateMachine.mPendingBondedDevices.clear();
mBondStateMachine.mPendingBondedDevices.add(mDevice);
testSendIntentCase(oldState, newState, expectedNewState, shouldBroadcast,
broadcastOldState, broadcastNewState);
}
private void testSendIntentNoPendingDevice(int oldState, int newState, int expectedNewState,
boolean shouldBroadcast, int broadcastOldState, int broadcastNewState) {
// Test for classic remote device.
mDeviceProperties.mDeviceType = BluetoothDevice.DEVICE_TYPE_CLASSIC;
mBondStateMachine.mPendingBondedDevices.clear();
testSendIntentCase(oldState, newState, expectedNewState, shouldBroadcast,
broadcastOldState, broadcastNewState);
// Test for dual-mode remote device.
mDeviceProperties.mDeviceType = BluetoothDevice.DEVICE_TYPE_DUAL;
mBondStateMachine.mPendingBondedDevices.clear();
testSendIntentCase(oldState, newState, expectedNewState, shouldBroadcast,
broadcastOldState, broadcastNewState);
}
private void testSendIntentBle(int oldState, int newState, int expectedNewState) {
// Test for low energy remote device.
mDeviceProperties.mDeviceType = BluetoothDevice.DEVICE_TYPE_LE;
mBondStateMachine.mPendingBondedDevices.clear();
testSendIntentCase(oldState, newState, newState, (oldState != newState),
oldState, newState);
}
private void verifyBondStateChangeIntent(int oldState, int newState, Intent intent) {
Assert.assertNotNull(intent);
Assert.assertEquals(BluetoothDevice.ACTION_BOND_STATE_CHANGED, intent.getAction());
Assert.assertEquals(mDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
Assert.assertEquals(newState, intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1));
Assert.assertEquals(oldState, intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE,
-1));
if (newState == BOND_NONE) {
Assert.assertEquals(TEST_BOND_REASON, intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
-1));
} else {
Assert.assertEquals(-1, intent.getIntExtra(BluetoothDevice.EXTRA_REASON, -1));
}
}
}