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 "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(&params);
    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(&params);
    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(&params);
    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