Home | History | Annotate | Download | only in bluetooth
      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 "extensions/browser/api/bluetooth/bluetooth_event_router.h"
      6 
      7 #include <map>
      8 #include <string>
      9 
     10 #include "base/bind.h"
     11 #include "base/bind_helpers.h"
     12 #include "base/lazy_instance.h"
     13 #include "base/logging.h"
     14 #include "base/memory/ref_counted.h"
     15 #include "base/memory/scoped_vector.h"
     16 #include "base/stl_util.h"
     17 #include "base/strings/utf_string_conversions.h"
     18 #include "content/public/browser/notification_details.h"
     19 #include "content/public/browser/notification_source.h"
     20 #include "device/bluetooth/bluetooth_adapter.h"
     21 #include "device/bluetooth/bluetooth_adapter_factory.h"
     22 #include "device/bluetooth/bluetooth_device.h"
     23 #include "device/bluetooth/bluetooth_discovery_session.h"
     24 #include "extensions/browser/api/bluetooth/bluetooth_api_pairing_delegate.h"
     25 #include "extensions/browser/api/bluetooth/bluetooth_api_utils.h"
     26 #include "extensions/browser/api/bluetooth/bluetooth_private_api.h"
     27 #include "extensions/browser/event_router.h"
     28 #include "extensions/browser/extension_host.h"
     29 #include "extensions/browser/extension_registry.h"
     30 #include "extensions/browser/notification_types.h"
     31 #include "extensions/common/api/bluetooth.h"
     32 #include "extensions/common/api/bluetooth_private.h"
     33 
     34 namespace extensions {
     35 
     36 namespace bluetooth = core_api::bluetooth;
     37 namespace bt_private = core_api::bluetooth_private;
     38 
     39 BluetoothEventRouter::BluetoothEventRouter(content::BrowserContext* context)
     40     : browser_context_(context),
     41       adapter_(NULL),
     42       num_event_listeners_(0),
     43       extension_registry_observer_(this),
     44       weak_ptr_factory_(this) {
     45   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
     46   DCHECK(browser_context_);
     47   registrar_.Add(this,
     48                  extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
     49                  content::Source<content::BrowserContext>(browser_context_));
     50   extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
     51 }
     52 
     53 BluetoothEventRouter::~BluetoothEventRouter() {
     54   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
     55   if (adapter_.get()) {
     56     adapter_->RemoveObserver(this);
     57     adapter_ = NULL;
     58   }
     59   CleanUpAllExtensions();
     60 }
     61 
     62 bool BluetoothEventRouter::IsBluetoothSupported() const {
     63   return adapter_.get() ||
     64          device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
     65 }
     66 
     67 void BluetoothEventRouter::GetAdapter(
     68     const device::BluetoothAdapterFactory::AdapterCallback& callback) {
     69   if (adapter_.get()) {
     70     callback.Run(scoped_refptr<device::BluetoothAdapter>(adapter_));
     71     return;
     72   }
     73 
     74   device::BluetoothAdapterFactory::GetAdapter(callback);
     75 }
     76 
     77 void BluetoothEventRouter::StartDiscoverySession(
     78     device::BluetoothAdapter* adapter,
     79     const std::string& extension_id,
     80     const base::Closure& callback,
     81     const base::Closure& error_callback) {
     82   if (adapter != adapter_.get()) {
     83     error_callback.Run();
     84     return;
     85   }
     86   DiscoverySessionMap::iterator iter =
     87       discovery_session_map_.find(extension_id);
     88   if (iter != discovery_session_map_.end() && iter->second->IsActive()) {
     89     DVLOG(1) << "An active discovery session exists for extension.";
     90     error_callback.Run();
     91     return;
     92   }
     93   adapter->StartDiscoverySession(
     94       base::Bind(&BluetoothEventRouter::OnStartDiscoverySession,
     95                  weak_ptr_factory_.GetWeakPtr(),
     96                  extension_id,
     97                  callback),
     98       error_callback);
     99 }
    100 
    101 void BluetoothEventRouter::StopDiscoverySession(
    102     device::BluetoothAdapter* adapter,
    103     const std::string& extension_id,
    104     const base::Closure& callback,
    105     const base::Closure& error_callback) {
    106   if (adapter != adapter_.get()) {
    107     error_callback.Run();
    108     return;
    109   }
    110   DiscoverySessionMap::iterator iter =
    111       discovery_session_map_.find(extension_id);
    112   if (iter == discovery_session_map_.end() || !iter->second->IsActive()) {
    113     DVLOG(1) << "No active discovery session exists for extension.";
    114     error_callback.Run();
    115     return;
    116   }
    117   device::BluetoothDiscoverySession* session = iter->second;
    118   session->Stop(callback, error_callback);
    119 }
    120 
    121 BluetoothApiPairingDelegate* BluetoothEventRouter::GetPairingDelegate(
    122     const std::string& extension_id) {
    123   return ContainsKey(pairing_delegate_map_, extension_id)
    124              ? pairing_delegate_map_[extension_id]
    125              : NULL;
    126 }
    127 
    128 void BluetoothEventRouter::OnAdapterInitialized(
    129     const base::Closure& callback,
    130     scoped_refptr<device::BluetoothAdapter> adapter) {
    131   if (!adapter_.get()) {
    132     adapter_ = adapter;
    133     adapter_->AddObserver(this);
    134   }
    135 
    136   callback.Run();
    137 }
    138 
    139 void BluetoothEventRouter::MaybeReleaseAdapter() {
    140   if (adapter_.get() && num_event_listeners_ == 0 &&
    141       pairing_delegate_map_.empty()) {
    142     adapter_->RemoveObserver(this);
    143     adapter_ = NULL;
    144   }
    145 }
    146 
    147 void BluetoothEventRouter::AddPairingDelegate(const std::string& extension_id) {
    148   if (!adapter_.get()) {
    149     base::Closure self_callback =
    150         base::Bind(&BluetoothEventRouter::AddPairingDelegate,
    151                    weak_ptr_factory_.GetWeakPtr(),
    152                    extension_id);
    153     GetAdapter(base::Bind(&BluetoothEventRouter::OnAdapterInitialized,
    154                           weak_ptr_factory_.GetWeakPtr(),
    155                           self_callback));
    156     return;
    157   }
    158 
    159   if (!ContainsKey(pairing_delegate_map_, extension_id)) {
    160     BluetoothApiPairingDelegate* delegate =
    161         new BluetoothApiPairingDelegate(extension_id, browser_context_);
    162     DCHECK(adapter_.get());
    163     adapter_->AddPairingDelegate(
    164         delegate, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
    165     pairing_delegate_map_[extension_id] = delegate;
    166   } else {
    167     LOG(ERROR) << "Pairing delegate already exists for extension. "
    168                << "There should be at most one onPairing listener.";
    169     NOTREACHED();
    170   }
    171 }
    172 
    173 void BluetoothEventRouter::RemovePairingDelegate(
    174     const std::string& extension_id) {
    175   if (ContainsKey(pairing_delegate_map_, extension_id)) {
    176     BluetoothApiPairingDelegate* delegate = pairing_delegate_map_[extension_id];
    177     if (adapter_.get())
    178       adapter_->RemovePairingDelegate(delegate);
    179     pairing_delegate_map_.erase(extension_id);
    180     delete delegate;
    181     MaybeReleaseAdapter();
    182   }
    183 }
    184 
    185 void BluetoothEventRouter::AdapterPresentChanged(
    186     device::BluetoothAdapter* adapter,
    187     bool present) {
    188   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    189   if (adapter != adapter_.get()) {
    190     DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress();
    191     return;
    192   }
    193   DispatchAdapterStateEvent();
    194 }
    195 
    196 void BluetoothEventRouter::AdapterPoweredChanged(
    197     device::BluetoothAdapter* adapter,
    198     bool has_power) {
    199   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    200   if (adapter != adapter_.get()) {
    201     DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress();
    202     return;
    203   }
    204   DispatchAdapterStateEvent();
    205 }
    206 
    207 void BluetoothEventRouter::AdapterDiscoveringChanged(
    208     device::BluetoothAdapter* adapter,
    209     bool discovering) {
    210   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    211   if (adapter != adapter_.get()) {
    212     DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress();
    213     return;
    214   }
    215 
    216   if (!discovering) {
    217     // If any discovery sessions are inactive, clean them up.
    218     DiscoverySessionMap active_session_map;
    219     for (DiscoverySessionMap::iterator iter = discovery_session_map_.begin();
    220          iter != discovery_session_map_.end();
    221          ++iter) {
    222       device::BluetoothDiscoverySession* session = iter->second;
    223       if (session->IsActive()) {
    224         active_session_map[iter->first] = session;
    225         continue;
    226       }
    227       delete session;
    228     }
    229     discovery_session_map_.swap(active_session_map);
    230     MaybeReleaseAdapter();
    231   }
    232 
    233   DispatchAdapterStateEvent();
    234 }
    235 
    236 void BluetoothEventRouter::DeviceAdded(device::BluetoothAdapter* adapter,
    237                                        device::BluetoothDevice* device) {
    238   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    239   if (adapter != adapter_.get()) {
    240     DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress();
    241     return;
    242   }
    243 
    244   DispatchDeviceEvent(bluetooth::OnDeviceAdded::kEventName, device);
    245 }
    246 
    247 void BluetoothEventRouter::DeviceChanged(device::BluetoothAdapter* adapter,
    248                                          device::BluetoothDevice* device) {
    249   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    250   if (adapter != adapter_.get()) {
    251     DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress();
    252     return;
    253   }
    254 
    255   DispatchDeviceEvent(bluetooth::OnDeviceChanged::kEventName, device);
    256 }
    257 
    258 void BluetoothEventRouter::DeviceRemoved(device::BluetoothAdapter* adapter,
    259                                          device::BluetoothDevice* device) {
    260   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    261   if (adapter != adapter_.get()) {
    262     DVLOG(1) << "Ignoring event for adapter " << adapter->GetAddress();
    263     return;
    264   }
    265 
    266   DispatchDeviceEvent(bluetooth::OnDeviceRemoved::kEventName, device);
    267 }
    268 
    269 void BluetoothEventRouter::OnListenerAdded() {
    270   num_event_listeners_++;
    271   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    272   if (!adapter_.get()) {
    273     GetAdapter(base::Bind(&BluetoothEventRouter::OnAdapterInitialized,
    274                           weak_ptr_factory_.GetWeakPtr(),
    275                           base::Bind(&base::DoNothing)));
    276   }
    277 }
    278 
    279 void BluetoothEventRouter::OnListenerRemoved() {
    280   if (num_event_listeners_ > 0)
    281     num_event_listeners_--;
    282   MaybeReleaseAdapter();
    283 }
    284 
    285 void BluetoothEventRouter::DispatchAdapterStateEvent() {
    286   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    287   core_api::bluetooth::AdapterState state;
    288   PopulateAdapterState(*adapter_.get(), &state);
    289 
    290   scoped_ptr<base::ListValue> args =
    291       bluetooth::OnAdapterStateChanged::Create(state);
    292   scoped_ptr<Event> event(new Event(
    293       bluetooth::OnAdapterStateChanged::kEventName,
    294       args.Pass()));
    295   EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass());
    296 }
    297 
    298 void BluetoothEventRouter::DispatchDeviceEvent(
    299     const std::string& event_name,
    300     device::BluetoothDevice* device) {
    301   bluetooth::Device extension_device;
    302   bluetooth::BluetoothDeviceToApiDevice(*device, &extension_device);
    303 
    304   scoped_ptr<base::ListValue> args =
    305       bluetooth::OnDeviceAdded::Create(extension_device);
    306   scoped_ptr<Event> event(new Event(event_name, args.Pass()));
    307   EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass());
    308 }
    309 
    310 void BluetoothEventRouter::CleanUpForExtension(
    311     const std::string& extension_id) {
    312   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    313   RemovePairingDelegate(extension_id);
    314 
    315   // Remove any discovery session initiated by the extension.
    316   DiscoverySessionMap::iterator session_iter =
    317       discovery_session_map_.find(extension_id);
    318   if (session_iter == discovery_session_map_.end())
    319     return;
    320   delete session_iter->second;
    321   discovery_session_map_.erase(session_iter);
    322 }
    323 
    324 void BluetoothEventRouter::CleanUpAllExtensions() {
    325   for (DiscoverySessionMap::iterator it = discovery_session_map_.begin();
    326        it != discovery_session_map_.end();
    327        ++it) {
    328     delete it->second;
    329   }
    330   discovery_session_map_.clear();
    331 
    332   PairingDelegateMap::iterator pairing_iter = pairing_delegate_map_.begin();
    333   while (pairing_iter != pairing_delegate_map_.end())
    334     RemovePairingDelegate(pairing_iter++->first);
    335 }
    336 
    337 void BluetoothEventRouter::OnStartDiscoverySession(
    338     const std::string& extension_id,
    339     const base::Closure& callback,
    340     scoped_ptr<device::BluetoothDiscoverySession> discovery_session) {
    341   // Clean up any existing session instance for the extension.
    342   DiscoverySessionMap::iterator iter =
    343       discovery_session_map_.find(extension_id);
    344   if (iter != discovery_session_map_.end())
    345     delete iter->second;
    346   discovery_session_map_[extension_id] = discovery_session.release();
    347   callback.Run();
    348 }
    349 
    350 void BluetoothEventRouter::Observe(
    351     int type,
    352     const content::NotificationSource& source,
    353     const content::NotificationDetails& details) {
    354   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    355   DCHECK_EQ(extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED, type);
    356   ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
    357   CleanUpForExtension(host->extension_id());
    358 }
    359 
    360 void BluetoothEventRouter::OnExtensionUnloaded(
    361     content::BrowserContext* browser_context,
    362     const Extension* extension,
    363     UnloadedExtensionInfo::Reason reason) {
    364   CleanUpForExtension(extension->id());
    365 }
    366 
    367 }  // namespace extensions
    368