[Nearby Presence] Implement GattServer::UpdateCharacteristic()
Implements nearby::chrome::GattServer::UpdateCharacteristic() to store the updated value if the characteristic is READ only property, and wait to be notified of a ReadRequest via the GattServiceObserver, and then use the stored value in response. Tested: Manually verified in prototype Bug: b/311430390 Change-Id: Icf806f34a416ad700822a54aee24ea2f7b05cbfe Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5049829 Commit-Queue: Juliet Lévesque <julietlevesque@google.com> Reviewed-by: Reilly Grant <reillyg@chromium.org> Reviewed-by: Ryan Hansberry <hansberry@chromium.org> Reviewed-by: Jack Shira <jackshira@google.com> Reviewed-by: Mustafa Emre Acer <meacer@chromium.org> Cr-Commit-Position: refs/heads/main@{#1277038}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
b8f1f64187
commit
1a046bab84
chrome
browser
resources
bluetooth_internals
services
sharing
device/bluetooth
@ -58,6 +58,7 @@ build_webui("build") {
|
||||
"$root_gen_dir/device/bluetooth/public/mojom/uuid.mojom-webui.ts",
|
||||
"$root_gen_dir/device/bluetooth/public/mojom/gatt_characteristic_properties.mojom-webui.ts",
|
||||
"$root_gen_dir/device/bluetooth/public/mojom/gatt_characteristic_permissions.mojom-webui.ts",
|
||||
"$root_gen_dir/device/bluetooth/public/mojom/gatt_service_error_code.mojom-webui.ts",
|
||||
]
|
||||
|
||||
ts_composite = true
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/logging.h"
|
||||
#include "device/bluetooth/bluetooth_gatt_characteristic.h"
|
||||
#include "device/bluetooth/bluetooth_gatt_service.h"
|
||||
#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
|
||||
|
||||
namespace {
|
||||
@ -152,11 +153,38 @@ BleV2GattServer::CreateCharacteristic(
|
||||
bool BleV2GattServer::UpdateCharacteristic(
|
||||
const api::ble_v2::GattCharacteristic& characteristic,
|
||||
const nearby::ByteArray& value) {
|
||||
// TODO(b/311430390):Implement to call on the Mojo remote to update the value
|
||||
// of the GATT Characteristic, and returns the success/failure of the
|
||||
// operation.
|
||||
NOTIMPLEMENTED();
|
||||
return false;
|
||||
VLOG(1) << "BleV2GattServer::" << __func__;
|
||||
|
||||
auto service_it = uuid_to_gatt_service_map_.find(characteristic.service_uuid);
|
||||
if (service_it == uuid_to_gatt_service_map_.end()) {
|
||||
LOG(WARNING) << __func__
|
||||
<< ": trying to update a characteristic in a service that "
|
||||
"doesn't exist";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* gatt_service = service_it->second.get();
|
||||
const auto& char_map =
|
||||
gatt_service->characteristic_uuid_to_characteristic_map;
|
||||
auto char_it = char_map.find(characteristic.uuid);
|
||||
if (char_it == char_map.end()) {
|
||||
LOG(WARNING) << __func__
|
||||
<< ": trying to update a characteristic that doesn't exist in "
|
||||
"the GATT service";
|
||||
return false;
|
||||
}
|
||||
|
||||
// //device/bluetooth is not responsible for storing the value of a GATT
|
||||
// characteristic -- it is the responsibility of the `GattService`'s Delegate.
|
||||
// The `GattService` will relay corresponding messages on its Delegate
|
||||
// to `BleV2GattServer`, so the `BleV2GattServer` is responsible for storing
|
||||
// the value of the GATT characteristic and providing it when a read
|
||||
// is requested by a GATT client in `OnLocalCharacteristicRead()`.
|
||||
VLOG(1) << __func__ << ": storing value for a characteristic at UUID = "
|
||||
<< characteristic.uuid.Get16BitAsString();
|
||||
gatt_service->characteristic_uuid_to_value_map.emplace(characteristic.uuid,
|
||||
value);
|
||||
return true;
|
||||
}
|
||||
|
||||
absl::Status BleV2GattServer::NotifyCharacteristicChanged(
|
||||
@ -165,7 +193,10 @@ absl::Status BleV2GattServer::NotifyCharacteristicChanged(
|
||||
const nearby::ByteArray& new_value) {
|
||||
// TODO(b/311430390): Implement to call on the Mojo remote to update the value
|
||||
// of the GATT Characteristic, and notify remote devices, and returns the
|
||||
// resulting Status of the operation.
|
||||
// resulting Status of the operation. When implementing, consider if
|
||||
// `UpdateCharacteristic()` needs to be called before calling
|
||||
// `NotifyCharacteristicChanged()` in the library, or in this class, so
|
||||
// `BleV2GattServer` holds onto the updated value for any READ requests.
|
||||
NOTIMPLEMENTED();
|
||||
return absl::Status();
|
||||
}
|
||||
@ -179,4 +210,68 @@ void BleV2GattServer::Stop() {
|
||||
BleV2GattServer::GattService::GattService() = default;
|
||||
BleV2GattServer::GattService::~GattService() = default;
|
||||
|
||||
void BleV2GattServer::OnLocalCharacteristicRead(
|
||||
bluetooth::mojom::DeviceInfoPtr remote_device,
|
||||
const device::BluetoothUUID& characteristic_uuid,
|
||||
const device::BluetoothUUID& service_uuid,
|
||||
uint32_t offset,
|
||||
OnLocalCharacteristicReadCallback callback) {
|
||||
VLOG(1) << "BleV2GattServer::" << __func__;
|
||||
|
||||
Uuid nearby_service_uuid = Uuid(service_uuid.value());
|
||||
Uuid nearby_characteristic_uuid = Uuid(characteristic_uuid.value());
|
||||
|
||||
// Expect that `OnLocalCharacteristicRead()` is called for a
|
||||
// characteristic that already exists in the `uuid_to_gatt_service_map_` of
|
||||
// the corresponding `GattService`. If this isn't true, it means the
|
||||
// corresponding GATT service in the browser process and this
|
||||
// `BleV2GattServer` have gotten out of sync.
|
||||
auto service_it = uuid_to_gatt_service_map_.find(nearby_service_uuid);
|
||||
CHECK(service_it != uuid_to_gatt_service_map_.end());
|
||||
auto* gatt_service = service_it->second.get();
|
||||
const auto& char_map =
|
||||
gatt_service->characteristic_uuid_to_characteristic_map;
|
||||
auto char_it = char_map.find(nearby_characteristic_uuid);
|
||||
CHECK(char_it != char_map.end());
|
||||
|
||||
// Return an error if the property and permission of the characteristic does
|
||||
// not support read requests. `nearby::api::ble_v2::GattCharacteristic` only
|
||||
// support a single property and permission.
|
||||
if ((char_it->second.property !=
|
||||
nearby::api::ble_v2::GattCharacteristic::Property::kRead) ||
|
||||
(char_it->second.permission !=
|
||||
nearby::api::ble_v2::GattCharacteristic::Permission::kRead)) {
|
||||
LOG(WARNING) << __func__
|
||||
<< ": trying to read a characteristic that does not support "
|
||||
"read requests";
|
||||
std::move(callback).Run(
|
||||
bluetooth::mojom::LocalCharacteristicReadResult::NewErrorCode(
|
||||
device::BluetoothGattService::GattErrorCode::kNotPermitted));
|
||||
return;
|
||||
}
|
||||
|
||||
// When a characteristic has a value set with
|
||||
// `BleV2GattServer::UpdateCharacteristic()`, then reading from the
|
||||
// characteristic yields that value. If there isn't a value in the
|
||||
// map for this characteristic, it means that it wasn't set correctly by
|
||||
// callers of `BleV2GattServer`.
|
||||
const auto& new_value_map = gatt_service->characteristic_uuid_to_value_map;
|
||||
auto new_value_it = new_value_map.find(nearby_characteristic_uuid);
|
||||
if (new_value_it == new_value_map.end()) {
|
||||
LOG(WARNING) << __func__
|
||||
<< ": value for the characteristic read request not found";
|
||||
std::move(callback).Run(
|
||||
bluetooth::mojom::LocalCharacteristicReadResult::NewErrorCode(
|
||||
device::BluetoothGattService::GattErrorCode::kNotSupported));
|
||||
return;
|
||||
}
|
||||
|
||||
const ByteArray& data = new_value_it->second;
|
||||
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data.data());
|
||||
std::vector<uint8_t> read_value(bytes, bytes + data.size());
|
||||
std::move(callback).Run(
|
||||
bluetooth::mojom::LocalCharacteristicReadResult::NewData(
|
||||
std::move(read_value)));
|
||||
}
|
||||
|
||||
} // namespace nearby::chrome
|
||||
|
@ -50,8 +50,22 @@ class BleV2GattServer : public ::nearby::api::ble_v2::GattServer,
|
||||
mojo::Remote<bluetooth::mojom::GattService> gatt_service_remote;
|
||||
base::flat_map<Uuid, api::ble_v2::GattCharacteristic>
|
||||
characteristic_uuid_to_characteristic_map;
|
||||
|
||||
// Characteristic UUID to value map. The value is set
|
||||
// in `UpdateCharacteristic()`, and this class is responsible for storing
|
||||
// the value of a GATT characteristic. See documentation in
|
||||
// `UpdateCharacteristic()`.
|
||||
base::flat_map<Uuid, nearby::ByteArray> characteristic_uuid_to_value_map;
|
||||
};
|
||||
|
||||
// bluetooth::mojom::GattServiceObserver:
|
||||
void OnLocalCharacteristicRead(
|
||||
bluetooth::mojom::DeviceInfoPtr remote_device,
|
||||
const device::BluetoothUUID& characteristic_uuid,
|
||||
const device::BluetoothUUID& service_uuid,
|
||||
uint32_t offset,
|
||||
OnLocalCharacteristicReadCallback callback) override;
|
||||
|
||||
std::unique_ptr<BluetoothAdapter> bluetooth_adapter_;
|
||||
|
||||
base::flat_map<Uuid, std::unique_ptr<GattService>> uuid_to_gatt_service_map_;
|
||||
|
@ -6,9 +6,12 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/containers/span.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/test/bind.h"
|
||||
#include "base/test/mock_callback.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/test/test_future.h"
|
||||
#include "chrome/services/sharing/nearby/platform/bluetooth_adapter.h"
|
||||
#include "chrome/services/sharing/nearby/test_support/fake_adapter.h"
|
||||
#include "chrome/services/sharing/nearby/test_support/fake_gatt_service.h"
|
||||
@ -20,9 +23,10 @@
|
||||
|
||||
namespace {
|
||||
|
||||
const char kServiceId[] = "TestServiceId";
|
||||
const char kCharacteristicUuid1[] = "1234";
|
||||
const char kCharacteristicUuid2[] = "4321";
|
||||
const char kServiceId[] = "12345678-1234-5678-9abc-def123456789";
|
||||
const char kCharacteristicUuid1[] = "00001101-0000-1000-8000-00805f9b34fb";
|
||||
const char kCharacteristicUuid2[] = "00001102-0000-1000-8000-00805f9b34fc";
|
||||
const char kNewCharacteristicValue[] = "1010101";
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -44,16 +48,36 @@ class BleV2GattServerTest : public testing::Test {
|
||||
ble_v2_gatt_server_ = std::make_unique<BleV2GattServer>(remote_adapter_);
|
||||
}
|
||||
|
||||
void CallCreateCharacteristic(std::string characteristic_uuid,
|
||||
bool expected_success) {
|
||||
void CallCreateCharacteristic(
|
||||
std::string characteristic_uuid,
|
||||
bool expected_success,
|
||||
api::ble_v2::GattCharacteristic::Permission permission =
|
||||
api::ble_v2::GattCharacteristic::Permission::kRead,
|
||||
api::ble_v2::GattCharacteristic::Property property =
|
||||
api::ble_v2::GattCharacteristic::Property::kRead) {
|
||||
gatt_characteristic_ = ble_v2_gatt_server_->CreateCharacteristic(
|
||||
/*service_uuid=*/Uuid(/*data=*/kServiceId),
|
||||
/*characteristic_uuid=*/Uuid(/*data=*/characteristic_uuid),
|
||||
/*permission=*/api::ble_v2::GattCharacteristic::Permission::kRead,
|
||||
/*property=*/api::ble_v2::GattCharacteristic::Property::kRead);
|
||||
/*permission=*/permission,
|
||||
/*property=*/property);
|
||||
EXPECT_EQ(expected_success, gatt_characteristic_.has_value());
|
||||
}
|
||||
|
||||
void CallUpdateCharacteristic(
|
||||
std::string characteristic_uuid,
|
||||
bool expected_success,
|
||||
api::ble_v2::GattCharacteristic::Permission permission =
|
||||
api::ble_v2::GattCharacteristic::Permission::kRead,
|
||||
api::ble_v2::GattCharacteristic::Property property =
|
||||
api::ble_v2::GattCharacteristic::Property::kRead) {
|
||||
api::ble_v2::GattCharacteristic gatt_characteristic = {
|
||||
Uuid(characteristic_uuid), Uuid(kServiceId), permission, property};
|
||||
bool result = ble_v2_gatt_server_->UpdateCharacteristic(
|
||||
/*characteristic=*/gatt_characteristic,
|
||||
/*value=*/nearby::ByteArray(kNewCharacteristicValue));
|
||||
EXPECT_EQ(expected_success, result);
|
||||
}
|
||||
|
||||
protected:
|
||||
base::test::TaskEnvironment task_environment_;
|
||||
std::optional<api::ble_v2::GattCharacteristic> gatt_characteristic_;
|
||||
@ -146,4 +170,95 @@ TEST_F(BleV2GattServerTest,
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BleV2GattServerTest,
|
||||
UpdateCharacteristic_FailureIfCharacteristicDoesntExist) {
|
||||
CallUpdateCharacteristic(
|
||||
/*characteristic_uuid=*/kCharacteristicUuid1,
|
||||
/*expected_success=*/false);
|
||||
}
|
||||
|
||||
TEST_F(BleV2GattServerTest,
|
||||
UpdateCharacteristic_ReadCharacteristicRequest_Success) {
|
||||
auto fake_gatt_service = std::make_unique<bluetooth::FakeGattService>();
|
||||
fake_gatt_service->SetCreateCharacteristicResult(/*success=*/true);
|
||||
auto* fake_gatt_service_ptr = fake_gatt_service.get();
|
||||
fake_adapter_->SetCreateLocalGattServiceResult(
|
||||
/*gatt_service=*/std::move(fake_gatt_service));
|
||||
CallCreateCharacteristic(
|
||||
/*characteristic_uuid=*/kCharacteristicUuid1,
|
||||
/*expected_success=*/true);
|
||||
|
||||
CallUpdateCharacteristic(
|
||||
/*characteristic_uuid=*/kCharacteristicUuid1,
|
||||
/*expected_success=*/true);
|
||||
|
||||
base::test::TestFuture<bluetooth::mojom::LocalCharacteristicReadResultPtr>
|
||||
future;
|
||||
fake_gatt_service_ptr->TriggerReadCharacteristicRequest(
|
||||
device::BluetoothUUID(kServiceId),
|
||||
device::BluetoothUUID(kCharacteristicUuid1), future.GetCallback());
|
||||
auto read_result = future.Take();
|
||||
EXPECT_FALSE(read_result->is_error_code());
|
||||
EXPECT_TRUE(read_result->is_data());
|
||||
EXPECT_EQ(kNewCharacteristicValue,
|
||||
base::as_string_view(
|
||||
base::as_chars(base::make_span(read_result->get_data()))));
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
BleV2GattServerTest,
|
||||
UpdateCharacteristic_ReadCharacteristicRequest_FailureIfCharacteristicDoesntSupportRead) {
|
||||
auto fake_gatt_service = std::make_unique<bluetooth::FakeGattService>();
|
||||
fake_gatt_service->SetCreateCharacteristicResult(/*success=*/true);
|
||||
auto* fake_gatt_service_ptr = fake_gatt_service.get();
|
||||
fake_adapter_->SetCreateLocalGattServiceResult(
|
||||
/*gatt_service=*/std::move(fake_gatt_service));
|
||||
CallCreateCharacteristic(
|
||||
/*characteristic_uuid=*/kCharacteristicUuid1,
|
||||
/*expected_success=*/true,
|
||||
/*permission=*/api::ble_v2::GattCharacteristic::Permission::kWrite,
|
||||
/*property=*/api::ble_v2::GattCharacteristic::Property::kWrite);
|
||||
|
||||
CallUpdateCharacteristic(
|
||||
/*characteristic_uuid=*/kCharacteristicUuid1,
|
||||
/*expected_success=*/true,
|
||||
/*permission=*/api::ble_v2::GattCharacteristic::Permission::kWrite,
|
||||
/*property=*/api::ble_v2::GattCharacteristic::Property::kWrite);
|
||||
|
||||
base::test::TestFuture<bluetooth::mojom::LocalCharacteristicReadResultPtr>
|
||||
future;
|
||||
fake_gatt_service_ptr->TriggerReadCharacteristicRequest(
|
||||
device::BluetoothUUID(kServiceId),
|
||||
device::BluetoothUUID(kCharacteristicUuid1), future.GetCallback());
|
||||
auto read_result = future.Take();
|
||||
EXPECT_TRUE(read_result->is_error_code());
|
||||
EXPECT_FALSE(read_result->is_data());
|
||||
EXPECT_EQ(device::BluetoothGattService::GattErrorCode::kNotPermitted,
|
||||
read_result->get_error_code());
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
BleV2GattServerTest,
|
||||
UpdateCharacteristic_ReadCharacteristicRequest_FailureIfReadRequestForCharacteristicValueDoesntExist) {
|
||||
auto fake_gatt_service = std::make_unique<bluetooth::FakeGattService>();
|
||||
fake_gatt_service->SetCreateCharacteristicResult(/*success=*/true);
|
||||
auto* fake_gatt_service_ptr = fake_gatt_service.get();
|
||||
fake_adapter_->SetCreateLocalGattServiceResult(
|
||||
/*gatt_service=*/std::move(fake_gatt_service));
|
||||
CallCreateCharacteristic(
|
||||
/*characteristic_uuid=*/kCharacteristicUuid1,
|
||||
/*expected_success=*/true);
|
||||
|
||||
base::test::TestFuture<bluetooth::mojom::LocalCharacteristicReadResultPtr>
|
||||
future;
|
||||
fake_gatt_service_ptr->TriggerReadCharacteristicRequest(
|
||||
device::BluetoothUUID(kServiceId),
|
||||
device::BluetoothUUID(kCharacteristicUuid1), future.GetCallback());
|
||||
auto read_result = future.Take();
|
||||
EXPECT_TRUE(read_result->is_error_code());
|
||||
EXPECT_FALSE(read_result->is_data());
|
||||
EXPECT_EQ(device::BluetoothGattService::GattErrorCode::kNotSupported,
|
||||
read_result->get_error_code());
|
||||
}
|
||||
|
||||
} // namespace nearby::chrome
|
||||
|
@ -228,6 +228,7 @@ void FakeAdapter::CreateLocalGattService(
|
||||
mojo::PendingRemote<mojom::GattServiceObserver> observer,
|
||||
CreateLocalGattServiceCallback callback) {
|
||||
mojo::PendingRemote<mojom::GattService> pending_gatt_service;
|
||||
fake_gatt_service_->SetObserver(std::move(observer));
|
||||
mojo::MakeSelfOwnedReceiver(
|
||||
std::move(fake_gatt_service_),
|
||||
pending_gatt_service.InitWithNewPipeAndPassReceiver());
|
||||
|
@ -4,6 +4,12 @@
|
||||
|
||||
#include "chrome/services/sharing/nearby/test_support/fake_gatt_service.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const uint32_t kReadCharacteristicOffset = 0;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace bluetooth {
|
||||
|
||||
FakeGattService::FakeGattService() = default;
|
||||
@ -19,8 +25,33 @@ void FakeGattService::CreateCharacteristic(
|
||||
std::move(callback).Run(/*success=*/set_create_characteristic_result_);
|
||||
}
|
||||
|
||||
void FakeGattService::SetObserver(
|
||||
mojo::PendingRemote<mojom::GattServiceObserver> observer) {
|
||||
observer_remote_.Bind(std::move(observer));
|
||||
}
|
||||
|
||||
void FakeGattService::SetCreateCharacteristicResult(bool success) {
|
||||
set_create_characteristic_result_ = success;
|
||||
}
|
||||
|
||||
void FakeGattService::TriggerReadCharacteristicRequest(
|
||||
const device::BluetoothUUID& service_uuid,
|
||||
const device::BluetoothUUID& characteristic_uuid,
|
||||
ValueCallback callback) {
|
||||
observer_remote_->OnLocalCharacteristicRead(
|
||||
/*device=*/mojom::DeviceInfo::New(),
|
||||
/*characteristic_uuid=*/characteristic_uuid,
|
||||
/*service_uuid=*/service_uuid,
|
||||
/*offset=*/kReadCharacteristicOffset,
|
||||
/*callback=*/
|
||||
base::BindOnce(&FakeGattService::OnLocalCharacteristicReadResponse,
|
||||
base::Unretained(this), std::move(callback)));
|
||||
}
|
||||
|
||||
void FakeGattService::OnLocalCharacteristicReadResponse(
|
||||
ValueCallback callback,
|
||||
mojom::LocalCharacteristicReadResultPtr read_result) {
|
||||
std::move(callback).Run(std::move(read_result));
|
||||
}
|
||||
|
||||
} // namespace bluetooth
|
||||
|
@ -7,11 +7,14 @@
|
||||
|
||||
#include "device/bluetooth/public/mojom/adapter.mojom.h"
|
||||
#include "mojo/public/cpp/bindings/receiver.h"
|
||||
#include "mojo/public/cpp/bindings/remote.h"
|
||||
|
||||
namespace bluetooth {
|
||||
|
||||
class FakeGattService : public mojom::GattService {
|
||||
public:
|
||||
using ValueCallback = base::OnceCallback<void(
|
||||
bluetooth::mojom::LocalCharacteristicReadResultPtr)>;
|
||||
FakeGattService();
|
||||
FakeGattService(const FakeGattService&) = delete;
|
||||
FakeGattService& operator=(const FakeGattService&) = delete;
|
||||
@ -24,11 +27,23 @@ class FakeGattService : public mojom::GattService {
|
||||
const device::BluetoothGattCharacteristic::Properties& property,
|
||||
CreateCharacteristicCallback callback) override;
|
||||
|
||||
void SetObserver(mojo::PendingRemote<mojom::GattServiceObserver> observer);
|
||||
|
||||
void TriggerReadCharacteristicRequest(
|
||||
const device::BluetoothUUID& service_uuid,
|
||||
const device::BluetoothUUID& characteristic_uuid,
|
||||
ValueCallback callback);
|
||||
|
||||
void SetCreateCharacteristicResult(bool success);
|
||||
int GetNumCharacteristicUuids() { return characteristic_uuids_.size(); }
|
||||
|
||||
private:
|
||||
void OnLocalCharacteristicReadResponse(
|
||||
ValueCallback callback,
|
||||
mojom::LocalCharacteristicReadResultPtr read_result);
|
||||
|
||||
std::vector<device::BluetoothUUID> characteristic_uuids_;
|
||||
mojo::Remote<mojom::GattServiceObserver> observer_remote_;
|
||||
bool set_create_characteristic_result_ = false;
|
||||
mojo::Receiver<mojom::GattService> gatt_server_{this};
|
||||
};
|
||||
|
@ -8,8 +8,35 @@
|
||||
#include "base/logging.h"
|
||||
#include "device/bluetooth/bluetooth_adapter.h"
|
||||
#include "device/bluetooth/bluetooth_local_gatt_characteristic.h"
|
||||
#include "device/bluetooth/device.h"
|
||||
#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
|
||||
|
||||
namespace {
|
||||
|
||||
std::string_view GattErrorCodeToString(
|
||||
device::BluetoothGattService::GattErrorCode error_code) {
|
||||
switch (error_code) {
|
||||
case device::BluetoothGattService::GattErrorCode::kUnknown:
|
||||
return "Unknown";
|
||||
case device::BluetoothGattService::GattErrorCode::kFailed:
|
||||
return "Failed";
|
||||
case device::BluetoothGattService::GattErrorCode::kInProgress:
|
||||
return "In Progress";
|
||||
case device::BluetoothGattService::GattErrorCode::kInvalidLength:
|
||||
return "Invalid Length";
|
||||
case device::BluetoothGattService::GattErrorCode::kNotPermitted:
|
||||
return "Not Permitted";
|
||||
case device::BluetoothGattService::GattErrorCode::kNotAuthorized:
|
||||
return "Not Authorized";
|
||||
case device::BluetoothGattService::GattErrorCode::kNotPaired:
|
||||
return "Not Paired";
|
||||
case device::BluetoothGattService::GattErrorCode::kNotSupported:
|
||||
return "Not Supported";
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace bluetooth {
|
||||
|
||||
GattService::GattService(
|
||||
@ -83,11 +110,17 @@ void GattService::OnCharacteristicReadRequest(
|
||||
const device::BluetoothLocalGattCharacteristic* characteristic,
|
||||
int offset,
|
||||
ValueCallback callback) {
|
||||
// TODO(b/311430390): Implement `OnCharacteristicReadRequest()` to notify
|
||||
// observers (which will be added as part of this TODO) to provide a
|
||||
// value for this read request. Only READ characteristics are supported for
|
||||
// the BLE V2 MVP use in Nearby Connections.
|
||||
NOTIMPLEMENTED();
|
||||
CHECK(characteristic);
|
||||
CHECK(base::Contains(characteristic_uuids_, characteristic->GetUUID()));
|
||||
|
||||
observer_remote_->OnLocalCharacteristicRead(
|
||||
/*remote_device=*/Device::ConstructDeviceInfoStruct(device),
|
||||
/*characteristic_uuid=*/characteristic->GetUUID(),
|
||||
/*service_uuid=*/service_id_,
|
||||
/*offset=*/offset,
|
||||
/*callback=*/
|
||||
base::BindOnce(&GattService::OnLocalCharacteristicReadResponse,
|
||||
base::Unretained(this), std::move(callback)));
|
||||
}
|
||||
|
||||
void GattService::OnCharacteristicWriteRequest(
|
||||
@ -142,4 +175,22 @@ void GattService::OnNotificationsStop(
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
void GattService::OnLocalCharacteristicReadResponse(
|
||||
ValueCallback callback,
|
||||
mojom::LocalCharacteristicReadResultPtr read_result) {
|
||||
if (read_result->is_error_code()) {
|
||||
LOG(WARNING) << __func__ << ": failed due to error: "
|
||||
<< GattErrorCodeToString(read_result->get_error_code());
|
||||
std::move(callback).Run(
|
||||
/*error_code=*/read_result->get_error_code(),
|
||||
/*data=*/std::vector<uint8_t>());
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK(read_result->is_data());
|
||||
std::move(callback).Run(
|
||||
/*error_code=*/std::nullopt,
|
||||
/*data=*/read_result->get_data());
|
||||
}
|
||||
|
||||
} // namespace bluetooth
|
||||
|
@ -86,6 +86,10 @@ class GattService : public mojom::GattService,
|
||||
const device::BluetoothDevice* device,
|
||||
const device::BluetoothLocalGattCharacteristic* characteristic) override;
|
||||
|
||||
void OnLocalCharacteristicReadResponse(
|
||||
ValueCallback callback,
|
||||
mojom::LocalCharacteristicReadResultPtr read_result);
|
||||
|
||||
const device::BluetoothUUID service_id_;
|
||||
std::set<device::BluetoothUUID> characteristic_uuids_;
|
||||
mojo::Remote<mojom::GattServiceObserver> observer_remote_;
|
||||
|
@ -12,20 +12,47 @@
|
||||
#include "device/bluetooth/test/fake_local_gatt_characteristic.h"
|
||||
#include "device/bluetooth/test/fake_local_gatt_service.h"
|
||||
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
|
||||
#include "device/bluetooth/test/mock_bluetooth_device.h"
|
||||
#include "mojo/public/cpp/bindings/remote.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const char kServiceId[] = "TestServiceId";
|
||||
const char kCharacteristicUuid[] = "1234";
|
||||
const char kServiceId[] = "12345678-1234-5678-9abc-def123456789";
|
||||
const char kCharacteristicUuid[] = "00001101-0000-1000-8000-00805f9b34fb";
|
||||
const char kTestDeviceName[] = "TestDeviceName";
|
||||
const char kTestDeviceAddress[] = "TestDeviceAddress";
|
||||
const std::vector<uint8_t> kReadCharacteristicValue = {0x01, 0x02, 0x03};
|
||||
const int kReadCharacteristicOffset = 0;
|
||||
|
||||
std::unique_ptr<bluetooth::FakeLocalGattCharacteristic>
|
||||
CreateFakeCharacteristic(device::BluetoothLocalGattService* service) {
|
||||
return std::make_unique<bluetooth::FakeLocalGattCharacteristic>(
|
||||
/*characteristic_id=*/kCharacteristicUuid,
|
||||
/*characteristic_uuid=*/device::BluetoothUUID(kCharacteristicUuid),
|
||||
/*service=*/service,
|
||||
/*properties=*/
|
||||
device::BluetoothGattCharacteristic::Permission::PERMISSION_READ,
|
||||
/*property=*/
|
||||
device::BluetoothGattCharacteristic::Property::PROPERTY_READ);
|
||||
}
|
||||
|
||||
std::unique_ptr<testing::NiceMock<device::MockBluetoothDevice>>
|
||||
CreateMockBluetoothDevice() {
|
||||
return std::make_unique<testing::NiceMock<device::MockBluetoothDevice>>(
|
||||
/*adapter=*/nullptr,
|
||||
/*class=*/0, kTestDeviceName, kTestDeviceAddress,
|
||||
/*paired=*/false,
|
||||
/*connected=*/false);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace bluetooth {
|
||||
|
||||
class GattServiceTest : public testing::Test {
|
||||
class GattServiceTest : public testing::Test,
|
||||
public mojom::GattServiceObserver {
|
||||
public:
|
||||
GattServiceTest() = default;
|
||||
~GattServiceTest() override = default;
|
||||
@ -46,7 +73,8 @@ class GattServiceTest : public testing::Test {
|
||||
|
||||
mojo::PendingReceiver<mojom::GattService> pending_gatt_service_receiver =
|
||||
remote_.BindNewPipeAndPassReceiver();
|
||||
mojo::PendingRemote<mojom::GattServiceObserver> pending_observer_remote;
|
||||
mojo::PendingRemote<mojom::GattServiceObserver> pending_observer_remote =
|
||||
observer_.BindNewPipeAndPassRemote();
|
||||
gatt_service_ = std::make_unique<GattService>(
|
||||
std::move(pending_gatt_service_receiver),
|
||||
std::move(pending_observer_remote), device::BluetoothUUID(kServiceId),
|
||||
@ -64,10 +92,76 @@ class GattServiceTest : public testing::Test {
|
||||
// test with the CHECK below.
|
||||
CHECK_EQ(0, create_local_gatt_service_calls_);
|
||||
create_local_gatt_service_calls_++;
|
||||
delegate_ = delegate;
|
||||
return fake_local_gatt_service_->GetWeakPtr();
|
||||
}
|
||||
|
||||
// mojo::GattServiceObserver:
|
||||
void OnLocalCharacteristicRead(
|
||||
bluetooth::mojom::DeviceInfoPtr remote_device,
|
||||
const device::BluetoothUUID& characteristic_uuid,
|
||||
const device::BluetoothUUID& service_uuid,
|
||||
uint32_t offset,
|
||||
OnLocalCharacteristicReadCallback callback) override {
|
||||
mojom::LocalCharacteristicReadResultPtr read_result;
|
||||
if (local_characteristic_read_error_code_.has_value()) {
|
||||
read_result = mojom::LocalCharacteristicReadResult::NewErrorCode(
|
||||
local_characteristic_read_error_code_.value());
|
||||
} else {
|
||||
CHECK(local_characteristic_read_value_.has_value());
|
||||
read_result = mojom::LocalCharacteristicReadResult::NewData(
|
||||
local_characteristic_read_value_.value());
|
||||
}
|
||||
|
||||
std::move(callback).Run(std::move(read_result));
|
||||
std::move(on_local_characteristic_read_callback_).Run();
|
||||
}
|
||||
|
||||
void CallCreateCharacteristic(
|
||||
bool gatt_service_exists,
|
||||
bool expected_success,
|
||||
device::BluetoothGattCharacteristic::Permissions permissions =
|
||||
device::BluetoothGattCharacteristic::Permission::PERMISSION_READ,
|
||||
device::BluetoothGattCharacteristic::Properties properties =
|
||||
device::BluetoothGattCharacteristic::Property::PROPERTY_READ) {
|
||||
if (gatt_service_exists) {
|
||||
// Simulate that the GATT service is created successfully, and is never
|
||||
// destroyed during the lifetime of this test.
|
||||
ON_CALL(*mock_bluetooth_adapter_, GetGattService)
|
||||
.WillByDefault(testing::Return(fake_local_gatt_service_.get()));
|
||||
} else {
|
||||
// Simulate the underlying platform GattService destruction.
|
||||
EXPECT_CALL(*mock_bluetooth_adapter_, GetGattService)
|
||||
.WillOnce(testing::Return(nullptr));
|
||||
}
|
||||
|
||||
base::test::TestFuture<bool> future;
|
||||
remote_->CreateCharacteristic(
|
||||
/*characteristic_uuid=*/device::BluetoothUUID(kCharacteristicUuid),
|
||||
/*permissions=*/permissions,
|
||||
/*properties=*/properties, future.GetCallback());
|
||||
EXPECT_EQ(expected_success, future.Take());
|
||||
EXPECT_EQ(expected_success,
|
||||
(nullptr != fake_local_gatt_service_->GetCharacteristic(
|
||||
kCharacteristicUuid)));
|
||||
}
|
||||
|
||||
void SetOnLocalCharacteristicReadCallback(base::OnceClosure callback) {
|
||||
on_local_characteristic_read_callback_ = std::move(callback);
|
||||
}
|
||||
|
||||
void SetOnLocalCharacteristicReadResult(
|
||||
std::optional<device::BluetoothGattService::GattErrorCode> error_code,
|
||||
std::optional<std::vector<uint8_t>> value) {
|
||||
local_characteristic_read_error_code_ = error_code;
|
||||
local_characteristic_read_value_ = value;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::optional<device::BluetoothGattService::GattErrorCode>
|
||||
local_characteristic_read_error_code_;
|
||||
std::optional<std::vector<uint8_t>> local_characteristic_read_value_;
|
||||
base::OnceClosure on_local_characteristic_read_callback_;
|
||||
int create_local_gatt_service_calls_ = 0;
|
||||
base::test::SingleThreadTaskEnvironment task_environment_;
|
||||
mojo::Remote<mojom::GattService> remote_;
|
||||
@ -75,6 +169,8 @@ class GattServiceTest : public testing::Test {
|
||||
scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
|
||||
mock_bluetooth_adapter_;
|
||||
std::unique_ptr<GattService> gatt_service_;
|
||||
raw_ptr<device::BluetoothLocalGattService::Delegate> delegate_;
|
||||
mojo::Receiver<mojom::GattServiceObserver> observer_{this};
|
||||
};
|
||||
|
||||
TEST_F(GattServiceTest, CreateGattServiceOnConstruction) {
|
||||
@ -100,10 +196,21 @@ TEST_F(GattServiceTest, CreateCharacteristic_FailureIfGattServiceIsDestroyed) {
|
||||
|
||||
TEST_F(GattServiceTest,
|
||||
CreateCharacteristic_FailureIfCreateGattCharacteristicFails) {
|
||||
EXPECT_CALL(*mock_bluetooth_adapter_, GetGattService)
|
||||
.WillOnce(testing::Return(fake_local_gatt_service_.get()));
|
||||
fake_local_gatt_service_->set_should_create_local_gatt_characteristic_succeed(
|
||||
false);
|
||||
CallCreateCharacteristic(/*gatt_service_exists=*/false,
|
||||
/*expected_success=*/false);
|
||||
}
|
||||
|
||||
TEST_F(GattServiceTest, CreateCharacteristic_SuccessIfCreated) {
|
||||
CallCreateCharacteristic(/*gatt_service_exists=*/true,
|
||||
/*expected_success=*/true);
|
||||
}
|
||||
|
||||
TEST_F(GattServiceTest, CreateCharacteristic_FailureIfAlreadyExists) {
|
||||
// Create the characteristic the first time.
|
||||
CallCreateCharacteristic(/*gatt_service_exists=*/true,
|
||||
/*expected_success=*/true);
|
||||
|
||||
// Expect failure on another call because it already exists.
|
||||
base::test::TestFuture<bool> future;
|
||||
remote_->CreateCharacteristic(
|
||||
/*characteristic_uuid=*/device::BluetoothUUID(kCharacteristicUuid),
|
||||
@ -113,70 +220,10 @@ TEST_F(GattServiceTest,
|
||||
device::BluetoothGattCharacteristic::Property::PROPERTY_READ,
|
||||
future.GetCallback());
|
||||
EXPECT_FALSE(future.Take());
|
||||
EXPECT_FALSE(
|
||||
fake_local_gatt_service_->GetCharacteristic(kCharacteristicUuid));
|
||||
}
|
||||
|
||||
TEST_F(GattServiceTest, CreateCharacteristic_SuccessIfCreated) {
|
||||
// Simulate that the GATT service is created successfully, and is never
|
||||
// destroyed during the lifetime of this test.
|
||||
ON_CALL(*mock_bluetooth_adapter_, GetGattService)
|
||||
.WillByDefault(testing::Return(fake_local_gatt_service_.get()));
|
||||
base::test::TestFuture<bool> future;
|
||||
remote_->CreateCharacteristic(
|
||||
/*characteristic_uuid=*/device::BluetoothUUID(kCharacteristicUuid),
|
||||
/*permissions=*/
|
||||
device::BluetoothGattCharacteristic::Permission::PERMISSION_READ,
|
||||
/*properties=*/
|
||||
device::BluetoothGattCharacteristic::Property::PROPERTY_READ,
|
||||
future.GetCallback());
|
||||
EXPECT_TRUE(future.Take());
|
||||
EXPECT_TRUE(fake_local_gatt_service_->GetCharacteristic(kCharacteristicUuid));
|
||||
}
|
||||
|
||||
TEST_F(GattServiceTest, CreateCharacteristic_FailureIfAlreadyExists) {
|
||||
// Simulate that the GATT service is created successfully, and is never
|
||||
// destroyed during the lifetime of this test.
|
||||
ON_CALL(*mock_bluetooth_adapter_, GetGattService)
|
||||
.WillByDefault(testing::Return(fake_local_gatt_service_.get()));
|
||||
|
||||
// Create the characteristic the first time.
|
||||
{
|
||||
base::test::TestFuture<bool> future;
|
||||
remote_->CreateCharacteristic(
|
||||
/*characteristic_uuid=*/device::BluetoothUUID(kCharacteristicUuid),
|
||||
/*permissions=*/
|
||||
device::BluetoothGattCharacteristic::Permission::PERMISSION_READ,
|
||||
/*properties=*/
|
||||
device::BluetoothGattCharacteristic::Property::PROPERTY_READ,
|
||||
future.GetCallback());
|
||||
EXPECT_TRUE(future.Take());
|
||||
EXPECT_TRUE(
|
||||
fake_local_gatt_service_->GetCharacteristic(kCharacteristicUuid));
|
||||
}
|
||||
|
||||
// Expect success on another call because it already exists.
|
||||
{
|
||||
base::test::TestFuture<bool> future;
|
||||
remote_->CreateCharacteristic(
|
||||
/*characteristic_uuid=*/device::BluetoothUUID(kCharacteristicUuid),
|
||||
/*permissions=*/
|
||||
device::BluetoothGattCharacteristic::Permission::PERMISSION_READ,
|
||||
/*properties=*/
|
||||
device::BluetoothGattCharacteristic::Property::PROPERTY_READ,
|
||||
future.GetCallback());
|
||||
EXPECT_FALSE(future.Take());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(GattServiceTest,
|
||||
CreateCharacteristic_Success_MultiplePermissionsAndProperties) {
|
||||
// Simulate that the GATT service is created successfully, and is never
|
||||
// destroyed during the lifetime of this test.
|
||||
ON_CALL(*mock_bluetooth_adapter_, GetGattService)
|
||||
.WillByDefault(testing::Return(fake_local_gatt_service_.get()));
|
||||
base::test::TestFuture<bool> future;
|
||||
|
||||
device::BluetoothGattCharacteristic::Permissions permissions =
|
||||
device::BluetoothGattCharacteristic::Permission::PERMISSION_READ |
|
||||
device::BluetoothGattCharacteristic::Permission::PERMISSION_WRITE;
|
||||
@ -184,11 +231,8 @@ TEST_F(GattServiceTest,
|
||||
device::BluetoothGattCharacteristic::Property::PROPERTY_READ |
|
||||
device::BluetoothGattCharacteristic::Property::PROPERTY_WRITE;
|
||||
|
||||
remote_->CreateCharacteristic(
|
||||
/*characteristic_uuid=*/device::BluetoothUUID(kCharacteristicUuid),
|
||||
/*permissions=*/permissions,
|
||||
/*properties=*/properties, future.GetCallback());
|
||||
EXPECT_TRUE(future.Take());
|
||||
CallCreateCharacteristic(/*gatt_service_exists=*/true,
|
||||
/*expected_success=*/true, permissions, properties);
|
||||
|
||||
auto* fake_characteristic =
|
||||
fake_local_gatt_service_->GetCharacteristic(kCharacteristicUuid);
|
||||
@ -197,4 +241,75 @@ TEST_F(GattServiceTest,
|
||||
EXPECT_EQ(permissions, fake_characteristic->GetPermissions());
|
||||
}
|
||||
|
||||
TEST_F(GattServiceTest, OnReadCharacteristic_Success) {
|
||||
// Simulate that the GATT service is created successfully, and is never
|
||||
// destroyed during the lifetime of this test. Simulate a successful
|
||||
// characteristic being added to the GATT service.
|
||||
CallCreateCharacteristic(/*gatt_service_exists=*/true,
|
||||
/*expected_success=*/true);
|
||||
|
||||
base::MockCallback<base::OnceClosure> mock_observer_callback;
|
||||
EXPECT_CALL(mock_observer_callback, Run).Times(1);
|
||||
SetOnLocalCharacteristicReadCallback(mock_observer_callback.Get());
|
||||
SetOnLocalCharacteristicReadResult(
|
||||
/*error_code=*/std::nullopt,
|
||||
/*value=*/kReadCharacteristicValue);
|
||||
|
||||
base::RunLoop run_loop;
|
||||
auto mock_device = CreateMockBluetoothDevice();
|
||||
auto fake_characteristic =
|
||||
CreateFakeCharacteristic(fake_local_gatt_service_.get());
|
||||
|
||||
delegate_->OnCharacteristicReadRequest(
|
||||
/*device=*/mock_device.get(),
|
||||
/*characteristic=*/fake_characteristic.get(),
|
||||
/*offset=*/kReadCharacteristicOffset,
|
||||
/*callback=*/
|
||||
base::BindLambdaForTesting(
|
||||
[&](std::optional<::device::BluetoothGattService::GattErrorCode>
|
||||
error_code,
|
||||
const std::vector<uint8_t>& value) {
|
||||
EXPECT_FALSE(error_code.has_value());
|
||||
EXPECT_FALSE(value.empty());
|
||||
run_loop.Quit();
|
||||
}));
|
||||
|
||||
run_loop.Run();
|
||||
}
|
||||
|
||||
TEST_F(GattServiceTest, OnReadCharacteristic_Failure) {
|
||||
// Simulate that the GATT service is created successfully, and is never
|
||||
// destroyed during the lifetime of this test. Simulate a successful
|
||||
// characteristic being added to the GATT service.
|
||||
CallCreateCharacteristic(/*gatt_service_exists=*/true,
|
||||
/*expected_success=*/true);
|
||||
|
||||
base::MockCallback<base::OnceClosure> mock_observer_callback;
|
||||
EXPECT_CALL(mock_observer_callback, Run).Times(1);
|
||||
SetOnLocalCharacteristicReadCallback(mock_observer_callback.Get());
|
||||
SetOnLocalCharacteristicReadResult(
|
||||
/*error_code=*/device::BluetoothGattService::GattErrorCode::kFailed,
|
||||
/*value=*/std::nullopt);
|
||||
|
||||
base::RunLoop run_loop;
|
||||
auto mock_device = CreateMockBluetoothDevice();
|
||||
auto fake_characteristic =
|
||||
CreateFakeCharacteristic(fake_local_gatt_service_.get());
|
||||
delegate_->OnCharacteristicReadRequest(
|
||||
/*device=*/mock_device.get(),
|
||||
/*characteristic=*/fake_characteristic.get(),
|
||||
/*offset=*/kReadCharacteristicOffset,
|
||||
/*callback=*/
|
||||
base::BindLambdaForTesting(
|
||||
[&](std::optional<::device::BluetoothGattService::GattErrorCode>
|
||||
error_code,
|
||||
const std::vector<uint8_t>& value) {
|
||||
EXPECT_TRUE(error_code.has_value());
|
||||
EXPECT_TRUE(value.empty());
|
||||
run_loop.Quit();
|
||||
}));
|
||||
|
||||
run_loop.Run();
|
||||
}
|
||||
|
||||
} // namespace bluetooth
|
||||
|
@ -9,6 +9,7 @@ mojom("mojom") {
|
||||
sources = [
|
||||
"gatt_characteristic_permissions.mojom",
|
||||
"gatt_characteristic_properties.mojom",
|
||||
"gatt_service_error_code.mojom",
|
||||
"uuid.mojom",
|
||||
]
|
||||
webui_module_path = "/"
|
||||
@ -32,13 +33,19 @@ mojom("mojom") {
|
||||
mojom = "bluetooth.mojom.GattCharacteristicPermissions"
|
||||
cpp = "::device::BluetoothGattCharacteristic::Permissions"
|
||||
},
|
||||
{
|
||||
mojom = "bluetooth.mojom.GattServiceErrorCode"
|
||||
cpp = "::device::BluetoothGattService::GattErrorCode"
|
||||
},
|
||||
]
|
||||
traits_headers = [
|
||||
"//device/bluetooth/public/mojom/uuid_mojom_traits.h",
|
||||
"//device/bluetooth/public/mojom/gatt_characteristic_mojom_traits.h",
|
||||
"//device/bluetooth/public/mojom/gatt_service_mojom_traits.h",
|
||||
]
|
||||
traits_sources = [
|
||||
"//device/bluetooth/public/mojom/gatt_characteristic_mojom_traits.cc",
|
||||
"//device/bluetooth/public/mojom/gatt_service_mojom_traits.cc",
|
||||
]
|
||||
traits_public_deps = [ "//device/bluetooth/public/cpp" ]
|
||||
},
|
||||
|
@ -8,6 +8,7 @@ import "device/bluetooth/public/mojom/device.mojom";
|
||||
import "device/bluetooth/public/mojom/uuid.mojom";
|
||||
import "device/bluetooth/public/mojom/gatt_characteristic_permissions.mojom";
|
||||
import "device/bluetooth/public/mojom/gatt_characteristic_properties.mojom";
|
||||
import "device/bluetooth/public/mojom/gatt_service_error_code.mojom";
|
||||
|
||||
// Possible errors sent as a response by Adapter.ConnectToDevice on a Device
|
||||
// connection request.
|
||||
@ -30,6 +31,11 @@ enum ConnectResult {
|
||||
INVALID_ARGS,
|
||||
};
|
||||
|
||||
union LocalCharacteristicReadResult {
|
||||
GattServiceErrorCode error_code;
|
||||
array<uint8> data;
|
||||
};
|
||||
|
||||
// The results of a successful connection via ConnectToServiceInsecurely().
|
||||
struct ConnectToServiceResult {
|
||||
pending_remote<Socket> socket;
|
||||
@ -158,6 +164,12 @@ interface GattService {
|
||||
// TODO(b/311430390): Implement additional methods that communicate read/write
|
||||
// requests on GATT characteristics.
|
||||
interface GattServiceObserver {
|
||||
// Called when a remote peripheral is reading from the characteristic.
|
||||
// On failures, |read_result| will be the error code. On success,
|
||||
// |read_result| will be the read result value.
|
||||
OnLocalCharacteristicRead(DeviceInfo remote_device,
|
||||
UUID characteristic_uuid, UUID service_uuid, uint32 offset) =>
|
||||
(LocalCharacteristicReadResult read_result);
|
||||
};
|
||||
|
||||
// Handles requests to either query Bluetooth adapter capabilities or state, or
|
||||
|
21
device/bluetooth/public/mojom/gatt_service_error_code.mojom
Normal file
21
device/bluetooth/public/mojom/gatt_service_error_code.mojom
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
module bluetooth.mojom;
|
||||
|
||||
// Possible result sent as a response to
|
||||
// GattServiceObserver.OnLocalCharacteristicRead, which is aligned with
|
||||
// BluetoothGattService::GattErrorCode found in
|
||||
// device/bluetooth/bluetooth_gatt_service.h.
|
||||
enum GattServiceErrorCode {
|
||||
kUnknown,
|
||||
kFailed,
|
||||
kInProgress,
|
||||
kInvalidLength,
|
||||
kNotPermitted,
|
||||
kNotAuthorized,
|
||||
kNotPaired,
|
||||
kNotSupported,
|
||||
};
|
||||
|
65
device/bluetooth/public/mojom/gatt_service_mojom_traits.cc
Normal file
65
device/bluetooth/public/mojom/gatt_service_mojom_traits.cc
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "device/bluetooth/public/mojom/gatt_service_mojom_traits.h"
|
||||
|
||||
namespace mojo {
|
||||
|
||||
bluetooth::mojom::GattServiceErrorCode
|
||||
EnumTraits<bluetooth::mojom::GattServiceErrorCode,
|
||||
device::BluetoothGattService::GattErrorCode>::
|
||||
ToMojom(device::BluetoothGattService::GattErrorCode input) {
|
||||
switch (input) {
|
||||
case device::BluetoothGattService::GattErrorCode::kUnknown:
|
||||
return bluetooth::mojom::GattServiceErrorCode::kUnknown;
|
||||
case device::BluetoothGattService::GattErrorCode::kFailed:
|
||||
return bluetooth::mojom::GattServiceErrorCode::kFailed;
|
||||
case device::BluetoothGattService::GattErrorCode::kInProgress:
|
||||
return bluetooth::mojom::GattServiceErrorCode::kInProgress;
|
||||
case device::BluetoothGattService::GattErrorCode::kInvalidLength:
|
||||
return bluetooth::mojom::GattServiceErrorCode::kInvalidLength;
|
||||
case device::BluetoothGattService::GattErrorCode::kNotPermitted:
|
||||
return bluetooth::mojom::GattServiceErrorCode::kNotPermitted;
|
||||
case device::BluetoothGattService::GattErrorCode::kNotAuthorized:
|
||||
return bluetooth::mojom::GattServiceErrorCode::kNotAuthorized;
|
||||
case device::BluetoothGattService::GattErrorCode::kNotPaired:
|
||||
return bluetooth::mojom::GattServiceErrorCode::kNotPaired;
|
||||
case device::BluetoothGattService::GattErrorCode::kNotSupported:
|
||||
return bluetooth::mojom::GattServiceErrorCode::kNotSupported;
|
||||
}
|
||||
}
|
||||
|
||||
bool EnumTraits<bluetooth::mojom::GattServiceErrorCode,
|
||||
device::BluetoothGattService::GattErrorCode>::
|
||||
FromMojom(bluetooth::mojom::GattServiceErrorCode input,
|
||||
device::BluetoothGattService::GattErrorCode* output) {
|
||||
switch (input) {
|
||||
case bluetooth::mojom::GattServiceErrorCode::kUnknown:
|
||||
*output = device::BluetoothGattService::GattErrorCode::kUnknown;
|
||||
return true;
|
||||
case bluetooth::mojom::GattServiceErrorCode::kFailed:
|
||||
*output = device::BluetoothGattService::GattErrorCode::kFailed;
|
||||
return true;
|
||||
case bluetooth::mojom::GattServiceErrorCode::kInProgress:
|
||||
*output = device::BluetoothGattService::GattErrorCode::kInProgress;
|
||||
return true;
|
||||
case bluetooth::mojom::GattServiceErrorCode::kInvalidLength:
|
||||
*output = device::BluetoothGattService::GattErrorCode::kInvalidLength;
|
||||
return true;
|
||||
case bluetooth::mojom::GattServiceErrorCode::kNotPermitted:
|
||||
*output = device::BluetoothGattService::GattErrorCode::kNotPermitted;
|
||||
return true;
|
||||
case bluetooth::mojom::GattServiceErrorCode::kNotAuthorized:
|
||||
*output = device::BluetoothGattService::GattErrorCode::kNotAuthorized;
|
||||
return true;
|
||||
case bluetooth::mojom::GattServiceErrorCode::kNotPaired:
|
||||
*output = device::BluetoothGattService::GattErrorCode::kNotPaired;
|
||||
return true;
|
||||
case bluetooth::mojom::GattServiceErrorCode::kNotSupported:
|
||||
*output = device::BluetoothGattService::GattErrorCode::kNotSupported;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mojo
|
25
device/bluetooth/public/mojom/gatt_service_mojom_traits.h
Normal file
25
device/bluetooth/public/mojom/gatt_service_mojom_traits.h
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef DEVICE_BLUETOOTH_PUBLIC_MOJOM_GATT_SERVICE_MOJOM_TRAITS_H_
|
||||
#define DEVICE_BLUETOOTH_PUBLIC_MOJOM_GATT_SERVICE_MOJOM_TRAITS_H_
|
||||
|
||||
#include "device/bluetooth/bluetooth_gatt_service.h"
|
||||
#include "device/bluetooth/public/mojom/gatt_service_error_code.mojom-shared.h"
|
||||
#include "mojo/public/cpp/bindings/struct_traits.h"
|
||||
|
||||
namespace mojo {
|
||||
|
||||
template <>
|
||||
struct EnumTraits<bluetooth::mojom::GattServiceErrorCode,
|
||||
device::BluetoothGattService::GattErrorCode> {
|
||||
static bluetooth::mojom::GattServiceErrorCode ToMojom(
|
||||
device::BluetoothGattService::GattErrorCode input);
|
||||
static bool FromMojom(bluetooth::mojom::GattServiceErrorCode input,
|
||||
device::BluetoothGattService::GattErrorCode* output);
|
||||
};
|
||||
|
||||
} // namespace mojo
|
||||
|
||||
#endif // DEVICE_BLUETOOTH_PUBLIC_MOJOM_GATT_SERVICE_MOJOM_TRAITS_H_
|
Reference in New Issue
Block a user