f4098659bac9ed697efe1b600dbc0b42e5a16070
[platform/framework/web/crosswalk.git] / src / extensions / browser / api / hid / hid_api.cc
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.
4
5 #include "extensions/browser/api/hid/hid_api.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "device/hid/hid_connection.h"
11 #include "device/hid/hid_device_info.h"
12 #include "device/hid/hid_service.h"
13 #include "extensions/browser/api/api_resource_manager.h"
14 #include "extensions/browser/api/extensions_api_client.h"
15 #include "extensions/common/api/hid.h"
16 #include "extensions/common/permissions/permissions_data.h"
17 #include "extensions/common/permissions/usb_device_permission.h"
18 #include "net/base/io_buffer.h"
19
20 namespace hid = extensions::core_api::hid;
21
22 using device::HidConnection;
23 using device::HidDeviceInfo;
24 using device::HidService;
25
26 namespace {
27
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.";
33
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();
39 }
40
41 }  // namespace
42
43 namespace extensions {
44
45 HidAsyncApiFunction::HidAsyncApiFunction()
46     : device_manager_(NULL), connection_manager_(NULL) {}
47
48 HidAsyncApiFunction::~HidAsyncApiFunction() {}
49
50 bool HidAsyncApiFunction::PrePrepare() {
51   device_manager_ = HidDeviceManager::Get(browser_context());
52   DCHECK(device_manager_);
53   connection_manager_ =
54       ApiResourceManager<HidConnectionResource>::Get(browser_context());
55   DCHECK(connection_manager_);
56   set_work_thread_id(content::BrowserThread::FILE);
57   return true;
58 }
59
60 bool HidAsyncApiFunction::Respond() { return error_.empty(); }
61
62 HidConnectionResource* HidAsyncApiFunction::GetHidConnectionResource(
63     int api_resource_id) {
64   return connection_manager_->Get(extension_->id(), api_resource_id);
65 }
66
67 void HidAsyncApiFunction::RemoveHidConnectionResource(int api_resource_id) {
68   connection_manager_->Remove(extension_->id(), api_resource_id);
69 }
70
71 void HidAsyncApiFunction::CompleteWithError(const std::string& error) {
72   SetError(error);
73   AsyncWorkCompleted();
74 }
75
76 HidGetDevicesFunction::HidGetDevicesFunction() {}
77
78 HidGetDevicesFunction::~HidGetDevicesFunction() {}
79
80 bool HidGetDevicesFunction::Prepare() {
81   parameters_ = hid::GetDevices::Params::Create(*args_);
82   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
83   return true;
84 }
85
86 void HidGetDevicesFunction::AsyncWorkStart() {
87   const uint16_t vendor_id = parameters_->options.vendor_id;
88   const uint16_t product_id = parameters_->options.product_id;
89   UsbDevicePermission::CheckParam param(
90       vendor_id, product_id, UsbDevicePermissionData::UNSPECIFIED_INTERFACE);
91   if (!extension()->permissions_data()->CheckAPIPermissionWithParam(
92           APIPermission::kUsbDevice, &param)) {
93     LOG(WARNING) << "Insufficient permissions to access device.";
94     CompleteWithError(kErrorPermissionDenied);
95     return;
96   }
97
98   SetResult(device_manager_->GetApiDevices(vendor_id, product_id).release());
99   AsyncWorkCompleted();
100 }
101
102 HidConnectFunction::HidConnectFunction() {}
103
104 HidConnectFunction::~HidConnectFunction() {}
105
106 bool HidConnectFunction::Prepare() {
107   parameters_ = hid::Connect::Params::Create(*args_);
108   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
109   return true;
110 }
111
112 void HidConnectFunction::AsyncWorkStart() {
113   device::HidDeviceInfo device_info;
114   if (!device_manager_->GetDeviceInfo(parameters_->device_id, &device_info)) {
115     CompleteWithError(kErrorInvalidDeviceId);
116     return;
117   }
118
119   UsbDevicePermission::CheckParam param(
120       device_info.vendor_id,
121       device_info.product_id,
122       UsbDevicePermissionData::UNSPECIFIED_INTERFACE);
123   if (!extension()->permissions_data()->CheckAPIPermissionWithParam(
124           APIPermission::kUsbDevice, &param)) {
125     LOG(WARNING) << "Insufficient permissions to access device.";
126     CompleteWithError(kErrorPermissionDenied);
127     return;
128   }
129
130   HidService* hid_service = ExtensionsAPIClient::Get()->GetHidService();
131   DCHECK(hid_service);
132   scoped_refptr<HidConnection> connection =
133       hid_service->Connect(device_info.device_id);
134   if (!connection) {
135     CompleteWithError(kErrorFailedToOpenDevice);
136     return;
137   }
138   int connection_id = connection_manager_->Add(
139       new HidConnectionResource(extension_->id(), connection));
140   SetResult(PopulateHidConnection(connection_id, connection));
141   AsyncWorkCompleted();
142 }
143
144 HidDisconnectFunction::HidDisconnectFunction() {}
145
146 HidDisconnectFunction::~HidDisconnectFunction() {}
147
148 bool HidDisconnectFunction::Prepare() {
149   parameters_ = hid::Disconnect::Params::Create(*args_);
150   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
151   return true;
152 }
153
154 void HidDisconnectFunction::AsyncWorkStart() {
155   int connection_id = parameters_->connection_id;
156   HidConnectionResource* resource =
157       connection_manager_->Get(extension_->id(), connection_id);
158   if (!resource) {
159     CompleteWithError(kErrorConnectionNotFound);
160     return;
161   }
162   connection_manager_->Remove(extension_->id(), connection_id);
163   AsyncWorkCompleted();
164 }
165
166 HidReceiveFunction::HidReceiveFunction() {}
167
168 HidReceiveFunction::~HidReceiveFunction() {}
169
170 bool HidReceiveFunction::Prepare() {
171   parameters_ = hid::Receive::Params::Create(*args_);
172   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
173   return true;
174 }
175
176 void HidReceiveFunction::AsyncWorkStart() {
177   int connection_id = parameters_->connection_id;
178   HidConnectionResource* resource =
179       connection_manager_->Get(extension_->id(), connection_id);
180   if (!resource) {
181     CompleteWithError(kErrorConnectionNotFound);
182     return;
183   }
184
185   scoped_refptr<device::HidConnection> connection = resource->connection();
186   has_report_id_ = connection->device_info().has_report_id;
187   int size = connection->device_info().max_input_report_size;
188   if (has_report_id_) {
189     ++size;  // One byte at the beginning of the buffer for the report ID.
190   }
191   buffer_ = new net::IOBufferWithSize(size);
192   connection->Read(buffer_, base::Bind(&HidReceiveFunction::OnFinished, this));
193 }
194
195 void HidReceiveFunction::OnFinished(bool success, size_t bytes) {
196   if (!success) {
197     CompleteWithError(kErrorTransfer);
198     return;
199   }
200
201   int report_id = 0;
202   const char* data = buffer_->data();
203   if (has_report_id_) {
204     if (bytes < 1) {
205       CompleteWithError(kErrorTransfer);
206       return;
207     }
208     report_id = data[0];
209     data++;
210     bytes--;
211   }
212
213   scoped_ptr<base::ListValue> result(new base::ListValue());
214   result->Append(new base::FundamentalValue(report_id));
215   result->Append(base::BinaryValue::CreateWithCopiedBuffer(data, bytes));
216   SetResultList(result.Pass());
217   AsyncWorkCompleted();
218 }
219
220 HidSendFunction::HidSendFunction() {}
221
222 HidSendFunction::~HidSendFunction() {}
223
224 bool HidSendFunction::Prepare() {
225   parameters_ = hid::Send::Params::Create(*args_);
226   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
227   return true;
228 }
229
230 void HidSendFunction::AsyncWorkStart() {
231   int connection_id = parameters_->connection_id;
232   HidConnectionResource* resource =
233       connection_manager_->Get(extension_->id(), connection_id);
234   if (!resource) {
235     CompleteWithError(kErrorConnectionNotFound);
236     return;
237   }
238
239   scoped_refptr<net::IOBufferWithSize> buffer(
240       new net::IOBufferWithSize(parameters_->data.size()));
241   memcpy(buffer->data(), parameters_->data.c_str(), parameters_->data.size());
242   resource->connection()->Write(static_cast<uint8_t>(parameters_->report_id),
243                                 buffer,
244                                 base::Bind(&HidSendFunction::OnFinished, this));
245 }
246
247 void HidSendFunction::OnFinished(bool success, size_t bytes) {
248   if (!success) {
249     CompleteWithError(kErrorTransfer);
250     return;
251   }
252   AsyncWorkCompleted();
253 }
254
255 HidReceiveFeatureReportFunction::HidReceiveFeatureReportFunction() {}
256
257 HidReceiveFeatureReportFunction::~HidReceiveFeatureReportFunction() {}
258
259 bool HidReceiveFeatureReportFunction::Prepare() {
260   parameters_ = hid::ReceiveFeatureReport::Params::Create(*args_);
261   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
262   return true;
263 }
264
265 void HidReceiveFeatureReportFunction::AsyncWorkStart() {
266   int connection_id = parameters_->connection_id;
267   HidConnectionResource* resource =
268       connection_manager_->Get(extension_->id(), connection_id);
269   if (!resource) {
270     CompleteWithError(kErrorConnectionNotFound);
271     return;
272   }
273
274   scoped_refptr<device::HidConnection> connection = resource->connection();
275   const int size = connection->device_info().max_feature_report_size;
276   buffer_ = new net::IOBufferWithSize(size);
277   connection->GetFeatureReport(
278       static_cast<uint8_t>(parameters_->report_id),
279       buffer_,
280       base::Bind(&HidReceiveFeatureReportFunction::OnFinished, this));
281 }
282
283 void HidReceiveFeatureReportFunction::OnFinished(bool success, size_t bytes) {
284   if (!success) {
285     CompleteWithError(kErrorTransfer);
286     return;
287   }
288
289   SetResult(base::BinaryValue::CreateWithCopiedBuffer(buffer_->data(), bytes));
290   AsyncWorkCompleted();
291 }
292
293 HidSendFeatureReportFunction::HidSendFeatureReportFunction() {}
294
295 HidSendFeatureReportFunction::~HidSendFeatureReportFunction() {}
296
297 bool HidSendFeatureReportFunction::Prepare() {
298   parameters_ = hid::SendFeatureReport::Params::Create(*args_);
299   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
300   return true;
301 }
302
303 void HidSendFeatureReportFunction::AsyncWorkStart() {
304   int connection_id = parameters_->connection_id;
305   HidConnectionResource* resource =
306       connection_manager_->Get(extension_->id(), connection_id);
307   if (!resource) {
308     CompleteWithError(kErrorConnectionNotFound);
309     return;
310   }
311   scoped_refptr<net::IOBufferWithSize> buffer(
312       new net::IOBufferWithSize(parameters_->data.size()));
313   resource->connection()->SendFeatureReport(
314       static_cast<uint8_t>(parameters_->report_id),
315       buffer,
316       base::Bind(&HidSendFeatureReportFunction::OnFinished, this));
317 }
318
319 void HidSendFeatureReportFunction::OnFinished(bool success, size_t bytes) {
320   if (!success) {
321     CompleteWithError(kErrorTransfer);
322     return;
323   }
324   AsyncWorkCompleted();
325 }
326
327 }  // namespace extensions