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