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