Add ICU message format support
[chromium-blink-merge.git] / extensions / browser / api / hid / hid_device_manager.cc
blob89a07df1ac9a80a7b58ef25dfff698d779366461
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_device_manager.h"
7 #include <limits>
8 #include <vector>
10 #include "base/lazy_instance.h"
11 #include "device/core/device_client.h"
12 #include "device/hid/hid_device_filter.h"
13 #include "device/hid/hid_service.h"
14 #include "extensions/browser/api/device_permissions_manager.h"
15 #include "extensions/common/permissions/permissions_data.h"
16 #include "extensions/common/permissions/usb_device_permission.h"
18 namespace hid = extensions::api::hid;
20 using device::HidDeviceFilter;
21 using device::HidDeviceId;
22 using device::HidDeviceInfo;
23 using device::HidService;
25 namespace extensions {
27 namespace {
29 void PopulateHidDeviceInfo(hid::HidDeviceInfo* output,
30 scoped_refptr<HidDeviceInfo> input) {
31 output->vendor_id = input->vendor_id();
32 output->product_id = input->product_id();
33 output->max_input_report_size = input->max_input_report_size();
34 output->max_output_report_size = input->max_output_report_size();
35 output->max_feature_report_size = input->max_feature_report_size();
37 for (const device::HidCollectionInfo& collection : input->collections()) {
38 // Don't expose sensitive data.
39 if (collection.usage.IsProtected()) {
40 continue;
43 hid::HidCollectionInfo* api_collection = new hid::HidCollectionInfo();
44 api_collection->usage_page = collection.usage.usage_page;
45 api_collection->usage = collection.usage.usage;
47 api_collection->report_ids.resize(collection.report_ids.size());
48 std::copy(collection.report_ids.begin(), collection.report_ids.end(),
49 api_collection->report_ids.begin());
51 output->collections.push_back(make_linked_ptr(api_collection));
54 const std::vector<uint8>& report_descriptor = input->report_descriptor();
55 if (report_descriptor.size() > 0) {
56 output->report_descriptor.assign(report_descriptor.begin(),
57 report_descriptor.end());
61 bool WillDispatchDeviceEvent(base::WeakPtr<HidDeviceManager> device_manager,
62 scoped_refptr<device::HidDeviceInfo> device_info,
63 content::BrowserContext* context,
64 const Extension* extension,
65 base::ListValue* event_args,
66 const base::DictionaryValue* listener_filter) {
67 if (device_manager && extension) {
68 return device_manager->HasPermission(extension, device_info, false);
70 return false;
73 } // namespace
75 struct HidDeviceManager::GetApiDevicesParams {
76 public:
77 GetApiDevicesParams(const Extension* extension,
78 const std::vector<HidDeviceFilter>& filters,
79 const GetApiDevicesCallback& callback)
80 : extension(extension), filters(filters), callback(callback) {}
81 ~GetApiDevicesParams() {}
83 const Extension* extension;
84 std::vector<HidDeviceFilter> filters;
85 GetApiDevicesCallback callback;
88 HidDeviceManager::HidDeviceManager(content::BrowserContext* context)
89 : browser_context_(context),
90 hid_service_observer_(this),
91 weak_factory_(this) {
92 event_router_ = EventRouter::Get(context);
93 if (event_router_) {
94 event_router_->RegisterObserver(this, hid::OnDeviceAdded::kEventName);
95 event_router_->RegisterObserver(this, hid::OnDeviceRemoved::kEventName);
99 HidDeviceManager::~HidDeviceManager() {
100 DCHECK(thread_checker_.CalledOnValidThread());
103 // static
104 BrowserContextKeyedAPIFactory<HidDeviceManager>*
105 HidDeviceManager::GetFactoryInstance() {
106 static base::LazyInstance<BrowserContextKeyedAPIFactory<HidDeviceManager> >
107 factory = LAZY_INSTANCE_INITIALIZER;
108 return &factory.Get();
111 void HidDeviceManager::GetApiDevices(
112 const Extension* extension,
113 const std::vector<HidDeviceFilter>& filters,
114 const GetApiDevicesCallback& callback) {
115 DCHECK(thread_checker_.CalledOnValidThread());
116 LazyInitialize();
118 if (enumeration_ready_) {
119 scoped_ptr<base::ListValue> devices =
120 CreateApiDeviceList(extension, filters);
121 base::MessageLoop::current()->PostTask(
122 FROM_HERE, base::Bind(callback, base::Passed(&devices)));
123 } else {
124 pending_enumerations_.push_back(
125 new GetApiDevicesParams(extension, filters, callback));
129 scoped_ptr<base::ListValue> HidDeviceManager::GetApiDevicesFromList(
130 const std::vector<scoped_refptr<HidDeviceInfo>>& devices) {
131 DCHECK(thread_checker_.CalledOnValidThread());
132 scoped_ptr<base::ListValue> device_list(new base::ListValue());
133 for (const auto& device : devices) {
134 const auto device_entry = resource_ids_.find(device->device_id());
135 DCHECK(device_entry != resource_ids_.end());
137 hid::HidDeviceInfo device_info;
138 device_info.device_id = device_entry->second;
139 PopulateHidDeviceInfo(&device_info, device);
140 device_list->Append(device_info.ToValue().release());
142 return device_list.Pass();
145 scoped_refptr<HidDeviceInfo> HidDeviceManager::GetDeviceInfo(int resource_id) {
146 DCHECK(thread_checker_.CalledOnValidThread());
147 HidService* hid_service = device::DeviceClient::Get()->GetHidService();
148 DCHECK(hid_service);
150 ResourceIdToDeviceIdMap::const_iterator device_iter =
151 device_ids_.find(resource_id);
152 if (device_iter == device_ids_.end()) {
153 return nullptr;
156 return hid_service->GetDeviceInfo(device_iter->second);
159 bool HidDeviceManager::HasPermission(const Extension* extension,
160 scoped_refptr<HidDeviceInfo> device_info,
161 bool update_last_used) {
162 DevicePermissionsManager* permissions_manager =
163 DevicePermissionsManager::Get(browser_context_);
164 CHECK(permissions_manager);
165 DevicePermissions* device_permissions =
166 permissions_manager->GetForExtension(extension->id());
167 DCHECK(device_permissions);
168 scoped_refptr<DevicePermissionEntry> permission_entry =
169 device_permissions->FindHidDeviceEntry(device_info);
170 if (permission_entry) {
171 if (update_last_used) {
172 permissions_manager->UpdateLastUsed(extension->id(), permission_entry);
174 return true;
177 UsbDevicePermission::CheckParam usbParam(
178 device_info->vendor_id(), device_info->product_id(),
179 UsbDevicePermissionData::UNSPECIFIED_INTERFACE);
180 if (extension->permissions_data()->CheckAPIPermissionWithParam(
181 APIPermission::kUsbDevice, &usbParam)) {
182 return true;
185 if (extension->permissions_data()->HasAPIPermission(
186 APIPermission::kU2fDevices)) {
187 HidDeviceFilter u2f_filter;
188 u2f_filter.SetUsagePage(0xF1D0);
189 if (u2f_filter.Matches(device_info)) {
190 return true;
194 return false;
197 void HidDeviceManager::Shutdown() {
198 if (event_router_) {
199 event_router_->UnregisterObserver(this);
203 void HidDeviceManager::OnListenerAdded(const EventListenerInfo& details) {
204 LazyInitialize();
207 void HidDeviceManager::OnDeviceAdded(scoped_refptr<HidDeviceInfo> device_info) {
208 DCHECK(thread_checker_.CalledOnValidThread());
209 DCHECK_LT(next_resource_id_, std::numeric_limits<int>::max());
210 int new_id = next_resource_id_++;
211 DCHECK(!ContainsKey(resource_ids_, device_info->device_id()));
212 resource_ids_[device_info->device_id()] = new_id;
213 device_ids_[new_id] = device_info->device_id();
215 // Don't generate events during the initial enumeration.
216 if (enumeration_ready_ && event_router_) {
217 api::hid::HidDeviceInfo api_device_info;
218 api_device_info.device_id = new_id;
219 PopulateHidDeviceInfo(&api_device_info, device_info);
221 if (api_device_info.collections.size() > 0) {
222 scoped_ptr<base::ListValue> args(
223 hid::OnDeviceAdded::Create(api_device_info));
224 DispatchEvent(events::HID_ON_DEVICE_ADDED, hid::OnDeviceAdded::kEventName,
225 args.Pass(), device_info);
230 void HidDeviceManager::OnDeviceRemoved(
231 scoped_refptr<HidDeviceInfo> device_info) {
232 DCHECK(thread_checker_.CalledOnValidThread());
233 const auto& resource_entry = resource_ids_.find(device_info->device_id());
234 DCHECK(resource_entry != resource_ids_.end());
235 int resource_id = resource_entry->second;
236 const auto& device_entry = device_ids_.find(resource_id);
237 DCHECK(device_entry != device_ids_.end());
238 resource_ids_.erase(resource_entry);
239 device_ids_.erase(device_entry);
241 if (event_router_) {
242 DCHECK(enumeration_ready_);
243 scoped_ptr<base::ListValue> args(hid::OnDeviceRemoved::Create(resource_id));
244 DispatchEvent(events::HID_ON_DEVICE_REMOVED,
245 hid::OnDeviceRemoved::kEventName, args.Pass(), device_info);
249 void HidDeviceManager::LazyInitialize() {
250 DCHECK(thread_checker_.CalledOnValidThread());
252 if (initialized_) {
253 return;
256 HidService* hid_service = device::DeviceClient::Get()->GetHidService();
257 DCHECK(hid_service);
258 hid_service->GetDevices(base::Bind(&HidDeviceManager::OnEnumerationComplete,
259 weak_factory_.GetWeakPtr()));
261 hid_service_observer_.Add(hid_service);
262 initialized_ = true;
265 scoped_ptr<base::ListValue> HidDeviceManager::CreateApiDeviceList(
266 const Extension* extension,
267 const std::vector<HidDeviceFilter>& filters) {
268 HidService* hid_service = device::DeviceClient::Get()->GetHidService();
269 DCHECK(hid_service);
271 scoped_ptr<base::ListValue> api_devices(new base::ListValue());
272 for (const ResourceIdToDeviceIdMap::value_type& map_entry : device_ids_) {
273 int resource_id = map_entry.first;
274 const HidDeviceId& device_id = map_entry.second;
276 scoped_refptr<HidDeviceInfo> device_info =
277 hid_service->GetDeviceInfo(device_id);
278 if (!device_info) {
279 continue;
282 if (!filters.empty() &&
283 !HidDeviceFilter::MatchesAny(device_info, filters)) {
284 continue;
287 if (!HasPermission(extension, device_info, false)) {
288 continue;
291 hid::HidDeviceInfo api_device_info;
292 api_device_info.device_id = resource_id;
293 PopulateHidDeviceInfo(&api_device_info, device_info);
295 // Expose devices with which user can communicate.
296 if (api_device_info.collections.size() > 0) {
297 api_devices->Append(api_device_info.ToValue().release());
301 return api_devices.Pass();
304 void HidDeviceManager::OnEnumerationComplete(
305 const std::vector<scoped_refptr<HidDeviceInfo>>& devices) {
306 DCHECK(resource_ids_.empty());
307 DCHECK(device_ids_.empty());
308 for (const scoped_refptr<HidDeviceInfo>& device_info : devices) {
309 OnDeviceAdded(device_info);
311 enumeration_ready_ = true;
313 for (const GetApiDevicesParams* params : pending_enumerations_) {
314 scoped_ptr<base::ListValue> devices =
315 CreateApiDeviceList(params->extension, params->filters);
316 params->callback.Run(devices.Pass());
318 pending_enumerations_.clear();
321 void HidDeviceManager::DispatchEvent(events::HistogramValue histogram_value,
322 const std::string& event_name,
323 scoped_ptr<base::ListValue> event_args,
324 scoped_refptr<HidDeviceInfo> device_info) {
325 scoped_ptr<Event> event(
326 new Event(histogram_value, event_name, event_args.Pass()));
327 event->will_dispatch_callback = base::Bind(
328 &WillDispatchDeviceEvent, weak_factory_.GetWeakPtr(), device_info);
329 event_router_->BroadcastEvent(event.Pass());
332 } // namespace extensions