bluetooth_options_handler.cc revision 868fa2fe829687343ffae624259930155e16dbd8
1// Copyright (c) 2012 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/options/chromeos/bluetooth_options_handler.h" 6 7#include "base/bind.h" 8#include "base/bind_helpers.h" 9#include "base/callback.h" 10#include "base/command_line.h" 11#include "base/strings/string_number_conversions.h" 12#include "base/strings/utf_string_conversions.h" 13#include "base/values.h" 14#include "content/public/browser/web_ui.h" 15#include "device/bluetooth/bluetooth_adapter.h" 16#include "device/bluetooth/bluetooth_adapter_factory.h" 17#include "device/bluetooth/bluetooth_device.h" 18#include "grit/chromium_strings.h" 19#include "grit/generated_resources.h" 20#include "third_party/cros_system_api/dbus/service_constants.h" 21#include "ui/base/l10n/l10n_util.h" 22 23namespace { 24 25// |UpdateDeviceCallback| takes a variable length list as an argument. The 26// value stored in each list element is indicated by the following constants. 27const int kUpdateDeviceAddressIndex = 0; 28const int kUpdateDeviceCommandIndex = 1; 29const int kUpdateDeviceAuthTokenIndex = 2; 30 31// |UpdateDeviceCallback| provides a command value of one of the following 32// constants that indicates what update it is providing to us. 33const char kConnectCommand[] = "connect"; 34const char kCancelCommand[] = "cancel"; 35const char kAcceptCommand[] = "accept"; 36const char kRejectCommand[] = "reject"; 37const char kDisconnectCommand[] = "disconnect"; 38const char kForgetCommand[] = "forget"; 39 40// |SendDeviceNotification| may include a pairing parameter whose value 41// is one of the following constants instructing the UI to perform a certain 42// action. 43const char kStartConnecting[] = "bluetoothStartConnecting"; 44const char kEnterPinCode[] = "bluetoothEnterPinCode"; 45const char kEnterPasskey[] = "bluetoothEnterPasskey"; 46const char kRemotePinCode[] = "bluetoothRemotePinCode"; 47const char kRemotePasskey[] = "bluetoothRemotePasskey"; 48const char kConfirmPasskey[] = "bluetoothConfirmPasskey"; 49 50// An invalid |entered| value to represent the "undefined" value. 51const int kInvalidEntered = 0xFFFF; 52 53} // namespace 54 55namespace chromeos { 56namespace options { 57 58BluetoothOptionsHandler::BluetoothOptionsHandler() : 59 discovering_(false), 60 pairing_device_passkey_(1000000), 61 pairing_device_entered_(kInvalidEntered), 62 weak_ptr_factory_(this) { 63} 64 65BluetoothOptionsHandler::~BluetoothOptionsHandler() { 66 if (discovering_) { 67 adapter_->StopDiscovering( 68 base::Bind(&base::DoNothing), 69 base::Bind(&base::DoNothing)); 70 discovering_ = false; 71 } 72 if (adapter_.get()) 73 adapter_->RemoveObserver(this); 74} 75 76void BluetoothOptionsHandler::GetLocalizedValues( 77 DictionaryValue* localized_strings) { 78 DCHECK(localized_strings); 79 80 static OptionsStringResource resources[] = { 81 { "bluetooth", IDS_OPTIONS_SETTINGS_SECTION_TITLE_BLUETOOTH }, 82 { "disableBluetooth", IDS_OPTIONS_SETTINGS_BLUETOOTH_DISABLE }, 83 { "enableBluetooth", IDS_OPTIONS_SETTINGS_BLUETOOTH_ENABLE }, 84 { "addBluetoothDevice", IDS_OPTIONS_SETTINGS_ADD_BLUETOOTH_DEVICE }, 85 { "bluetoothAddDeviceTitle", 86 IDS_OPTIONS_SETTINGS_BLUETOOTH_ADD_DEVICE_TITLE }, 87 { "bluetoothOptionsPageTabTitle", 88 IDS_OPTIONS_SETTINGS_BLUETOOTH_ADD_DEVICE_TITLE }, 89 { "findBluetoothDevices", IDS_OPTIONS_SETTINGS_FIND_BLUETOOTH_DEVICES }, 90 { "bluetoothNoDevices", IDS_OPTIONS_SETTINGS_BLUETOOTH_NO_DEVICES }, 91 { "bluetoothNoDevicesFound", 92 IDS_OPTIONS_SETTINGS_BLUETOOTH_NO_DEVICES_FOUND }, 93 { "bluetoothScanning", IDS_OPTIONS_SETTINGS_BLUETOOTH_SCANNING }, 94 { "bluetoothDeviceConnecting", IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECTING }, 95 { "bluetoothConnectDevice", IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT }, 96 { "bluetoothDisconnectDevice", IDS_OPTIONS_SETTINGS_BLUETOOTH_DISCONNECT }, 97 { "bluetoothForgetDevice", IDS_OPTIONS_SETTINGS_BLUETOOTH_FORGET }, 98 { "bluetoothCancel", IDS_OPTIONS_SETTINGS_BLUETOOTH_CANCEL }, 99 { "bluetoothEnterKey", IDS_OPTIONS_SETTINGS_BLUETOOTH_ENTER_KEY }, 100 { "bluetoothDismissError", IDS_OPTIONS_SETTINGS_BLUETOOTH_DISMISS_ERROR }, 101 102 // Device connecting and pairing. 103 { "bluetoothStartConnecting", 104 IDS_OPTIONS_SETTINGS_BLUETOOTH_START_CONNECTING }, 105 { "bluetoothAcceptPasskey", 106 IDS_OPTIONS_SETTINGS_BLUETOOTH_ACCEPT_PASSKEY }, 107 { "bluetoothRejectPasskey", 108 IDS_OPTIONS_SETTINGS_BLUETOOTH_REJECT_PASSKEY }, 109 { "bluetoothEnterPinCode", 110 IDS_OPTIONS_SETTINGS_BLUETOOTH_ENTER_PIN_CODE_REQUEST }, 111 { "bluetoothEnterPasskey", 112 IDS_OPTIONS_SETTINGS_BLUETOOTH_ENTER_PASSKEY_REQUEST }, 113 { "bluetoothRemotePinCode", 114 IDS_OPTIONS_SETTINGS_BLUETOOTH_REMOTE_PIN_CODE_REQUEST }, 115 { "bluetoothRemotePasskey", 116 IDS_OPTIONS_SETTINGS_BLUETOOTH_REMOTE_PASSKEY_REQUEST }, 117 { "bluetoothConfirmPasskey", 118 IDS_OPTIONS_SETTINGS_BLUETOOTH_CONFIRM_PASSKEY_REQUEST }, 119 120 // Error messages. 121 { "bluetoothStartDiscoveryFailed", 122 IDS_OPTIONS_SETTINGS_BLUETOOTH_START_DISCOVERY_FAILED }, 123 { "bluetoothStopDiscoveryFailed", 124 IDS_OPTIONS_SETTINGS_BLUETOOTH_STOP_DISCOVERY_FAILED }, 125 { "bluetoothChangePowerFailed", 126 IDS_OPTIONS_SETTINGS_BLUETOOTH_CHANGE_POWER_FAILED }, 127 { "bluetoothConnectUnknownError", 128 IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_UNKNOWN_ERROR }, 129 { "bluetoothConnectInProgress", 130 IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_IN_PROGRESS }, 131 { "bluetoothConnectFailed", 132 IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_FAILED }, 133 { "bluetoothConnectAuthFailed", 134 IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_AUTH_FAILED }, 135 { "bluetoothConnectAuthCanceled", 136 IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_AUTH_CANCELED }, 137 { "bluetoothConnectAuthRejected", 138 IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_AUTH_REJECTED }, 139 { "bluetoothConnectAuthTimeout", 140 IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_AUTH_TIMEOUT }, 141 { "bluetoothConnectUnsupportedDevice", 142 IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_UNSUPPORTED_DEVICE }, 143 { "bluetoothDisconnectFailed", 144 IDS_OPTIONS_SETTINGS_BLUETOOTH_DISCONNECT_FAILED }, 145 { "bluetoothForgetFailed", 146 IDS_OPTIONS_SETTINGS_BLUETOOTH_FORGET_FAILED }}; 147 148 RegisterStrings(localized_strings, resources, arraysize(resources)); 149} 150 151// TODO(kevers): Reorder methods to match ordering in the header file. 152 153void BluetoothOptionsHandler::AdapterPresentChanged( 154 device::BluetoothAdapter* adapter, 155 bool present) { 156 DCHECK(adapter == adapter_.get()); 157 if (present) { 158 web_ui()->CallJavascriptFunction( 159 "options.BrowserOptions.showBluetoothSettings"); 160 161 // Update the checkbox and visibility based on the powered state of the 162 // new adapter. 163 AdapterPoweredChanged(adapter_.get(), adapter_->IsPowered()); 164 } else { 165 web_ui()->CallJavascriptFunction( 166 "options.BrowserOptions.hideBluetoothSettings"); 167 } 168} 169 170void BluetoothOptionsHandler::AdapterPoweredChanged( 171 device::BluetoothAdapter* adapter, 172 bool powered) { 173 DCHECK(adapter == adapter_.get()); 174 base::FundamentalValue checked(powered); 175 web_ui()->CallJavascriptFunction( 176 "options.BrowserOptions.setBluetoothState", checked); 177} 178 179void BluetoothOptionsHandler::RegisterMessages() { 180 web_ui()->RegisterMessageCallback("bluetoothEnableChange", 181 base::Bind(&BluetoothOptionsHandler::EnableChangeCallback, 182 base::Unretained(this))); 183 web_ui()->RegisterMessageCallback("findBluetoothDevices", 184 base::Bind(&BluetoothOptionsHandler::FindDevicesCallback, 185 base::Unretained(this))); 186 web_ui()->RegisterMessageCallback("updateBluetoothDevice", 187 base::Bind(&BluetoothOptionsHandler::UpdateDeviceCallback, 188 base::Unretained(this))); 189 web_ui()->RegisterMessageCallback("stopBluetoothDeviceDiscovery", 190 base::Bind(&BluetoothOptionsHandler::StopDiscoveryCallback, 191 base::Unretained(this))); 192 web_ui()->RegisterMessageCallback("getPairedBluetoothDevices", 193 base::Bind(&BluetoothOptionsHandler::GetPairedDevicesCallback, 194 base::Unretained(this))); 195} 196 197void BluetoothOptionsHandler::InitializeHandler() { 198 device::BluetoothAdapterFactory::GetAdapter( 199 base::Bind(&BluetoothOptionsHandler::InitializeAdapter, 200 weak_ptr_factory_.GetWeakPtr())); 201} 202 203void BluetoothOptionsHandler::InitializePage() { 204 // Show or hide the bluetooth settings and update the checkbox based 205 // on the current present/powered state. 206 AdapterPresentChanged(adapter_.get(), adapter_->IsPresent()); 207 // Automatically start device discovery if the "Add Bluetooth Device" 208 // overlay is visible. 209 web_ui()->CallJavascriptFunction( 210 "options.BluetoothOptions.updateDiscovery"); 211} 212 213void BluetoothOptionsHandler::InitializeAdapter( 214 scoped_refptr<device::BluetoothAdapter> adapter) { 215 adapter_ = adapter; 216 CHECK(adapter_); 217 adapter_->AddObserver(this); 218} 219 220void BluetoothOptionsHandler::EnableChangeCallback( 221 const ListValue* args) { 222 bool bluetooth_enabled; 223 args->GetBoolean(0, &bluetooth_enabled); 224 225 adapter_->SetPowered(bluetooth_enabled, 226 base::Bind(&base::DoNothing), 227 base::Bind(&BluetoothOptionsHandler::EnableChangeError, 228 weak_ptr_factory_.GetWeakPtr())); 229} 230 231void BluetoothOptionsHandler::EnableChangeError() { 232 VLOG(1) << "Failed to change power state."; 233 ReportError("bluetoothChangePowerFailed", std::string()); 234} 235 236void BluetoothOptionsHandler::FindDevicesCallback( 237 const ListValue* args) { 238 if (!discovering_) { 239 discovering_ = true; 240 adapter_->StartDiscovering( 241 base::Bind(&base::DoNothing), 242 base::Bind(&BluetoothOptionsHandler::FindDevicesError, 243 weak_ptr_factory_.GetWeakPtr())); 244 } 245} 246 247void BluetoothOptionsHandler::FindDevicesError() { 248 VLOG(1) << "Failed to start discovery."; 249 ReportError("bluetoothStartDiscoveryFailed", std::string()); 250} 251 252void BluetoothOptionsHandler::UpdateDeviceCallback( 253 const ListValue* args) { 254 std::string address; 255 args->GetString(kUpdateDeviceAddressIndex, &address); 256 257 device::BluetoothDevice* device = adapter_->GetDevice(address); 258 if (!device) 259 return; 260 261 std::string command; 262 args->GetString(kUpdateDeviceCommandIndex, &command); 263 264 if (command == kConnectCommand) { 265 int size = args->GetSize(); 266 if (size > kUpdateDeviceAuthTokenIndex) { 267 // PIN code or Passkey entry during the pairing process. 268 std::string auth_token; 269 args->GetString(kUpdateDeviceAuthTokenIndex, &auth_token); 270 271 if (device->ExpectingPinCode()) { 272 DeviceConnecting(device); 273 // PIN Code is an array of 1 to 16 8-bit bytes, the usual 274 // interpretation, and the one shared by BlueZ, is a UTF-8 string 275 // of as many characters that will fit in that space, thus we 276 // can use the auth token from JavaScript unmodified. 277 VLOG(1) << "PIN Code supplied: " << address << ": " << auth_token; 278 device->SetPinCode(auth_token); 279 } else if (device->ExpectingPasskey()) { 280 DeviceConnecting(device); 281 // Passkey is a numeric in the range 0-999999, in this case the 282 // JavaScript code should have ensured the auth token string only 283 // contains digits so a simple conversion is sufficient. In the 284 // failure case, just use 0 since that's the most likely Passkey 285 // anyway, and if it's refused the device will request a new one. 286 unsigned passkey = 0; 287 base::StringToUint(auth_token, &passkey); 288 289 VLOG(1) << "Passkey supplied: " << address << ": " << passkey; 290 device->SetPasskey(passkey); 291 } else { 292 LOG(WARNING) << "Auth token supplied after pairing ended: " << address 293 << ": " << auth_token; 294 } 295 } else { 296 // Determine if the device supports pairing: 297 PairingDelegate* delegate = NULL; 298 if (device->IsPairable()) 299 delegate = this; 300 301 // Connection request. 302 VLOG(1) << "Connect: " << address; 303 device->Connect( 304 delegate, 305 base::Bind(&BluetoothOptionsHandler::Connected, 306 weak_ptr_factory_.GetWeakPtr()), 307 base::Bind(&BluetoothOptionsHandler::ConnectError, 308 weak_ptr_factory_.GetWeakPtr(), 309 device->GetAddress())); 310 } 311 } else if (command == kCancelCommand) { 312 // Cancel pairing. 313 VLOG(1) << "Cancel pairing: " << address; 314 device->CancelPairing(); 315 } else if (command == kAcceptCommand) { 316 // Confirm displayed Passkey. 317 VLOG(1) << "Confirm pairing: " << address; 318 device->ConfirmPairing(); 319 } else if (command == kRejectCommand) { 320 // Reject displayed Passkey. 321 VLOG(1) << "Reject pairing: " << address; 322 device->RejectPairing(); 323 } else if (command == kDisconnectCommand) { 324 // Disconnect from device. 325 VLOG(1) << "Disconnect device: " << address; 326 device->Disconnect( 327 base::Bind(&base::DoNothing), 328 base::Bind(&BluetoothOptionsHandler::DisconnectError, 329 weak_ptr_factory_.GetWeakPtr(), 330 device->GetAddress())); 331 } else if (command == kForgetCommand) { 332 // Disconnect from device and delete pairing information. 333 VLOG(1) << "Forget device: " << address; 334 device->Forget(base::Bind(&BluetoothOptionsHandler::ForgetError, 335 weak_ptr_factory_.GetWeakPtr(), 336 device->GetAddress())); 337 } else { 338 LOG(WARNING) << "Unknown updateBluetoothDevice command: " << command; 339 } 340} 341 342void BluetoothOptionsHandler::Connected() { 343 // Invalidate the local cache. 344 pairing_device_address_.clear(); 345 pairing_device_entered_ = kInvalidEntered; 346 347 web_ui()->CallJavascriptFunction( 348 "options.BluetoothPairing.dismissDialog"); 349} 350 351void BluetoothOptionsHandler::ConnectError( 352 const std::string& address, 353 device::BluetoothDevice::ConnectErrorCode error_code) { 354 const char* error_name = NULL; 355 356 // Invalidate the local cache. 357 pairing_device_address_.clear(); 358 pairing_device_entered_ = kInvalidEntered; 359 360 VLOG(1) << "Failed to connect to device: " << address; 361 switch (error_code) { 362 case device::BluetoothDevice::ERROR_UNKNOWN: 363 error_name = "bluetoothConnectUnknownError"; 364 break; 365 case device::BluetoothDevice::ERROR_INPROGRESS: 366 error_name = "bluetoothConnectInProgress"; 367 break; 368 case device::BluetoothDevice::ERROR_FAILED: 369 error_name = "bluetoothConnectFailed"; 370 break; 371 case device::BluetoothDevice::ERROR_AUTH_FAILED: 372 error_name = "bluetoothConnectAuthFailed"; 373 break; 374 case device::BluetoothDevice::ERROR_AUTH_CANCELED: 375 error_name = "bluetoothConnectAuthCanceled"; 376 break; 377 case device::BluetoothDevice::ERROR_AUTH_REJECTED: 378 error_name = "bluetoothConnectAuthRejected"; 379 break; 380 case device::BluetoothDevice::ERROR_AUTH_TIMEOUT: 381 error_name = "bluetoothConnectAuthTimeout"; 382 break; 383 case device::BluetoothDevice::ERROR_UNSUPPORTED_DEVICE: 384 error_name = "bluetoothConnectUnsupportedDevice"; 385 break; 386 } 387 // Report an error only if there's an error to report. 388 if (error_name) 389 ReportError(error_name, address); 390} 391 392void BluetoothOptionsHandler::DisconnectError(const std::string& address) { 393 VLOG(1) << "Failed to disconnect from device: " << address; 394 ReportError("bluetoothDisconnectFailed", address); 395} 396 397void BluetoothOptionsHandler::ForgetError(const std::string& address) { 398 VLOG(1) << "Failed to disconnect and unpair device: " << address; 399 ReportError("bluetoothForgetFailed", address); 400} 401 402void BluetoothOptionsHandler::StopDiscoveryCallback( 403 const ListValue* args) { 404 if (discovering_) { 405 adapter_->StopDiscovering( 406 base::Bind(&base::DoNothing), 407 base::Bind(&BluetoothOptionsHandler::StopDiscoveryError, 408 weak_ptr_factory_.GetWeakPtr())); 409 discovering_ = false; 410 } 411} 412 413void BluetoothOptionsHandler::StopDiscoveryError() { 414 VLOG(1) << "Failed to stop discovery."; 415 ReportError("bluetoothStopDiscoveryFailed", std::string()); 416} 417 418void BluetoothOptionsHandler::GetPairedDevicesCallback( 419 const ListValue* args) { 420 device::BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); 421 422 for (device::BluetoothAdapter::DeviceList::iterator iter = devices.begin(); 423 iter != devices.end(); ++iter) 424 SendDeviceNotification(*iter, NULL); 425} 426 427void BluetoothOptionsHandler::SendDeviceNotification( 428 const device::BluetoothDevice* device, 429 base::DictionaryValue* params) { 430 base::DictionaryValue js_properties; 431 js_properties.SetString("name", device->GetName()); 432 js_properties.SetString("address", device->GetAddress()); 433 js_properties.SetBoolean("paired", device->IsPaired()); 434 js_properties.SetBoolean("connected", device->IsConnected()); 435 js_properties.SetBoolean("connecting", device->IsConnecting()); 436 js_properties.SetBoolean("connectable", device->IsConnectable()); 437 if (params) 438 js_properties.MergeDictionary(params); 439 440 // Use the cached values to update js_property. 441 if (device->GetAddress() == pairing_device_address_) { 442 std::string pairing; 443 if (!js_properties.GetString("pairing", &pairing)) { 444 pairing = pairing_device_pairing_; 445 js_properties.SetString("pairing", pairing); 446 } 447 if (pairing == kRemotePinCode && !js_properties.HasKey("pincode")) 448 js_properties.SetString("pincode", pairing_device_pincode_); 449 if (pairing == kRemotePasskey && !js_properties.HasKey("passkey")) 450 js_properties.SetInteger("passkey", pairing_device_passkey_); 451 if ((pairing == kRemotePinCode || pairing == kRemotePasskey) && 452 !js_properties.HasKey("entered") && 453 pairing_device_entered_ != kInvalidEntered) { 454 js_properties.SetInteger("entered", pairing_device_entered_); 455 } 456 } 457 458 // Update the cache with the new information. 459 if (js_properties.HasKey("pairing")) { 460 pairing_device_address_ = device->GetAddress(); 461 js_properties.GetString("pairing", &pairing_device_pairing_); 462 js_properties.GetString("pincode", &pairing_device_pincode_); 463 js_properties.GetInteger("passkey", &pairing_device_passkey_); 464 if (!js_properties.GetInteger("entered", &pairing_device_entered_)) 465 pairing_device_entered_ = kInvalidEntered; 466 } 467 468 web_ui()->CallJavascriptFunction( 469 "options.BrowserOptions.addBluetoothDevice", 470 js_properties); 471} 472 473void BluetoothOptionsHandler::RequestPinCode(device::BluetoothDevice* device) { 474 DictionaryValue params; 475 params.SetString("pairing", kEnterPinCode); 476 SendDeviceNotification(device, ¶ms); 477} 478 479void BluetoothOptionsHandler::RequestPasskey(device::BluetoothDevice* device) { 480 DictionaryValue params; 481 params.SetString("pairing", kEnterPasskey); 482 SendDeviceNotification(device, ¶ms); 483} 484 485void BluetoothOptionsHandler::DisplayPinCode(device::BluetoothDevice* device, 486 const std::string& pincode) { 487 DictionaryValue params; 488 params.SetString("pairing", kRemotePinCode); 489 params.SetString("pincode", pincode); 490 SendDeviceNotification(device, ¶ms); 491} 492 493void BluetoothOptionsHandler::DisplayPasskey(device::BluetoothDevice* device, 494 uint32 passkey) { 495 DictionaryValue params; 496 params.SetString("pairing", kRemotePasskey); 497 params.SetInteger("passkey", passkey); 498 SendDeviceNotification(device, ¶ms); 499} 500 501void BluetoothOptionsHandler::KeysEntered(device::BluetoothDevice* device, 502 uint32 entered) { 503 DictionaryValue params; 504 params.SetInteger("entered", entered); 505 SendDeviceNotification(device, ¶ms); 506} 507 508void BluetoothOptionsHandler::ConfirmPasskey(device::BluetoothDevice* device, 509 uint32 passkey) { 510 DictionaryValue params; 511 params.SetString("pairing", kConfirmPasskey); 512 params.SetInteger("passkey", passkey); 513 SendDeviceNotification(device, ¶ms); 514} 515 516void BluetoothOptionsHandler::DismissDisplayOrConfirm() { 517 DCHECK(adapter_); 518 519 // We can receive this delegate call when we haven't been asked to display or 520 // confirm anything; we can determine that by checking whether we've saved 521 // pairing information for the device. This is also a handy way to get the 522 // BluetoothDevice object we need. 523 if (!pairing_device_address_.empty()) { 524 device::BluetoothDevice* device = 525 adapter_->GetDevice(pairing_device_address_); 526 DCHECK(device); 527 DeviceConnecting(device); 528 } 529} 530 531void BluetoothOptionsHandler::ReportError( 532 const std::string& error, 533 const std::string& address) { 534 base::DictionaryValue properties; 535 properties.SetString("label", error); 536 properties.SetString("address", address); 537 web_ui()->CallJavascriptFunction( 538 "options.BluetoothPairing.showMessage", 539 properties); 540} 541 542void BluetoothOptionsHandler::DeviceAdded(device::BluetoothAdapter* adapter, 543 device::BluetoothDevice* device) { 544 DCHECK(adapter == adapter_.get()); 545 DCHECK(device); 546 SendDeviceNotification(device, NULL); 547} 548 549void BluetoothOptionsHandler::DeviceChanged(device::BluetoothAdapter* adapter, 550 device::BluetoothDevice* device) { 551 DCHECK(adapter == adapter_.get()); 552 DCHECK(device); 553 SendDeviceNotification(device, NULL); 554} 555 556void BluetoothOptionsHandler::DeviceRemoved(device::BluetoothAdapter* adapter, 557 device::BluetoothDevice* device) { 558 DCHECK(adapter == adapter_.get()); 559 DCHECK(device); 560 561 // Invalidate the local cache if the pairing device is removed. 562 if (pairing_device_address_ == device->GetAddress()) { 563 pairing_device_address_.clear(); 564 pairing_device_entered_ = kInvalidEntered; 565 } 566 567 base::StringValue address(device->GetAddress()); 568 web_ui()->CallJavascriptFunction( 569 "options.BrowserOptions.removeBluetoothDevice", 570 address); 571} 572 573void BluetoothOptionsHandler::DeviceConnecting( 574 device::BluetoothDevice* device) { 575 DCHECK(device); 576 DictionaryValue params; 577 params.SetString("pairing", kStartConnecting); 578 SendDeviceNotification(device, ¶ms); 579} 580 581} // namespace options 582} // namespace chromeos 583