Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / extensions / browser / api / hid / hid_api.cc
blobd67f56499d88346f99b184179e09d220e31e4776
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/browser/api/hid/hid_api.h"
7 #include <string>
8 #include <vector>
10 #include "base/stl_util.h"
11 #include "device/core/device_client.h"
12 #include "device/hid/hid_connection.h"
13 #include "device/hid/hid_device_filter.h"
14 #include "device/hid/hid_device_info.h"
15 #include "device/hid/hid_service.h"
16 #include "extensions/browser/api/api_resource_manager.h"
17 #include "extensions/common/api/hid.h"
18 #include "net/base/io_buffer.h"
20 namespace hid = extensions::core_api::hid;
22 using device::HidConnection;
23 using device::HidDeviceFilter;
24 using device::HidDeviceInfo;
25 using device::HidService;
27 namespace {
29 const char kErrorServiceUnavailable[] = "HID services are unavailable.";
30 const char kErrorPermissionDenied[] = "Permission to access device was denied.";
31 const char kErrorInvalidDeviceId[] = "Invalid HID device ID.";
32 const char kErrorFailedToOpenDevice[] = "Failed to open HID device.";
33 const char kErrorConnectionNotFound[] = "Connection not established.";
34 const char kErrorTransfer[] = "Transfer failed.";
36 base::Value* PopulateHidConnection(int connection_id,
37 scoped_refptr<HidConnection> connection) {
38 hid::HidConnectInfo connection_value;
39 connection_value.connection_id = connection_id;
40 return connection_value.ToValue().release();
43 void ConvertHidDeviceFilter(linked_ptr<hid::DeviceFilter> input,
44 HidDeviceFilter* output) {
45 if (input->vendor_id) {
46 output->SetVendorId(*input->vendor_id);
48 if (input->product_id) {
49 output->SetProductId(*input->product_id);
51 if (input->usage_page) {
52 output->SetUsagePage(*input->usage_page);
54 if (input->usage) {
55 output->SetUsage(*input->usage);
59 } // namespace
61 namespace extensions {
63 HidGetDevicesFunction::HidGetDevicesFunction() {}
65 HidGetDevicesFunction::~HidGetDevicesFunction() {}
67 ExtensionFunction::ResponseAction HidGetDevicesFunction::Run() {
68 scoped_ptr<core_api::hid::GetDevices::Params> parameters =
69 hid::GetDevices::Params::Create(*args_);
70 EXTENSION_FUNCTION_VALIDATE(parameters.get());
72 HidDeviceManager* device_manager = HidDeviceManager::Get(browser_context());
73 if (!device_manager) {
74 return RespondNow(Error(kErrorServiceUnavailable));
77 std::vector<HidDeviceFilter> filters;
78 if (parameters->options.filters) {
79 filters.resize(parameters->options.filters->size());
80 for (size_t i = 0; i < parameters->options.filters->size(); ++i) {
81 ConvertHidDeviceFilter(parameters->options.filters->at(i), &filters[i]);
84 if (parameters->options.vendor_id) {
85 HidDeviceFilter legacy_filter;
86 legacy_filter.SetVendorId(*parameters->options.vendor_id);
87 if (parameters->options.product_id) {
88 legacy_filter.SetProductId(*parameters->options.product_id);
90 filters.push_back(legacy_filter);
93 device_manager->GetApiDevices(
94 extension(), filters,
95 base::Bind(&HidGetDevicesFunction::OnEnumerationComplete, this));
96 return RespondLater();
99 void HidGetDevicesFunction::OnEnumerationComplete(
100 scoped_ptr<base::ListValue> devices) {
101 Respond(OneArgument(devices.release()));
104 HidConnectFunction::HidConnectFunction() : connection_manager_(nullptr) {
107 HidConnectFunction::~HidConnectFunction() {}
109 ExtensionFunction::ResponseAction HidConnectFunction::Run() {
110 scoped_ptr<core_api::hid::Connect::Params> parameters =
111 hid::Connect::Params::Create(*args_);
112 EXTENSION_FUNCTION_VALIDATE(parameters.get());
114 HidDeviceManager* device_manager = HidDeviceManager::Get(browser_context());
115 if (!device_manager) {
116 return RespondNow(Error(kErrorServiceUnavailable));
119 connection_manager_ =
120 ApiResourceManager<HidConnectionResource>::Get(browser_context());
121 if (!connection_manager_) {
122 return RespondNow(Error(kErrorServiceUnavailable));
125 scoped_refptr<HidDeviceInfo> device_info =
126 device_manager->GetDeviceInfo(parameters->device_id);
127 if (!device_info) {
128 return RespondNow(Error(kErrorInvalidDeviceId));
131 if (!HidDeviceManager::HasPermission(extension(), device_info)) {
132 return RespondNow(Error(kErrorPermissionDenied));
135 HidService* hid_service = device::DeviceClient::Get()->GetHidService();
136 if (!hid_service) {
137 return RespondNow(Error(kErrorServiceUnavailable));
140 hid_service->Connect(
141 device_info->device_id(),
142 base::Bind(&HidConnectFunction::OnConnectComplete, this));
143 return RespondLater();
146 void HidConnectFunction::OnConnectComplete(
147 scoped_refptr<HidConnection> connection) {
148 if (!connection.get()) {
149 Respond(Error(kErrorFailedToOpenDevice));
150 return;
153 DCHECK(connection_manager_);
154 int connection_id = connection_manager_->Add(
155 new HidConnectionResource(extension_id(), connection));
156 Respond(OneArgument(PopulateHidConnection(connection_id, connection)));
159 HidDisconnectFunction::HidDisconnectFunction() {}
161 HidDisconnectFunction::~HidDisconnectFunction() {}
163 ExtensionFunction::ResponseAction HidDisconnectFunction::Run() {
164 scoped_ptr<core_api::hid::Disconnect::Params> parameters =
165 hid::Disconnect::Params::Create(*args_);
166 EXTENSION_FUNCTION_VALIDATE(parameters.get());
168 ApiResourceManager<HidConnectionResource>* connection_manager =
169 ApiResourceManager<HidConnectionResource>::Get(browser_context());
170 if (!connection_manager) {
171 return RespondNow(Error(kErrorServiceUnavailable));
174 int connection_id = parameters->connection_id;
175 HidConnectionResource* resource =
176 connection_manager->Get(extension_id(), connection_id);
177 if (!resource) {
178 return RespondNow(Error(kErrorConnectionNotFound));
181 connection_manager->Remove(extension_id(), connection_id);
182 return RespondNow(NoArguments());
185 HidConnectionIoFunction::HidConnectionIoFunction() {
188 HidConnectionIoFunction::~HidConnectionIoFunction() {
191 ExtensionFunction::ResponseAction HidConnectionIoFunction::Run() {
192 if (!ValidateParameters()) {
193 return RespondNow(Error(error_));
196 ApiResourceManager<HidConnectionResource>* connection_manager =
197 ApiResourceManager<HidConnectionResource>::Get(browser_context());
198 if (!connection_manager) {
199 return RespondNow(Error(kErrorServiceUnavailable));
202 HidConnectionResource* resource =
203 connection_manager->Get(extension_id(), connection_id_);
204 if (!resource) {
205 return RespondNow(Error(kErrorConnectionNotFound));
208 StartWork(resource->connection().get());
209 return RespondLater();
212 HidReceiveFunction::HidReceiveFunction() {}
214 HidReceiveFunction::~HidReceiveFunction() {}
216 bool HidReceiveFunction::ValidateParameters() {
217 parameters_ = hid::Receive::Params::Create(*args_);
218 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
219 set_connection_id(parameters_->connection_id);
220 return true;
223 void HidReceiveFunction::StartWork(HidConnection* connection) {
224 connection->Read(base::Bind(&HidReceiveFunction::OnFinished, this));
227 void HidReceiveFunction::OnFinished(bool success,
228 scoped_refptr<net::IOBuffer> buffer,
229 size_t size) {
230 if (success) {
231 DCHECK_GE(size, 1u);
232 int report_id = reinterpret_cast<uint8_t*>(buffer->data())[0];
234 Respond(TwoArguments(new base::FundamentalValue(report_id),
235 base::BinaryValue::CreateWithCopiedBuffer(
236 buffer->data() + 1, size - 1)));
237 } else {
238 Respond(Error(kErrorTransfer));
242 HidSendFunction::HidSendFunction() {}
244 HidSendFunction::~HidSendFunction() {}
246 bool HidSendFunction::ValidateParameters() {
247 parameters_ = hid::Send::Params::Create(*args_);
248 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
249 set_connection_id(parameters_->connection_id);
250 return true;
253 void HidSendFunction::StartWork(HidConnection* connection) {
254 scoped_refptr<net::IOBufferWithSize> buffer(
255 new net::IOBufferWithSize(parameters_->data.size() + 1));
256 buffer->data()[0] = static_cast<uint8_t>(parameters_->report_id);
257 memcpy(buffer->data() + 1, parameters_->data.data(),
258 parameters_->data.size());
259 connection->Write(buffer, buffer->size(),
260 base::Bind(&HidSendFunction::OnFinished, this));
263 void HidSendFunction::OnFinished(bool success) {
264 if (success) {
265 Respond(NoArguments());
266 } else {
267 Respond(Error(kErrorTransfer));
271 HidReceiveFeatureReportFunction::HidReceiveFeatureReportFunction() {}
273 HidReceiveFeatureReportFunction::~HidReceiveFeatureReportFunction() {}
275 bool HidReceiveFeatureReportFunction::ValidateParameters() {
276 parameters_ = hid::ReceiveFeatureReport::Params::Create(*args_);
277 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
278 set_connection_id(parameters_->connection_id);
279 return true;
282 void HidReceiveFeatureReportFunction::StartWork(HidConnection* connection) {
283 connection->GetFeatureReport(
284 static_cast<uint8_t>(parameters_->report_id),
285 base::Bind(&HidReceiveFeatureReportFunction::OnFinished, this));
288 void HidReceiveFeatureReportFunction::OnFinished(
289 bool success,
290 scoped_refptr<net::IOBuffer> buffer,
291 size_t size) {
292 if (success) {
293 Respond(OneArgument(
294 base::BinaryValue::CreateWithCopiedBuffer(buffer->data(), size)));
295 } else {
296 Respond(Error(kErrorTransfer));
300 HidSendFeatureReportFunction::HidSendFeatureReportFunction() {}
302 HidSendFeatureReportFunction::~HidSendFeatureReportFunction() {}
304 bool HidSendFeatureReportFunction::ValidateParameters() {
305 parameters_ = hid::SendFeatureReport::Params::Create(*args_);
306 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
307 set_connection_id(parameters_->connection_id);
308 return true;
311 void HidSendFeatureReportFunction::StartWork(HidConnection* connection) {
312 scoped_refptr<net::IOBufferWithSize> buffer(
313 new net::IOBufferWithSize(parameters_->data.size() + 1));
314 buffer->data()[0] = static_cast<uint8_t>(parameters_->report_id);
315 memcpy(buffer->data() + 1, vector_as_array(&parameters_->data),
316 parameters_->data.size());
317 connection->SendFeatureReport(
318 buffer, buffer->size(),
319 base::Bind(&HidSendFeatureReportFunction::OnFinished, this));
322 void HidSendFeatureReportFunction::OnFinished(bool success) {
323 if (success) {
324 Respond(NoArguments());
325 } else {
326 Respond(Error(kErrorTransfer));
330 } // namespace extensions