Add testing/scripts/OWNERS
[chromium-blink-merge.git] / extensions / browser / api / hid / hid_api.cc
blobfcb8abf55951b422d4c913c158ec37cca5210fdf
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 "device/core/device_client.h"
11 #include "device/hid/hid_connection.h"
12 #include "device/hid/hid_device_filter.h"
13 #include "device/hid/hid_device_info.h"
14 #include "device/hid/hid_service.h"
15 #include "extensions/browser/api/api_resource_manager.h"
16 #include "extensions/common/api/hid.h"
17 #include "net/base/io_buffer.h"
19 namespace hid = extensions::core_api::hid;
21 using device::HidConnection;
22 using device::HidDeviceFilter;
23 using device::HidDeviceInfo;
24 using device::HidService;
26 namespace {
28 const char kErrorPermissionDenied[] = "Permission to access device was denied.";
29 const char kErrorInvalidDeviceId[] = "Invalid HID device ID.";
30 const char kErrorFailedToOpenDevice[] = "Failed to open HID device.";
31 const char kErrorConnectionNotFound[] = "Connection not established.";
32 const char kErrorTransfer[] = "Transfer failed.";
34 base::Value* PopulateHidConnection(int connection_id,
35 scoped_refptr<HidConnection> connection) {
36 hid::HidConnectInfo connection_value;
37 connection_value.connection_id = connection_id;
38 return connection_value.ToValue().release();
41 void ConvertHidDeviceFilter(linked_ptr<hid::DeviceFilter> input,
42 HidDeviceFilter* output) {
43 if (input->vendor_id) {
44 output->SetVendorId(*input->vendor_id);
46 if (input->product_id) {
47 output->SetProductId(*input->product_id);
49 if (input->usage_page) {
50 output->SetUsagePage(*input->usage_page);
52 if (input->usage) {
53 output->SetUsage(*input->usage);
57 } // namespace
59 namespace extensions {
61 HidAsyncApiFunction::HidAsyncApiFunction()
62 : device_manager_(NULL), connection_manager_(NULL) {}
64 HidAsyncApiFunction::~HidAsyncApiFunction() {}
66 bool HidAsyncApiFunction::PrePrepare() {
67 #if defined(OS_MACOSX)
68 // Migration from FILE thread to UI thread. OS X gets it first.
69 set_work_thread_id(content::BrowserThread::UI);
70 #else
71 // TODO(reillyg): Migrate Linux/CrOS and Windows as well.
72 set_work_thread_id(content::BrowserThread::FILE);
73 #endif
74 device_manager_ = HidDeviceManager::Get(browser_context());
75 if (!device_manager_) {
76 return false;
78 connection_manager_ =
79 ApiResourceManager<HidConnectionResource>::Get(browser_context());
80 if (!connection_manager_) {
81 return false;
83 return true;
86 bool HidAsyncApiFunction::Respond() { return error_.empty(); }
88 HidConnectionResource* HidAsyncApiFunction::GetHidConnectionResource(
89 int api_resource_id) {
90 return connection_manager_->Get(extension_->id(), api_resource_id);
93 void HidAsyncApiFunction::RemoveHidConnectionResource(int api_resource_id) {
94 connection_manager_->Remove(extension_->id(), api_resource_id);
97 void HidAsyncApiFunction::CompleteWithError(const std::string& error) {
98 SetError(error);
99 AsyncWorkCompleted();
102 HidGetDevicesFunction::HidGetDevicesFunction() {}
104 HidGetDevicesFunction::~HidGetDevicesFunction() {}
106 bool HidGetDevicesFunction::Prepare() {
107 parameters_ = hid::GetDevices::Params::Create(*args_);
108 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
109 return true;
112 void HidGetDevicesFunction::AsyncWorkStart() {
113 std::vector<HidDeviceFilter> filters;
114 if (parameters_->options.filters) {
115 filters.resize(parameters_->options.filters->size());
116 for (size_t i = 0; i < parameters_->options.filters->size(); ++i) {
117 ConvertHidDeviceFilter(parameters_->options.filters->at(i), &filters[i]);
120 if (parameters_->options.vendor_id) {
121 HidDeviceFilter legacy_filter;
122 legacy_filter.SetVendorId(*parameters_->options.vendor_id);
123 if (parameters_->options.product_id) {
124 legacy_filter.SetProductId(*parameters_->options.product_id);
126 filters.push_back(legacy_filter);
129 SetResult(device_manager_->GetApiDevices(extension(), filters).release());
130 AsyncWorkCompleted();
133 HidConnectFunction::HidConnectFunction() {}
135 HidConnectFunction::~HidConnectFunction() {}
137 bool HidConnectFunction::Prepare() {
138 parameters_ = hid::Connect::Params::Create(*args_);
139 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
140 return true;
143 void HidConnectFunction::AsyncWorkStart() {
144 HidDeviceInfo device_info;
145 if (!device_manager_->GetDeviceInfo(parameters_->device_id, &device_info)) {
146 CompleteWithError(kErrorInvalidDeviceId);
147 return;
150 if (!device_manager_->HasPermission(extension(), device_info)) {
151 LOG(WARNING) << "Insufficient permissions to access device.";
152 CompleteWithError(kErrorPermissionDenied);
153 return;
156 HidService* hid_service = device::DeviceClient::Get()->GetHidService();
157 DCHECK(hid_service);
159 hid_service->Connect(
160 device_info.device_id,
161 base::Bind(&HidConnectFunction::OnConnectComplete, this));
164 void HidConnectFunction::OnConnectComplete(
165 scoped_refptr<HidConnection> connection) {
166 if (!connection.get()) {
167 CompleteWithError(kErrorFailedToOpenDevice);
168 return;
171 int connection_id = connection_manager_->Add(
172 new HidConnectionResource(extension_->id(), connection));
173 SetResult(PopulateHidConnection(connection_id, connection));
174 AsyncWorkCompleted();
177 HidDisconnectFunction::HidDisconnectFunction() {}
179 HidDisconnectFunction::~HidDisconnectFunction() {}
181 bool HidDisconnectFunction::Prepare() {
182 parameters_ = hid::Disconnect::Params::Create(*args_);
183 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
184 return true;
187 void HidDisconnectFunction::AsyncWorkStart() {
188 int connection_id = parameters_->connection_id;
189 HidConnectionResource* resource =
190 connection_manager_->Get(extension_->id(), connection_id);
191 if (!resource) {
192 CompleteWithError(kErrorConnectionNotFound);
193 return;
195 connection_manager_->Remove(extension_->id(), connection_id);
196 AsyncWorkCompleted();
199 HidReceiveFunction::HidReceiveFunction() {}
201 HidReceiveFunction::~HidReceiveFunction() {}
203 bool HidReceiveFunction::Prepare() {
204 parameters_ = hid::Receive::Params::Create(*args_);
205 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
206 return true;
209 void HidReceiveFunction::AsyncWorkStart() {
210 int connection_id = parameters_->connection_id;
211 HidConnectionResource* resource =
212 connection_manager_->Get(extension_->id(), connection_id);
213 if (!resource) {
214 CompleteWithError(kErrorConnectionNotFound);
215 return;
218 scoped_refptr<device::HidConnection> connection = resource->connection();
219 connection->Read(base::Bind(&HidReceiveFunction::OnFinished, this));
222 void HidReceiveFunction::OnFinished(bool success,
223 scoped_refptr<net::IOBuffer> buffer,
224 size_t size) {
225 if (!success) {
226 CompleteWithError(kErrorTransfer);
227 return;
230 DCHECK_GE(size, 1u);
231 int report_id = reinterpret_cast<uint8_t*>(buffer->data())[0];
233 scoped_ptr<base::ListValue> result(new base::ListValue());
234 result->Append(new base::FundamentalValue(report_id));
235 result->Append(
236 base::BinaryValue::CreateWithCopiedBuffer(buffer->data() + 1, size - 1));
237 SetResultList(result.Pass());
238 AsyncWorkCompleted();
241 HidSendFunction::HidSendFunction() {}
243 HidSendFunction::~HidSendFunction() {}
245 bool HidSendFunction::Prepare() {
246 parameters_ = hid::Send::Params::Create(*args_);
247 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
248 return true;
251 void HidSendFunction::AsyncWorkStart() {
252 int connection_id = parameters_->connection_id;
253 HidConnectionResource* resource =
254 connection_manager_->Get(extension_->id(), connection_id);
255 if (!resource) {
256 CompleteWithError(kErrorConnectionNotFound);
257 return;
260 scoped_refptr<net::IOBufferWithSize> buffer(
261 new net::IOBufferWithSize(parameters_->data.size() + 1));
262 buffer->data()[0] = static_cast<uint8_t>(parameters_->report_id);
263 memcpy(
264 buffer->data() + 1, parameters_->data.c_str(), parameters_->data.size());
265 resource->connection()->Write(
266 buffer, buffer->size(), base::Bind(&HidSendFunction::OnFinished, this));
269 void HidSendFunction::OnFinished(bool success) {
270 if (!success) {
271 CompleteWithError(kErrorTransfer);
272 return;
274 AsyncWorkCompleted();
277 HidReceiveFeatureReportFunction::HidReceiveFeatureReportFunction() {}
279 HidReceiveFeatureReportFunction::~HidReceiveFeatureReportFunction() {}
281 bool HidReceiveFeatureReportFunction::Prepare() {
282 parameters_ = hid::ReceiveFeatureReport::Params::Create(*args_);
283 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
284 return true;
287 void HidReceiveFeatureReportFunction::AsyncWorkStart() {
288 int connection_id = parameters_->connection_id;
289 HidConnectionResource* resource =
290 connection_manager_->Get(extension_->id(), connection_id);
291 if (!resource) {
292 CompleteWithError(kErrorConnectionNotFound);
293 return;
296 scoped_refptr<device::HidConnection> connection = resource->connection();
297 connection->GetFeatureReport(
298 static_cast<uint8_t>(parameters_->report_id),
299 base::Bind(&HidReceiveFeatureReportFunction::OnFinished, this));
302 void HidReceiveFeatureReportFunction::OnFinished(
303 bool success,
304 scoped_refptr<net::IOBuffer> buffer,
305 size_t size) {
306 if (!success) {
307 CompleteWithError(kErrorTransfer);
308 return;
311 SetResult(base::BinaryValue::CreateWithCopiedBuffer(buffer->data(), size));
312 AsyncWorkCompleted();
315 HidSendFeatureReportFunction::HidSendFeatureReportFunction() {}
317 HidSendFeatureReportFunction::~HidSendFeatureReportFunction() {}
319 bool HidSendFeatureReportFunction::Prepare() {
320 parameters_ = hid::SendFeatureReport::Params::Create(*args_);
321 EXTENSION_FUNCTION_VALIDATE(parameters_.get());
322 return true;
325 void HidSendFeatureReportFunction::AsyncWorkStart() {
326 int connection_id = parameters_->connection_id;
327 HidConnectionResource* resource =
328 connection_manager_->Get(extension_->id(), connection_id);
329 if (!resource) {
330 CompleteWithError(kErrorConnectionNotFound);
331 return;
334 scoped_refptr<net::IOBufferWithSize> buffer(
335 new net::IOBufferWithSize(parameters_->data.size() + 1));
336 buffer->data()[0] = static_cast<uint8_t>(parameters_->report_id);
337 memcpy(
338 buffer->data() + 1, parameters_->data.c_str(), parameters_->data.size());
339 resource->connection()->SendFeatureReport(
340 buffer,
341 buffer->size(),
342 base::Bind(&HidSendFeatureReportFunction::OnFinished, this));
345 void HidSendFeatureReportFunction::OnFinished(bool success) {
346 if (!success) {
347 CompleteWithError(kErrorTransfer);
348 return;
350 AsyncWorkCompleted();
353 } // namespace extensions