Home | History | Annotate | Download | only in login
      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(&params);
    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(&params);
    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(&params);
    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