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