Home | History | Annotate | Download | only in bluetooth_low_energy
      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_low_energy/bluetooth_low_energy_api.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/lazy_instance.h"
      9 #include "base/strings/stringprintf.h"
     10 #include "chrome/browser/extensions/api/bluetooth_low_energy/utils.h"
     11 #include "chrome/common/extensions/api/bluetooth/bluetooth_manifest_data.h"
     12 #include "chrome/common/extensions/api/bluetooth_low_energy.h"
     13 #include "content/public/browser/browser_thread.h"
     14 #include "extensions/browser/event_router.h"
     15 #include "extensions/common/permissions/permissions_data.h"
     16 
     17 using content::BrowserContext;
     18 using content::BrowserThread;
     19 
     20 namespace apibtle = extensions::api::bluetooth_low_energy;
     21 
     22 namespace extensions {
     23 
     24 namespace {
     25 
     26 const char kErrorAdapterNotInitialized[] =
     27     "Could not initialize Bluetooth adapter";
     28 const char kErrorAlreadyConnected[] = "Already connected";
     29 const char kErrorAlreadyNotifying[] = "Already notifying";
     30 const char kErrorInProgress[] = "In progress";
     31 const char kErrorNotConnected[] = "Not connected";
     32 const char kErrorNotNotifying[] = "Not notifying";
     33 const char kErrorNotFound[] = "Instance not found";
     34 const char kErrorOperationFailed[] = "Operation failed";
     35 const char kErrorPermissionDenied[] = "Permission denied";
     36 const char kErrorPlatformNotSupported[] =
     37     "This operation is not supported on the current platform";
     38 
     39 // Returns the correct error string based on error status |status|. This is used
     40 // to set the value of |chrome.runtime.lastError.message| and should not be
     41 // passed |BluetoothLowEnergyEventRouter::kStatusSuccess|.
     42 std::string StatusToString(BluetoothLowEnergyEventRouter::Status status) {
     43   switch (status) {
     44     case BluetoothLowEnergyEventRouter::kStatusErrorPermissionDenied:
     45       return kErrorPermissionDenied;
     46     case BluetoothLowEnergyEventRouter::kStatusErrorNotFound:
     47       return kErrorNotFound;
     48     case BluetoothLowEnergyEventRouter::kStatusErrorAlreadyConnected:
     49       return kErrorAlreadyConnected;
     50     case BluetoothLowEnergyEventRouter::kStatusErrorAlreadyNotifying:
     51       return kErrorAlreadyNotifying;
     52     case BluetoothLowEnergyEventRouter::kStatusErrorNotConnected:
     53       return kErrorNotConnected;
     54     case BluetoothLowEnergyEventRouter::kStatusErrorNotNotifying:
     55       return kErrorNotNotifying;
     56     case BluetoothLowEnergyEventRouter::kStatusErrorInProgress:
     57       return kErrorInProgress;
     58     case BluetoothLowEnergyEventRouter::kStatusSuccess:
     59       NOTREACHED();
     60       break;
     61     default:
     62       return kErrorOperationFailed;
     63   }
     64   return "";
     65 }
     66 
     67 extensions::BluetoothLowEnergyEventRouter* GetEventRouter(
     68     BrowserContext* context) {
     69   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     70   return extensions::BluetoothLowEnergyAPI::Get(context)->event_router();
     71 }
     72 
     73 void DoWorkCallback(const base::Callback<bool()>& callback) {
     74   DCHECK(!callback.is_null());
     75   callback.Run();
     76 }
     77 
     78 }  // namespace
     79 
     80 
     81 static base::LazyInstance<BrowserContextKeyedAPIFactory<BluetoothLowEnergyAPI> >
     82     g_factory = LAZY_INSTANCE_INITIALIZER;
     83 
     84 // static
     85 BrowserContextKeyedAPIFactory<BluetoothLowEnergyAPI>*
     86 BluetoothLowEnergyAPI::GetFactoryInstance() {
     87   return g_factory.Pointer();
     88 }
     89 
     90 // static
     91 BluetoothLowEnergyAPI* BluetoothLowEnergyAPI::Get(BrowserContext* context) {
     92   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     93   return GetFactoryInstance()->Get(context);
     94 }
     95 
     96 BluetoothLowEnergyAPI::BluetoothLowEnergyAPI(BrowserContext* context)
     97     : event_router_(new BluetoothLowEnergyEventRouter(context)),
     98       browser_context_(context) {
     99   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    100 }
    101 
    102 BluetoothLowEnergyAPI::~BluetoothLowEnergyAPI() {
    103 }
    104 
    105 void BluetoothLowEnergyAPI::Shutdown() {
    106   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    107 }
    108 
    109 namespace api {
    110 
    111 BluetoothLowEnergyExtensionFunction::BluetoothLowEnergyExtensionFunction() {
    112 }
    113 
    114 BluetoothLowEnergyExtensionFunction::~BluetoothLowEnergyExtensionFunction() {
    115 }
    116 
    117 bool BluetoothLowEnergyExtensionFunction::RunAsync() {
    118   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    119 
    120   if (!BluetoothManifestData::CheckLowEnergyPermitted(GetExtension())) {
    121     error_ = kErrorPermissionDenied;
    122     return false;
    123   }
    124 
    125   BluetoothLowEnergyEventRouter* event_router =
    126       GetEventRouter(browser_context());
    127   if (!event_router->IsBluetoothSupported()) {
    128     SetError(kErrorPlatformNotSupported);
    129     return false;
    130   }
    131 
    132   // It is safe to pass |this| here as ExtensionFunction is refcounted.
    133   if (!event_router->InitializeAdapterAndInvokeCallback(base::Bind(
    134           &DoWorkCallback,
    135           base::Bind(&BluetoothLowEnergyExtensionFunction::DoWork, this)))) {
    136     SetError(kErrorAdapterNotInitialized);
    137     return false;
    138   }
    139 
    140   return true;
    141 }
    142 
    143 bool BluetoothLowEnergyConnectFunction::DoWork() {
    144   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    145 
    146   BluetoothLowEnergyEventRouter* event_router =
    147       GetEventRouter(browser_context());
    148 
    149   // The adapter must be initialized at this point, but return an error instead
    150   // of asserting.
    151   if (!event_router->HasAdapter()) {
    152     SetError(kErrorAdapterNotInitialized);
    153     SendResponse(false);
    154     return false;
    155   }
    156 
    157   scoped_ptr<apibtle::Connect::Params> params(
    158       apibtle::Connect::Params::Create(*args_));
    159   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
    160 
    161   bool persistent = false;  // Not persistent by default.
    162   apibtle::ConnectProperties* properties = params.get()->properties.get();
    163   if (properties)
    164     persistent = properties->persistent;
    165 
    166   event_router->Connect(
    167       persistent,
    168       GetExtension(),
    169       params->device_address,
    170       base::Bind(&BluetoothLowEnergyConnectFunction::SuccessCallback, this),
    171       base::Bind(&BluetoothLowEnergyConnectFunction::ErrorCallback, this));
    172 
    173   return true;
    174 }
    175 
    176 void BluetoothLowEnergyConnectFunction::SuccessCallback() {
    177   SendResponse(true);
    178 }
    179 
    180 void BluetoothLowEnergyConnectFunction::ErrorCallback(
    181     BluetoothLowEnergyEventRouter::Status status) {
    182   SetError(StatusToString(status));
    183   SendResponse(false);
    184 }
    185 
    186 bool BluetoothLowEnergyDisconnectFunction::DoWork() {
    187   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    188 
    189   BluetoothLowEnergyEventRouter* event_router =
    190       GetEventRouter(browser_context());
    191 
    192   // The adapter must be initialized at this point, but return an error instead
    193   // of asserting.
    194   if (!event_router->HasAdapter()) {
    195     SetError(kErrorAdapterNotInitialized);
    196     SendResponse(false);
    197     return false;
    198   }
    199 
    200   scoped_ptr<apibtle::Disconnect::Params> params(
    201       apibtle::Disconnect::Params::Create(*args_));
    202   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
    203 
    204   event_router->Disconnect(
    205       GetExtension(),
    206       params->device_address,
    207       base::Bind(&BluetoothLowEnergyDisconnectFunction::SuccessCallback, this),
    208       base::Bind(&BluetoothLowEnergyDisconnectFunction::ErrorCallback, this));
    209 
    210   return true;
    211 }
    212 
    213 void BluetoothLowEnergyDisconnectFunction::SuccessCallback() {
    214   SendResponse(true);
    215 }
    216 
    217 void BluetoothLowEnergyDisconnectFunction::ErrorCallback(
    218     BluetoothLowEnergyEventRouter::Status status) {
    219   SetError(StatusToString(status));
    220   SendResponse(false);
    221 }
    222 
    223 bool BluetoothLowEnergyGetServiceFunction::DoWork() {
    224   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    225 
    226   BluetoothLowEnergyEventRouter* event_router =
    227       GetEventRouter(browser_context());
    228 
    229   // The adapter must be initialized at this point, but return an error instead
    230   // of asserting.
    231   if (!event_router->HasAdapter()) {
    232     SetError(kErrorAdapterNotInitialized);
    233     SendResponse(false);
    234     return false;
    235   }
    236 
    237   scoped_ptr<apibtle::GetService::Params> params(
    238       apibtle::GetService::Params::Create(*args_));
    239   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
    240 
    241   apibtle::Service service;
    242   BluetoothLowEnergyEventRouter::Status status =
    243       event_router->GetService(params->service_id, &service);
    244   if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
    245     SetError(StatusToString(status));
    246     SendResponse(false);
    247     return false;
    248   }
    249 
    250   results_ = apibtle::GetService::Results::Create(service);
    251   SendResponse(true);
    252 
    253   return true;
    254 }
    255 
    256 bool BluetoothLowEnergyGetServicesFunction::DoWork() {
    257   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    258 
    259   BluetoothLowEnergyEventRouter* event_router =
    260       GetEventRouter(browser_context());
    261 
    262   // The adapter must be initialized at this point, but return an error instead
    263   // of asserting.
    264   if (!event_router->HasAdapter()) {
    265     SetError(kErrorAdapterNotInitialized);
    266     SendResponse(false);
    267     return false;
    268   }
    269 
    270   scoped_ptr<apibtle::GetServices::Params> params(
    271       apibtle::GetServices::Params::Create(*args_));
    272   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
    273 
    274   BluetoothLowEnergyEventRouter::ServiceList service_list;
    275   if (!event_router->GetServices(params->device_address, &service_list)) {
    276     SetError(kErrorNotFound);
    277     SendResponse(false);
    278     return false;
    279   }
    280 
    281   results_ = apibtle::GetServices::Results::Create(service_list);
    282   SendResponse(true);
    283 
    284   return true;
    285 }
    286 
    287 bool BluetoothLowEnergyGetCharacteristicFunction::DoWork() {
    288   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    289 
    290   BluetoothLowEnergyEventRouter* event_router =
    291       GetEventRouter(browser_context());
    292 
    293   // The adapter must be initialized at this point, but return an error instead
    294   // of asserting.
    295   if (!event_router->HasAdapter()) {
    296     SetError(kErrorAdapterNotInitialized);
    297     SendResponse(false);
    298     return false;
    299   }
    300 
    301   scoped_ptr<apibtle::GetCharacteristic::Params> params(
    302       apibtle::GetCharacteristic::Params::Create(*args_));
    303   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
    304 
    305   apibtle::Characteristic characteristic;
    306   BluetoothLowEnergyEventRouter::Status status =
    307       event_router->GetCharacteristic(
    308           GetExtension(), params->characteristic_id, &characteristic);
    309   if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
    310     SetError(StatusToString(status));
    311     SendResponse(false);
    312     return false;
    313   }
    314 
    315   // Manually construct the result instead of using
    316   // apibtle::GetCharacteristic::Result::Create as it doesn't convert lists of
    317   // enums correctly.
    318   SetResult(apibtle::CharacteristicToValue(&characteristic).release());
    319   SendResponse(true);
    320 
    321   return true;
    322 }
    323 
    324 bool BluetoothLowEnergyGetCharacteristicsFunction::DoWork() {
    325   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    326 
    327   BluetoothLowEnergyEventRouter* event_router =
    328       GetEventRouter(browser_context());
    329 
    330   // The adapter must be initialized at this point, but return an error instead
    331   // of asserting.
    332   if (!event_router->HasAdapter()) {
    333     SetError(kErrorAdapterNotInitialized);
    334     SendResponse(false);
    335     return false;
    336   }
    337 
    338   scoped_ptr<apibtle::GetCharacteristics::Params> params(
    339       apibtle::GetCharacteristics::Params::Create(*args_));
    340   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
    341 
    342   BluetoothLowEnergyEventRouter::CharacteristicList characteristic_list;
    343   BluetoothLowEnergyEventRouter::Status status =
    344       event_router->GetCharacteristics(
    345           GetExtension(), params->service_id, &characteristic_list);
    346   if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
    347     SetError(StatusToString(status));
    348     SendResponse(false);
    349     return false;
    350   }
    351 
    352   // Manually construct the result instead of using
    353   // apibtle::GetCharacteristics::Result::Create as it doesn't convert lists of
    354   // enums correctly.
    355   scoped_ptr<base::ListValue> result(new base::ListValue());
    356   for (BluetoothLowEnergyEventRouter::CharacteristicList::iterator iter =
    357            characteristic_list.begin();
    358        iter != characteristic_list.end();
    359        ++iter)
    360     result->Append(apibtle::CharacteristicToValue(iter->get()).release());
    361 
    362   SetResult(result.release());
    363   SendResponse(true);
    364 
    365   return true;
    366 }
    367 
    368 bool BluetoothLowEnergyGetIncludedServicesFunction::DoWork() {
    369   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    370 
    371   BluetoothLowEnergyEventRouter* event_router =
    372       GetEventRouter(browser_context());
    373 
    374   // The adapter must be initialized at this point, but return an error instead
    375   // of asserting.
    376   if (!event_router->HasAdapter()) {
    377     SetError(kErrorAdapterNotInitialized);
    378     SendResponse(false);
    379     return false;
    380   }
    381 
    382   scoped_ptr<apibtle::GetIncludedServices::Params> params(
    383       apibtle::GetIncludedServices::Params::Create(*args_));
    384   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
    385 
    386   BluetoothLowEnergyEventRouter::ServiceList service_list;
    387   BluetoothLowEnergyEventRouter::Status status =
    388       event_router->GetIncludedServices(params->service_id, &service_list);
    389   if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
    390     SetError(StatusToString(status));
    391     SendResponse(false);
    392     return false;
    393   }
    394 
    395   results_ = apibtle::GetIncludedServices::Results::Create(service_list);
    396   SendResponse(true);
    397 
    398   return true;
    399 }
    400 
    401 bool BluetoothLowEnergyGetDescriptorFunction::DoWork() {
    402   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    403 
    404   BluetoothLowEnergyEventRouter* event_router =
    405       GetEventRouter(browser_context());
    406 
    407   // The adapter must be initialized at this point, but return an error instead
    408   // of asserting.
    409   if (!event_router->HasAdapter()) {
    410     SetError(kErrorAdapterNotInitialized);
    411     SendResponse(false);
    412     return false;
    413   }
    414 
    415   scoped_ptr<apibtle::GetDescriptor::Params> params(
    416       apibtle::GetDescriptor::Params::Create(*args_));
    417   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
    418 
    419   apibtle::Descriptor descriptor;
    420   BluetoothLowEnergyEventRouter::Status status = event_router->GetDescriptor(
    421       GetExtension(), params->descriptor_id, &descriptor);
    422   if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
    423     SetError(StatusToString(status));
    424     SendResponse(false);
    425     return false;
    426   }
    427 
    428   // Manually construct the result instead of using
    429   // apibtle::GetDescriptor::Result::Create as it doesn't convert lists of enums
    430   // correctly.
    431   SetResult(apibtle::DescriptorToValue(&descriptor).release());
    432   SendResponse(true);
    433 
    434   return true;
    435 }
    436 
    437 bool BluetoothLowEnergyGetDescriptorsFunction::DoWork() {
    438   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    439 
    440   BluetoothLowEnergyEventRouter* event_router =
    441       GetEventRouter(browser_context());
    442 
    443   // The adapter must be initialized at this point, but return an error instead
    444   // of asserting.
    445   if (!event_router->HasAdapter()) {
    446     SetError(kErrorAdapterNotInitialized);
    447     SendResponse(false);
    448     return false;
    449   }
    450 
    451   scoped_ptr<apibtle::GetDescriptors::Params> params(
    452       apibtle::GetDescriptors::Params::Create(*args_));
    453   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
    454 
    455   BluetoothLowEnergyEventRouter::DescriptorList descriptor_list;
    456   BluetoothLowEnergyEventRouter::Status status = event_router->GetDescriptors(
    457       GetExtension(), params->characteristic_id, &descriptor_list);
    458   if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
    459     SetError(StatusToString(status));
    460     SendResponse(false);
    461     return false;
    462   }
    463 
    464   // Manually construct the result instead of using
    465   // apibtle::GetDescriptors::Result::Create as it doesn't convert lists of
    466   // enums correctly.
    467   scoped_ptr<base::ListValue> result(new base::ListValue());
    468   for (BluetoothLowEnergyEventRouter::DescriptorList::iterator iter =
    469            descriptor_list.begin();
    470        iter != descriptor_list.end();
    471        ++iter)
    472     result->Append(apibtle::DescriptorToValue(iter->get()).release());
    473 
    474   SetResult(result.release());
    475   SendResponse(true);
    476 
    477   return true;
    478 }
    479 
    480 bool BluetoothLowEnergyReadCharacteristicValueFunction::DoWork() {
    481   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    482 
    483   BluetoothLowEnergyEventRouter* event_router =
    484       GetEventRouter(browser_context());
    485 
    486   // The adapter must be initialized at this point, but return an error instead
    487   // of asserting.
    488   if (!event_router->HasAdapter()) {
    489     SetError(kErrorAdapterNotInitialized);
    490     SendResponse(false);
    491     return false;
    492   }
    493 
    494   scoped_ptr<apibtle::ReadCharacteristicValue::Params> params(
    495       apibtle::ReadCharacteristicValue::Params::Create(*args_));
    496   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
    497 
    498   instance_id_ = params->characteristic_id;
    499   event_router->ReadCharacteristicValue(
    500       GetExtension(),
    501       instance_id_,
    502       base::Bind(
    503           &BluetoothLowEnergyReadCharacteristicValueFunction::SuccessCallback,
    504           this),
    505       base::Bind(
    506           &BluetoothLowEnergyReadCharacteristicValueFunction::ErrorCallback,
    507           this));
    508 
    509   return true;
    510 }
    511 
    512 void BluetoothLowEnergyReadCharacteristicValueFunction::SuccessCallback() {
    513   // Obtain info on the characteristic and see whether or not the characteristic
    514   // is still around.
    515   apibtle::Characteristic characteristic;
    516   BluetoothLowEnergyEventRouter::Status status =
    517       GetEventRouter(browser_context())
    518           ->GetCharacteristic(GetExtension(), instance_id_, &characteristic);
    519   if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
    520     SetError(StatusToString(status));
    521     SendResponse(false);
    522     return;
    523   }
    524 
    525   // Manually construct the result instead of using
    526   // apibtle::GetCharacteristic::Result::Create as it doesn't convert lists of
    527   // enums correctly.
    528   SetResult(apibtle::CharacteristicToValue(&characteristic).release());
    529   SendResponse(true);
    530 }
    531 
    532 void BluetoothLowEnergyReadCharacteristicValueFunction::ErrorCallback(
    533     BluetoothLowEnergyEventRouter::Status status) {
    534   SetError(StatusToString(status));
    535   SendResponse(false);
    536 }
    537 
    538 bool BluetoothLowEnergyWriteCharacteristicValueFunction::DoWork() {
    539   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    540 
    541   BluetoothLowEnergyEventRouter* event_router =
    542       GetEventRouter(browser_context());
    543 
    544   // The adapter must be initialized at this point, but return an error instead
    545   // of asserting.
    546   if (!event_router->HasAdapter()) {
    547     SetError(kErrorAdapterNotInitialized);
    548     SendResponse(false);
    549     return false;
    550   }
    551 
    552   scoped_ptr<apibtle::WriteCharacteristicValue::Params> params(
    553       apibtle::WriteCharacteristicValue::Params::Create(*args_));
    554   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
    555 
    556   std::vector<uint8> value(params->value.begin(), params->value.end());
    557   event_router->WriteCharacteristicValue(
    558       GetExtension(),
    559       params->characteristic_id,
    560       value,
    561       base::Bind(
    562           &BluetoothLowEnergyWriteCharacteristicValueFunction::SuccessCallback,
    563           this),
    564       base::Bind(
    565           &BluetoothLowEnergyWriteCharacteristicValueFunction::ErrorCallback,
    566           this));
    567 
    568   return true;
    569 }
    570 
    571 void BluetoothLowEnergyWriteCharacteristicValueFunction::SuccessCallback() {
    572   results_ = apibtle::WriteCharacteristicValue::Results::Create();
    573   SendResponse(true);
    574 }
    575 
    576 void BluetoothLowEnergyWriteCharacteristicValueFunction::ErrorCallback(
    577     BluetoothLowEnergyEventRouter::Status status) {
    578   SetError(StatusToString(status));
    579   SendResponse(false);
    580 }
    581 
    582 bool BluetoothLowEnergyStartCharacteristicNotificationsFunction::DoWork() {
    583   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    584 
    585   BluetoothLowEnergyEventRouter* event_router =
    586       GetEventRouter(browser_context());
    587 
    588   // The adapter must be initialized at this point, but return an error instead
    589   // of asserting.
    590   if (!event_router->HasAdapter()) {
    591     SetError(kErrorAdapterNotInitialized);
    592     SendResponse(false);
    593     return false;
    594   }
    595 
    596   scoped_ptr<apibtle::StartCharacteristicNotifications::Params> params(
    597       apibtle::StartCharacteristicNotifications::Params::Create(*args_));
    598   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
    599 
    600   bool persistent = false;  // Not persistent by default.
    601   apibtle::NotificationProperties* properties = params.get()->properties.get();
    602   if (properties)
    603     persistent = properties->persistent;
    604 
    605   event_router->StartCharacteristicNotifications(
    606       persistent,
    607       GetExtension(),
    608       params->characteristic_id,
    609       base::Bind(&BluetoothLowEnergyStartCharacteristicNotificationsFunction::
    610                      SuccessCallback,
    611                  this),
    612       base::Bind(&BluetoothLowEnergyStartCharacteristicNotificationsFunction::
    613                      ErrorCallback,
    614                  this));
    615 
    616   return true;
    617 }
    618 
    619 void
    620 BluetoothLowEnergyStartCharacteristicNotificationsFunction::SuccessCallback() {
    621   SendResponse(true);
    622 }
    623 
    624 void BluetoothLowEnergyStartCharacteristicNotificationsFunction::ErrorCallback(
    625     BluetoothLowEnergyEventRouter::Status status) {
    626   SetError(StatusToString(status));
    627   SendResponse(false);
    628 }
    629 
    630 bool BluetoothLowEnergyStopCharacteristicNotificationsFunction::DoWork() {
    631   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    632 
    633   BluetoothLowEnergyEventRouter* event_router =
    634       GetEventRouter(browser_context());
    635 
    636   // The adapter must be initialized at this point, but return an error instead
    637   // of asserting.
    638   if (!event_router->HasAdapter()) {
    639     SetError(kErrorAdapterNotInitialized);
    640     SendResponse(false);
    641     return false;
    642   }
    643 
    644   scoped_ptr<apibtle::StopCharacteristicNotifications::Params> params(
    645       apibtle::StopCharacteristicNotifications::Params::Create(*args_));
    646   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
    647 
    648   event_router->StopCharacteristicNotifications(
    649       GetExtension(),
    650       params->characteristic_id,
    651       base::Bind(&BluetoothLowEnergyStopCharacteristicNotificationsFunction::
    652                      SuccessCallback,
    653                  this),
    654       base::Bind(&BluetoothLowEnergyStopCharacteristicNotificationsFunction::
    655                      ErrorCallback,
    656                  this));
    657 
    658   return true;
    659 }
    660 
    661 void
    662 BluetoothLowEnergyStopCharacteristicNotificationsFunction::SuccessCallback() {
    663   SendResponse(true);
    664 }
    665 
    666 void BluetoothLowEnergyStopCharacteristicNotificationsFunction::ErrorCallback(
    667     BluetoothLowEnergyEventRouter::Status status) {
    668   SetError(StatusToString(status));
    669   SendResponse(false);
    670 }
    671 
    672 bool BluetoothLowEnergyReadDescriptorValueFunction::DoWork() {
    673   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    674 
    675   BluetoothLowEnergyEventRouter* event_router =
    676       GetEventRouter(browser_context());
    677 
    678   // The adapter must be initialized at this point, but return an error instead
    679   // of asserting.
    680   if (!event_router->HasAdapter()) {
    681     SetError(kErrorAdapterNotInitialized);
    682     SendResponse(false);
    683     return false;
    684   }
    685 
    686   scoped_ptr<apibtle::ReadDescriptorValue::Params> params(
    687       apibtle::ReadDescriptorValue::Params::Create(*args_));
    688   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
    689 
    690   instance_id_ = params->descriptor_id;
    691   event_router->ReadDescriptorValue(
    692       GetExtension(),
    693       instance_id_,
    694       base::Bind(
    695           &BluetoothLowEnergyReadDescriptorValueFunction::SuccessCallback,
    696           this),
    697       base::Bind(&BluetoothLowEnergyReadDescriptorValueFunction::ErrorCallback,
    698                  this));
    699 
    700   return true;
    701 }
    702 
    703 void BluetoothLowEnergyReadDescriptorValueFunction::SuccessCallback() {
    704   // Obtain info on the descriptor and see whether or not the descriptor is
    705   // still around.
    706   apibtle::Descriptor descriptor;
    707   BluetoothLowEnergyEventRouter::Status status =
    708       GetEventRouter(browser_context())
    709           ->GetDescriptor(GetExtension(), instance_id_, &descriptor);
    710   if (status != BluetoothLowEnergyEventRouter::kStatusSuccess) {
    711     SetError(StatusToString(status));
    712     SendResponse(false);
    713     return;
    714   }
    715 
    716   // Manually construct the result instead of using
    717   // apibtle::GetDescriptor::Results::Create as it doesn't convert lists of
    718   // enums correctly.
    719   SetResult(apibtle::DescriptorToValue(&descriptor).release());
    720   SendResponse(true);
    721 }
    722 
    723 void BluetoothLowEnergyReadDescriptorValueFunction::ErrorCallback(
    724     BluetoothLowEnergyEventRouter::Status status) {
    725   SetError(StatusToString(status));
    726   SendResponse(false);
    727 }
    728 
    729 bool BluetoothLowEnergyWriteDescriptorValueFunction::DoWork() {
    730   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    731 
    732   BluetoothLowEnergyEventRouter* event_router =
    733       GetEventRouter(browser_context());
    734 
    735   // The adapter must be initialized at this point, but return an error instead
    736   // of asserting.
    737   if (!event_router->HasAdapter()) {
    738     SetError(kErrorAdapterNotInitialized);
    739     SendResponse(false);
    740     return false;
    741   }
    742 
    743   scoped_ptr<apibtle::WriteDescriptorValue::Params> params(
    744       apibtle::WriteDescriptorValue::Params::Create(*args_));
    745   EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
    746 
    747   std::vector<uint8> value(params->value.begin(), params->value.end());
    748   event_router->WriteDescriptorValue(
    749       GetExtension(),
    750       params->descriptor_id,
    751       value,
    752       base::Bind(
    753           &BluetoothLowEnergyWriteDescriptorValueFunction::SuccessCallback,
    754           this),
    755       base::Bind(&BluetoothLowEnergyWriteDescriptorValueFunction::ErrorCallback,
    756                  this));
    757 
    758   return true;
    759 }
    760 
    761 void BluetoothLowEnergyWriteDescriptorValueFunction::SuccessCallback() {
    762   results_ = apibtle::WriteDescriptorValue::Results::Create();
    763   SendResponse(true);
    764 }
    765 
    766 void BluetoothLowEnergyWriteDescriptorValueFunction::ErrorCallback(
    767     BluetoothLowEnergyEventRouter::Status status) {
    768   SetError(StatusToString(status));
    769   SendResponse(false);
    770 }
    771 
    772 }  // namespace api
    773 }  // namespace extensions
    774