blob: e9f364a714ade2348231eea4083c7125c0c8ad51 [file] [log] [blame]
/*
* Copyright 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.libraries.testing.deviceshadower.helpers.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.util.Log;
import com.android.libraries.testing.deviceshadower.DeviceShadowEnvironment;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Future;
/**
* Helper class to operate a device as gatt server.
*/
public class BluetoothGattMaster {
private static final String TAG = "BluetoothGattMaster";
/**
* Callback of BluetoothGattMaster.
*/
public interface Callback {
void onConnectionStateChange(String address, int status, int newState);
void onCharacteristicReadRequest(String address, UUID uuid);
void onCharacteristicWriteRequest(String address, UUID uuid, byte[] value,
boolean preparedWrite, boolean responseNeeded);
void onDescriptorReadRequest(String address, UUID uuid);
void onDescriptorWriteRequest(String address, UUID uuid, byte[] value,
boolean preparedWrite, boolean responseNeeded);
void onNotificationSent(String address, int status);
void onExecuteWrite(String address, boolean execute);
void onServiceAdded(UUID uuid, int status);
void onMtuChanged(String address, int mtu);
}
private final String mAddress;
private final Callback mCallback;
private final Context mContext;
private BluetoothGattServer mGattServer;
private final Map<UUID, BluetoothGattCharacteristic> mCharacteristics = new HashMap<>();
public BluetoothGattMaster(String address, Callback callback, Context context) {
this.mAddress = address;
this.mCallback = callback;
this.mContext = context;
DeviceShadowEnvironment.addDevice(address).bluetooth()
.setAdapterInitialState(BluetoothAdapter.STATE_ON);
}
public Future<Void> start(final BluetoothGattService service) {
return DeviceShadowEnvironment.run(mAddress, new Runnable() {
@Override
public void run() {
BluetoothManager manager = mContext.getSystemService(BluetoothManager.class);
mGattServer = manager.openGattServer(mContext, mGattServerCallback);
mGattServer.addService(service);
}
});
}
public Future<Void> stop() {
return DeviceShadowEnvironment.run(mAddress, new Runnable() {
@Override
public void run() {
mGattServer.close();
}
});
}
public Future<Void> notifyCharacteristic(
final String remoteAddress, final UUID uuid, final byte[] value,
final boolean confirm) {
return DeviceShadowEnvironment.run(mAddress, new Runnable() {
@Override
public void run() {
BluetoothGattCharacteristic characteristic = mCharacteristics.get(uuid);
characteristic.setValue(value);
mGattServer.notifyCharacteristicChanged(
BluetoothAdapter.getDefaultAdapter().getRemoteDevice(remoteAddress),
characteristic, confirm);
}
});
}
private BluetoothGattServerCallback mGattServerCallback = new BluetoothGattServerCallback() {
@Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
String address = device.getAddress();
Log.v(TAG, String.format(
"BluetoothGattServerManager.onConnectionStateChange on %s: status %d,"
+ " newState %d", address, status, newState));
mCallback.onConnectionStateChange(address, status, newState);
}
@Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset,
BluetoothGattCharacteristic characteristic) {
String address = device.getAddress();
UUID uuid = characteristic.getUuid();
Log.v(TAG,
String.format("BluetoothGattServerManager.onCharacteristicReadRequest on %s: "
+ "characteristic %s, request %d, offset %d",
address, uuid, requestId, offset));
mCallback.onCharacteristicReadRequest(address, uuid);
mGattServer.sendResponse(
device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
characteristic.getValue());
}
@Override
public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
BluetoothGattCharacteristic characteristic, boolean preparedWrite,
boolean responseNeeded,
int offset, byte[] value) {
String address = device.getAddress();
UUID uuid = characteristic.getUuid();
Log.v(TAG,
String.format("BluetoothGattServerManager.onCharacteristicWriteRequest on %s: "
+ "characteristic %s, request %d, offset %d, preparedWrite %b, "
+ "responseNeeded %b",
address, uuid, requestId, offset, preparedWrite, responseNeeded));
mCallback.onCharacteristicWriteRequest(address, uuid, value, preparedWrite,
responseNeeded);
if (responseNeeded) {
mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
null);
}
}
@Override
public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset,
BluetoothGattDescriptor descriptor) {
String address = device.getAddress();
UUID uuid = descriptor.getUuid();
Log.v(TAG, String.format("BluetoothGattServerManager.onDescriptorReadRequest on %s: "
+ " descriptor %s, requestId %d, offset %d",
address, uuid, requestId, offset));
mCallback.onDescriptorReadRequest(address, uuid);
mGattServer.sendResponse(
device, requestId, BluetoothGatt.GATT_SUCCESS, offset, descriptor.getValue());
}
@Override
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded,
int offset, byte[] value) {
String address = device.getAddress();
UUID uuid = descriptor.getUuid();
Log.v(TAG, String.format("BluetoothGattServerManager.onDescriptorWriteRequest on %s: "
+ "descriptor %s, requestId %d, offset %d, preparedWrite %b, "
+ "responseNeeded %b",
address, uuid, requestId, offset, preparedWrite, responseNeeded));
mCallback.onDescriptorWriteRequest(address, uuid, value, preparedWrite, responseNeeded);
if (responseNeeded) {
mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
null);
}
}
@Override
public void onNotificationSent(BluetoothDevice device, int status) {
String address = device.getAddress();
Log.v(TAG,
String.format("BluetoothGattServerManager.onNotificationSent on %s: status %d",
address, status));
mCallback.onNotificationSent(address, status);
}
@Override
public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
/*** Not implemented yet
String address = device.getAddress();
Log.v(TAG, String.format(
"BluetoothGattServerManager.onExecuteWrite on %s: requestId %d, execute %b",
address, requestId, execute));
callback.onExecuteWrite(address, execute);
*/
}
@Override
public void onServiceAdded(int status, BluetoothGattService service) {
UUID uuid = service.getUuid();
Log.v(TAG, String.format(
"BluetoothGattServerManager.onServiceAdded: service %s, status %d",
uuid, status));
mCallback.onServiceAdded(uuid, status);
for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
mCharacteristics.put(characteristic.getUuid(), characteristic);
}
}
@Override
public void onMtuChanged(BluetoothDevice device, int mtu) {
Log.v(TAG, String.format("onMtuChanged(mtu: %s)", mtu));
mCallback.onMtuChanged(device.getAddress(), mtu);
}
};
}