blob: dd80d852f95c7682abe4934253a278ad266df102 [file] [log] [blame]
package com.google.android.connecteddevice.transport.ble;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.ParcelUuid;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.connecteddevice.transport.ble.testable.BluetoothGattServerHandler;
import com.google.android.connecteddevice.transport.ble.testable.BluetoothManagerHandler;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.util.UUID;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@RunWith(AndroidJUnit4.class)
public class OnDeviceBlePeripheralManagerTest {
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
private BluetoothAdapter adapter;
@Mock private AdvertiseCallback mockAdvertiseCallback;
@Mock private BlePeripheralManager.Callback mockCallback;
@Mock private BluetoothManagerHandler mockBluetoothManager;
@Mock private BluetoothGattServerHandler mockGattServer;
@Mock private BlePeripheralManager.OnCharacteristicReadListener mockOnCharacteristicReadListener;
private OnDeviceBlePeripheralManager blePeripheralManager;
private BluetoothDevice testBluetoothDevice;
private BluetoothDevice unknownBluetoothDevice;
@Before
public void setUp() {
Context context = ApplicationProvider.getApplicationContext();
PackageManager packageManager = context.getPackageManager();
adapter = ((BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE)).getAdapter();
blePeripheralManager = new OnDeviceBlePeripheralManager(context, mockBluetoothManager);
shadowOf(adapter).setIsMultipleAdvertisementSupported(true);
shadowOf(packageManager).setSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE, true);
blePeripheralManager.registerCallback(mockCallback);
testBluetoothDevice = adapter.getRemoteDevice("00:11:22:33:AA:BB");
unknownBluetoothDevice = adapter.getRemoteDevice("99:11:22:33:AA:BB");
when(mockBluetoothManager.getAdapter()).thenReturn(adapter);
when(mockBluetoothManager.openGattServer(any())).thenReturn(mockGattServer);
blePeripheralManager.addOnCharacteristicReadListener(mockOnCharacteristicReadListener);
}
@Test
public void onConnectionStateChange_invokeConnectedCallback() {
BluetoothGattServerCallback callback = setupGattServer();
callback.onConnectionStateChange(
testBluetoothDevice, BluetoothGatt.GATT_SUCCESS, BluetoothProfile.STATE_CONNECTED);
verify(mockCallback).onRemoteDeviceConnected(testBluetoothDevice);
}
@Test
public void onConnectionStateChange_invokeDisconnectedCallback() {
BluetoothGattServerCallback callback = setupGattServer();
callback.onConnectionStateChange(
testBluetoothDevice, BluetoothGatt.GATT_SUCCESS, BluetoothProfile.STATE_CONNECTED);
callback.onConnectionStateChange(
testBluetoothDevice, BluetoothGatt.GATT_SUCCESS, BluetoothProfile.STATE_DISCONNECTED);
verify(mockCallback).onRemoteDeviceDisconnected(testBluetoothDevice);
}
@Test
public void onConnectionStateChange_unknownDevice_doNotInvokeDisconnectedCallback() {
BluetoothGattServerCallback callback = setupGattServer();
callback.onConnectionStateChange(
testBluetoothDevice, BluetoothGatt.GATT_SUCCESS, BluetoothProfile.STATE_CONNECTED);
callback.onConnectionStateChange(
unknownBluetoothDevice, BluetoothGatt.GATT_SUCCESS, BluetoothProfile.STATE_DISCONNECTED);
verify(mockCallback, never()).onRemoteDeviceDisconnected(testBluetoothDevice);
}
@Test
public void onConnectionStateChange_doNotCloseGattServer() {
BluetoothGattServerCallback callback = setupGattServer();
callback.onConnectionStateChange(
testBluetoothDevice, BluetoothGatt.GATT_SUCCESS, BluetoothProfile.STATE_CONNECTED);
callback.onConnectionStateChange(
testBluetoothDevice, BluetoothGatt.GATT_SUCCESS, BluetoothProfile.STATE_DISCONNECTED);
verify(mockGattServer, never()).close();
}
@Test
public void onConnectionStateChange_multipleCallbacks_doNotRepeatCleanup() {
BluetoothGattServerCallback callback = setupGattServer();
callback.onConnectionStateChange(
testBluetoothDevice, BluetoothGatt.GATT_SUCCESS, BluetoothProfile.STATE_CONNECTED);
verify(mockGattServer).clearServices();
callback.onConnectionStateChange(
testBluetoothDevice, BluetoothGatt.GATT_SUCCESS, BluetoothProfile.STATE_CONNECTED);
verify(mockGattServer).clearServices();
}
@Test
public void disconnect_cancelingConnectionOnTheDevice() {
BluetoothGattServerCallback callback = setupGattServer();
callback.onConnectionStateChange(
testBluetoothDevice, BluetoothGatt.GATT_SUCCESS, BluetoothProfile.STATE_CONNECTED);
blePeripheralManager.disconnect();
verify(mockGattServer).cancelConnection(testBluetoothDevice);
verify(mockCallback, never()).onRemoteDeviceDisconnected(testBluetoothDevice);
verify(mockGattServer, never()).close();
}
@Test
public void cleanup_closeGattServer() {
setupGattServer();
blePeripheralManager.cleanup();
verify(mockGattServer).close();
}
@Test
public void cleanup_disconnectDevice() {
BluetoothGattServerCallback callback = setupGattServer();
callback.onConnectionStateChange(
testBluetoothDevice, BluetoothGatt.GATT_SUCCESS, BluetoothProfile.STATE_CONNECTED);
blePeripheralManager.cleanup();
verify(mockGattServer).cancelConnection(testBluetoothDevice);
}
@Test
public void onNotificationSent_invokeListeners() {
BluetoothGattServerCallback callback = setupGattServer();
callback.onConnectionStateChange(
testBluetoothDevice, BluetoothGatt.GATT_SUCCESS, BluetoothProfile.STATE_CONNECTED);
callback.onNotificationSent(testBluetoothDevice, BluetoothGatt.GATT_SUCCESS);
verify(mockOnCharacteristicReadListener).onCharacteristicRead(testBluetoothDevice);
}
@Test
public void onConnectionStateChange_disconnect_clearListeners() {
BluetoothGattServerCallback callback = setupGattServer();
callback.onConnectionStateChange(
testBluetoothDevice, BluetoothGatt.GATT_SUCCESS, BluetoothProfile.STATE_CONNECTED);
callback.onConnectionStateChange(
testBluetoothDevice, BluetoothGatt.GATT_SUCCESS, BluetoothProfile.STATE_DISCONNECTED);
callback.onNotificationSent(testBluetoothDevice, BluetoothGatt.GATT_SUCCESS);
verify(mockOnCharacteristicReadListener, never()).onCharacteristicRead(testBluetoothDevice);
}
@CanIgnoreReturnValue
private BluetoothGattServerCallback setupGattServer() {
UUID uuid = UUID.randomUUID();
AdvertiseData advertiseData =
new AdvertiseData.Builder().addServiceUuid(new ParcelUuid(uuid)).build();
AdvertiseData scanResponse =
new AdvertiseData.Builder().addServiceUuid(new ParcelUuid(uuid)).build();
BluetoothGattService service =
new BluetoothGattService(uuid, BluetoothGattService.SERVICE_TYPE_PRIMARY);
blePeripheralManager.startAdvertising(
service, advertiseData, scanResponse, mockAdvertiseCallback);
ArgumentCaptor<BluetoothGattServerCallback> captor =
ArgumentCaptor.forClass(BluetoothGattServerCallback.class);
verify(mockBluetoothManager).openGattServer(captor.capture());
return captor.getValue();
}
}