• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <stdarg.h>
8 #include <string>
9 #include <vector>
10 
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/file_util.h"
14 #include "base/files/file_path.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/process/kill.h"
18 #include "base/process/launch.h"
19 #include "base/process/process_handle.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/sys_info.h"
23 #include "base/task_runner.h"
24 #include "base/threading/sequenced_worker_pool.h"
25 #include "chrome/browser/browser_process.h"
26 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
27 #include "chrome/browser/policy/browser_policy_connector.h"
28 #include "chrome/common/pref_names.h"
29 #include "chromeos/system/statistics_provider.h"
30 #include "content/public/browser/browser_thread.h"
31 
32 namespace chromeos {
33 namespace system {
34 
35 namespace {
36 
37 const char kTpControl[] = "/opt/google/touchpad/tpcontrol";
38 const char kMouseControl[] = "/opt/google/mouse/mousecontrol";
39 
40 const char kRemoraRequisition[] = "remora";
41 
42 typedef base::RefCountedData<bool> RefCountedBool;
43 
ScriptExists(const std::string & script)44 bool ScriptExists(const std::string& script) {
45   DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
46   return base::PathExists(base::FilePath(script));
47 }
48 
49 // Executes the input control script asynchronously, if it exists.
ExecuteScriptOnFileThread(const std::vector<std::string> & argv)50 void ExecuteScriptOnFileThread(const std::vector<std::string>& argv) {
51   DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
52   DCHECK(!argv.empty());
53   const std::string& script(argv[0]);
54 
55   // Script must exist on device.
56   DCHECK(!base::SysInfo::IsRunningOnChromeOS() || ScriptExists(script));
57 
58   if (!ScriptExists(script))
59     return;
60 
61   base::ProcessHandle handle;
62   base::LaunchProcess(CommandLine(argv), base::LaunchOptions(), &handle);
63   base::EnsureProcessGetsReaped(handle);
64 }
65 
ExecuteScript(int argc,...)66 void ExecuteScript(int argc, ...) {
67   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
68   std::vector<std::string> argv;
69   va_list vl;
70   va_start(vl, argc);
71   for (int i = 0; i < argc; ++i) {
72     argv.push_back(va_arg(vl, const char*));
73   }
74   va_end(vl);
75 
76   // Control scripts can take long enough to cause SIGART during shutdown
77   // (http://crbug.com/261426). Run the blocking pool task with
78   // CONTINUE_ON_SHUTDOWN so it won't be joined when Chrome shuts down.
79   base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
80   scoped_refptr<base::TaskRunner> runner =
81       pool->GetTaskRunnerWithShutdownBehavior(
82           base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
83   runner->PostTask(FROM_HERE, base::Bind(&ExecuteScriptOnFileThread, argv));
84 }
85 
SetPointerSensitivity(const char * script,int value)86 void SetPointerSensitivity(const char* script, int value) {
87   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
88   DCHECK(value >= kMinPointerSensitivity && value <= kMaxPointerSensitivity);
89   ExecuteScript(
90       3, script, "sensitivity", base::StringPrintf("%d", value).c_str());
91 }
92 
SetTPControl(const char * control,bool enabled)93 void SetTPControl(const char* control, bool enabled) {
94   ExecuteScript(3, kTpControl, control, enabled ? "on" : "off");
95 }
96 
DeviceExistsBlockingPool(const char * script,scoped_refptr<RefCountedBool> exists)97 void DeviceExistsBlockingPool(const char* script,
98                               scoped_refptr<RefCountedBool> exists) {
99   DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
100   exists->data = false;
101   if (!ScriptExists(script))
102     return;
103 
104   std::vector<std::string> argv;
105   argv.push_back(script);
106   argv.push_back("status");
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:" << script << "=" << exists->data;
112 }
113 
RunCallbackUIThread(scoped_refptr<RefCountedBool> exists,const DeviceExistsCallback & callback)114 void RunCallbackUIThread(scoped_refptr<RefCountedBool> exists,
115                          const DeviceExistsCallback& callback) {
116   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
117   DVLOG(1) << "RunCallbackUIThread " << exists->data;
118   callback.Run(exists->data);
119 }
120 
DeviceExists(const char * script,const DeviceExistsCallback & callback)121 void DeviceExists(const char* script, const DeviceExistsCallback& callback) {
122   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
123 
124   // One or both of the control scripts can apparently hang during shutdown
125   // (http://crbug.com/255546). Run the blocking pool task with
126   // CONTINUE_ON_SHUTDOWN so it won't be joined when Chrome shuts down.
127   scoped_refptr<RefCountedBool> exists(new RefCountedBool(false));
128   base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
129   scoped_refptr<base::TaskRunner> runner =
130       pool->GetTaskRunnerWithShutdownBehavior(
131           base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
132   runner->PostTaskAndReply(FROM_HERE,
133       base::Bind(&DeviceExistsBlockingPool, script, exists),
134       base::Bind(&RunCallbackUIThread, exists, callback));
135 }
136 
137 }  // namespace
138 
139 namespace touchpad_settings {
140 
TouchpadExists(const DeviceExistsCallback & callback)141 void TouchpadExists(const DeviceExistsCallback& callback) {
142   DeviceExists(kTpControl, callback);
143 }
144 
145 // Sets the touchpad sensitivity in the range [1, 5].
SetSensitivity(int value)146 void SetSensitivity(int value) {
147   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
148   SetPointerSensitivity(kTpControl, value);
149 }
150 
SetTapToClick(bool enabled)151 void SetTapToClick(bool enabled) {
152   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
153   SetTPControl("taptoclick", enabled);
154 }
155 
SetThreeFingerClick(bool enabled)156 void SetThreeFingerClick(bool enabled) {
157   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
158 
159   // For Alex/ZGB.
160   SetTPControl("t5r2_three_finger_click", enabled);
161 }
162 
SetTapDragging(bool enabled)163 void SetTapDragging(bool enabled) {
164   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
165   SetTPControl("tap_dragging", enabled);
166 }
167 
168 }  // namespace touchpad_settings
169 
170 namespace mouse_settings {
171 
MouseExists(const DeviceExistsCallback & callback)172 void MouseExists(const DeviceExistsCallback& callback) {
173   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
174   DeviceExists(kMouseControl, callback);
175 }
176 
177 // Sets the touchpad sensitivity in the range [1, 5].
SetSensitivity(int value)178 void SetSensitivity(int value) {
179   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
180   SetPointerSensitivity(kMouseControl, value);
181 }
182 
SetPrimaryButtonRight(bool right)183 void SetPrimaryButtonRight(bool right) {
184   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
185   ExecuteScript(3, kMouseControl, "swap_left_right", right ? "1" : "0");
186 }
187 
188 }  // namespace mouse_settings
189 
190 namespace keyboard_settings {
191 
ForceKeyboardDrivenUINavigation()192 bool ForceKeyboardDrivenUINavigation() {
193   policy::BrowserPolicyConnector* connector =
194       g_browser_process->browser_policy_connector();
195   if (!connector)
196     return false;
197 
198   policy::DeviceCloudPolicyManagerChromeOS* policy_manager =
199       connector->GetDeviceCloudPolicyManager();
200   if (!policy_manager)
201     return false;
202 
203   if (base::strcasecmp(policy_manager->GetDeviceRequisition().c_str(),
204                        kRemoraRequisition) == 0) {
205     return true;
206   }
207 
208   bool keyboard_driven = false;
209   if (chromeos::system::StatisticsProvider::GetInstance()->GetMachineFlag(
210       kOemKeyboardDrivenOobeKey, &keyboard_driven)) {
211     return keyboard_driven;
212   }
213 
214   return false;
215 }
216 
217 }  // namespace keyboard_settings
218 
219 }  // namespace system
220 }  // namespace chromeos
221