Home | History | Annotate | Download | only in chromeos
      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, &params);
    477 }
    478 
    479 void BluetoothOptionsHandler::RequestPasskey(device::BluetoothDevice* device) {
    480   DictionaryValue params;
    481   params.SetString("pairing", kEnterPasskey);
    482   SendDeviceNotification(device, &params);
    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, &params);
    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, &params);
    499 }
    500 
    501 void BluetoothOptionsHandler::KeysEntered(device::BluetoothDevice* device,
    502                                           uint32 entered) {
    503   DictionaryValue params;
    504   params.SetInteger("entered", entered);
    505   SendDeviceNotification(device, &params);
    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, &params);
    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, &params);
    579 }
    580 
    581 }  // namespace options
    582 }  // namespace chromeos
    583