Home | History | Annotate | Download | only in bluetooth
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/extensions/api/bluetooth/bluetooth_private_api.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/lazy_instance.h"
      9 #include "base/strings/string_util.h"
     10 #include "chrome/browser/extensions/api/bluetooth/bluetooth_api.h"
     11 #include "chrome/browser/extensions/api/bluetooth/bluetooth_event_router.h"
     12 #include "chrome/common/extensions/api/bluetooth_private.h"
     13 #include "device/bluetooth/bluetooth_adapter.h"
     14 #include "device/bluetooth/bluetooth_adapter_factory.h"
     15 
     16 namespace bt_private = extensions::api::bluetooth_private;
     17 
     18 namespace extensions {
     19 
     20 static base::LazyInstance<BrowserContextKeyedAPIFactory<BluetoothPrivateAPI> >
     21     g_factory = LAZY_INSTANCE_INITIALIZER;
     22 
     23 // static
     24 BrowserContextKeyedAPIFactory<BluetoothPrivateAPI>*
     25 BluetoothPrivateAPI::GetFactoryInstance() {
     26   return g_factory.Pointer();
     27 }
     28 
     29 BluetoothPrivateAPI::BluetoothPrivateAPI(content::BrowserContext* context)
     30     : browser_context_(context) {
     31   EventRouter::Get(browser_context_)
     32       ->RegisterObserver(this, bt_private::OnPairing::kEventName);
     33 }
     34 
     35 BluetoothPrivateAPI::~BluetoothPrivateAPI() {}
     36 
     37 void BluetoothPrivateAPI::Shutdown() {
     38   EventRouter::Get(browser_context_)->UnregisterObserver(this);
     39 }
     40 
     41 void BluetoothPrivateAPI::OnListenerAdded(const EventListenerInfo& details) {
     42   // This function can be called multiple times for the same JS listener, for
     43   // example, once for the addListener call and again if it is a lazy listener.
     44   if (!details.browser_context)
     45     return;
     46 
     47   BluetoothAPI::Get(browser_context_)->event_router()->AddPairingDelegate(
     48       details.extension_id);
     49 }
     50 
     51 void BluetoothPrivateAPI::OnListenerRemoved(const EventListenerInfo& details) {
     52   // This function can be called multiple times for the same JS listener, for
     53   // example, once for the addListener call and again if it is a lazy listener.
     54   if (!details.browser_context)
     55     return;
     56 
     57   BluetoothAPI::Get(browser_context_)->event_router()->RemovePairingDelegate(
     58       details.extension_id);
     59 }
     60 
     61 namespace api {
     62 
     63 namespace {
     64 
     65 const char kNameProperty[] = "name";
     66 const char kPoweredProperty[] = "powered";
     67 const char kDiscoverableProperty[] = "discoverable";
     68 
     69 const char kSetAdapterPropertyError[] = "Error setting adapter properties: $1";
     70 
     71 const char kDeviceNotFoundError[] =
     72     "Given address is not a valid Bluetooth device.";
     73 
     74 const char kPairingNotEnabled[] =
     75     "Pairing must be enabled to set a pairing response.";
     76 
     77 const char kInvalidPairingResponseOptions[] =
     78     "Invalid pairing response options";
     79 
     80 const char kAdapterNotPresent[] =
     81     "Could not find a Bluetooth adapter.";
     82 
     83 // Returns true if the pairing response options passed into the
     84 // setPairingResponse function are valid.
     85 bool ValidatePairingResponseOptions(
     86     const device::BluetoothDevice* device,
     87     const bt_private::SetPairingResponseOptions& options) {
     88   bool response = options.response != bt_private::PAIRING_RESPONSE_NONE;
     89   bool pincode = options.pincode.get() != NULL;
     90   bool passkey = options.passkey.get() != NULL;
     91 
     92   if (!response && !pincode && !passkey)
     93     return false;
     94   if (pincode && passkey)
     95     return false;
     96   if (options.response != bt_private::PAIRING_RESPONSE_CONFIRM &&
     97       (pincode || passkey))
     98     return false;
     99 
    100   // Check the BluetoothDevice is in expecting the correct response.
    101   if (!device->ExpectingConfirmation() && !device->ExpectingPinCode() &&
    102       !device->ExpectingPasskey())
    103     return false;
    104   if (pincode && !device->ExpectingPinCode())
    105     return false;
    106   if (passkey && !device->ExpectingPasskey())
    107     return false;
    108   if (options.response == bt_private::PAIRING_RESPONSE_CONFIRM && !pincode &&
    109       !passkey && !device->ExpectingConfirmation())
    110     return false;
    111 
    112   return true;
    113 }
    114 
    115 }  // namespace
    116 
    117 BluetoothPrivateSetAdapterStateFunction::
    118     BluetoothPrivateSetAdapterStateFunction() {}
    119 
    120 BluetoothPrivateSetAdapterStateFunction::
    121     ~BluetoothPrivateSetAdapterStateFunction() {}
    122 
    123 bool BluetoothPrivateSetAdapterStateFunction::DoWork(
    124     scoped_refptr<device::BluetoothAdapter> adapter) {
    125   scoped_ptr<bt_private::SetAdapterState::Params> params(
    126       bt_private::SetAdapterState::Params::Create(*args_));
    127   EXTENSION_FUNCTION_VALIDATE(params.get());
    128 
    129   if (!adapter->IsPresent()) {
    130     SetError(kAdapterNotPresent);
    131     SendResponse(false);
    132     return true;
    133   }
    134 
    135   const bt_private::NewAdapterState& new_state = params->adapter_state;
    136 
    137   // These properties are not owned.
    138   std::string* name = new_state.name.get();
    139   bool* powered = new_state.powered.get();
    140   bool* discoverable = new_state.discoverable.get();
    141 
    142   if (name && adapter->GetName() != *name) {
    143     pending_properties_.insert(kNameProperty);
    144     adapter->SetName(*name,
    145                      CreatePropertySetCallback(kNameProperty),
    146                      CreatePropertyErrorCallback(kNameProperty));
    147   }
    148 
    149   if (powered && adapter->IsPowered() != *powered) {
    150     pending_properties_.insert(kPoweredProperty);
    151     adapter->SetPowered(*powered,
    152                         CreatePropertySetCallback(kPoweredProperty),
    153                         CreatePropertyErrorCallback(kPoweredProperty));
    154   }
    155 
    156   if (discoverable && adapter->IsDiscoverable() != *discoverable) {
    157     pending_properties_.insert(kDiscoverableProperty);
    158     adapter->SetDiscoverable(
    159         *discoverable,
    160         CreatePropertySetCallback(kDiscoverableProperty),
    161         CreatePropertyErrorCallback(kDiscoverableProperty));
    162   }
    163 
    164   if (pending_properties_.empty())
    165     SendResponse(true);
    166   return true;
    167 }
    168 
    169 base::Closure
    170 BluetoothPrivateSetAdapterStateFunction::CreatePropertySetCallback(
    171     const std::string& property_name) {
    172   return base::Bind(
    173       &BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertySet,
    174       this,
    175       property_name);
    176 }
    177 
    178 base::Closure
    179 BluetoothPrivateSetAdapterStateFunction::CreatePropertyErrorCallback(
    180     const std::string& property_name) {
    181   return base::Bind(
    182       &BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertyError,
    183       this,
    184       property_name);
    185 }
    186 
    187 void BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertySet(
    188     const std::string& property) {
    189   DCHECK(pending_properties_.find(property) != pending_properties_.end());
    190   DCHECK(failed_properties_.find(property) == failed_properties_.end());
    191 
    192   pending_properties_.erase(property);
    193   if (pending_properties_.empty()) {
    194     if (failed_properties_.empty())
    195       SendResponse(true);
    196     else
    197       SendError();
    198   }
    199 }
    200 
    201 void BluetoothPrivateSetAdapterStateFunction::OnAdapterPropertyError(
    202     const std::string& property) {
    203   DCHECK(pending_properties_.find(property) != pending_properties_.end());
    204   DCHECK(failed_properties_.find(property) == failed_properties_.end());
    205 
    206   pending_properties_.erase(property);
    207   failed_properties_.insert(property);
    208   if (pending_properties_.empty())
    209     SendError();
    210 }
    211 
    212 void BluetoothPrivateSetAdapterStateFunction::SendError() {
    213   DCHECK(pending_properties_.empty());
    214   DCHECK(!failed_properties_.empty());
    215 
    216   std::vector<std::string> failed_vector;
    217   std::copy(failed_properties_.begin(),
    218             failed_properties_.end(),
    219             std::back_inserter(failed_vector));
    220 
    221   std::vector<std::string> replacements(1);
    222   replacements[0] = JoinString(failed_vector, ", ");
    223   std::string error =
    224       ReplaceStringPlaceholders(kSetAdapterPropertyError, replacements, NULL);
    225   SetError(error);
    226   SendResponse(false);
    227 }
    228 
    229 BluetoothPrivateSetPairingResponseFunction::
    230     BluetoothPrivateSetPairingResponseFunction() {}
    231 
    232 BluetoothPrivateSetPairingResponseFunction::
    233     ~BluetoothPrivateSetPairingResponseFunction() {}
    234 
    235 bool BluetoothPrivateSetPairingResponseFunction::DoWork(
    236     scoped_refptr<device::BluetoothAdapter> adapter) {
    237   scoped_ptr<bt_private::SetPairingResponse::Params> params(
    238       bt_private::SetPairingResponse::Params::Create(*args_));
    239   EXTENSION_FUNCTION_VALIDATE(params.get());
    240   const bt_private::SetPairingResponseOptions& options = params->options;
    241 
    242   BluetoothEventRouter* router =
    243       BluetoothAPI::Get(browser_context())->event_router();
    244   if (!router->GetPairingDelegate(extension_id())) {
    245     SetError(kPairingNotEnabled);
    246     SendResponse(false);
    247     return true;
    248   }
    249 
    250   const std::string& device_address = options.device.address;
    251   device::BluetoothDevice* device = adapter->GetDevice(device_address);
    252   if (!device) {
    253     SetError(kDeviceNotFoundError);
    254     SendResponse(false);
    255     return true;
    256   }
    257 
    258   if (!ValidatePairingResponseOptions(device, options)) {
    259     SetError(kInvalidPairingResponseOptions);
    260     SendResponse(false);
    261     return true;
    262   }
    263 
    264   if (options.pincode.get()) {
    265     device->SetPinCode(*options.pincode.get());
    266   } else if (options.passkey.get()) {
    267     device->SetPasskey(*options.passkey.get());
    268   } else {
    269     switch (options.response) {
    270       case bt_private::PAIRING_RESPONSE_CONFIRM:
    271         device->ConfirmPairing();
    272         break;
    273       case bt_private::PAIRING_RESPONSE_REJECT:
    274         device->RejectPairing();
    275         break;
    276       case bt_private::PAIRING_RESPONSE_CANCEL:
    277         device->CancelPairing();
    278         break;
    279       default:
    280         NOTREACHED();
    281     }
    282   }
    283 
    284   SendResponse(true);
    285   return true;
    286 }
    287 
    288 }  // namespace api
    289 
    290 }  // namespace extensions
    291