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 23 namespace { 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. 27 const int kUpdateDeviceAddressIndex = 0; 28 const int kUpdateDeviceCommandIndex = 1; 29 const 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. 33 const char kConnectCommand[] = "connect"; 34 const char kCancelCommand[] = "cancel"; 35 const char kAcceptCommand[] = "accept"; 36 const char kRejectCommand[] = "reject"; 37 const char kDisconnectCommand[] = "disconnect"; 38 const 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. 43 const char kStartConnecting[] = "bluetoothStartConnecting"; 44 const char kEnterPinCode[] = "bluetoothEnterPinCode"; 45 const char kEnterPasskey[] = "bluetoothEnterPasskey"; 46 const char kRemotePinCode[] = "bluetoothRemotePinCode"; 47 const char kRemotePasskey[] = "bluetoothRemotePasskey"; 48 const char kConfirmPasskey[] = "bluetoothConfirmPasskey"; 49 50 // An invalid |entered| value to represent the "undefined" value. 51 const int kInvalidEntered = 0xFFFF; 52 53 } // namespace 54 55 namespace chromeos { 56 namespace options { 57 58 BluetoothOptionsHandler::BluetoothOptionsHandler() : 59 discovering_(false), 60 pairing_device_passkey_(1000000), 61 pairing_device_entered_(kInvalidEntered), 62 weak_ptr_factory_(this) { 63 } 64 65 BluetoothOptionsHandler::~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 76 void 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 153 void 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 170 void 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 179 void 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 197 void BluetoothOptionsHandler::InitializeHandler() { 198 device::BluetoothAdapterFactory::GetAdapter( 199 base::Bind(&BluetoothOptionsHandler::InitializeAdapter, 200 weak_ptr_factory_.GetWeakPtr())); 201 } 202 203 void 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 213 void BluetoothOptionsHandler::InitializeAdapter( 214 scoped_refptr<device::BluetoothAdapter> adapter) { 215 adapter_ = adapter; 216 CHECK(adapter_.get()); 217 adapter_->AddObserver(this); 218 } 219 220 void 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 231 void BluetoothOptionsHandler::EnableChangeError() { 232 VLOG(1) << "Failed to change power state."; 233 ReportError("bluetoothChangePowerFailed", std::string()); 234 } 235 236 void 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 247 void BluetoothOptionsHandler::FindDevicesError() { 248 VLOG(1) << "Failed to start discovery."; 249 ReportError("bluetoothStartDiscoveryFailed", std::string()); 250 } 251 252 void 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 342 void 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 351 void 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 392 void BluetoothOptionsHandler::DisconnectError(const std::string& address) { 393 VLOG(1) << "Failed to disconnect from device: " << address; 394 ReportError("bluetoothDisconnectFailed", address); 395 } 396 397 void BluetoothOptionsHandler::ForgetError(const std::string& address) { 398 VLOG(1) << "Failed to disconnect and unpair device: " << address; 399 ReportError("bluetoothForgetFailed", address); 400 } 401 402 void 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 413 void BluetoothOptionsHandler::StopDiscoveryError() { 414 VLOG(1) << "Failed to stop discovery."; 415 ReportError("bluetoothStopDiscoveryFailed", std::string()); 416 } 417 418 void 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 427 void 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 473 void BluetoothOptionsHandler::RequestPinCode(device::BluetoothDevice* device) { 474 DictionaryValue params; 475 params.SetString("pairing", kEnterPinCode); 476 SendDeviceNotification(device, ¶ms); 477 } 478 479 void BluetoothOptionsHandler::RequestPasskey(device::BluetoothDevice* device) { 480 DictionaryValue params; 481 params.SetString("pairing", kEnterPasskey); 482 SendDeviceNotification(device, ¶ms); 483 } 484 485 void 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 493 void 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 501 void BluetoothOptionsHandler::KeysEntered(device::BluetoothDevice* device, 502 uint32 entered) { 503 DictionaryValue params; 504 params.SetInteger("entered", entered); 505 SendDeviceNotification(device, ¶ms); 506 } 507 508 void 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 516 void BluetoothOptionsHandler::DismissDisplayOrConfirm() { 517 DCHECK(adapter_.get()); 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 531 void 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 542 void BluetoothOptionsHandler::DeviceAdded(device::BluetoothAdapter* adapter, 543 device::BluetoothDevice* device) { 544 DCHECK(adapter == adapter_.get()); 545 DCHECK(device); 546 SendDeviceNotification(device, NULL); 547 } 548 549 void BluetoothOptionsHandler::DeviceChanged(device::BluetoothAdapter* adapter, 550 device::BluetoothDevice* device) { 551 DCHECK(adapter == adapter_.get()); 552 DCHECK(device); 553 SendDeviceNotification(device, NULL); 554 } 555 556 void 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 573 void 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