hid_detection_screen_handler.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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/ui/webui/chromeos/login/hid_detection_screen_handler.h"
6
7#include "base/bind.h"
8#include "base/command_line.h"
9#include "base/compiler_specific.h"
10#include "base/macros.h"
11#include "base/metrics/histogram.h"
12#include "base/prefs/pref_service.h"
13#include "base/strings/string16.h"
14#include "base/strings/string_number_conversions.h"
15#include "base/strings/utf_string_conversions.h"
16#include "chrome/browser/browser_process.h"
17#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
18#include "chrome/common/pref_names.h"
19#include "chromeos/chromeos_switches.h"
20#include "device/bluetooth/bluetooth_adapter_factory.h"
21#include "grit/generated_resources.h"
22#include "ui/base/l10n/l10n_util.h"
23
24namespace {
25
26const char kJsScreenPath[] = "login.HIDDetectionScreen";
27
28// Variants of pairing state.
29const char kRemotePinCode[] = "bluetoothRemotePinCode";
30const char kRemotePasskey[] = "bluetoothRemotePasskey";
31
32// Possible ui-states for device-blocks.
33const char kSearchingState[] = "searching";
34const char kUSBConnectedState[] = "connected";
35const char kBTPairedState[] = "paired";
36const char kBTPairingState[] = "pairing";
37// Special state for notifications that don't switch ui-state, but add info.
38const char kBTUpdateState[] = "update";
39
40// Names of possible arguments used for ui update.
41const char kPincodeArgName[] = "pincode";
42const char kDeviceNameArgName[] = "name";
43const char kLabelArgName[] = "keyboard-label";
44
45// Standard length of pincode for pairing BT keyboards.
46const int kPincodeLength = 6;
47
48bool DeviceIsPointing(device::BluetoothDevice::DeviceType device_type) {
49  return device_type == device::BluetoothDevice::DEVICE_MOUSE ||
50         device_type == device::BluetoothDevice::DEVICE_KEYBOARD_MOUSE_COMBO ||
51         device_type == device::BluetoothDevice::DEVICE_TABLET;
52}
53
54bool DeviceIsPointing(const device::InputServiceLinux::InputDeviceInfo& info) {
55  return info.is_mouse || info.is_touchpad || info.is_touchscreen ||
56         info.is_tablet;
57}
58
59bool DeviceIsKeyboard(device::BluetoothDevice::DeviceType device_type) {
60  return device_type == device::BluetoothDevice::DEVICE_KEYBOARD ||
61         device_type == device::BluetoothDevice::DEVICE_KEYBOARD_MOUSE_COMBO;
62}
63
64}  // namespace
65
66namespace chromeos {
67
68HIDDetectionScreenHandler::HIDDetectionScreenHandler(
69    CoreOobeActor* core_oobe_actor)
70    : BaseScreenHandler(kJsScreenPath),
71      delegate_(NULL),
72      core_oobe_actor_(core_oobe_actor),
73      show_on_init_(false),
74      mouse_is_pairing_(false),
75      pointing_device_connect_type_(InputDeviceInfo::TYPE_UNKNOWN),
76      keyboard_is_pairing_(false),
77      keyboard_device_connect_type_(InputDeviceInfo::TYPE_UNKNOWN),
78      switch_on_adapter_when_ready_(false),
79      weak_ptr_factory_(this) {
80}
81
82HIDDetectionScreenHandler::~HIDDetectionScreenHandler() {
83  adapter_initially_powered_.reset();
84  if (adapter_.get())
85    adapter_->RemoveObserver(this);
86  input_service_proxy_.RemoveObserver(this);
87  if (delegate_)
88    delegate_->OnActorDestroyed(this);
89}
90
91void HIDDetectionScreenHandler::OnStartDiscoverySession(
92    scoped_ptr<device::BluetoothDiscoverySession> discovery_session) {
93  VLOG(1) << "BT Discovery session started";
94  discovery_session_ = discovery_session.Pass();
95  UpdateDevices();
96}
97
98void HIDDetectionScreenHandler::SetPoweredError() {
99  LOG(ERROR) << "Failed to power BT adapter";
100}
101
102void HIDDetectionScreenHandler::SetPoweredOffError() {
103  LOG(ERROR) << "Failed to power off BT adapter";
104}
105
106void HIDDetectionScreenHandler::FindDevicesError() {
107  VLOG(1) << "Failed to start Bluetooth discovery.";
108}
109
110void HIDDetectionScreenHandler::Show() {
111  if (!page_is_ready()) {
112    show_on_init_ = true;
113    return;
114  }
115  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableDemoMode))
116    core_oobe_actor_->InitDemoModeDetection();
117  input_service_proxy_.AddObserver(this);
118  UpdateDevices();
119
120  PrefService* local_state = g_browser_process->local_state();
121  int num_of_times_dialog_was_shown = local_state->GetInteger(
122      prefs::kTimesHIDDialogShown);
123  local_state->SetInteger(prefs::kTimesHIDDialogShown,
124                          num_of_times_dialog_was_shown + 1);
125
126  ShowScreen(OobeUI::kScreenHIDDetection, NULL);
127  if (!pointing_device_id_.empty())
128    SendPointingDeviceNotification();
129  if (!keyboard_device_id_.empty())
130    SendKeyboardDeviceNotification(NULL);
131}
132
133void HIDDetectionScreenHandler::Hide() {
134  if (adapter_.get())
135    adapter_->RemoveObserver(this);
136  input_service_proxy_.RemoveObserver(this);
137}
138
139void HIDDetectionScreenHandler::SetDelegate(Delegate* delegate) {
140  delegate_ = delegate;
141  if (page_is_ready())
142    Initialize();
143}
144
145void HIDDetectionScreenHandler::CheckIsScreenRequired(
146    const base::Callback<void(bool)>& on_check_done) {
147  input_service_proxy_.GetDevices(
148      base::Bind(&HIDDetectionScreenHandler::OnGetInputDevicesListForCheck,
149                 weak_ptr_factory_.GetWeakPtr(),
150                 on_check_done));
151}
152
153void HIDDetectionScreenHandler::DeclareLocalizedValues(
154    LocalizedValuesBuilder* builder) {
155  builder->Add("hidDetectionContinue", IDS_HID_DETECTION_CONTINUE_BUTTON);
156  builder->Add("hidDetectionInvitation", IDS_HID_DETECTION_INVITATION_TEXT);
157  builder->Add("hidDetectionPrerequisites",
158      IDS_HID_DETECTION_PRECONDITION_TEXT);
159  builder->Add("hidDetectionMouseSearching", IDS_HID_DETECTION_SEARCHING_MOUSE);
160  builder->Add("hidDetectionKeyboardSearching",
161      IDS_HID_DETECTION_SEARCHING_KEYBOARD);
162  builder->Add("hidDetectionUSBMouseConnected",
163      IDS_HID_DETECTION_CONNECTED_USB_MOUSE);
164  builder->Add("hidDetectionUSBKeyboardConnected",
165      IDS_HID_DETECTION_CONNECTED_USB_KEYBOARD);
166  builder->Add("hidDetectionBTMousePaired",
167      IDS_HID_DETECTION_PAIRED_BLUETOOTH_MOUSE);
168  builder->Add("hidDetectionBTEnterKey", IDS_HID_DETECTION_BLUETOOTH_ENTER_KEY);
169}
170
171void HIDDetectionScreenHandler::Initialize() {
172  if (!page_is_ready() || !delegate_)
173    return;
174
175  device::BluetoothAdapterFactory::GetAdapter(
176      base::Bind(&HIDDetectionScreenHandler::InitializeAdapter,
177                 weak_ptr_factory_.GetWeakPtr()));
178
179  if (show_on_init_) {
180    Show();
181    show_on_init_ = false;
182  }
183}
184
185void HIDDetectionScreenHandler::RegisterMessages() {
186  AddCallback(
187      "HIDDetectionOnContinue", &HIDDetectionScreenHandler::HandleOnContinue);
188}
189
190void HIDDetectionScreenHandler::HandleOnContinue() {
191  // Continue button pressed.
192  ContinueScenarioType scenario_type;
193  if (!pointing_device_id_.empty() && !keyboard_device_id_.empty())
194    scenario_type = All_DEVICES_DETECTED;
195  else if (pointing_device_id_.empty())
196    scenario_type = KEYBOARD_DEVICE_ONLY_DETECTED;
197  else
198    scenario_type = POINTING_DEVICE_ONLY_DETECTED;
199
200  UMA_HISTOGRAM_ENUMERATION(
201      "HIDDetection.OOBEDevicesDetectedOnContinuePressed",
202      scenario_type,
203      CONTINUE_SCENARIO_TYPE_SIZE);
204
205  // Switch off BT adapter if it was off before the screen and no BT device
206  // connected.
207  if (adapter_ && adapter_->IsPresent() && adapter_->IsPowered() &&
208      !(pointing_device_connect_type_ == InputDeviceInfo::TYPE_BLUETOOTH ||
209        keyboard_device_connect_type_ == InputDeviceInfo::TYPE_BLUETOOTH) &&
210      adapter_initially_powered_ && !(*adapter_initially_powered_)) {
211    VLOG(1) << "Switching off BT adapter after HID OOBE screen as unused.";
212    adapter_->SetPowered(
213        false,
214        base::Bind(&base::DoNothing),
215        base::Bind(&HIDDetectionScreenHandler::SetPoweredOffError,
216                   weak_ptr_factory_.GetWeakPtr()));
217  }
218
219  core_oobe_actor_->StopDemoModeDetection();
220  if (delegate_)
221    delegate_->OnExit();
222}
223
224void HIDDetectionScreenHandler::InitializeAdapter(
225    scoped_refptr<device::BluetoothAdapter> adapter) {
226  adapter_ = adapter;
227  CHECK(adapter_.get());
228
229  adapter_->AddObserver(this);
230  UpdateDevices();
231}
232
233void HIDDetectionScreenHandler::StartBTDiscoverySession() {
234  adapter_->StartDiscoverySession(
235      base::Bind(&HIDDetectionScreenHandler::OnStartDiscoverySession,
236                 weak_ptr_factory_.GetWeakPtr()),
237      base::Bind(&HIDDetectionScreenHandler::FindDevicesError,
238                 weak_ptr_factory_.GetWeakPtr()));
239}
240
241void HIDDetectionScreenHandler::RequestPinCode(
242    device::BluetoothDevice* device) {
243  VLOG(1) << "RequestPinCode id = " << device->GetDeviceID()
244          << " name = " << device->GetName();
245  device->CancelPairing();
246}
247
248void HIDDetectionScreenHandler::RequestPasskey(
249    device::BluetoothDevice* device) {
250  VLOG(1) << "RequestPassKey id = " << device->GetDeviceID()
251          << " name = " << device->GetName();
252  device->CancelPairing();
253}
254
255void HIDDetectionScreenHandler::DisplayPinCode(device::BluetoothDevice* device,
256                                               const std::string& pincode) {
257  VLOG(1) << "DisplayPinCode id = " << device->GetDeviceID()
258          << " name = " << device->GetName();
259  base::DictionaryValue params;
260  params.SetString("state", kBTPairingState);
261  params.SetString("pairing-state", kRemotePinCode);
262  params.SetString("pincode", pincode);
263  params.SetString(kDeviceNameArgName, device->GetName());
264  SendKeyboardDeviceNotification(&params);
265}
266
267void HIDDetectionScreenHandler::DisplayPasskey(
268    device::BluetoothDevice* device, uint32 passkey) {
269  VLOG(1) << "DisplayPassKey id = " << device->GetDeviceID()
270          << " name = " << device->GetName();
271  base::DictionaryValue params;
272  params.SetString("state", kBTPairingState);
273  params.SetString("pairing-state", kRemotePasskey);
274  params.SetInteger("passkey", passkey);
275  std::string pincode = base::UintToString(passkey);
276  pincode = std::string(kPincodeLength - pincode.length(), '0').append(pincode);
277  params.SetString("pincode", pincode);
278  params.SetString(kDeviceNameArgName, device->GetName());
279  SendKeyboardDeviceNotification(&params);
280}
281
282void HIDDetectionScreenHandler::KeysEntered(
283    device::BluetoothDevice* device, uint32 entered) {
284  VLOG(1) << "Keys entered";
285  base::DictionaryValue params;
286  params.SetString("state", kBTUpdateState);
287  params.SetInteger("keysEntered", entered);
288  SendKeyboardDeviceNotification(&params);
289}
290
291void HIDDetectionScreenHandler::ConfirmPasskey(
292    device::BluetoothDevice* device, uint32 passkey) {
293  VLOG(1) << "Confirm Passkey";
294  device->CancelPairing();
295}
296
297void HIDDetectionScreenHandler::AuthorizePairing(
298    device::BluetoothDevice* device) {
299  // There is never any circumstance where this will be called, since the
300  // HID detection screen  handler will only be used for outgoing pairing
301  // requests, but play it safe.
302  VLOG(1) << "Authorize pairing";
303  device->ConfirmPairing();
304}
305
306void HIDDetectionScreenHandler::AdapterPresentChanged(
307    device::BluetoothAdapter* adapter, bool present) {
308  if (present && switch_on_adapter_when_ready_) {
309    VLOG(1) << "Switching on BT adapter on HID OOBE screen.";
310    adapter_initially_powered_.reset(new bool(adapter_->IsPowered()));
311    adapter_->SetPowered(
312        true,
313        base::Bind(&HIDDetectionScreenHandler::StartBTDiscoverySession,
314                   weak_ptr_factory_.GetWeakPtr()),
315        base::Bind(&HIDDetectionScreenHandler::SetPoweredError,
316                   weak_ptr_factory_.GetWeakPtr()));
317  }
318}
319
320void HIDDetectionScreenHandler::TryPairingAsPointingDevice(
321    device::BluetoothDevice* device) {
322  if (pointing_device_id_.empty() &&
323      DeviceIsPointing(device->GetDeviceType()) &&
324      device->IsPairable() && !device->IsPaired() && !mouse_is_pairing_) {
325    ConnectBTDevice(device);
326  }
327}
328
329void HIDDetectionScreenHandler::TryPairingAsKeyboardDevice(
330    device::BluetoothDevice* device) {
331  if (keyboard_device_id_.empty() &&
332      DeviceIsKeyboard(device->GetDeviceType()) &&
333      device->IsPairable() && !device->IsPaired() && !keyboard_is_pairing_) {
334    ConnectBTDevice(device);
335  }
336}
337
338void HIDDetectionScreenHandler::DeviceAdded(
339    device::BluetoothAdapter* adapter, device::BluetoothDevice* device) {
340  VLOG(1) << "BT input device added id = " << device->GetDeviceID() <<
341      " name = " << device->GetName();
342  TryPairingAsPointingDevice(device);
343  TryPairingAsKeyboardDevice(device);
344}
345
346void HIDDetectionScreenHandler::DeviceChanged(
347    device::BluetoothAdapter* adapter, device::BluetoothDevice* device) {
348  VLOG(1) << "BT device changed id = " << device->GetDeviceID() << " name = " <<
349      device->GetName();
350  TryPairingAsPointingDevice(device);
351  TryPairingAsKeyboardDevice(device);
352}
353
354void HIDDetectionScreenHandler::DeviceRemoved(
355    device::BluetoothAdapter* adapter, device::BluetoothDevice* device) {
356  VLOG(1) << "BT device removed id = " << device->GetDeviceID() << " name = " <<
357      device->GetName();
358}
359
360void HIDDetectionScreenHandler::OnInputDeviceAdded(
361    const InputDeviceInfo& info) {
362  VLOG(1) << "Input device added id = " << info.id << " name = " << info.name;
363  // TODO(merkulova): deal with all available device types, e.g. joystick.
364  if (!keyboard_device_id_.empty() && !pointing_device_id_.empty())
365    return;
366
367  if (pointing_device_id_.empty() && DeviceIsPointing(info)) {
368    pointing_device_id_ = info.id;
369    pointing_device_name_ = info.name;
370    pointing_device_connect_type_ = info.type;
371    SendPointingDeviceNotification();
372  }
373  if (keyboard_device_id_.empty() && info.is_keyboard) {
374    keyboard_device_id_ = info.id;
375    keyboard_device_name_ = info.name;
376    keyboard_device_connect_type_ = info.type;
377    SendKeyboardDeviceNotification(NULL);
378  }
379}
380
381void HIDDetectionScreenHandler::OnInputDeviceRemoved(const std::string& id) {
382  if (id == keyboard_device_id_) {
383    keyboard_device_id_.clear();
384    keyboard_device_name_.clear();
385    keyboard_device_connect_type_ = InputDeviceInfo::TYPE_UNKNOWN;
386    SendKeyboardDeviceNotification(NULL);
387    UpdateDevices();
388  } else if (id == pointing_device_id_) {
389    pointing_device_id_.clear();
390    pointing_device_name_.clear();
391    pointing_device_connect_type_ = InputDeviceInfo::TYPE_UNKNOWN;
392    SendPointingDeviceNotification();
393    UpdateDevices();
394  }
395}
396
397// static
398void HIDDetectionScreenHandler::RegisterPrefs(PrefRegistrySimple* registry) {
399  registry->RegisterIntegerPref(prefs::kTimesHIDDialogShown, 0);
400}
401
402void HIDDetectionScreenHandler::UpdateDevices() {
403  input_service_proxy_.GetDevices(
404      base::Bind(&HIDDetectionScreenHandler::OnGetInputDevicesList,
405                 weak_ptr_factory_.GetWeakPtr()));
406}
407
408void HIDDetectionScreenHandler::UpdateBTDevices() {
409  if (!adapter_ || !adapter_->IsPresent() || !adapter_->IsPowered())
410    return;
411
412  // If no connected devices found as pointing device and keyboard, we try to
413  // connect some type-suitable active bluetooth device.
414  std::vector<device::BluetoothDevice*> bt_devices = adapter_->GetDevices();
415  for (std::vector<device::BluetoothDevice*>::const_iterator it =
416           bt_devices.begin();
417       it != bt_devices.end() &&
418           (keyboard_device_id_.empty() || pointing_device_id_.empty());
419       ++it) {
420    TryPairingAsPointingDevice(*it);
421    TryPairingAsKeyboardDevice(*it);
422  }
423}
424
425void HIDDetectionScreenHandler::ProcessConnectedDevicesList(
426    const std::vector<InputDeviceInfo>& devices) {
427  for (std::vector<InputDeviceInfo>::const_iterator it = devices.begin();
428       it != devices.end() &&
429       (pointing_device_id_.empty() || keyboard_device_id_.empty());
430       ++it) {
431    if (pointing_device_id_.empty() && DeviceIsPointing(*it)) {
432      pointing_device_id_ = it->id;
433      pointing_device_name_ = it->name;
434      pointing_device_connect_type_ = it->type;
435      if (page_is_ready())
436        SendPointingDeviceNotification();
437    }
438    if (keyboard_device_id_.empty() && it->is_keyboard) {
439      keyboard_device_id_ = it->id;
440      keyboard_device_name_ = it->name;
441      keyboard_device_connect_type_ = it->type;
442      if (page_is_ready())
443        SendKeyboardDeviceNotification(NULL);
444    }
445  }
446}
447
448void HIDDetectionScreenHandler::TryInitiateBTDevicesUpdate() {
449  if ((pointing_device_id_.empty() || keyboard_device_id_.empty()) &&
450      adapter_) {
451    if (!adapter_->IsPresent()) {
452      // Switch on BT adapter later when it's available.
453      switch_on_adapter_when_ready_ = true;
454    } else if (!adapter_->IsPowered()) {
455      VLOG(1) << "Switching on BT adapter on HID OOBE screen.";
456      adapter_initially_powered_.reset(new bool(false));
457      adapter_->SetPowered(
458          true,
459          base::Bind(&HIDDetectionScreenHandler::StartBTDiscoverySession,
460                     weak_ptr_factory_.GetWeakPtr()),
461          base::Bind(&HIDDetectionScreenHandler::SetPoweredError,
462                     weak_ptr_factory_.GetWeakPtr()));
463    } else {
464      UpdateBTDevices();
465    }
466  }
467}
468
469void HIDDetectionScreenHandler::OnGetInputDevicesListForCheck(
470    const base::Callback<void(bool)>& on_check_done,
471    const std::vector<InputDeviceInfo>& devices) {
472  ProcessConnectedDevicesList(devices);
473
474  // Screen is not required if both devices are present.
475  bool all_devices_autodetected = !pointing_device_id_.empty() &&
476                                  !keyboard_device_id_.empty();
477  UMA_HISTOGRAM_BOOLEAN("HIDDetection.OOBEDialogShown",
478                        !all_devices_autodetected);
479
480  on_check_done.Run(!all_devices_autodetected);
481}
482
483void HIDDetectionScreenHandler::OnGetInputDevicesList(
484    const std::vector<InputDeviceInfo>& devices) {
485  ProcessConnectedDevicesList(devices);
486  TryInitiateBTDevicesUpdate();
487}
488
489void HIDDetectionScreenHandler::ConnectBTDevice(
490    device::BluetoothDevice* device) {
491  if (!device->IsPairable() || device->IsPaired())
492    return;
493  device::BluetoothDevice::DeviceType device_type = device->GetDeviceType();
494
495  if (device_type == device::BluetoothDevice::DEVICE_MOUSE ||
496      device_type == device::BluetoothDevice::DEVICE_TABLET) {
497    if (mouse_is_pairing_)
498      return;
499    mouse_is_pairing_ = true;
500  } else if (device_type == device::BluetoothDevice::DEVICE_KEYBOARD) {
501    if (keyboard_is_pairing_)
502      return;
503    keyboard_is_pairing_ = true;
504  } else if (device_type ==
505      device::BluetoothDevice::DEVICE_KEYBOARD_MOUSE_COMBO) {
506    if (mouse_is_pairing_ || keyboard_is_pairing_)
507      return;
508    mouse_is_pairing_ = true;
509    keyboard_is_pairing_ = true;
510  }
511  device->Connect(this,
512            base::Bind(&HIDDetectionScreenHandler::BTConnected,
513                       weak_ptr_factory_.GetWeakPtr(), device_type),
514            base::Bind(&HIDDetectionScreenHandler::BTConnectError,
515                       weak_ptr_factory_.GetWeakPtr(),
516                       device->GetAddress(), device_type));
517}
518
519void HIDDetectionScreenHandler::BTConnected(
520    device::BluetoothDevice::DeviceType device_type) {
521  if (DeviceIsPointing(device_type))
522    mouse_is_pairing_ = false;
523  if (DeviceIsKeyboard(device_type))
524    keyboard_is_pairing_ = false;
525}
526
527void HIDDetectionScreenHandler::BTConnectError(
528    const std::string& address,
529    device::BluetoothDevice::DeviceType device_type,
530    device::BluetoothDevice::ConnectErrorCode error_code) {
531  LOG(WARNING) << "BTConnectError while connecting " << address
532               << " error code = " << error_code;
533  if (DeviceIsPointing(device_type))
534    mouse_is_pairing_ = false;
535  if (DeviceIsKeyboard(device_type)) {
536    keyboard_is_pairing_ = false;
537    SendKeyboardDeviceNotification(NULL);
538  }
539
540  if (pointing_device_id_.empty() || keyboard_device_id_.empty())
541    UpdateDevices();
542}
543
544
545void HIDDetectionScreenHandler::SendPointingDeviceNotification() {
546  std::string state;
547  if (pointing_device_id_.empty())
548    state = kSearchingState;
549  else if (pointing_device_connect_type_ == InputDeviceInfo::TYPE_BLUETOOTH)
550    state = kBTPairedState;
551  else
552    state = kUSBConnectedState;
553  CallJS("setPointingDeviceState", state);
554}
555
556void HIDDetectionScreenHandler::SendKeyboardDeviceNotification(
557    base::DictionaryValue* params) {
558  base::DictionaryValue state_info;
559  if (params)
560    state_info.MergeDictionary(params);
561
562  base::string16 device_name;
563  if (!state_info.GetString(kDeviceNameArgName, &device_name)) {
564    device_name = l10n_util::GetStringUTF16(
565        IDS_HID_DETECTION_DEFAULT_KEYBOARD_NAME);
566  }
567
568  if (keyboard_device_id_.empty()) {
569    if (!state_info.HasKey("state")) {
570      state_info.SetString("state", kSearchingState);
571    } else if (state_info.HasKey(kPincodeArgName)) {
572      state_info.SetString(
573          kLabelArgName,
574          l10n_util::GetStringFUTF16(
575              IDS_HID_DETECTION_BLUETOOTH_REMOTE_PIN_CODE_REQUEST,
576              device_name));
577    }
578  } else if (keyboard_device_connect_type_ == InputDeviceInfo::TYPE_BLUETOOTH) {
579    state_info.SetString("state", kBTPairedState);
580    state_info.SetString(
581        kLabelArgName,
582        l10n_util::GetStringFUTF16(
583            IDS_HID_DETECTION_PAIRED_BLUETOOTH_KEYBOARD,
584            base::UTF8ToUTF16(keyboard_device_name_)));
585  } else {
586    state_info.SetString("state", kUSBConnectedState);
587  }
588  CallJS("setKeyboardDeviceState", state_info);
589}
590
591}  // namespace chromeos
592