Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / extensions / browser / api / hid / hid_api.cc
blob1d284a4a32a010fea0d5da0a85a8461e35a21e3a
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/browser/api/device_permissions_prompt.h"
18 #include "extensions/browser/api/extensions_api_client.h"
19 #include "extensions/common/api/hid.h"
20 #include "net/base/io_buffer.h"
22 namespace hid = extensions::api::hid;
24 using device::HidConnection;
25 using device::HidDeviceFilter;
26 using device::HidDeviceInfo;
27 using device::HidService;
29 namespace {
31 const char kErrorPermissionDenied[] = "Permission to access device was denied.";
32 const char kErrorInvalidDeviceId[] = "Invalid HID device ID.";
33 const char kErrorFailedToOpenDevice[] = "Failed to open HID device.";
34 const char kErrorConnectionNotFound[] = "Connection not established.";
35 const char kErrorTransfer[] = "Transfer failed.";
37 base::Value* PopulateHidConnection(int connection_id,
38 scoped_refptr<HidConnection> connection) {
39 hid::HidConnectInfo connection_value;
40 connection_value.connection_id = connection_id;
41 return connection_value.ToValue().release();
44 void ConvertHidDeviceFilter(linked_ptr<hid::DeviceFilter> input,
45 HidDeviceFilter* output) {
46 if (input->vendor_id) {
47 output->SetVendorId(*input->vendor_id);
49 if (input->product_id) {
50 output->SetProductId(*input->product_id);
52 if (input->usage_page) {
53 output->SetUsagePage(*input->usage_page);
55 if (input->usage) {
56 output->SetUsage(*input->usage);
60 } // namespace
62 namespace extensions {
64 HidGetDevicesFunction::HidGetDevicesFunction() {}
66 HidGetDevicesFunction::~HidGetDevicesFunction() {}
68 ExtensionFunction::ResponseAction HidGetDevicesFunction::Run() {
69 scoped_ptr<api::hid::GetDevices::Params> parameters =
70 hid::GetDevices::Params::Create(*args_);
71 EXTENSION_FUNCTION_VALIDATE(parameters);
73 HidDeviceManager* device_manager = HidDeviceManager::Get(browser_context());
74 CHECK(device_manager);
76 std::vector<HidDeviceFilter> filters;
77 if (parameters->options.filters) {
78 filters.resize(parameters->options.filters->size());
79 for (size_t i = 0; i < parameters->options.filters->size(); ++i) {
80 ConvertHidDeviceFilter(parameters->options.filters->at(i), &filters[i]);
83 if (parameters->options.vendor_id) {
84 HidDeviceFilter legacy_filter;
85 legacy_filter.SetVendorId(*parameters->options.vendor_id);
86 if (parameters->options.product_id) {
87 legacy_filter.SetProductId(*parameters->options.product_id);
89 filters.push_back(legacy_filter);
92 device_manager->GetApiDevices(
93 extension(), filters,
94 base::Bind(&HidGetDevicesFunction::OnEnumerationComplete, this));
95 return RespondLater();
98 void HidGetDevicesFunction::OnEnumerationComplete(
99 scoped_ptr<base::ListValue> devices) {
100 Respond(OneArgument(devices.release()));
103 HidGetUserSelectedDevicesFunction::HidGetUserSelectedDevicesFunction() {
106 HidGetUserSelectedDevicesFunction::~HidGetUserSelectedDevicesFunction() {
109 ExtensionFunction::ResponseAction HidGetUserSelectedDevicesFunction::Run() {
110 scoped_ptr<api::hid::GetUserSelectedDevices::Params> parameters =
111 hid::GetUserSelectedDevices::Params::Create(*args_);
112 EXTENSION_FUNCTION_VALIDATE(parameters);
114 content::WebContents* web_contents = GetSenderWebContents();
115 if (!web_contents || !user_gesture()) {
116 return RespondNow(OneArgument(new base::ListValue()));
119 bool multiple = false;
120 std::vector<HidDeviceFilter> filters;
121 if (parameters->options) {
122 multiple = parameters->options->multiple && *parameters->options->multiple;
123 if (parameters->options->filters) {
124 const auto& api_filters = *parameters->options->filters;
125 filters.resize(api_filters.size());
126 for (size_t i = 0; i < api_filters.size(); ++i) {
127 ConvertHidDeviceFilter(api_filters[i], &filters[i]);
132 prompt_ =
133 ExtensionsAPIClient::Get()->CreateDevicePermissionsPrompt(web_contents);
134 CHECK(prompt_);
135 prompt_->AskForHidDevices(
136 extension(), browser_context(), multiple, filters,
137 base::Bind(&HidGetUserSelectedDevicesFunction::OnDevicesChosen, this));
138 return RespondLater();
141 void HidGetUserSelectedDevicesFunction::OnDevicesChosen(
142 const std::vector<scoped_refptr<HidDeviceInfo>>& devices) {
143 HidDeviceManager* device_manager = HidDeviceManager::Get(browser_context());
144 CHECK(device_manager);
145 Respond(OneArgument(device_manager->GetApiDevicesFromList(devices).Pass()));
148 HidConnectFunction::HidConnectFunction() : connection_manager_(nullptr) {
151 HidConnectFunction::~HidConnectFunction() {}
153 ExtensionFunction::ResponseAction HidConnectFunction::Run() {
154 scoped_ptr<api::hid::Connect::Params> parameters =
155 hid::Connect::Params::Create(*args_);
156 EXTENSION_FUNCTION_VALIDATE(parameters);
158 HidDeviceManager* device_manager = HidDeviceManager::Get(browser_context());
159 CHECK(device_manager);
161 connection_manager_ =
162 ApiResourceManager<HidConnectionResource>::Get(browser_context());
163 CHECK(connection_manager_);
165 scoped_refptr<HidDeviceInfo> device_info =
166 device_manager->GetDeviceInfo(parameters->device_id);
167 if (!device_info) {
168 return RespondNow(Error(kErrorInvalidDeviceId));
171 if (!device_manager->HasPermission(extension(), device_info, true)) {
172 return RespondNow(Error(kErrorPermissionDenied));
175 HidService* hid_service = device::DeviceClient::Get()->GetHidService();
176 CHECK(hid_service);
178 hid_service->Connect(
179 device_info->device_id(),
180 base::Bind(&HidConnectFunction::OnConnectComplete, this));
181 return RespondLater();
184 void HidConnectFunction::OnConnectComplete(
185 scoped_refptr<HidConnection> connection) {
186 if (!connection) {
187 Respond(Error(kErrorFailedToOpenDevice));
188 return;
191 DCHECK(connection_manager_);
192 int connection_id = connection_manager_->Add(
193 new HidConnectionResource(extension_id(), connection));
194 Respond(OneArgument(PopulateHidConnection(connection_id, connection)));
197 HidDisconnectFunction::HidDisconnectFunction() {}
199 HidDisconnectFunction::~HidDisconnectFunction() {}
201 ExtensionFunction::ResponseAction HidDisconnectFunction::Run() {
202 scoped_ptr<api::hid::Disconnect::Params> parameters =
203 hid::Disconnect::Params::Create(*args_);
204 EXTENSION_FUNCTION_VALIDATE(parameters);
206 ApiResourceManager<HidConnectionResource>* connection_manager =
207 ApiResourceManager<HidConnectionResource>::Get(browser_context());
208 CHECK(connection_manager);
210 int connection_id = parameters->connection_id;
211 HidConnectionResource* resource =
212 connection_manager->Get(extension_id(), connection_id);
213 if (!resource) {
214 return RespondNow(Error(kErrorConnectionNotFound));
217 connection_manager->Remove(extension_id(), connection_id);
218 return RespondNow(NoArguments());
221 HidConnectionIoFunction::HidConnectionIoFunction() {
224 HidConnectionIoFunction::~HidConnectionIoFunction() {
227 ExtensionFunction::ResponseAction HidConnectionIoFunction::Run() {
228 if (!ValidateParameters()) {
229 return RespondNow(Error(error_));
232 ApiResourceManager<HidConnectionResource>* connection_manager =
233 ApiResourceManager<HidConnectionResource>::Get(browser_context());
234 CHECK(connection_manager);
236 HidConnectionResource* resource =
237 connection_manager->Get(extension_id(), connection_id_);
238 if (!resource) {
239 return RespondNow(Error(kErrorConnectionNotFound));
242 StartWork(resource->connection().get());
243 return RespondLater();
246 HidReceiveFunction::HidReceiveFunction() {}
248 HidReceiveFunction::~HidReceiveFunction() {}
250 bool HidReceiveFunction::ValidateParameters() {
251 parameters_ = hid::Receive::Params::Create(*args_);
252 EXTENSION_FUNCTION_VALIDATE(parameters_);
253 set_connection_id(parameters_->connection_id);
254 return true;
257 void HidReceiveFunction::StartWork(HidConnection* connection) {
258 connection->Read(base::Bind(&HidReceiveFunction::OnFinished, this));
261 void HidReceiveFunction::OnFinished(bool success,
262 scoped_refptr<net::IOBuffer> buffer,
263 size_t size) {
264 if (success) {
265 DCHECK_GE(size, 1u);
266 int report_id = reinterpret_cast<uint8_t*>(buffer->data())[0];
268 Respond(TwoArguments(new base::FundamentalValue(report_id),
269 base::BinaryValue::CreateWithCopiedBuffer(
270 buffer->data() + 1, size - 1)));
271 } else {
272 Respond(Error(kErrorTransfer));
276 HidSendFunction::HidSendFunction() {}
278 HidSendFunction::~HidSendFunction() {}
280 bool HidSendFunction::ValidateParameters() {
281 parameters_ = hid::Send::Params::Create(*args_);
282 EXTENSION_FUNCTION_VALIDATE(parameters_);
283 set_connection_id(parameters_->connection_id);
284 return true;
287 void HidSendFunction::StartWork(HidConnection* connection) {
288 scoped_refptr<net::IOBufferWithSize> buffer(
289 new net::IOBufferWithSize(parameters_->data.size() + 1));
290 buffer->data()[0] = static_cast<uint8_t>(parameters_->report_id);
291 memcpy(buffer->data() + 1, parameters_->data.data(),
292 parameters_->data.size());
293 connection->Write(buffer, buffer->size(),
294 base::Bind(&HidSendFunction::OnFinished, this));
297 void HidSendFunction::OnFinished(bool success) {
298 if (success) {
299 Respond(NoArguments());
300 } else {
301 Respond(Error(kErrorTransfer));
305 HidReceiveFeatureReportFunction::HidReceiveFeatureReportFunction() {}
307 HidReceiveFeatureReportFunction::~HidReceiveFeatureReportFunction() {}
309 bool HidReceiveFeatureReportFunction::ValidateParameters() {
310 parameters_ = hid::ReceiveFeatureReport::Params::Create(*args_);
311 EXTENSION_FUNCTION_VALIDATE(parameters_);
312 set_connection_id(parameters_->connection_id);
313 return true;
316 void HidReceiveFeatureReportFunction::StartWork(HidConnection* connection) {
317 connection->GetFeatureReport(
318 static_cast<uint8_t>(parameters_->report_id),
319 base::Bind(&HidReceiveFeatureReportFunction::OnFinished, this));
322 void HidReceiveFeatureReportFunction::OnFinished(
323 bool success,
324 scoped_refptr<net::IOBuffer> buffer,
325 size_t size) {
326 if (success) {
327 Respond(OneArgument(
328 base::BinaryValue::CreateWithCopiedBuffer(buffer->data(), size)));
329 } else {
330 Respond(Error(kErrorTransfer));
334 HidSendFeatureReportFunction::HidSendFeatureReportFunction() {}
336 HidSendFeatureReportFunction::~HidSendFeatureReportFunction() {}
338 bool HidSendFeatureReportFunction::ValidateParameters() {
339 parameters_ = hid::SendFeatureReport::Params::Create(*args_);
340 EXTENSION_FUNCTION_VALIDATE(parameters_);
341 set_connection_id(parameters_->connection_id);
342 return true;
345 void HidSendFeatureReportFunction::StartWork(HidConnection* connection) {
346 scoped_refptr<net::IOBufferWithSize> buffer(
347 new net::IOBufferWithSize(parameters_->data.size() + 1));
348 buffer->data()[0] = static_cast<uint8_t>(parameters_->report_id);
349 memcpy(buffer->data() + 1, vector_as_array(&parameters_->data),
350 parameters_->data.size());
351 connection->SendFeatureReport(
352 buffer, buffer->size(),
353 base::Bind(&HidSendFeatureReportFunction::OnFinished, this));
356 void HidSendFeatureReportFunction::OnFinished(bool success) {
357 if (success) {
358 Respond(NoArguments());
359 } else {
360 Respond(Error(kErrorTransfer));
364 } // namespace extensions