blob: 69617c8b4e30f8ef0d763f4d5b55ff813c39e693 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/device/public/cpp/hid/fake_hid_manager.h"
#include <memory>
#include <utility>
#include "base/guid.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
namespace device {
FakeHidConnection::FakeHidConnection(
mojom::HidDeviceInfoPtr device,
mojo::PendingReceiver<mojom::HidConnection> receiver,
mojo::PendingRemote<mojom::HidConnectionClient> connection_client,
mojo::PendingRemote<mojom::HidConnectionWatcher> watcher)
: receiver_(this, std::move(receiver)),
device_(std::move(device)),
watcher_(std::move(watcher)) {
receiver_.set_disconnect_handler(base::BindOnce(
[](FakeHidConnection* self) { delete self; }, base::Unretained(this)));
if (watcher_) {
watcher_.set_disconnect_handler(base::BindOnce(
[](FakeHidConnection* self) { delete self; }, base::Unretained(this)));
}
if (connection_client)
client_.Bind(std::move(connection_client));
}
FakeHidConnection::~FakeHidConnection() = default;
// mojom::HidConnection implementation:
void FakeHidConnection::Read(ReadCallback callback) {
const char kResult[] = "This is a HID input report.";
uint8_t report_id = device_->has_report_id ? 1 : 0;
std::vector<uint8_t> buffer(kResult, kResult + sizeof(kResult) - 1);
std::move(callback).Run(true, report_id, buffer);
}
void FakeHidConnection::Write(uint8_t report_id,
const std::vector<uint8_t>& buffer,
WriteCallback callback) {
const char kExpected[] = "o-report"; // 8 bytes
if (buffer.size() != sizeof(kExpected) - 1) {
std::move(callback).Run(false);
return;
}
int expected_report_id = device_->has_report_id ? 1 : 0;
if (report_id != expected_report_id) {
std::move(callback).Run(false);
return;
}
if (memcmp(buffer.data(), kExpected, sizeof(kExpected) - 1) != 0) {
std::move(callback).Run(false);
return;
}
std::move(callback).Run(true);
}
void FakeHidConnection::GetFeatureReport(uint8_t report_id,
GetFeatureReportCallback callback) {
uint8_t expected_report_id = device_->has_report_id ? 1 : 0;
if (report_id != expected_report_id) {
std::move(callback).Run(false, base::nullopt);
return;
}
const char kResult[] = "This is a HID feature report.";
std::vector<uint8_t> buffer;
if (device_->has_report_id)
buffer.push_back(report_id);
buffer.insert(buffer.end(), kResult, kResult + sizeof(kResult) - 1);
std::move(callback).Run(true, buffer);
}
void FakeHidConnection::SendFeatureReport(uint8_t report_id,
const std::vector<uint8_t>& buffer,
SendFeatureReportCallback callback) {
const char kExpected[] = "The app is setting this HID feature report.";
if (buffer.size() != sizeof(kExpected) - 1) {
std::move(callback).Run(false);
return;
}
int expected_report_id = device_->has_report_id ? 1 : 0;
if (report_id != expected_report_id) {
std::move(callback).Run(false);
return;
}
if (memcmp(buffer.data(), kExpected, sizeof(kExpected) - 1) != 0) {
std::move(callback).Run(false);
return;
}
std::move(callback).Run(true);
}
// Implementation of FakeHidManager.
FakeHidManager::FakeHidManager() = default;
FakeHidManager::~FakeHidManager() = default;
void FakeHidManager::Bind(mojo::PendingReceiver<mojom::HidManager> receiver) {
receivers_.Add(this, std::move(receiver));
}
// mojom::HidManager implementation:
void FakeHidManager::AddReceiver(
mojo::PendingReceiver<mojom::HidManager> receiver) {
Bind(std::move(receiver));
}
void FakeHidManager::GetDevicesAndSetClient(
mojo::PendingAssociatedRemote<mojom::HidManagerClient> client,
GetDevicesCallback callback) {
GetDevices(std::move(callback));
if (!client.is_valid())
return;
clients_.Add(std::move(client));
}
void FakeHidManager::GetDevices(GetDevicesCallback callback) {
std::vector<mojom::HidDeviceInfoPtr> device_list;
for (auto& map_entry : devices_)
device_list.push_back(map_entry.second->Clone());
std::move(callback).Run(std::move(device_list));
}
void FakeHidManager::Connect(
const std::string& device_guid,
mojo::PendingRemote<mojom::HidConnectionClient> connection_client,
mojo::PendingRemote<mojom::HidConnectionWatcher> watcher,
ConnectCallback callback) {
if (!base::Contains(devices_, device_guid)) {
std::move(callback).Run(mojo::NullRemote());
return;
}
mojo::PendingRemote<mojom::HidConnection> connection;
// FakeHidConnection is self-owned.
new FakeHidConnection(devices_[device_guid]->Clone(),
connection.InitWithNewPipeAndPassReceiver(),
std::move(connection_client), std::move(watcher));
std::move(callback).Run(std::move(connection));
}
mojom::HidDeviceInfoPtr FakeHidManager::CreateAndAddDevice(
const std::string& physical_device_id,
uint16_t vendor_id,
uint16_t product_id,
const std::string& product_name,
const std::string& serial_number,
mojom::HidBusType bus_type) {
mojom::HidDeviceInfoPtr device = mojom::HidDeviceInfo::New();
device->guid = base::GenerateGUID();
device->physical_device_id = physical_device_id;
device->vendor_id = vendor_id;
device->product_id = product_id;
device->product_name = product_name;
device->serial_number = serial_number;
device->bus_type = bus_type;
AddDevice(device.Clone());
return device;
}
mojom::HidDeviceInfoPtr FakeHidManager::CreateAndAddDeviceWithTopLevelUsage(
const std::string& physical_device_id,
uint16_t vendor_id,
uint16_t product_id,
const std::string& product_name,
const std::string& serial_number,
mojom::HidBusType bus_type,
uint16_t usage_page,
uint16_t usage) {
mojom::HidDeviceInfoPtr device = mojom::HidDeviceInfo::New();
device->guid = base::GenerateGUID();
device->physical_device_id = physical_device_id;
device->vendor_id = vendor_id;
device->product_id = product_id;
device->product_name = product_name;
device->serial_number = serial_number;
device->bus_type = bus_type;
std::vector<mojom::HidReportDescriptionPtr> input_reports;
std::vector<mojom::HidReportDescriptionPtr> output_reports;
std::vector<mojom::HidReportDescriptionPtr> feature_reports;
std::vector<mojom::HidCollectionInfoPtr> children;
device->collections.push_back(mojom::HidCollectionInfo::New(
mojom::HidUsageAndPage::New(usage, usage_page), std::vector<uint8_t>(),
mojom::kHIDCollectionTypeApplication, std::move(input_reports),
std::move(output_reports), std::move(feature_reports),
std::move(children)));
AddDevice(device.Clone());
return device;
}
void FakeHidManager::AddDevice(mojom::HidDeviceInfoPtr device) {
std::string guid = device->guid;
devices_[guid] = std::move(device);
mojom::HidDeviceInfo* device_info = devices_[guid].get();
for (auto& client : clients_)
client->DeviceAdded(device_info->Clone());
}
void FakeHidManager::RemoveDevice(const std::string& guid) {
if (base::Contains(devices_, guid)) {
mojom::HidDeviceInfo* device_info = devices_[guid].get();
for (auto& client : clients_)
client->DeviceRemoved(device_info->Clone());
devices_.erase(guid);
}
}
void FakeHidManager::SimulateConnectionError() {
clients_.Clear();
receivers_.Clear();
}
} // namespace device