• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "chrome/browser/extensions/api/hid/hid_device_manager.h"
6 
7 #include <limits>
8 #include <vector>
9 
10 #include "base/lazy_instance.h"
11 #include "device/hid/hid_service.h"
12 
13 using device::HidService;
14 using device::HidUsageAndPage;
15 
16 namespace extensions {
17 
HidDeviceManager(content::BrowserContext * context)18 HidDeviceManager::HidDeviceManager(content::BrowserContext* context)
19   : next_resource_id_(0) {}
20 
~HidDeviceManager()21 HidDeviceManager::~HidDeviceManager() {}
22 
23 // static
24 BrowserContextKeyedAPIFactory<HidDeviceManager>*
GetFactoryInstance()25 HidDeviceManager::GetFactoryInstance() {
26   static base::LazyInstance<BrowserContextKeyedAPIFactory<HidDeviceManager> >
27       factory = LAZY_INSTANCE_INITIALIZER;
28   return &factory.Get();
29 }
30 
GetApiDevices(uint16_t vendor_id,uint16_t product_id)31 scoped_ptr<base::ListValue> HidDeviceManager::GetApiDevices(
32     uint16_t vendor_id,
33     uint16_t product_id) {
34   UpdateDevices();
35 
36   HidService* hid_service = HidService::GetInstance();
37   DCHECK(hid_service);
38   base::ListValue* api_devices = new base::ListValue();
39   for (ResourceIdToDeviceIdMap::const_iterator device_iter =
40            device_ids_.begin();
41        device_iter != device_ids_.end();
42        ++device_iter) {
43     int resource_id = device_iter->first;
44     device::HidDeviceId device_id = device_iter->second;
45     device::HidDeviceInfo device_info;
46     if (hid_service->GetDeviceInfo(device_id, &device_info)) {
47       if (device_info.vendor_id == vendor_id &&
48           device_info.product_id == product_id &&
49           IsDeviceAccessible(device_info)) {
50         api::hid::HidDeviceInfo api_device_info;
51         api_device_info.device_id = resource_id;
52         api_device_info.vendor_id = device_info.vendor_id;
53         api_device_info.product_id = device_info.product_id;
54         for (std::vector<device::HidUsageAndPage>::const_iterator usage_iter =
55                  device_info.usages.begin();
56              usage_iter != device_info.usages.end();
57              ++usage_iter) {
58           api::hid::HidUsageAndPage* usage_and_page =
59               new api::hid::HidUsageAndPage();
60           usage_and_page->usage_page = (*usage_iter).usage_page;
61           usage_and_page->usage = (*usage_iter).usage;
62           linked_ptr<api::hid::HidUsageAndPage> usage_and_page_ptr(
63               usage_and_page);
64           api_device_info.usages.push_back(usage_and_page_ptr);
65         }
66         api_devices->Append(api_device_info.ToValue().release());
67       }
68     }
69   }
70   return scoped_ptr<base::ListValue>(api_devices);
71 }
72 
GetDeviceInfo(int resource_id,device::HidDeviceInfo * device_info)73 bool HidDeviceManager::GetDeviceInfo(int resource_id,
74                                      device::HidDeviceInfo* device_info) {
75   UpdateDevices();
76   HidService* hid_service = HidService::GetInstance();
77   DCHECK(hid_service);
78 
79   ResourceIdToDeviceIdMap::const_iterator device_iter =
80       device_ids_.find(resource_id);
81   if (device_iter == device_ids_.end())
82     return false;
83 
84   return hid_service->GetDeviceInfo(device_iter->second, device_info);
85 }
86 
UpdateDevices()87 void HidDeviceManager::UpdateDevices() {
88   thread_checker_.CalledOnValidThread();
89   HidService* hid_service = HidService::GetInstance();
90   DCHECK(hid_service);
91 
92   std::vector<device::HidDeviceInfo> devices;
93   hid_service->GetDevices(&devices);
94 
95   // Build an updated bidi mapping between resource ID and underlying device ID.
96   DeviceIdToResourceIdMap new_resource_ids;
97   ResourceIdToDeviceIdMap new_device_ids;
98   for (std::vector<device::HidDeviceInfo>::const_iterator iter =
99            devices.begin();
100        iter != devices.end();
101        ++iter) {
102     const device::HidDeviceInfo& device_info = *iter;
103     DeviceIdToResourceIdMap::iterator resource_iter =
104         resource_ids_.find(device_info.device_id);
105     int new_id;
106     if (resource_iter != resource_ids_.end()) {
107       new_id = resource_iter->second;
108     } else {
109       DCHECK_LT(next_resource_id_, std::numeric_limits<int>::max());
110       new_id = next_resource_id_++;
111     }
112     new_resource_ids[device_info.device_id] = new_id;
113     new_device_ids[new_id] = device_info.device_id;
114   }
115   device_ids_.swap(new_device_ids);
116   resource_ids_.swap(new_resource_ids);
117 }
118 
119 // static
120 // TODO(rockot): Add some tests for this.
IsDeviceAccessible(const device::HidDeviceInfo & device_info)121 bool HidDeviceManager::IsDeviceAccessible(
122     const device::HidDeviceInfo& device_info) {
123   for (std::vector<device::HidUsageAndPage>::const_iterator iter =
124            device_info.usages.begin();
125       iter != device_info.usages.end(); ++iter) {
126     if (!IsUsageAccessible(*iter)) {
127       return false;
128     }
129   }
130   return true;
131 }
132 
133 // static
IsUsageAccessible(const HidUsageAndPage & usage_and_page)134 bool HidDeviceManager::IsUsageAccessible(
135     const HidUsageAndPage& usage_and_page) {
136   if (usage_and_page.usage_page == HidUsageAndPage::kPageKeyboard)
137     return false;
138 
139   if (usage_and_page.usage_page != HidUsageAndPage::kPageGenericDesktop)
140     return true;
141 
142   uint16_t usage = usage_and_page.usage;
143   if (usage == HidUsageAndPage::kGenericDesktopPointer ||
144       usage == HidUsageAndPage::kGenericDesktopMouse ||
145       usage == HidUsageAndPage::kGenericDesktopKeyboard ||
146       usage == HidUsageAndPage::kGenericDesktopKeypad) {
147     return false;
148   }
149 
150   if (usage >= HidUsageAndPage::kGenericDesktopSystemControl &&
151       usage <= HidUsageAndPage::kGenericDesktopSystemWarmRestart) {
152     return false;
153   }
154 
155   if (usage >= HidUsageAndPage::kGenericDesktopSystemDock &&
156       usage <= HidUsageAndPage::kGenericDesktopSystemDisplaySwap) {
157     return false;
158   }
159 
160   return true;
161 }
162 
163 }  // namespace extensions
164