Upstream version 11.39.250.0
[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/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"
18
19 namespace hid = extensions::core_api::hid;
20
21 using device::HidConnection;
22 using device::HidDeviceFilter;
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 void ConvertHidDeviceFilter(linked_ptr<hid::DeviceFilter> input,
42                             HidDeviceFilter* output) {
43   if (input->vendor_id) {
44     output->SetVendorId(*input->vendor_id);
45   }
46   if (input->product_id) {
47     output->SetProductId(*input->product_id);
48   }
49   if (input->usage_page) {
50     output->SetUsagePage(*input->usage_page);
51   }
52   if (input->usage) {
53     output->SetUsage(*input->usage);
54   }
55 }
56
57 }  // namespace
58
59 namespace extensions {
60
61 HidAsyncApiFunction::HidAsyncApiFunction()
62     : device_manager_(NULL), connection_manager_(NULL) {}
63
64 HidAsyncApiFunction::~HidAsyncApiFunction() {}
65
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   DCHECK(device_manager_);
76   connection_manager_ =
77       ApiResourceManager<HidConnectionResource>::Get(browser_context());
78   DCHECK(connection_manager_);
79   return true;
80 }
81
82 bool HidAsyncApiFunction::Respond() { return error_.empty(); }
83
84 HidConnectionResource* HidAsyncApiFunction::GetHidConnectionResource(
85     int api_resource_id) {
86   return connection_manager_->Get(extension_->id(), api_resource_id);
87 }
88
89 void HidAsyncApiFunction::RemoveHidConnectionResource(int api_resource_id) {
90   connection_manager_->Remove(extension_->id(), api_resource_id);
91 }
92
93 void HidAsyncApiFunction::CompleteWithError(const std::string& error) {
94   SetError(error);
95   AsyncWorkCompleted();
96 }
97
98 HidGetDevicesFunction::HidGetDevicesFunction() {}
99
100 HidGetDevicesFunction::~HidGetDevicesFunction() {}
101
102 bool HidGetDevicesFunction::Prepare() {
103   parameters_ = hid::GetDevices::Params::Create(*args_);
104   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
105   return true;
106 }
107
108 void HidGetDevicesFunction::AsyncWorkStart() {
109   std::vector<HidDeviceFilter> filters;
110   if (parameters_->options.filters) {
111     filters.resize(parameters_->options.filters->size());
112     for (size_t i = 0; i < parameters_->options.filters->size(); ++i) {
113       ConvertHidDeviceFilter(parameters_->options.filters->at(i), &filters[i]);
114     }
115   }
116   if (parameters_->options.vendor_id) {
117     HidDeviceFilter legacy_filter;
118     legacy_filter.SetVendorId(*parameters_->options.vendor_id);
119     if (parameters_->options.product_id) {
120       legacy_filter.SetProductId(*parameters_->options.product_id);
121     }
122     filters.push_back(legacy_filter);
123   }
124
125   SetResult(device_manager_->GetApiDevices(extension(), filters).release());
126   AsyncWorkCompleted();
127 }
128
129 HidConnectFunction::HidConnectFunction() {}
130
131 HidConnectFunction::~HidConnectFunction() {}
132
133 bool HidConnectFunction::Prepare() {
134   parameters_ = hid::Connect::Params::Create(*args_);
135   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
136   return true;
137 }
138
139 void HidConnectFunction::AsyncWorkStart() {
140   device::HidDeviceInfo device_info;
141   if (!device_manager_->GetDeviceInfo(parameters_->device_id, &device_info)) {
142     CompleteWithError(kErrorInvalidDeviceId);
143     return;
144   }
145
146   if (!device_manager_->HasPermission(extension(), device_info)) {
147     LOG(WARNING) << "Insufficient permissions to access device.";
148     CompleteWithError(kErrorPermissionDenied);
149     return;
150   }
151
152   HidService* hid_service = device::DeviceClient::Get()->GetHidService();
153   DCHECK(hid_service);
154   scoped_refptr<HidConnection> connection =
155       hid_service->Connect(device_info.device_id);
156   if (!connection.get()) {
157     CompleteWithError(kErrorFailedToOpenDevice);
158     return;
159   }
160   int connection_id = connection_manager_->Add(
161       new HidConnectionResource(extension_->id(), connection));
162   SetResult(PopulateHidConnection(connection_id, connection));
163   AsyncWorkCompleted();
164 }
165
166 HidDisconnectFunction::HidDisconnectFunction() {}
167
168 HidDisconnectFunction::~HidDisconnectFunction() {}
169
170 bool HidDisconnectFunction::Prepare() {
171   parameters_ = hid::Disconnect::Params::Create(*args_);
172   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
173   return true;
174 }
175
176 void HidDisconnectFunction::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   connection_manager_->Remove(extension_->id(), connection_id);
185   AsyncWorkCompleted();
186 }
187
188 HidReceiveFunction::HidReceiveFunction() {}
189
190 HidReceiveFunction::~HidReceiveFunction() {}
191
192 bool HidReceiveFunction::Prepare() {
193   parameters_ = hid::Receive::Params::Create(*args_);
194   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
195   return true;
196 }
197
198 void HidReceiveFunction::AsyncWorkStart() {
199   int connection_id = parameters_->connection_id;
200   HidConnectionResource* resource =
201       connection_manager_->Get(extension_->id(), connection_id);
202   if (!resource) {
203     CompleteWithError(kErrorConnectionNotFound);
204     return;
205   }
206
207   scoped_refptr<device::HidConnection> connection = resource->connection();
208   connection->Read(base::Bind(&HidReceiveFunction::OnFinished, this));
209 }
210
211 void HidReceiveFunction::OnFinished(bool success,
212                                     scoped_refptr<net::IOBuffer> buffer,
213                                     size_t size) {
214   if (!success) {
215     CompleteWithError(kErrorTransfer);
216     return;
217   }
218
219   DCHECK_GE(size, 1u);
220   int report_id = reinterpret_cast<uint8_t*>(buffer->data())[0];
221
222   scoped_ptr<base::ListValue> result(new base::ListValue());
223   result->Append(new base::FundamentalValue(report_id));
224   result->Append(
225       base::BinaryValue::CreateWithCopiedBuffer(buffer->data() + 1, size - 1));
226   SetResultList(result.Pass());
227   AsyncWorkCompleted();
228 }
229
230 HidSendFunction::HidSendFunction() {}
231
232 HidSendFunction::~HidSendFunction() {}
233
234 bool HidSendFunction::Prepare() {
235   parameters_ = hid::Send::Params::Create(*args_);
236   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
237   return true;
238 }
239
240 void HidSendFunction::AsyncWorkStart() {
241   int connection_id = parameters_->connection_id;
242   HidConnectionResource* resource =
243       connection_manager_->Get(extension_->id(), connection_id);
244   if (!resource) {
245     CompleteWithError(kErrorConnectionNotFound);
246     return;
247   }
248
249   scoped_refptr<net::IOBufferWithSize> buffer(
250       new net::IOBufferWithSize(parameters_->data.size() + 1));
251   buffer->data()[0] = static_cast<uint8_t>(parameters_->report_id);
252   memcpy(
253       buffer->data() + 1, parameters_->data.c_str(), parameters_->data.size());
254   resource->connection()->Write(
255       buffer, buffer->size(), base::Bind(&HidSendFunction::OnFinished, this));
256 }
257
258 void HidSendFunction::OnFinished(bool success) {
259   if (!success) {
260     CompleteWithError(kErrorTransfer);
261     return;
262   }
263   AsyncWorkCompleted();
264 }
265
266 HidReceiveFeatureReportFunction::HidReceiveFeatureReportFunction() {}
267
268 HidReceiveFeatureReportFunction::~HidReceiveFeatureReportFunction() {}
269
270 bool HidReceiveFeatureReportFunction::Prepare() {
271   parameters_ = hid::ReceiveFeatureReport::Params::Create(*args_);
272   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
273   return true;
274 }
275
276 void HidReceiveFeatureReportFunction::AsyncWorkStart() {
277   int connection_id = parameters_->connection_id;
278   HidConnectionResource* resource =
279       connection_manager_->Get(extension_->id(), connection_id);
280   if (!resource) {
281     CompleteWithError(kErrorConnectionNotFound);
282     return;
283   }
284
285   scoped_refptr<device::HidConnection> connection = resource->connection();
286   connection->GetFeatureReport(
287       static_cast<uint8_t>(parameters_->report_id),
288       base::Bind(&HidReceiveFeatureReportFunction::OnFinished, this));
289 }
290
291 void HidReceiveFeatureReportFunction::OnFinished(
292     bool success,
293     scoped_refptr<net::IOBuffer> buffer,
294     size_t size) {
295   if (!success) {
296     CompleteWithError(kErrorTransfer);
297     return;
298   }
299
300   SetResult(base::BinaryValue::CreateWithCopiedBuffer(buffer->data(), size));
301   AsyncWorkCompleted();
302 }
303
304 HidSendFeatureReportFunction::HidSendFeatureReportFunction() {}
305
306 HidSendFeatureReportFunction::~HidSendFeatureReportFunction() {}
307
308 bool HidSendFeatureReportFunction::Prepare() {
309   parameters_ = hid::SendFeatureReport::Params::Create(*args_);
310   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
311   return true;
312 }
313
314 void HidSendFeatureReportFunction::AsyncWorkStart() {
315   int connection_id = parameters_->connection_id;
316   HidConnectionResource* resource =
317       connection_manager_->Get(extension_->id(), connection_id);
318   if (!resource) {
319     CompleteWithError(kErrorConnectionNotFound);
320     return;
321   }
322
323   scoped_refptr<net::IOBufferWithSize> buffer(
324       new net::IOBufferWithSize(parameters_->data.size() + 1));
325   buffer->data()[0] = static_cast<uint8_t>(parameters_->report_id);
326   memcpy(
327       buffer->data() + 1, parameters_->data.c_str(), parameters_->data.size());
328   resource->connection()->SendFeatureReport(
329       buffer,
330       buffer->size(),
331       base::Bind(&HidSendFeatureReportFunction::OnFinished, this));
332 }
333
334 void HidSendFeatureReportFunction::OnFinished(bool success) {
335   if (!success) {
336     CompleteWithError(kErrorTransfer);
337     return;
338   }
339   AsyncWorkCompleted();
340 }
341
342 }  // namespace extensions