[Android] Add partial output to TimeoutError raised in cmd_helper.
[chromium-blink-merge.git] / device / hid / input_service_linux.cc
blob81cac1a33da7364e9a4fbed161eb19b071e03116
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 "device/hid/input_service_linux.h"
7 #include "base/bind.h"
8 #include "base/lazy_instance.h"
9 #include "base/logging.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/threading/thread_restrictions.h"
13 #include "device/udev_linux/udev.h"
15 namespace device {
17 namespace {
19 const char kSubsystemHid[] = "hid";
20 const char kSubsystemInput[] = "input";
21 const char kTypeBluetooth[] = "bluetooth";
22 const char kTypeUsb[] = "usb";
23 const char kTypeSerio[] = "serio";
24 const char kIdInputAccelerometer[] = "ID_INPUT_ACCELEROMETER";
25 const char kIdInputJoystick[] = "ID_INPUT_JOYSTICK";
26 const char kIdInputKey[] = "ID_INPUT_KEY";
27 const char kIdInputKeyboard[] = "ID_INPUT_KEYBOARD";
28 const char kIdInputMouse[] = "ID_INPUT_MOUSE";
29 const char kIdInputTablet[] = "ID_INPUT_TABLET";
30 const char kIdInputTouchpad[] = "ID_INPUT_TOUCHPAD";
31 const char kIdInputTouchscreen[] = "ID_INPUT_TOUCHSCREEN";
33 // The instance will be reset when message loop destroys.
34 base::LazyInstance<scoped_ptr<InputServiceLinux> >::Leaky
35 g_input_service_linux_ptr = LAZY_INSTANCE_INITIALIZER;
37 bool GetBoolProperty(udev_device* device, const char* key) {
38 CHECK(device);
39 CHECK(key);
40 const char* property = udev_device_get_property_value(device, key);
41 if (!property)
42 return false;
43 int value;
44 if (!base::StringToInt(property, &value)) {
45 LOG(ERROR) << "Not an integer value for " << key << " property";
46 return false;
48 return (value != 0);
51 InputServiceLinux::InputDeviceInfo::Type GetDeviceType(udev_device* device) {
52 if (udev_device_get_parent_with_subsystem_devtype(
53 device, kTypeBluetooth, NULL)) {
54 return InputServiceLinux::InputDeviceInfo::TYPE_BLUETOOTH;
56 if (udev_device_get_parent_with_subsystem_devtype(device, kTypeUsb, NULL))
57 return InputServiceLinux::InputDeviceInfo::TYPE_USB;
58 if (udev_device_get_parent_with_subsystem_devtype(device, kTypeSerio, NULL))
59 return InputServiceLinux::InputDeviceInfo::TYPE_SERIO;
60 return InputServiceLinux::InputDeviceInfo::TYPE_UNKNOWN;
63 std::string GetParentDeviceName(udev_device* device, const char* subsystem) {
64 udev_device* parent =
65 udev_device_get_parent_with_subsystem_devtype(device, subsystem, NULL);
66 if (!parent)
67 return std::string();
68 const char* name = udev_device_get_property_value(parent, "NAME");
69 if (!name)
70 return std::string();
71 std::string result;
72 base::TrimString(name, "\"", &result);
73 return result;
76 class InputServiceLinuxImpl : public InputServiceLinux,
77 public DeviceMonitorLinux::Observer {
78 public:
79 // Implements DeviceMonitorLinux::Observer:
80 void OnDeviceAdded(udev_device* device) override;
81 void OnDeviceRemoved(udev_device* device) override;
83 private:
84 friend class InputServiceLinux;
86 InputServiceLinuxImpl();
87 ~InputServiceLinuxImpl() override;
89 DISALLOW_COPY_AND_ASSIGN(InputServiceLinuxImpl);
92 InputServiceLinuxImpl::InputServiceLinuxImpl() {
93 base::ThreadRestrictions::AssertIOAllowed();
94 base::MessageLoop::current()->AddDestructionObserver(this);
96 DeviceMonitorLinux::GetInstance()->AddObserver(this);
97 DeviceMonitorLinux::GetInstance()->Enumerate(base::Bind(
98 &InputServiceLinuxImpl::OnDeviceAdded, base::Unretained(this)));
101 InputServiceLinuxImpl::~InputServiceLinuxImpl() {
102 if (DeviceMonitorLinux::HasInstance())
103 DeviceMonitorLinux::GetInstance()->RemoveObserver(this);
104 base::MessageLoop::current()->RemoveDestructionObserver(this);
107 void InputServiceLinuxImpl::OnDeviceAdded(udev_device* device) {
108 DCHECK(CalledOnValidThread());
109 if (!device)
110 return;
111 const char* devnode = udev_device_get_devnode(device);
112 if (!devnode)
113 return;
115 InputDeviceInfo info;
116 info.id = devnode;
118 const char* subsystem = udev_device_get_subsystem(device);
119 if (!subsystem)
120 return;
121 if (strcmp(subsystem, kSubsystemHid) == 0) {
122 info.subsystem = InputServiceLinux::InputDeviceInfo::SUBSYSTEM_HID;
123 info.name = GetParentDeviceName(device, kSubsystemHid);
124 } else if (strcmp(subsystem, kSubsystemInput) == 0) {
125 info.subsystem = InputServiceLinux::InputDeviceInfo::SUBSYSTEM_INPUT;
126 info.name = GetParentDeviceName(device, kSubsystemInput);
127 } else {
128 return;
131 info.type = GetDeviceType(device);
133 info.is_accelerometer = GetBoolProperty(device, kIdInputAccelerometer);
134 info.is_joystick = GetBoolProperty(device, kIdInputJoystick);
135 info.is_key = GetBoolProperty(device, kIdInputKey);
136 info.is_keyboard = GetBoolProperty(device, kIdInputKeyboard);
137 info.is_mouse = GetBoolProperty(device, kIdInputMouse);
138 info.is_tablet = GetBoolProperty(device, kIdInputTablet);
139 info.is_touchpad = GetBoolProperty(device, kIdInputTouchpad);
140 info.is_touchscreen = GetBoolProperty(device, kIdInputTouchscreen);
142 AddDevice(info);
145 void InputServiceLinuxImpl::OnDeviceRemoved(udev_device* device) {
146 DCHECK(CalledOnValidThread());
147 if (!device)
148 return;
149 const char* devnode = udev_device_get_devnode(device);
150 if (devnode)
151 RemoveDevice(devnode);
154 } // namespace
156 InputServiceLinux::InputDeviceInfo::InputDeviceInfo()
157 : subsystem(SUBSYSTEM_UNKNOWN),
158 type(TYPE_UNKNOWN),
159 is_accelerometer(false),
160 is_joystick(false),
161 is_key(false),
162 is_keyboard(false),
163 is_mouse(false),
164 is_tablet(false),
165 is_touchpad(false),
166 is_touchscreen(false) {}
168 InputServiceLinux::InputServiceLinux() {
171 InputServiceLinux::~InputServiceLinux() {
172 DCHECK(CalledOnValidThread());
175 // static
176 InputServiceLinux* InputServiceLinux::GetInstance() {
177 if (!HasInstance())
178 g_input_service_linux_ptr.Get().reset(new InputServiceLinuxImpl());
179 return g_input_service_linux_ptr.Get().get();
182 // static
183 bool InputServiceLinux::HasInstance() {
184 return g_input_service_linux_ptr.Get().get();
187 // static
188 void InputServiceLinux::SetForTesting(InputServiceLinux* service) {
189 g_input_service_linux_ptr.Get().reset(service);
192 void InputServiceLinux::AddObserver(Observer* observer) {
193 DCHECK(CalledOnValidThread());
194 if (observer)
195 observers_.AddObserver(observer);
198 void InputServiceLinux::RemoveObserver(Observer* observer) {
199 DCHECK(CalledOnValidThread());
200 if (observer)
201 observers_.RemoveObserver(observer);
204 void InputServiceLinux::GetDevices(std::vector<InputDeviceInfo>* devices) {
205 DCHECK(CalledOnValidThread());
206 for (DeviceMap::iterator it = devices_.begin(), ie = devices_.end(); it != ie;
207 ++it) {
208 devices->push_back(it->second);
212 bool InputServiceLinux::GetDeviceInfo(const std::string& id,
213 InputDeviceInfo* info) const {
214 DCHECK(CalledOnValidThread());
215 DeviceMap::const_iterator it = devices_.find(id);
216 if (it == devices_.end())
217 return false;
218 *info = it->second;
219 return true;
222 void InputServiceLinux::WillDestroyCurrentMessageLoop() {
223 DCHECK(CalledOnValidThread());
224 g_input_service_linux_ptr.Get().reset(NULL);
227 void InputServiceLinux::AddDevice(const InputDeviceInfo& info) {
228 devices_[info.id] = info;
229 FOR_EACH_OBSERVER(Observer, observers_, OnInputDeviceAdded(info));
232 void InputServiceLinux::RemoveDevice(const std::string& id) {
233 devices_.erase(id);
234 FOR_EACH_OBSERVER(Observer, observers_, OnInputDeviceRemoved(id));
237 bool InputServiceLinux::CalledOnValidThread() const {
238 return thread_checker_.CalledOnValidThread();
241 } // namespace device