|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "chrome/browser/chromeos/bluetooth/bluetooth_adapter.h" | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/lazy_instance.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/stl_util.h" | 
|  | #include "base/values.h" | 
|  | #include "chrome/browser/chromeos/bluetooth/bluetooth_device.h" | 
|  | #include "chromeos/dbus/bluetooth_adapter_client.h" | 
|  | #include "chromeos/dbus/bluetooth_device_client.h" | 
|  | #include "chromeos/dbus/bluetooth_manager_client.h" | 
|  | #include "chromeos/dbus/bluetooth_out_of_band_client.h" | 
|  | #include "chromeos/dbus/dbus_thread_manager.h" | 
|  | #include "dbus/object_path.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Shared default adapter instance, we don't want to keep this class around | 
|  | // if nobody is using it so use a WeakPtr and create the object when needed; | 
|  | // since Google C++ Style (and clang's static analyzer) forbids us having | 
|  | // exit-time destructors we use a leaky lazy instance for it. | 
|  | base::LazyInstance<base::WeakPtr<chromeos::BluetoothAdapter> >::Leaky | 
|  | default_adapter = LAZY_INSTANCE_INITIALIZER; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | namespace chromeos { | 
|  |  | 
|  | BluetoothAdapter::BluetoothAdapter() : track_default_(false), | 
|  | powered_(false), | 
|  | discovering_(false), | 
|  | weak_ptr_factory_(this) { | 
|  | DBusThreadManager::Get()->GetBluetoothManagerClient()-> | 
|  | AddObserver(this); | 
|  | DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | 
|  | AddObserver(this); | 
|  | DBusThreadManager::Get()->GetBluetoothDeviceClient()-> | 
|  | AddObserver(this); | 
|  | } | 
|  |  | 
|  | BluetoothAdapter::~BluetoothAdapter() { | 
|  | DBusThreadManager::Get()->GetBluetoothDeviceClient()-> | 
|  | RemoveObserver(this); | 
|  | DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | 
|  | RemoveObserver(this); | 
|  | DBusThreadManager::Get()->GetBluetoothManagerClient()-> | 
|  | RemoveObserver(this); | 
|  |  | 
|  | STLDeleteValues(&devices_); | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::AddObserver(Observer* observer) { | 
|  | DCHECK(observer); | 
|  | observers_.AddObserver(observer); | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::RemoveObserver(Observer* observer) { | 
|  | DCHECK(observer); | 
|  | observers_.RemoveObserver(observer); | 
|  | } | 
|  |  | 
|  | bool BluetoothAdapter::IsPresent() const { | 
|  | return !object_path_.value().empty() && !address_.empty(); | 
|  | } | 
|  |  | 
|  | bool BluetoothAdapter::IsPowered() const { | 
|  | return powered_; | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::SetPowered(bool powered, | 
|  | const base::Closure& callback, | 
|  | const ErrorCallback& error_callback) { | 
|  | DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | 
|  | GetProperties(object_path_)->powered.Set( | 
|  | powered, | 
|  | base::Bind(&BluetoothAdapter::OnSetPowered, | 
|  | weak_ptr_factory_.GetWeakPtr(), | 
|  | callback, | 
|  | error_callback)); | 
|  | } | 
|  |  | 
|  | bool BluetoothAdapter::IsDiscovering() const { | 
|  | return discovering_; | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::SetDiscovering(bool discovering, | 
|  | const base::Closure& callback, | 
|  | const ErrorCallback& error_callback) { | 
|  | if (discovering) { | 
|  | DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | 
|  | StartDiscovery(object_path_, | 
|  | base::Bind(&BluetoothAdapter::OnStartDiscovery, | 
|  | weak_ptr_factory_.GetWeakPtr(), | 
|  | callback, | 
|  | error_callback)); | 
|  | } else { | 
|  | DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | 
|  | StopDiscovery(object_path_, | 
|  | base::Bind(&BluetoothAdapter::OnStopDiscovery, | 
|  | weak_ptr_factory_.GetWeakPtr(), | 
|  | callback, | 
|  | error_callback)); | 
|  | } | 
|  | } | 
|  |  | 
|  | BluetoothAdapter::DeviceList BluetoothAdapter::GetDevices() { | 
|  | ConstDeviceList const_devices = | 
|  | const_cast<const BluetoothAdapter *>(this)->GetDevices(); | 
|  |  | 
|  | DeviceList devices; | 
|  | for (ConstDeviceList::const_iterator i = const_devices.begin(); | 
|  | i != const_devices.end(); ++i) | 
|  | devices.push_back(const_cast<BluetoothDevice *>(*i)); | 
|  |  | 
|  | return devices; | 
|  | } | 
|  |  | 
|  | BluetoothAdapter::ConstDeviceList BluetoothAdapter::GetDevices() const { | 
|  | ConstDeviceList devices; | 
|  | for (DevicesMap::const_iterator iter = devices_.begin(); | 
|  | iter != devices_.end(); ++iter) | 
|  | devices.push_back(iter->second); | 
|  |  | 
|  | return devices; | 
|  | } | 
|  |  | 
|  | BluetoothDevice* BluetoothAdapter::GetDevice(const std::string& address) { | 
|  | return const_cast<BluetoothDevice *>( | 
|  | const_cast<const BluetoothAdapter *>(this)->GetDevice(address)); | 
|  | } | 
|  |  | 
|  | const BluetoothDevice* BluetoothAdapter::GetDevice( | 
|  | const std::string& address) const { | 
|  | DevicesMap::const_iterator iter = devices_.find(address); | 
|  | if (iter != devices_.end()) | 
|  | return iter->second; | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::ReadLocalOutOfBandPairingData( | 
|  | const BluetoothOutOfBandPairingDataCallback& callback, | 
|  | const ErrorCallback& error_callback) { | 
|  | DBusThreadManager::Get()->GetBluetoothOutOfBandClient()-> | 
|  | ReadLocalData(object_path_, | 
|  | base::Bind(&BluetoothAdapter::OnReadLocalData, | 
|  | weak_ptr_factory_.GetWeakPtr(), | 
|  | callback, | 
|  | error_callback)); | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::TrackDefaultAdapter() { | 
|  | DVLOG(1) << "Tracking default adapter"; | 
|  | track_default_ = true; | 
|  | DBusThreadManager::Get()->GetBluetoothManagerClient()-> | 
|  | DefaultAdapter(base::Bind(&BluetoothAdapter::AdapterCallback, | 
|  | weak_ptr_factory_.GetWeakPtr())); | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::FindAdapter(const std::string& address) { | 
|  | DVLOG(1) << "Using adapter " << address; | 
|  | track_default_ = false; | 
|  | DBusThreadManager::Get()->GetBluetoothManagerClient()-> | 
|  | FindAdapter(address, | 
|  | base::Bind(&BluetoothAdapter::AdapterCallback, | 
|  | weak_ptr_factory_.GetWeakPtr())); | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::AdapterCallback(const dbus::ObjectPath& adapter_path, | 
|  | bool success) { | 
|  | if (success) { | 
|  | ChangeAdapter(adapter_path); | 
|  | } else if (!object_path_.value().empty()) { | 
|  | RemoveAdapter(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::DefaultAdapterChanged( | 
|  | const dbus::ObjectPath& adapter_path) { | 
|  | if (track_default_) | 
|  | ChangeAdapter(adapter_path); | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::AdapterRemoved(const dbus::ObjectPath& adapter_path) { | 
|  | if (adapter_path == object_path_) | 
|  | RemoveAdapter(); | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::ChangeAdapter(const dbus::ObjectPath& adapter_path) { | 
|  | if (object_path_.value().empty()) { | 
|  | DVLOG(1) << "Adapter path initialized to " << adapter_path.value(); | 
|  | } else if (object_path_.value() != adapter_path.value()) { | 
|  | DVLOG(1) << "Adapter path changed from " << object_path_.value() | 
|  | << " to " << adapter_path.value(); | 
|  |  | 
|  | RemoveAdapter(); | 
|  | } else { | 
|  | DVLOG(1) << "Adapter address updated"; | 
|  | } | 
|  |  | 
|  | object_path_ = adapter_path; | 
|  |  | 
|  | // Update properties to their new values. | 
|  | BluetoothAdapterClient::Properties* properties = | 
|  | DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | 
|  | GetProperties(object_path_); | 
|  |  | 
|  | address_ = properties->address.value(); | 
|  | name_ = properties->name.value(); | 
|  |  | 
|  | // Delay announcing a new adapter until we have an address. | 
|  | if (address_.empty()) { | 
|  | DVLOG(1) << "Adapter address not yet known"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | PoweredChanged(properties->powered.value()); | 
|  | DiscoveringChanged(properties->discovering.value()); | 
|  | DevicesChanged(properties->devices.value()); | 
|  |  | 
|  | FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | 
|  | AdapterPresentChanged(this, true)); | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::RemoveAdapter() { | 
|  | const bool adapter_was_present = IsPresent(); | 
|  |  | 
|  | DVLOG(1) << "Adapter lost."; | 
|  | PoweredChanged(false); | 
|  | DiscoveringChanged(false); | 
|  | ClearDevices(); | 
|  |  | 
|  | object_path_ = dbus::ObjectPath(""); | 
|  | address_.clear(); | 
|  | name_.clear(); | 
|  |  | 
|  | if (adapter_was_present) | 
|  | FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | 
|  | AdapterPresentChanged(this, false)); | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::OnSetPowered(const base::Closure& callback, | 
|  | const ErrorCallback& error_callback, | 
|  | bool success) { | 
|  | if (success) | 
|  | callback.Run(); | 
|  | else | 
|  | error_callback.Run(); | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::PoweredChanged(bool powered) { | 
|  | if (powered == powered_) | 
|  | return; | 
|  |  | 
|  | powered_ = powered; | 
|  |  | 
|  | FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | 
|  | AdapterPoweredChanged(this, powered_)); | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::OnStartDiscovery(const base::Closure& callback, | 
|  | const ErrorCallback& error_callback, | 
|  | const dbus::ObjectPath& adapter_path, | 
|  | bool success) { | 
|  | if (success) { | 
|  | DVLOG(1) << object_path_.value() << ": started discovery."; | 
|  |  | 
|  | // Clear devices found in previous discovery attempts | 
|  | ClearDiscoveredDevices(); | 
|  | callback.Run(); | 
|  | } else { | 
|  | // TODO(keybuk): in future, don't run the callback if the error was just | 
|  | // that we were already discovering. | 
|  | error_callback.Run(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::OnStopDiscovery(const base::Closure& callback, | 
|  | const ErrorCallback& error_callback, | 
|  | const dbus::ObjectPath& adapter_path, | 
|  | bool success) { | 
|  | if (success) { | 
|  | DVLOG(1) << object_path_.value() << ": stopped discovery."; | 
|  | callback.Run(); | 
|  | // Leave found devices available for perusing. | 
|  | } else { | 
|  | // TODO(keybuk): in future, don't run the callback if the error was just | 
|  | // that we weren't discovering. | 
|  | error_callback.Run(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::DiscoveringChanged(bool discovering) { | 
|  | if (discovering == discovering_) | 
|  | return; | 
|  |  | 
|  | discovering_ = discovering; | 
|  |  | 
|  | FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | 
|  | AdapterDiscoveringChanged(this, discovering_)); | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::OnReadLocalData( | 
|  | const BluetoothOutOfBandPairingDataCallback& callback, | 
|  | const ErrorCallback& error_callback, | 
|  | const BluetoothOutOfBandPairingData& data, | 
|  | bool success) { | 
|  | if (success) | 
|  | callback.Run(data); | 
|  | else | 
|  | error_callback.Run(); | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::AdapterPropertyChanged( | 
|  | const dbus::ObjectPath& adapter_path, | 
|  | const std::string& property_name) { | 
|  | if (adapter_path != object_path_) | 
|  | return; | 
|  |  | 
|  | BluetoothAdapterClient::Properties* properties = | 
|  | DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | 
|  | GetProperties(object_path_); | 
|  |  | 
|  | if (property_name == properties->address.name()) { | 
|  | ChangeAdapter(object_path_); | 
|  |  | 
|  | } else if (!address_.empty()) { | 
|  | if (property_name == properties->powered.name()) { | 
|  | PoweredChanged(properties->powered.value()); | 
|  |  | 
|  | } else if (property_name == properties->discovering.name()) { | 
|  | DiscoveringChanged(properties->discovering.value()); | 
|  |  | 
|  | } else if (property_name == properties->devices.name()) { | 
|  | DevicesChanged(properties->devices.value()); | 
|  |  | 
|  | } else if (property_name == properties->name.name()) { | 
|  | name_ = properties->name.value(); | 
|  |  | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::DevicePropertyChanged( | 
|  | const dbus::ObjectPath& device_path, | 
|  | const std::string& property_name) { | 
|  | UpdateDevice(device_path); | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::UpdateDevice(const dbus::ObjectPath& device_path) { | 
|  | BluetoothDeviceClient::Properties* properties = | 
|  | DBusThreadManager::Get()->GetBluetoothDeviceClient()-> | 
|  | GetProperties(device_path); | 
|  |  | 
|  | // When we first see a device, we may not know the address yet and need to | 
|  | // wait for the DevicePropertyChanged signal before adding the device. | 
|  | const std::string address = properties->address.value(); | 
|  | if (address.empty()) | 
|  | return; | 
|  |  | 
|  | // The device may be already known to us, either because this is an update | 
|  | // to properties, or the device going from discovered to connected and | 
|  | // pairing gaining an object path in the process. In any case, we want | 
|  | // to update the existing object, not create a new one. | 
|  | DevicesMap::iterator iter = devices_.find(address); | 
|  | BluetoothDevice* device; | 
|  | const bool update_device = (iter != devices_.end()); | 
|  | if (update_device) { | 
|  | device = iter->second; | 
|  | } else { | 
|  | device = BluetoothDevice::Create(this); | 
|  | devices_[address] = device; | 
|  | } | 
|  |  | 
|  | const bool was_paired = device->IsPaired(); | 
|  | if (!was_paired) { | 
|  | DVLOG(1) << "Assigned object path " << device_path.value() << " to device " | 
|  | << address; | 
|  | device->SetObjectPath(device_path); | 
|  | } | 
|  | device->Update(properties, true); | 
|  |  | 
|  | // Don't send a duplicate added event for supported devices that were | 
|  | // previously visible or for already paired devices, send a changed | 
|  | // event instead. We always send one event or the other since we always | 
|  | // inform observers about paired devices whether or not they're supported. | 
|  | if (update_device && (device->IsSupported() || was_paired)) { | 
|  | FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | 
|  | DeviceChanged(this, device)); | 
|  | } else { | 
|  | FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | 
|  | DeviceAdded(this, device)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::ClearDevices() { | 
|  | DevicesMap replace; | 
|  | devices_.swap(replace); | 
|  | for (DevicesMap::iterator iter = replace.begin(); | 
|  | iter != replace.end(); ++iter) { | 
|  | BluetoothDevice* device = iter->second; | 
|  | if (device->IsSupported() || device->IsPaired()) | 
|  | FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | 
|  | DeviceRemoved(this, device)); | 
|  |  | 
|  | delete device; | 
|  | } | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::DeviceCreated(const dbus::ObjectPath& adapter_path, | 
|  | const dbus::ObjectPath& device_path) { | 
|  | if (adapter_path != object_path_) | 
|  | return; | 
|  |  | 
|  | UpdateDevice(device_path); | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::DeviceRemoved(const dbus::ObjectPath& adapter_path, | 
|  | const dbus::ObjectPath& device_path) { | 
|  | if (adapter_path != object_path_) | 
|  | return; | 
|  |  | 
|  | DevicesMap::iterator iter = devices_.begin(); | 
|  | while (iter != devices_.end()) { | 
|  | BluetoothDevice* device = iter->second; | 
|  | DevicesMap::iterator temp = iter; | 
|  | ++iter; | 
|  |  | 
|  | if (device->object_path_ != device_path) | 
|  | continue; | 
|  |  | 
|  | // DeviceRemoved can also be called to indicate a device that is visible | 
|  | // during discovery has disconnected, but it is still visible to the | 
|  | // adapter, so don't remove in that case and only clear the object path. | 
|  | if (!device->IsVisible()) { | 
|  | FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | 
|  | DeviceRemoved(this, device)); | 
|  |  | 
|  | DVLOG(1) << "Removed device " << device->address(); | 
|  |  | 
|  | delete device; | 
|  | devices_.erase(temp); | 
|  | } else { | 
|  | DVLOG(1) << "Removed object path from device " << device->address(); | 
|  | device->RemoveObjectPath(); | 
|  |  | 
|  | // If the device is not supported then we want to act as if it was | 
|  | // removed, even though it is still visible to the adapter. | 
|  | if (!device->IsSupported()) { | 
|  | FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | 
|  | DeviceRemoved(this, device)); | 
|  | } else { | 
|  | FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | 
|  | DeviceChanged(this, device)); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::DevicesChanged( | 
|  | const std::vector<dbus::ObjectPath>& devices) { | 
|  | for (std::vector<dbus::ObjectPath>::const_iterator iter = | 
|  | devices.begin(); iter != devices.end(); ++iter) | 
|  | UpdateDevice(*iter); | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::ClearDiscoveredDevices() { | 
|  | DevicesMap::iterator iter = devices_.begin(); | 
|  | while (iter != devices_.end()) { | 
|  | BluetoothDevice* device = iter->second; | 
|  | DevicesMap::iterator temp = iter; | 
|  | ++iter; | 
|  |  | 
|  | if (!device->IsPaired()) { | 
|  | if (device->IsSupported()) | 
|  | FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | 
|  | DeviceRemoved(this, device)); | 
|  |  | 
|  | delete device; | 
|  | devices_.erase(temp); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::DeviceFound( | 
|  | const dbus::ObjectPath& adapter_path, const std::string& address, | 
|  | const BluetoothDeviceClient::Properties& properties) { | 
|  | if (adapter_path != object_path_) | 
|  | return; | 
|  |  | 
|  | // DeviceFound can also be called to indicate that a device we've | 
|  | // paired with is now visible to the adapter during discovery, in which | 
|  | // case we want to update the existing object, not create a new one. | 
|  | BluetoothDevice* device; | 
|  | DevicesMap::iterator iter = devices_.find(address); | 
|  | const bool update_device = (iter != devices_.end()); | 
|  | if (update_device) { | 
|  | device = iter->second; | 
|  | } else { | 
|  | device = BluetoothDevice::Create(this); | 
|  | devices_[address] = device; | 
|  | } | 
|  |  | 
|  | DVLOG(1) << "Device " << address << " is visible to the adapter"; | 
|  | device->SetVisible(true); | 
|  | device->Update(&properties, false); | 
|  |  | 
|  | // Don't send a duplicated added event for duplicate signals for supported | 
|  | // devices that were previously visible (should never happen) or for already | 
|  | // paired devices, send a changed event instead. We do not inform observers | 
|  | // if we find or update an unconnected and unsupported device. | 
|  | if (update_device && (device->IsSupported() || device->IsPaired())) { | 
|  | FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | 
|  | DeviceChanged(this, device)); | 
|  | } else if (device->IsSupported()) { | 
|  | FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | 
|  | DeviceAdded(this, device)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void BluetoothAdapter::DeviceDisappeared(const dbus::ObjectPath& adapter_path, | 
|  | const std::string& address) { | 
|  | if (adapter_path != object_path_) | 
|  | return; | 
|  |  | 
|  | DevicesMap::iterator iter = devices_.find(address); | 
|  | if (iter == devices_.end()) | 
|  | return; | 
|  |  | 
|  | BluetoothDevice* device = iter->second; | 
|  |  | 
|  | // DeviceDisappeared can also be called to indicate that a device we've | 
|  | // paired with is no longer visible to the adapter, so don't remove | 
|  | // in that case and only clear the visible flag. | 
|  | if (!device->IsPaired()) { | 
|  | if (device->IsSupported()) | 
|  | FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | 
|  | DeviceRemoved(this, device)); | 
|  |  | 
|  | DVLOG(1) << "Discovered device " << device->address() | 
|  | << " is no longer visible to the adapter"; | 
|  |  | 
|  | delete device; | 
|  | devices_.erase(iter); | 
|  | } else { | 
|  | DVLOG(1) << "Paired device " << device->address() | 
|  | << " is no longer visible to the adapter"; | 
|  | device->SetVisible(false); | 
|  |  | 
|  | FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | 
|  | DeviceChanged(this, device)); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | // static | 
|  | scoped_refptr<BluetoothAdapter> BluetoothAdapter::DefaultAdapter() { | 
|  | if (!default_adapter.Get().get()) { | 
|  | BluetoothAdapter* new_adapter = new BluetoothAdapter; | 
|  | default_adapter.Get() = new_adapter->weak_ptr_factory_.GetWeakPtr(); | 
|  | default_adapter.Get()->TrackDefaultAdapter(); | 
|  | } | 
|  |  | 
|  | return scoped_refptr<BluetoothAdapter>(default_adapter.Get()); | 
|  | } | 
|  |  | 
|  | // static | 
|  | BluetoothAdapter* BluetoothAdapter::Create(const std::string& address) { | 
|  | BluetoothAdapter* adapter = new BluetoothAdapter; | 
|  | adapter->FindAdapter(address); | 
|  | return adapter; | 
|  | } | 
|  |  | 
|  | }  // namespace chromeos |