OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h" | 5 #include "chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h" |
6 | 6 |
7 #include "base/bind.h" | |
7 #include "base/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
8 #include "base/macros.h" | 9 #include "base/macros.h" |
10 #include "base/strings/utf_string_conversions.h" | |
11 #include "chrome/browser/chromeos/device/input_service_proxy.h" | |
ygorshenin1
2014/04/24 11:30:24
Not needed here.
merkulova
2014/04/24 12:49:46
Done.
| |
9 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" | 12 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" |
13 #include "device/bluetooth/bluetooth_adapter.h" | |
ygorshenin1
2014/04/24 11:30:24
Not needed here.
merkulova
2014/04/24 12:49:46
Done.
| |
14 #include "device/bluetooth/bluetooth_adapter_factory.h" | |
15 #include "device/bluetooth/bluetooth_device.h" | |
ygorshenin1
2014/04/24 11:30:24
Not needed here.
merkulova
2014/04/24 12:49:46
Done.
| |
10 #include "grit/chromium_strings.h" | 16 #include "grit/chromium_strings.h" |
11 #include "grit/generated_resources.h" | 17 #include "grit/generated_resources.h" |
18 #include "ui/base/l10n/l10n_util.h" | |
12 | 19 |
13 namespace { | 20 namespace { |
14 | 21 |
15 const char kJsScreenPath[] = "login.HIDDetectionScreen"; | 22 const char kJsScreenPath[] = "login.HIDDetectionScreen"; |
16 | 23 |
24 // |UpdateDeviceCallback| takes a variable length list as an argument. The | |
25 // value stored in each list element is indicated by the following constants. | |
26 const int kUpdateDeviceAddressIndex = 0; | |
27 const int kUpdateDeviceCommandIndex = 1; | |
28 const int kUpdateDeviceAuthTokenIndex = 2; | |
29 | |
30 // |UpdateDeviceCallback| provides a command value of one of the following | |
31 // constants that indicates what update it is providing to us. | |
32 const char kConnectCommand[] = "connect"; | |
33 const char kCancelCommand[] = "cancel"; | |
34 const char kAcceptCommand[] = "accept"; | |
35 const char kRejectCommand[] = "reject"; | |
36 const char kDisconnectCommand[] = "disconnect"; | |
37 const char kForgetCommand[] = "forget"; | |
38 | |
39 // |SendDeviceNotification| may include a pairing parameter whose value | |
40 // is one of the following constants instructing the UI to perform a certain | |
41 // action. | |
42 const char kStartConnecting[] = "bluetoothStartConnecting"; | |
43 const char kEnterPinCode[] = "bluetoothEnterPinCode"; | |
44 const char kEnterPasskey[] = "bluetoothEnterPasskey"; | |
45 const char kRemotePinCode[] = "bluetoothRemotePinCode"; | |
46 const char kRemotePasskey[] = "bluetoothRemotePasskey"; | |
47 const char kConfirmPasskey[] = "bluetoothConfirmPasskey"; | |
48 | |
49 // An invalid |entered| value to represent the "undefined" value. | |
50 const int kInvalidEntered = 0xFFFF; | |
51 | |
17 } // namespace | 52 } // namespace |
18 | 53 |
19 namespace chromeos { | 54 namespace chromeos { |
20 | 55 |
21 HIDDetectionScreenHandler::HIDDetectionScreenHandler() | 56 HIDDetectionScreenHandler::HIDDetectionScreenHandler() |
22 : BaseScreenHandler(kJsScreenPath), | 57 : BaseScreenHandler(kJsScreenPath), |
23 delegate_(NULL), | 58 delegate_(NULL), |
24 show_on_init_(false) { | 59 show_on_init_(false), |
60 adapter_(NULL), | |
ygorshenin1
2014/04/24 11:30:24
scoped_refptr is initialized to nullptr automatica
merkulova
2014/04/24 12:49:46
Done.
| |
61 pairing_device_passkey_(1000000), | |
ygorshenin1
2014/04/24 11:30:24
Where this field is used?
merkulova
2014/04/24 12:49:46
Removed
| |
62 pairing_device_entered_(kInvalidEntered), | |
ygorshenin1
2014/04/24 11:30:24
Where this field is used?
merkulova
2014/04/24 12:49:46
Removed
| |
63 keyboard_is_connecting_(false), | |
64 weak_ptr_factory_(this) { | |
65 pointing_device_id_.clear(); | |
66 keyboard_device_id_.clear(); | |
25 } | 67 } |
26 | 68 |
27 HIDDetectionScreenHandler::~HIDDetectionScreenHandler() { | 69 HIDDetectionScreenHandler::~HIDDetectionScreenHandler() { |
70 if (adapter_.get()) | |
71 adapter_->RemoveObserver(this); | |
72 input_service_proxy_.RemoveObserver(this); | |
28 if (delegate_) | 73 if (delegate_) |
29 delegate_->OnActorDestroyed(this); | 74 delegate_->OnActorDestroyed(this); |
30 } | 75 } |
31 | 76 |
32 void HIDDetectionScreenHandler::PrepareToShow() { | 77 void HIDDetectionScreenHandler::PrepareToShow() {} |
78 | |
79 void HIDDetectionScreenHandler::OnStartDiscoverySession( | |
80 scoped_ptr<device::BluetoothDiscoverySession> discovery_session) { | |
81 VLOG(1) << "BT Discovery session started"; | |
82 discovery_session_ = discovery_session.Pass(); | |
83 UpdateDevices(); | |
84 } | |
85 | |
86 void HIDDetectionScreenHandler::FindDevicesError() { | |
87 VLOG(1) << "Failed to start Bluetooth discovery."; | |
33 } | 88 } |
34 | 89 |
35 void HIDDetectionScreenHandler::Show() { | 90 void HIDDetectionScreenHandler::Show() { |
36 if (!page_is_ready()) { | 91 if (!page_is_ready()) { |
37 show_on_init_ = true; | 92 show_on_init_ = true; |
38 return; | 93 return; |
39 } | 94 } |
95 input_service_proxy_.AddObserver(this); | |
96 UpdateDevices(/*true*/false /*skip screen if devices present*/); | |
Nikita (slow)
2014/04/24 12:22:45
Debug code?
merkulova
2014/04/24 12:49:46
Removed
| |
40 ShowScreen(OobeUI::kScreenHIDDetection, NULL); | 97 ShowScreen(OobeUI::kScreenHIDDetection, NULL); |
41 } | 98 } |
42 | 99 |
43 void HIDDetectionScreenHandler::Hide() { | 100 void HIDDetectionScreenHandler::Hide() { |
101 if (adapter_.get()) | |
102 adapter_->RemoveObserver(this); | |
103 input_service_proxy_.RemoveObserver(this); | |
44 } | 104 } |
45 | 105 |
46 void HIDDetectionScreenHandler::SetDelegate(Delegate* delegate) { | 106 void HIDDetectionScreenHandler::SetDelegate(Delegate* delegate) { |
47 delegate_ = delegate; | 107 delegate_ = delegate; |
48 if (page_is_ready()) | 108 if (page_is_ready()) |
49 Initialize(); | 109 Initialize(); |
50 } | 110 } |
51 | 111 |
52 void HIDDetectionScreenHandler::DeclareLocalizedValues( | 112 void HIDDetectionScreenHandler::DeclareLocalizedValues( |
53 LocalizedValuesBuilder* builder) { | 113 LocalizedValuesBuilder* builder) { |
54 builder->Add("hidDetectionContinue", IDS_HID_DETECTION_CONTINUE_BUTTON); | 114 builder->Add("hidDetectionContinue", IDS_HID_DETECTION_CONTINUE_BUTTON); |
115 builder->Add("hidDetectionInvitation", IDS_HID_DETECTION_INVITATION_TEXT); | |
116 builder->Add("hidDetectionPrerequisites", | |
117 IDS_HID_DETECTION_PRECONDITION_TEXT); | |
118 builder->Add("hidDetectionMouseSearching", IDS_HID_DETECTION_SEARCHING_MOUSE); | |
119 builder->Add("hidDetectionKeyboardSearching", | |
120 IDS_HID_DETECTION_SEARCHING_KEYBOARD); | |
121 builder->Add("hidDetectionUSBMouseConnected", | |
122 IDS_HID_DETECTION_CONNECTED_USB_MOUSE); | |
123 builder->Add("hidDetectionUSBKeyboardConnected", | |
124 IDS_HID_DETECTION_CONNECTED_USB_KEYBOARD); | |
125 builder->Add("hidDetectionBTMousePaired", | |
126 IDS_HID_DETECTION_PAIRED_BLUETOOTH_MOUSE); | |
127 builder->Add("hidDetectionBTKeyboardPaired", | |
128 IDS_HID_DETECTION_PAIRED_BLUETOOTH_MOUSE); | |
129 builder->Add("hidDetectionBTEnterKey", IDS_HID_DETECTION_BLUETOOTH_ENTER_KEY); | |
55 } | 130 } |
56 | 131 |
57 void HIDDetectionScreenHandler::Initialize() { | 132 void HIDDetectionScreenHandler::Initialize() { |
58 if (!page_is_ready() || !delegate_) | 133 if (!page_is_ready() || !delegate_) |
59 return; | 134 return; |
60 | 135 |
136 device::BluetoothAdapterFactory::GetAdapter( | |
137 base::Bind(&HIDDetectionScreenHandler::InitializeAdapter, | |
138 weak_ptr_factory_.GetWeakPtr())); | |
139 | |
61 if (show_on_init_) { | 140 if (show_on_init_) { |
62 Show(); | 141 Show(); |
63 show_on_init_ = false; | 142 show_on_init_ = false; |
64 } | 143 } |
65 } | 144 } |
66 | 145 |
67 void HIDDetectionScreenHandler::RegisterMessages() { | 146 void HIDDetectionScreenHandler::RegisterMessages() { |
68 AddCallback( | 147 AddCallback( |
69 "HIDDetectionOnContinue", &HIDDetectionScreenHandler::HandleOnContinue); | 148 "HIDDetectionOnContinue", &HIDDetectionScreenHandler::HandleOnContinue); |
70 } | 149 } |
71 | 150 |
72 void HIDDetectionScreenHandler::HandleOnContinue() { | 151 void HIDDetectionScreenHandler::HandleOnContinue() { |
73 if (delegate_) | 152 if (delegate_) |
74 delegate_->OnExit(); | 153 delegate_->OnExit(); |
75 } | 154 } |
76 | 155 |
156 void HIDDetectionScreenHandler::InitializeAdapter( | |
157 scoped_refptr<device::BluetoothAdapter> adapter) { | |
158 adapter_ = adapter; | |
159 CHECK(adapter_.get()); | |
160 adapter_->SetPowered( | |
161 true, | |
162 base::Bind(&HIDDetectionScreenHandler::StartBTDiscoverySession, | |
163 weak_ptr_factory_.GetWeakPtr()), | |
164 base::Bind(&HIDDetectionScreenHandler::FindDevicesError, | |
165 weak_ptr_factory_.GetWeakPtr())); | |
166 | |
167 adapter_->AddObserver(this); | |
168 } | |
169 | |
170 void HIDDetectionScreenHandler::StartBTDiscoverySession() { | |
171 adapter_->StartDiscoverySession( | |
172 base::Bind(&HIDDetectionScreenHandler::OnStartDiscoverySession, | |
173 weak_ptr_factory_.GetWeakPtr()), | |
174 base::Bind(&HIDDetectionScreenHandler::FindDevicesError, | |
175 weak_ptr_factory_.GetWeakPtr())); | |
176 | |
177 } | |
178 | |
179 void HIDDetectionScreenHandler::RequestPinCode( | |
180 device::BluetoothDevice* device) { | |
181 VLOG(1) << "RequestPinCode id = " << device->GetDeviceID() << " name = " << | |
Nikita (slow)
2014/04/24 12:22:45
nit: More readable:
VLOG(1) << "RequestPinCode i
merkulova
2014/04/24 12:49:46
Done.
| |
182 device->GetName(); | |
183 } | |
184 | |
185 void HIDDetectionScreenHandler::RequestPasskey( | |
186 device::BluetoothDevice* device) { | |
187 VLOG(1) << "RequestPassKey id = " << device->GetDeviceID() << " name = " << | |
188 device->GetName(); | |
189 } | |
190 | |
191 void HIDDetectionScreenHandler::DisplayPinCode(device::BluetoothDevice* device, | |
192 const std::string& pincode) { | |
193 VLOG(1) << "DisplayPinCode id = " << device->GetDeviceID() << " name = " << | |
194 device->GetName(); | |
195 base::DictionaryValue params; | |
196 params.SetString("pairing", kRemotePinCode); | |
Nikita (slow)
2014/04/24 12:22:45
nit: Extract string constants into unnamed namespa
merkulova
2014/04/24 12:49:46
Done.
| |
197 params.SetString("pincode", pincode); | |
198 SendKeyboardDeviceNotification(¶ms); | |
199 } | |
200 | |
201 void HIDDetectionScreenHandler::DisplayPasskey( | |
202 device::BluetoothDevice* device, uint32 passkey) { | |
203 VLOG(1) << "DisplayPassKey id = " << device->GetDeviceID() << " name = " << | |
ygorshenin1
2014/04/24 11:30:24
Add "// TODO" comment + NOTIMPLEMENTED() to all me
merkulova
2014/04/24 12:49:46
Done.
| |
204 device->GetName(); | |
205 } | |
206 | |
207 void HIDDetectionScreenHandler::KeysEntered( | |
208 device::BluetoothDevice* device, uint32 entered) { | |
209 VLOG(1) << "Keys entered"; | |
210 } | |
211 | |
212 void HIDDetectionScreenHandler::ConfirmPasskey( | |
213 device::BluetoothDevice* device, uint32 passkey) { | |
214 VLOG(1) << "Confirm Passkey"; | |
215 } | |
216 | |
217 void HIDDetectionScreenHandler::AuthorizePairing( | |
218 device::BluetoothDevice* device) { | |
219 // There is never any circumstance where this will be called, since the | |
220 // HID detection screen handler will only be used for outgoing pairing | |
221 // requests, but play it safe. | |
222 VLOG(1) << "Authorize pairing"; | |
223 device->ConfirmPairing(); | |
224 } | |
225 | |
226 void HIDDetectionScreenHandler::DeviceAdded( | |
227 device::BluetoothAdapter* adapter, device::BluetoothDevice* device) { | |
228 VLOG(1) << "BT input device added id = " << device->GetDeviceID() << | |
229 " name = " << device->GetName(); | |
230 if (pointing_device_id_.empty() && | |
231 device->GetDeviceType() == device::BluetoothDevice::DEVICE_MOUSE) { | |
232 ConnectBTDevice(device); | |
233 } | |
234 if (keyboard_device_id_.empty() && | |
235 device->GetDeviceType() == device::BluetoothDevice::DEVICE_KEYBOARD) { | |
236 ConnectBTDevice(device); | |
237 } | |
238 } | |
239 | |
240 void HIDDetectionScreenHandler::DeviceChanged( | |
241 device::BluetoothAdapter* adapter, device::BluetoothDevice* device) { | |
242 VLOG(1) << "BT device changed id = " << device->GetDeviceID() << " name = " << | |
243 device->GetName(); | |
244 } | |
245 | |
246 void HIDDetectionScreenHandler::DeviceRemoved( | |
247 device::BluetoothAdapter* adapter, device::BluetoothDevice* device) { | |
248 VLOG(1) << "BT device removed id = " << device->GetDeviceID() << " name = " << | |
249 device->GetName(); | |
250 } | |
251 | |
252 void HIDDetectionScreenHandler::OnInputDeviceAdded( | |
253 const InputDeviceInfo& info) { | |
254 VLOG(1) << "Input device added id = " << info.id << " name = " << info.name; | |
255 // TODO(merkulova): deal with all available device types. | |
256 if (!keyboard_device_id_.empty() && !pointing_device_id_.empty()) | |
257 return; | |
258 | |
259 if (pointing_device_id_.empty() && (info.is_mouse || info.is_touchpad)) { | |
260 pointing_device_id_ = info.id; | |
261 pointing_device_name_ = info.name; | |
262 pointing_device_connect_type_ = info.type; | |
263 SendPointingDeviceNotification(); | |
264 } else if (keyboard_device_id_.empty() && info.is_keyboard) { | |
265 keyboard_device_id_ = info.id; | |
266 keyboard_device_name_ = info.name; | |
267 keyboard_device_connect_type_ = info.type; | |
268 SendKeyboardDeviceNotification(NULL); | |
269 } | |
270 } | |
271 | |
272 void HIDDetectionScreenHandler::OnInputDeviceRemoved(const std::string& id) { | |
273 if (id == keyboard_device_id_) { | |
274 keyboard_device_id_.clear(); | |
275 keyboard_device_name_.clear(); | |
276 keyboard_device_connect_type_ = InputDeviceInfo::TYPE_UNKNOWN; | |
277 SendKeyboardDeviceNotification(NULL); | |
278 UpdateDevices(); | |
279 } else if (id == pointing_device_id_) { | |
280 pointing_device_id_.clear(); | |
281 pointing_device_name_.clear(); | |
282 pointing_device_connect_type_ = InputDeviceInfo::TYPE_UNKNOWN; | |
283 SendPointingDeviceNotification(); | |
284 UpdateDevices(); | |
285 } | |
286 } | |
287 | |
288 void HIDDetectionScreenHandler::UpdateDevices(bool skipScreenIfDevicesPresent) { | |
ygorshenin1
2014/04/24 11:30:24
Use unix_hacker_style instead of camelCaseStyle fo
merkulova
2014/04/24 12:49:46
Done.
| |
289 input_service_proxy_.GetDevices( | |
290 base::Bind(&HIDDetectionScreenHandler::OnGetInputDevicesList, | |
291 base::Unretained(this), | |
292 skipScreenIfDevicesPresent)); | |
293 } | |
294 | |
295 void HIDDetectionScreenHandler::OnGetInputDevicesList( | |
296 bool skipScreenIfDevicesPresent, | |
297 const std::vector<InputDeviceInfo>& devices) { | |
298 | |
Nikita (slow)
2014/04/24 12:22:45
nit: Drop empty line.
merkulova
2014/04/24 12:49:46
Done.
| |
299 for (std::vector<InputDeviceInfo>::const_iterator it = devices.begin(); | |
300 it != devices.end() && | |
301 (pointing_device_id_.empty() || keyboard_device_id_.empty()); | |
302 it++) { | |
ygorshenin1
2014/04/24 11:30:24
nit: use ++it when |it| is an iterator.
merkulova
2014/04/24 12:49:46
Done.
| |
303 if (pointing_device_id_.empty() && (it->is_mouse || it->is_touchpad)) { | |
304 pointing_device_id_ = it->id; | |
305 pointing_device_name_ = it->name; | |
306 pointing_device_connect_type_ = it->type; | |
307 SendPointingDeviceNotification(); | |
308 } | |
309 if (keyboard_device_id_.empty() && it->is_keyboard) { | |
310 keyboard_device_id_ = it->id; | |
311 keyboard_device_name_ = it->name; | |
312 keyboard_device_connect_type_ = it->type; | |
313 SendKeyboardDeviceNotification(NULL); | |
314 } | |
315 } | |
316 if (adapter_ && | |
Nikita (slow)
2014/04/24 12:22:45
nit: Add short comment for this block.
merkulova
2014/04/24 12:49:46
Done.
| |
317 (pointing_device_id_.empty() || keyboard_device_id_.empty())) { | |
318 std::vector<device::BluetoothDevice*> bt_devices = adapter_->GetDevices(); | |
319 for (std::vector<device::BluetoothDevice*>::const_iterator it = | |
320 bt_devices.begin(); | |
321 it != bt_devices.end() && | |
322 (keyboard_device_id_.empty() || pointing_device_id_.empty()); | |
323 it++) { | |
324 if (keyboard_device_id_.empty() && | |
325 (*it)->GetDeviceType() == device::BluetoothDevice::DEVICE_KEYBOARD && | |
326 !keyboard_is_connecting_) { | |
327 keyboard_is_connecting_ = true; | |
328 ConnectBTDevice(*it); | |
329 break; | |
330 } | |
331 if (pointing_device_id_.empty() && | |
332 (*it)->GetDeviceType() == device::BluetoothDevice::DEVICE_MOUSE) { | |
333 ConnectBTDevice((*it)); | |
334 } | |
335 } | |
336 } | |
337 // Skip screen if both devices are present and skip was requested. | |
338 if (!pointing_device_id_.empty() && | |
339 !keyboard_device_id_.empty() && | |
340 skipScreenIfDevicesPresent) { | |
341 HandleOnContinue(); | |
342 } | |
343 | |
ygorshenin1
2014/04/24 11:30:24
nit: delete blank line.
merkulova
2014/04/24 12:49:46
Done.
| |
344 } | |
345 | |
346 void HIDDetectionScreenHandler::ConnectBTDevice( | |
347 device::BluetoothDevice* device) { | |
348 if (!device->IsPairable()) | |
349 return; | |
350 device->Connect(this, | |
351 base::Bind(&HIDDetectionScreenHandler::BTConnected, | |
352 weak_ptr_factory_.GetWeakPtr()), | |
353 base::Bind(&HIDDetectionScreenHandler::BTConnectError, | |
354 weak_ptr_factory_.GetWeakPtr(), | |
355 device->GetAddress())); | |
356 } | |
357 | |
358 void HIDDetectionScreenHandler::BTConnected() { | |
359 keyboard_is_connecting_ = false; | |
360 } | |
361 | |
362 void HIDDetectionScreenHandler::BTConnectError( | |
363 const std::string& address, | |
364 device::BluetoothDevice::ConnectErrorCode error_code) { | |
365 LOG(WARNING) << "BTConnectError"; | |
366 keyboard_is_connecting_ = false; | |
367 UpdateDevices(); | |
368 } | |
369 | |
370 | |
371 void HIDDetectionScreenHandler::SendPointingDeviceNotification() { | |
372 base::DictionaryValue js_properties; | |
373 if (pointing_device_id_.empty()) { | |
374 js_properties.SetBoolean("searching", true); | |
375 } else if (pointing_device_connect_type_ == InputDeviceInfo::TYPE_BLUETOOTH) { | |
376 js_properties.SetBoolean("BTPaired", true); | |
377 } else { | |
378 js_properties.SetBoolean("USBConnected", true); | |
379 } | |
380 web_ui()->CallJavascriptFunction( | |
ygorshenin1
2014/04/24 11:30:24
Use CallJS when it's possible.
merkulova
2014/04/24 12:49:46
Done.
| |
381 "login.HIDDetectionScreen.setPointingDeviceState", | |
382 js_properties); | |
383 } | |
384 | |
385 void HIDDetectionScreenHandler::SendKeyboardDeviceNotification( | |
386 base::DictionaryValue* params) { | |
387 base::DictionaryValue js_properties; | |
Nikita (slow)
2014/04/24 12:22:45
nit: Use more descriptive name like |state| instea
merkulova
2014/04/24 12:49:46
Done.
| |
388 if (params) | |
389 js_properties.MergeDictionary(params); | |
390 | |
391 if (keyboard_device_id_.empty()) { | |
392 std::string pairing; | |
393 if (!js_properties.GetString("pairing", &pairing)) { | |
394 js_properties.SetBoolean("searching", true); | |
395 } else if (js_properties.HasKey("pincode")) { | |
396 std::string device_name; | |
397 if (!js_properties.GetString("name", &device_name)) { | |
398 device_name = base::UTF16ToASCII( | |
399 l10n_util::GetStringUTF16(IDS_HID_DETECTION_DEFAULT_KEYBOARD_NAME)); | |
400 } | |
401 js_properties.SetString( | |
402 "keyboard-label", | |
403 l10n_util::GetStringFUTF16( | |
404 IDS_HID_DETECTION_BLUETOOTH_REMOTE_PIN_CODE_REQUEST, | |
405 base::ASCIIToUTF16(device_name))); | |
406 } | |
407 } else if (keyboard_device_connect_type_ == InputDeviceInfo::TYPE_BLUETOOTH) { | |
408 js_properties.SetBoolean("BTPaired", true); | |
409 } else { | |
410 js_properties.SetBoolean("USBConnected", true); | |
411 } | |
412 web_ui()->CallJavascriptFunction( | |
413 "login.HIDDetectionScreen.setKeyboardDeviceState", | |
414 js_properties); | |
415 } | |
416 | |
77 } // namespace chromeos | 417 } // namespace chromeos |
OLD | NEW |