Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / system / input_device_settings.cc
1 // Copyright (c) 2012 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/chromeos/system/input_device_settings.h"
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/file_util.h"
10 #include "base/files/file_path.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/process/kill.h"
14 #include "base/process/launch.h"
15 #include "base/process/process_handle.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/sys_info.h"
19 #include "base/task_runner.h"
20 #include "base/threading/sequenced_worker_pool.h"
21 #include "chrome/browser/browser_process.h"
22 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
23 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
24 #include "chrome/common/pref_names.h"
25 #include "chromeos/system/statistics_provider.h"
26 #include "content/public/browser/browser_thread.h"
27
28 namespace chromeos {
29 namespace system {
30
31 namespace {
32
33 InputDeviceSettings* g_instance_;
34 InputDeviceSettings* g_test_instance_;
35
36 const char kDeviceTypeTouchpad[] = "touchpad";
37 const char kDeviceTypeMouse[] = "mouse";
38 const char kInputControl[] = "/opt/google/input/inputcontrol";
39
40 typedef base::RefCountedData<bool> RefCountedBool;
41
42 bool ScriptExists(const std::string& script) {
43   DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
44   return base::PathExists(base::FilePath(script));
45 }
46
47 // Executes the input control script asynchronously, if it exists.
48 void ExecuteScriptOnFileThread(const std::vector<std::string>& argv) {
49   DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
50   DCHECK(!argv.empty());
51   const std::string& script(argv[0]);
52
53   // Script must exist on device.
54   DCHECK(!base::SysInfo::IsRunningOnChromeOS() || ScriptExists(script));
55
56   if (!ScriptExists(script))
57     return;
58
59   base::ProcessHandle handle;
60   base::LaunchProcess(CommandLine(argv), base::LaunchOptions(), &handle);
61   base::EnsureProcessGetsReaped(handle);
62 }
63
64 void ExecuteScript(const std::vector<std::string>& argv) {
65   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
66
67   if (argv.size() == 1)
68     return;
69
70   VLOG(1) << "About to launch: \""
71           << CommandLine(argv).GetCommandLineString() << "\"";
72
73   // Control scripts can take long enough to cause SIGART during shutdown
74   // (http://crbug.com/261426). Run the blocking pool task with
75   // CONTINUE_ON_SHUTDOWN so it won't be joined when Chrome shuts down.
76   base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
77   scoped_refptr<base::TaskRunner> runner =
78       pool->GetTaskRunnerWithShutdownBehavior(
79           base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
80   runner->PostTask(FROM_HERE, base::Bind(&ExecuteScriptOnFileThread, argv));
81 }
82
83 void AddSensitivityArguments(const char* device_type, int value,
84                              std::vector<std::string>* argv) {
85   DCHECK(value >= kMinPointerSensitivity && value <= kMaxPointerSensitivity);
86   argv->push_back(base::StringPrintf("--%s_sensitivity=%d",
87                                      device_type, value));
88 }
89
90 void AddTPControlArguments(const char* control,
91                            bool enabled,
92                            std::vector<std::string>* argv) {
93   argv->push_back(base::StringPrintf("--%s=%d", control, enabled ? 1 : 0));
94 }
95
96 void DeviceExistsBlockingPool(const char* device_type,
97                               scoped_refptr<RefCountedBool> exists) {
98   DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
99   exists->data = false;
100   if (!ScriptExists(kInputControl))
101     return;
102
103   std::vector<std::string> argv;
104   argv.push_back(kInputControl);
105   argv.push_back(base::StringPrintf("--type=%s", device_type));
106   argv.push_back("--list");
107   std::string output;
108   // Output is empty if the device is not found.
109   exists->data = base::GetAppOutput(CommandLine(argv), &output) &&
110       !output.empty();
111   DVLOG(1) << "DeviceExistsBlockingPool:" << device_type << "=" << exists->data;
112 }
113
114 void RunCallbackUIThread(
115     scoped_refptr<RefCountedBool> exists,
116     const InputDeviceSettings::DeviceExistsCallback& callback) {
117   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
118   DVLOG(1) << "RunCallbackUIThread " << exists->data;
119   callback.Run(exists->data);
120 }
121
122 void DeviceExists(const char* script,
123                   const InputDeviceSettings::DeviceExistsCallback& callback) {
124   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
125
126   // One or both of the control scripts can apparently hang during shutdown
127   // (http://crbug.com/255546). Run the blocking pool task with
128   // CONTINUE_ON_SHUTDOWN so it won't be joined when Chrome shuts down.
129   scoped_refptr<RefCountedBool> exists(new RefCountedBool(false));
130   base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
131   scoped_refptr<base::TaskRunner> runner =
132       pool->GetTaskRunnerWithShutdownBehavior(
133           base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
134   runner->PostTaskAndReply(FROM_HERE,
135       base::Bind(&DeviceExistsBlockingPool, script, exists),
136       base::Bind(&RunCallbackUIThread, exists, callback));
137 }
138
139 class InputDeviceSettingsImpl : public InputDeviceSettings {
140  public:
141   InputDeviceSettingsImpl();
142
143  private:
144   // Overridden from InputDeviceSettings.
145   virtual void TouchpadExists(const DeviceExistsCallback& callback) OVERRIDE;
146   virtual void UpdateTouchpadSettings(const TouchpadSettings& settings)
147       OVERRIDE;
148   virtual void SetTouchpadSensitivity(int value) OVERRIDE;
149   virtual void SetTapToClick(bool enabled) OVERRIDE;
150   virtual void SetThreeFingerClick(bool enabled) OVERRIDE;
151   virtual void SetTapDragging(bool enabled) OVERRIDE;
152   virtual void SetNaturalScroll(bool enabled) OVERRIDE;
153   virtual void MouseExists(const DeviceExistsCallback& callback) OVERRIDE;
154   virtual void UpdateMouseSettings(const MouseSettings& update) OVERRIDE;
155   virtual void SetMouseSensitivity(int value) OVERRIDE;
156   virtual void SetPrimaryButtonRight(bool right) OVERRIDE;
157   virtual bool ForceKeyboardDrivenUINavigation() OVERRIDE;
158   virtual void ReapplyTouchpadSettings() OVERRIDE;
159   virtual void ReapplyMouseSettings() OVERRIDE;
160
161  private:
162   TouchpadSettings current_touchpad_settings_;
163   MouseSettings current_mouse_settings_;
164
165   DISALLOW_COPY_AND_ASSIGN(InputDeviceSettingsImpl);
166 };
167
168 InputDeviceSettingsImpl::InputDeviceSettingsImpl() {}
169
170 void InputDeviceSettingsImpl::TouchpadExists(
171     const DeviceExistsCallback& callback) {
172   DeviceExists(kDeviceTypeTouchpad, callback);
173 }
174
175 void InputDeviceSettingsImpl::UpdateTouchpadSettings(
176     const TouchpadSettings& settings) {
177   std::vector<std::string> argv;
178   if (current_touchpad_settings_.Update(settings, &argv))
179     ExecuteScript(argv);
180 }
181
182 void InputDeviceSettingsImpl::SetTouchpadSensitivity(int value) {
183   TouchpadSettings settings;
184   settings.SetSensitivity(value);
185   UpdateTouchpadSettings(settings);
186 }
187
188 void InputDeviceSettingsImpl::SetNaturalScroll(bool enabled) {
189   TouchpadSettings settings;
190   settings.SetNaturalScroll(enabled);
191   UpdateTouchpadSettings(settings);
192 }
193
194 void InputDeviceSettingsImpl::SetTapToClick(bool enabled) {
195   TouchpadSettings settings;
196   settings.SetTapToClick(enabled);
197   UpdateTouchpadSettings(settings);
198 }
199
200 void InputDeviceSettingsImpl::SetThreeFingerClick(bool enabled) {
201   // For Alex/ZGB.
202   TouchpadSettings settings;
203   settings.SetThreeFingerClick(enabled);
204   UpdateTouchpadSettings(settings);
205 }
206
207 void InputDeviceSettingsImpl::SetTapDragging(bool enabled) {
208   TouchpadSettings settings;
209   settings.SetTapDragging(enabled);
210   UpdateTouchpadSettings(settings);
211 }
212
213 void InputDeviceSettingsImpl::MouseExists(
214     const DeviceExistsCallback& callback) {
215   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
216   DeviceExists(kDeviceTypeMouse, callback);
217 }
218
219 void InputDeviceSettingsImpl::UpdateMouseSettings(const MouseSettings& update) {
220   std::vector<std::string> argv;
221   if (current_mouse_settings_.Update(update, &argv))
222     ExecuteScript(argv);
223 }
224
225 void InputDeviceSettingsImpl::SetMouseSensitivity(int value) {
226   MouseSettings settings;
227   settings.SetSensitivity(value);
228   UpdateMouseSettings(settings);
229 }
230
231 void InputDeviceSettingsImpl::SetPrimaryButtonRight(bool right) {
232   MouseSettings settings;
233   settings.SetPrimaryButtonRight(right);
234   UpdateMouseSettings(settings);
235 }
236
237 bool InputDeviceSettingsImpl::ForceKeyboardDrivenUINavigation() {
238   policy::BrowserPolicyConnectorChromeOS* connector =
239       g_browser_process->platform_part()->browser_policy_connector_chromeos();
240   if (!connector)
241     return false;
242
243   policy::DeviceCloudPolicyManagerChromeOS* policy_manager =
244       connector->GetDeviceCloudPolicyManager();
245   if (!policy_manager)
246     return false;
247
248   if (policy_manager->IsRemoraRequisition() ||
249       policy_manager->IsSharkRequisition()) {
250     return true;
251   }
252
253   bool keyboard_driven = false;
254   if (chromeos::system::StatisticsProvider::GetInstance()->GetMachineFlag(
255           kOemKeyboardDrivenOobeKey, &keyboard_driven)) {
256     return keyboard_driven;
257   }
258
259   return false;
260 }
261
262 void InputDeviceSettingsImpl::ReapplyTouchpadSettings() {
263   TouchpadSettings settings = current_touchpad_settings_;
264   current_touchpad_settings_ = TouchpadSettings();
265   UpdateTouchpadSettings(settings);
266 }
267
268 void InputDeviceSettingsImpl::ReapplyMouseSettings() {
269   MouseSettings settings = current_mouse_settings_;
270   current_mouse_settings_ = MouseSettings();
271   UpdateMouseSettings(settings);
272 }
273
274 }  // namespace
275
276 TouchpadSettings::TouchpadSettings() {}
277
278 TouchpadSettings& TouchpadSettings::operator=(const TouchpadSettings& other) {
279   if (&other != this) {
280     sensitivity_ = other.sensitivity_;
281     tap_to_click_ = other.tap_to_click_;
282     three_finger_click_ = other.three_finger_click_;
283     tap_dragging_ = other.tap_dragging_;
284     natural_scroll_ = other.natural_scroll_;
285   }
286   return *this;
287 }
288
289 void TouchpadSettings::SetSensitivity(int value) {
290   sensitivity_.Set(value);
291 }
292
293 int TouchpadSettings::GetSensitivity() const {
294   return sensitivity_.value();
295 }
296
297 void TouchpadSettings::SetTapToClick(bool enabled) {
298   tap_to_click_.Set(enabled);
299 }
300
301 bool TouchpadSettings::GetTapToClick() const {
302   return tap_to_click_.value();
303 }
304
305 void TouchpadSettings::SetNaturalScroll(bool enabled) {
306   natural_scroll_.Set(enabled);
307 }
308
309 bool TouchpadSettings::GetNaturalScroll() const {
310   return natural_scroll_.value();
311 }
312
313 void TouchpadSettings::SetThreeFingerClick(bool enabled) {
314   three_finger_click_.Set(enabled);
315 }
316
317 bool TouchpadSettings::GetThreeFingerClick() const {
318   return three_finger_click_.value();
319 }
320
321 void TouchpadSettings::SetTapDragging(bool enabled) {
322   tap_dragging_.Set(enabled);
323 }
324
325 bool TouchpadSettings::GetTapDragging() const {
326   return tap_dragging_.value();
327 }
328
329 bool TouchpadSettings::Update(const TouchpadSettings& settings,
330                               std::vector<std::string>* argv) {
331   if (argv)
332     argv->push_back(kInputControl);
333   bool updated = false;
334   if (sensitivity_.Update(settings.sensitivity_)) {
335     updated = true;
336     if (argv)
337       AddSensitivityArguments(kDeviceTypeTouchpad, sensitivity_.value(), argv);
338   }
339   if (tap_to_click_.Update(settings.tap_to_click_)) {
340     updated = true;
341     if (argv)
342       AddTPControlArguments("tapclick", tap_to_click_.value(), argv);
343   }
344   if (three_finger_click_.Update(settings.three_finger_click_)) {
345     updated = true;
346     if (argv)
347       AddTPControlArguments("t5r2_three_finger_click",
348                             three_finger_click_.value(),
349                             argv);
350   }
351   if (tap_dragging_.Update(settings.tap_dragging_)) {
352     updated = true;
353     if (argv)
354       AddTPControlArguments("tapdrag", tap_dragging_.value(), argv);
355   }
356   if (natural_scroll_.Update(settings.natural_scroll_)) {
357     updated = true;
358     if (argv)
359       AddTPControlArguments("australian_scrolling", natural_scroll_.value(),
360                             argv);
361   }
362   return updated;
363 }
364
365 MouseSettings::MouseSettings() {}
366
367 MouseSettings& MouseSettings::operator=(const MouseSettings& other) {
368   if (&other != this) {
369     sensitivity_ = other.sensitivity_;
370     primary_button_right_ = other.primary_button_right_;
371   }
372   return *this;
373 }
374
375 void MouseSettings::SetSensitivity(int value) {
376   sensitivity_.Set(value);
377 }
378
379 int MouseSettings::GetSensitivity() const {
380   return sensitivity_.value();
381 }
382
383 void MouseSettings::SetPrimaryButtonRight(bool right) {
384   primary_button_right_.Set(right);
385 }
386
387 bool MouseSettings::GetPrimaryButtonRight() const {
388   return primary_button_right_.value();
389 }
390
391 bool MouseSettings::Update(const MouseSettings& settings,
392                            std::vector<std::string>* argv) {
393   if (argv)
394     argv->push_back(kInputControl);
395   bool updated = false;
396   if (sensitivity_.Update(settings.sensitivity_)) {
397     updated = true;
398     if (argv)
399       AddSensitivityArguments(kDeviceTypeMouse, sensitivity_.value(), argv);
400   }
401   if (primary_button_right_.Update(settings.primary_button_right_)) {
402     updated = true;
403     if (argv) {
404       AddTPControlArguments("mouse_swap_lr", primary_button_right_.value(),
405                             argv);
406     }
407   }
408   return updated;
409 }
410
411 // static
412 InputDeviceSettings* InputDeviceSettings::Get() {
413   if (g_test_instance_)
414     return g_test_instance_;
415   if (!g_instance_)
416     g_instance_ = new InputDeviceSettingsImpl;
417   return g_instance_;
418 }
419
420 // static
421 void InputDeviceSettings::SetSettingsForTesting(
422     InputDeviceSettings* test_settings) {
423   if (g_test_instance_ == test_settings)
424     return;
425   delete g_test_instance_;
426   g_test_instance_ = test_settings;
427 }
428
429 }  // namespace system
430 }  // namespace chromeos