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"
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::core_api::hid
;
24 using device::HidConnection
;
25 using device::HidDeviceFilter
;
26 using device::HidDeviceInfo
;
27 using device::HidService
;
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
);
56 output
->SetUsage(*input
->usage
);
62 namespace extensions
{
64 HidGetDevicesFunction::HidGetDevicesFunction() {}
66 HidGetDevicesFunction::~HidGetDevicesFunction() {}
68 ExtensionFunction::ResponseAction
HidGetDevicesFunction::Run() {
69 scoped_ptr
<core_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(
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
<core_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
]);
133 ExtensionsAPIClient::Get()->CreateDevicePermissionsPrompt(web_contents
);
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
<core_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
);
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();
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
) {
187 Respond(Error(kErrorFailedToOpenDevice
));
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
<core_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
);
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_
);
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
);
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
,
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)));
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
);
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
) {
299 Respond(NoArguments());
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
);
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(
324 scoped_refptr
<net::IOBuffer
> buffer
,
328 base::BinaryValue::CreateWithCopiedBuffer(buffer
->data(), size
)));
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
);
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(¶meters_
->data
),
350 parameters_
->data
.size());
351 connection
->SendFeatureReport(
352 buffer
, buffer
->size(),
353 base::Bind(&HidSendFeatureReportFunction::OnFinished
, this));
356 void HidSendFeatureReportFunction::OnFinished(bool success
) {
358 Respond(NoArguments());
360 Respond(Error(kErrorTransfer
));
364 } // namespace extensions