17d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
57d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "device/bluetooth/bluetooth_adapter_chromeos.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <string>
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/bind.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/logging.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/metrics/histogram.h"
12010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/sequenced_task_runner.h"
13010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/single_thread_task_runner.h"
141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/sys_info.h"
15010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/thread_task_runner_handle.h"
167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "chromeos/dbus/bluetooth_adapter_client.h"
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chromeos/dbus/bluetooth_agent_manager_client.h"
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chromeos/dbus/bluetooth_agent_service_provider.h"
197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "chromeos/dbus/bluetooth_device_client.h"
207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "chromeos/dbus/bluetooth_input_client.h"
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/dbus/dbus_thread_manager.h"
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "device/bluetooth/bluetooth_device.h"
237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "device/bluetooth/bluetooth_device_chromeos.h"
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "device/bluetooth/bluetooth_pairing_chromeos.h"
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h"
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h"
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h"
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "device/bluetooth/bluetooth_socket_chromeos.h"
29010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "device/bluetooth/bluetooth_socket_thread.h"
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "device/bluetooth/bluetooth_uuid.h"
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "third_party/cros_system_api/dbus/service_constants.h"
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using device::BluetoothAdapter;
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using device::BluetoothDevice;
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using device::BluetoothSocket;
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using device::BluetoothUUID;
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace {
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// The agent path is relatively meaningless since BlueZ only permits one to
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// exist per D-Bus connection, it just has to be unique within Chromium.
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char kAgentPath[] = "/org/chromium/bluetooth_agent";
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void OnUnregisterAgentError(const std::string& error_name,
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                            const std::string& error_message) {
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // It's okay if the agent didn't exist, it means we never saw an adapter.
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (error_name == bluetooth_agent_manager::kErrorDoesNotExist)
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  LOG(WARNING) << "Failed to unregister pairing agent: "
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)               << error_name << ": " << error_message;
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochnamespace device {
570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// static
590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbase::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const InitCallback& init_callback) {
610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return chromeos::BluetoothAdapterChromeOS::CreateAdapter();
620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace chromeos {
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// static
690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbase::WeakPtr<BluetoothAdapter> BluetoothAdapterChromeOS::CreateAdapter() {
700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  BluetoothAdapterChromeOS* adapter = new BluetoothAdapterChromeOS();
710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return adapter->weak_ptr_factory_.GetWeakPtr();
720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)BluetoothAdapterChromeOS::BluetoothAdapterChromeOS()
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : num_discovery_sessions_(0),
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      discovery_request_pending_(false),
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      weak_ptr_factory_(this) {
78010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
79010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  socket_thread_ = device::BluetoothSocketThread::Get();
80010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothAdapterClient()->AddObserver(this);
827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothDeviceClient()->AddObserver(this);
837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothInputClient()->AddObserver(this);
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Register the pairing agent.
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  agent_.reset(BluetoothAgentServiceProvider::Create(
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      system_bus, dbus::ObjectPath(kAgentPath), this));
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(agent_.get());
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::vector<dbus::ObjectPath> object_paths =
927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothAdapterClient()->GetAdapters();
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!object_paths.empty()) {
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    VLOG(1) << object_paths.size() << " Bluetooth adapter(s) available.";
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SetAdapter(object_paths[0]);
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() {
1017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this);
1027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this);
1037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this);
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << "Unregistering pairing agent";
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      UnregisterAgent(
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          dbus::ObjectPath(kAgentPath),
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          base::Bind(&base::DoNothing),
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          base::Bind(&OnUnregisterAgentError));
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::AddObserver(
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    BluetoothAdapter::Observer* observer) {
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(observer);
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  observers_.AddObserver(observer);
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::RemoveObserver(
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    BluetoothAdapter::Observer* observer) {
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(observer);
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  observers_.RemoveObserver(observer);
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)std::string BluetoothAdapterChromeOS::GetAddress() const {
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!IsPresent())
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return std::string();
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothAdapterClient::Properties* properties =
1307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothAdapterClient()->
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetProperties(object_path_);
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(properties);
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return BluetoothDevice::CanonicalizeAddress(properties->address.value());
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)std::string BluetoothAdapterChromeOS::GetName() const {
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!IsPresent())
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return std::string();
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothAdapterClient::Properties* properties =
1427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothAdapterClient()->
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetProperties(object_path_);
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(properties);
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return properties->alias.value();
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BluetoothAdapterChromeOS::SetName(const std::string& name,
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       const base::Closure& callback,
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       const ErrorCallback& error_callback) {
1525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!IsPresent())
1535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    error_callback.Run();
1545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothAdapterClient()->
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      GetProperties(object_path_)->alias.Set(
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          name,
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     callback,
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     error_callback));
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool BluetoothAdapterChromeOS::IsInitialized() const {
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return true;
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool BluetoothAdapterChromeOS::IsPresent() const {
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return !object_path_.value().empty();
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool BluetoothAdapterChromeOS::IsPowered() const {
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!IsPresent())
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothAdapterClient::Properties* properties =
1777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothAdapterClient()->
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetProperties(object_path_);
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return properties->powered.value();
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::SetPowered(
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool powered,
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::Closure& callback,
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ErrorCallback& error_callback) {
1875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!IsPresent())
1885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    error_callback.Run();
1895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothAdapterClient()->
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      GetProperties(object_path_)->powered.Set(
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          powered,
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     callback,
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     error_callback));
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool BluetoothAdapterChromeOS::IsDiscoverable() const {
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!IsPresent())
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BluetoothAdapterClient::Properties* properties =
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothAdapterClient()->
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          GetProperties(object_path_);
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return properties->discoverable.value();
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BluetoothAdapterChromeOS::SetDiscoverable(
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool discoverable,
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Closure& callback,
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ErrorCallback& error_callback) {
2145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!IsPresent())
2155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    error_callback.Run();
2165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothAdapterClient()->
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      GetProperties(object_path_)->discoverable.Set(
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          discoverable,
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::Bind(&BluetoothAdapterChromeOS::OnSetDiscoverable,
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     callback,
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     error_callback));
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool BluetoothAdapterChromeOS::IsDiscovering() const {
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!IsPresent())
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothAdapterClient::Properties* properties =
2317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothAdapterClient()->
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetProperties(object_path_);
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return properties->discovering.value();
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothAdapterChromeOS::CreateRfcommService(
238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const BluetoothUUID& uuid,
239116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const ServiceOptions& options,
240cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const CreateServiceCallback& callback,
241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const CreateServiceErrorCallback& error_callback) {
242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  VLOG(1) << object_path_.value() << ": Creating RFCOMM service: "
243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          << uuid.canonical_value();
244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_refptr<BluetoothSocketChromeOS> socket =
245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      BluetoothSocketChromeOS::CreateBluetoothSocket(
2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          ui_task_runner_, socket_thread_);
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  socket->Listen(this,
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 BluetoothSocketChromeOS::kRfcomm,
249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 uuid,
250116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 options,
251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 base::Bind(callback, socket),
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 error_callback);
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BluetoothAdapterChromeOS::CreateL2capService(
256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const BluetoothUUID& uuid,
257116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const ServiceOptions& options,
258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const CreateServiceCallback& callback,
259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const CreateServiceErrorCallback& error_callback) {
260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  VLOG(1) << object_path_.value() << ": Creating L2CAP service: "
261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          << uuid.canonical_value();
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_refptr<BluetoothSocketChromeOS> socket =
263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      BluetoothSocketChromeOS::CreateBluetoothSocket(
2645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          ui_task_runner_, socket_thread_);
265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  socket->Listen(this,
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 BluetoothSocketChromeOS::kL2cap,
267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 uuid,
268116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 options,
269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 base::Bind(callback, socket),
270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 error_callback);
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothAdapterChromeOS::RemovePairingDelegateInternal(
274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    BluetoothDevice::PairingDelegate* pairing_delegate) {
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Before removing a pairing delegate make sure that there aren't any devices
276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // currently using it; if there are, clear the pairing context which will
277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // make any responses no-ops.
278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (DevicesMap::iterator iter = devices_.begin();
279a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       iter != devices_.end(); ++iter) {
280a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    BluetoothDeviceChromeOS* device_chromeos =
281a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        static_cast<BluetoothDeviceChromeOS*>(iter->second);
282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (pairing && pairing->GetPairingDelegate() == pairing_delegate)
285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      device_chromeos->EndPairing();
286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::AdapterAdded(
290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const dbus::ObjectPath& object_path) {
291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Set the adapter to the newly added adapter only if no adapter is present.
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!IsPresent())
293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SetAdapter(object_path);
294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::AdapterRemoved(
297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const dbus::ObjectPath& object_path) {
298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (object_path == object_path_)
299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    RemoveAdapter();
300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::AdapterPropertyChanged(
303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const dbus::ObjectPath& object_path,
304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& property_name) {
305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (object_path != object_path_)
306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothAdapterClient::Properties* properties =
3097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothAdapterClient()->
310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetProperties(object_path_);
311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (property_name == properties->powered.name())
313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    PoweredChanged(properties->powered.value());
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else if (property_name == properties->discoverable.name())
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DiscoverableChanged(properties->discoverable.value());
316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  else if (property_name == properties->discovering.name())
317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DiscoveringChanged(properties->discovering.value());
318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::DeviceAdded(
321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const dbus::ObjectPath& object_path) {
3227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothDeviceClient::Properties* properties =
3237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothDeviceClient()->
324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetProperties(object_path);
325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (properties->adapter.value() != object_path_)
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothDeviceChromeOS* device_chromeos =
329010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      new BluetoothDeviceChromeOS(this,
330010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                  object_path,
331010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                  ui_task_runner_,
332010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                  socket_thread_);
333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(devices_.find(device_chromeos->GetAddress()) == devices_.end());
334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  devices_[device_chromeos->GetAddress()] = device_chromeos;
336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    DeviceAdded(this, device_chromeos));
339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::DeviceRemoved(
342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const dbus::ObjectPath& object_path) {
343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (DevicesMap::iterator iter = devices_.begin();
344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       iter != devices_.end(); ++iter) {
3457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    BluetoothDeviceChromeOS* device_chromeos =
3467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        static_cast<BluetoothDeviceChromeOS*>(iter->second);
347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (device_chromeos->object_path() == object_path) {
348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      devices_.erase(iter);
349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        DeviceRemoved(this, device_chromeos));
352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      delete device_chromeos;
353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::DevicePropertyChanged(
359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const dbus::ObjectPath& object_path,
360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& property_name) {
3617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!device_chromeos)
363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothDeviceClient::Properties* properties =
3667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothDeviceClient()->
367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetProperties(object_path);
368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (property_name == properties->bluetooth_class.name() ||
370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      property_name == properties->address.name() ||
371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      property_name == properties->alias.name() ||
372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      property_name == properties->paired.name() ||
373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      property_name == properties->trusted.name() ||
374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      property_name == properties->connected.name() ||
375cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      property_name == properties->uuids.name() ||
376cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      property_name == properties->rssi.name() ||
377cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      property_name == properties->connection_rssi.name() ||
378cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      property_name == properties->connection_tx_power.name())
379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    NotifyDeviceChanged(device_chromeos);
380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
381a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // When a device becomes paired, mark it as trusted so that the user does
382a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // not need to approve every incoming connection
383a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (property_name == properties->paired.name() &&
384cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      properties->paired.value() && !properties->trusted.value())
385a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    device_chromeos->SetTrusted();
386a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // UMA connection counting
388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (property_name == properties->connected.name()) {
389cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // PlayStation joystick tries to reconnect after disconnection from USB.
390cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // If it is still not trusted, set it, so it becomes available on the
391cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // list of known devices.
392cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (properties->connected.value() && device_chromeos->IsTrustable() &&
393cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        !properties->trusted.value())
394cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      device_chromeos->SetTrusted();
395cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int count = 0;
397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (DevicesMap::iterator iter = devices_.begin();
399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         iter != devices_.end(); ++iter) {
400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (iter->second->IsPaired() && iter->second->IsConnected())
401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ++count;
402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UMA_HISTOGRAM_COUNTS_100("Bluetooth.ConnectedDeviceCount", count);
405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::InputPropertyChanged(
409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const dbus::ObjectPath& object_path,
410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& property_name) {
4117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!device_chromeos)
413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothInputClient::Properties* properties =
4167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothInputClient()->
417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetProperties(object_path);
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Properties structure can be removed, which triggers a change in the
420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // BluetoothDevice::IsConnectable() property, as does a change in the
421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // actual reconnect_mode property.
422c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!properties ||
423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      property_name == properties->reconnect_mode.name())
424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    NotifyDeviceChanged(device_chromeos);
425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
427a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid BluetoothAdapterChromeOS::Released() {
428a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(agent_.get());
429a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << "Release";
430a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
431a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Called after we unregister the pairing agent, e.g. when changing I/O
432a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // capabilities. Nothing much to be done right now.
433a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
434a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
435a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothAdapterChromeOS::RequestPinCode(
436a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const dbus::ObjectPath& device_path,
437a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const PinCodeCallback& callback) {
438a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(agent_.get());
439a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << device_path.value() << ": RequestPinCode";
440a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
441a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  BluetoothPairingChromeOS* pairing = GetPairing(device_path);
442a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!pairing) {
443a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    callback.Run(REJECTED, "");
444a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
445a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
446a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
447a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pairing->RequestPinCode(callback);
448a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
449a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
450a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothAdapterChromeOS::DisplayPinCode(
451a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const dbus::ObjectPath& device_path,
452a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& pincode) {
453a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(agent_.get());
454a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << device_path.value() << ": DisplayPinCode: " << pincode;
455a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
456a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  BluetoothPairingChromeOS* pairing = GetPairing(device_path);
457a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!pairing)
458a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
459a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
460a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pairing->DisplayPinCode(pincode);
461a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
462a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
463a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothAdapterChromeOS::RequestPasskey(
464a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const dbus::ObjectPath& device_path,
465a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const PasskeyCallback& callback) {
466a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(agent_.get());
467a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << device_path.value() << ": RequestPasskey";
468a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
469a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  BluetoothPairingChromeOS* pairing = GetPairing(device_path);
470a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!pairing) {
471a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    callback.Run(REJECTED, 0);
472a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
473a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
474a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
475a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pairing->RequestPasskey(callback);
476a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
477a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
478a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothAdapterChromeOS::DisplayPasskey(
479a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const dbus::ObjectPath& device_path,
480a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    uint32 passkey,
481a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    uint16 entered) {
482a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(agent_.get());
483a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << device_path.value() << ": DisplayPasskey: " << passkey
484a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          << " (" << entered << " entered)";
485a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
486a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  BluetoothPairingChromeOS* pairing = GetPairing(device_path);
487a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!pairing)
488a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
489a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
490a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (entered == 0)
491a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    pairing->DisplayPasskey(passkey);
492a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
493a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pairing->KeysEntered(entered);
494a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
495a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
496a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothAdapterChromeOS::RequestConfirmation(
497a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const dbus::ObjectPath& device_path,
498a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    uint32 passkey,
499a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const ConfirmationCallback& callback) {
500a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(agent_.get());
501a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << device_path.value() << ": RequestConfirmation: " << passkey;
502a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
503a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  BluetoothPairingChromeOS* pairing = GetPairing(device_path);
504a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!pairing) {
505a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    callback.Run(REJECTED);
506a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
507a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
508a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
509a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pairing->RequestConfirmation(passkey, callback);
510a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
511a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
512a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothAdapterChromeOS::RequestAuthorization(
513a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const dbus::ObjectPath& device_path,
514a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const ConfirmationCallback& callback) {
515a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(agent_.get());
516a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << device_path.value() << ": RequestAuthorization";
517a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
518a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  BluetoothPairingChromeOS* pairing = GetPairing(device_path);
519a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!pairing) {
520a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    callback.Run(REJECTED);
521a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
522a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
523a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
524a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pairing->RequestAuthorization(callback);
525a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
526a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
527a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothAdapterChromeOS::AuthorizeService(
528a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const dbus::ObjectPath& device_path,
529a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& uuid,
530a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const ConfirmationCallback& callback) {
531a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(agent_.get());
532a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << device_path.value() << ": AuthorizeService: " << uuid;
533a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
53446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(device_path);
53546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!device_chromeos) {
53646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    callback.Run(CANCELLED);
53746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
53846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
53946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
54046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // We always set paired devices to Trusted, so the only reason that this
54146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // method call would ever be called is in the case of a race condition where
54246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // our "Set('Trusted', true)" method call is still pending in the Bluetooth
54346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // daemon because it's busy handling the incoming connection.
54446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (device_chromeos->IsPaired()) {
54546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    callback.Run(SUCCESS);
54646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
54746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
54846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
54946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // TODO(keybuk): reject service authorizations when not paired, determine
55046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // whether this is acceptable long-term.
55146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  LOG(WARNING) << "Rejecting service connection from unpaired device "
55246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)               << device_chromeos->GetAddress() << " for UUID " << uuid;
55346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  callback.Run(REJECTED);
554a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
555a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
556a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothAdapterChromeOS::Cancel() {
557a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(agent_.get());
558a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << "Cancel";
559a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
560a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
561a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothAdapterChromeOS::OnRegisterAgent() {
562a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << "Pairing agent registered, requesting to be made default";
563a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
564a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
565a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      RequestDefaultAgent(
566a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          dbus::ObjectPath(kAgentPath),
567a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgent,
568a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr()),
569a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          base::Bind(&BluetoothAdapterChromeOS::OnRequestDefaultAgentError,
570a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr()));
571a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
572a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
573a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
574a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothAdapterChromeOS::OnRegisterAgentError(
575a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& error_name,
576a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& error_message) {
577a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Our agent being already registered isn't an error.
578a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (error_name == bluetooth_agent_manager::kErrorAlreadyExists)
579a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
580a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
581a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  LOG(WARNING) << ": Failed to register pairing agent: "
582a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)               << error_name << ": " << error_message;
583a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
584a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
585a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothAdapterChromeOS::OnRequestDefaultAgent() {
586a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << "Pairing agent now default";
587a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
588a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
589a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothAdapterChromeOS::OnRequestDefaultAgentError(
590a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& error_name,
591a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& error_message) {
592a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  LOG(WARNING) << ": Failed to make pairing agent default: "
593a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)               << error_name << ": " << error_message;
594a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
595a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
5967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)BluetoothDeviceChromeOS*
5977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)BluetoothAdapterChromeOS::GetDeviceWithPath(
598c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const dbus::ObjectPath& object_path) {
599c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (DevicesMap::iterator iter = devices_.begin();
600c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       iter != devices_.end(); ++iter) {
6017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    BluetoothDeviceChromeOS* device_chromeos =
6027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        static_cast<BluetoothDeviceChromeOS*>(iter->second);
603c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (device_chromeos->object_path() == object_path)
604c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return device_chromeos;
605c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
606c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
607c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return NULL;
608c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
609c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
610a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BluetoothPairingChromeOS* BluetoothAdapterChromeOS::GetPairing(
611a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const dbus::ObjectPath& object_path)
612a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles){
613a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  BluetoothDeviceChromeOS* device_chromeos = GetDeviceWithPath(object_path);
614a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!device_chromeos) {
615a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LOG(WARNING) << "Pairing Agent request for unknown device: "
616a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 << object_path.value();
617a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return NULL;
618a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
619a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
620a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  BluetoothPairingChromeOS* pairing = device_chromeos->GetPairing();
621a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (pairing)
622a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return pairing;
623a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
624a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // The device doesn't have its own pairing context, so this is an incoming
625a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // pairing request that should use our best default delegate (if we have one).
626a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  BluetoothDevice::PairingDelegate* pairing_delegate = DefaultPairingDelegate();
627a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!pairing_delegate)
628a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return NULL;
629a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
630a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return device_chromeos->BeginPairing(pairing_delegate);
631a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
632a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
6337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) {
634c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!IsPresent());
635c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  object_path_ = object_path;
636c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
637c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  VLOG(1) << object_path_.value() << ": using adapter.";
638c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
639a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << "Registering pairing agent";
640a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothAgentManagerClient()->
641a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      RegisterAgent(
642a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          dbus::ObjectPath(kAgentPath),
643a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          bluetooth_agent_manager::kKeyboardDisplayCapability,
644a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgent,
645a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr()),
646a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgentError,
647a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr()));
648a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
6495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetDefaultAdapterName();
650c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothAdapterClient::Properties* properties =
6527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothAdapterClient()->
653c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetProperties(object_path_);
654c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
655c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  PresentChanged(true);
656c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
657c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (properties->powered.value())
658c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    PoweredChanged(true);
6595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (properties->discoverable.value())
6605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DiscoverableChanged(true);
661c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (properties->discovering.value())
662c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DiscoveringChanged(true);
663c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
664c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::vector<dbus::ObjectPath> device_paths =
6657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothDeviceClient()->
666c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetDevicesForAdapter(object_path_);
667c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
668c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (std::vector<dbus::ObjectPath>::iterator iter = device_paths.begin();
669c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       iter != device_paths.end(); ++iter) {
670010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DeviceAdded(*iter);
671c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
672c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
673c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BluetoothAdapterChromeOS::SetDefaultAdapterName() {
6751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  std::string board = base::SysInfo::GetLsbReleaseBoard();
676c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string alias;
677c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (board.substr(0, 6) == "stumpy") {
678c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    alias = "Chromebox";
679c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else if (board.substr(0, 4) == "link") {
680c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    alias = "Chromebook Pixel";
681c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
682c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    alias = "Chromebook";
683c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
684c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetName(alias, base::Bind(&base::DoNothing), base::Bind(&base::DoNothing));
686c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
687c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::RemoveAdapter() {
689c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(IsPresent());
690c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  VLOG(1) << object_path_.value() << ": adapter removed.";
691c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BluetoothAdapterClient::Properties* properties =
6937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      DBusThreadManager::Get()->GetBluetoothAdapterClient()->
694c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          GetProperties(object_path_);
695c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
696c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  object_path_ = dbus::ObjectPath("");
697c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
698c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (properties->powered.value())
699c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    PoweredChanged(false);
7005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (properties->discoverable.value())
7015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DiscoverableChanged(false);
702c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (properties->discovering.value())
703c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DiscoveringChanged(false);
704c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
705c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Copy the devices list here and clear the original so that when we
706c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // send DeviceRemoved(), GetDevices() returns no devices.
707c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevicesMap devices = devices_;
708c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  devices_.clear();
709c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
710c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (DevicesMap::iterator iter = devices.begin();
711c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       iter != devices.end(); ++iter) {
712c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
713c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      DeviceRemoved(this, iter->second));
714c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    delete iter->second;
715c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
716c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
717c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  PresentChanged(false);
718c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
719c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::PoweredChanged(bool powered) {
721c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
722c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    AdapterPoweredChanged(this, powered));
723c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
724c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BluetoothAdapterChromeOS::DiscoverableChanged(bool discoverable) {
7265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
7275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    AdapterDiscoverableChanged(this, discoverable));
7285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::DiscoveringChanged(
731c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool discovering) {
732a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If the adapter stopped discovery due to a reason other than a request by
733a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // us, reset the count to 0.
734a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << "Discovering changed: " << discovering;
735a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!discovering && !discovery_request_pending_
736a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      && num_discovery_sessions_ > 0) {
737a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    VLOG(1) << "Marking sessions as inactive.";
738a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    num_discovery_sessions_ = 0;
739a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    MarkDiscoverySessionsAsInactive();
740a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
741c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
742c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    AdapterDiscoveringChanged(this, discovering));
743c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
744c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::PresentChanged(bool present) {
746c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
747c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    AdapterPresentChanged(this, present));
748c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
749c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::NotifyDeviceChanged(
7517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    BluetoothDeviceChromeOS* device) {
752c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(device->adapter_ == this);
753c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
754c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_,
755c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    DeviceChanged(this, device));
756c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
757c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothAdapterChromeOS::NotifyGattServiceAdded(
7595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    BluetoothRemoteGattServiceChromeOS* service) {
7605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(service->GetAdapter(), this);
7615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(
7625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_,
7635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this);
7645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
7665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    observers_,
7675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    GattServiceAdded(this, service->GetDevice(), service));
7685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
7695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothAdapterChromeOS::NotifyGattServiceRemoved(
7715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    BluetoothRemoteGattServiceChromeOS* service) {
7725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(service->GetAdapter(), this);
7735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(
7745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      static_cast<BluetoothDeviceChromeOS*>(service->GetDevice())->adapter_,
7755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this);
7765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
7785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    observers_,
7795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    GattServiceRemoved(this, service->GetDevice(), service));
7805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
7815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothAdapterChromeOS::NotifyGattServiceChanged(
7835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    BluetoothRemoteGattServiceChromeOS* service) {
7845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(service->GetAdapter(), this);
7855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
7875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    observers_,
7885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    GattServiceChanged(this, service));
7895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
7905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothAdapterChromeOS::NotifyGattDiscoveryComplete(
7925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    BluetoothRemoteGattServiceChromeOS* service) {
7935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(service->GetAdapter(), this);
7945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
7965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    observers_,
7975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    GattDiscoveryCompleteForService(this, service));
7985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
7995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothAdapterChromeOS::NotifyGattCharacteristicAdded(
8015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    BluetoothRemoteGattCharacteristicChromeOS* characteristic) {
8025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
8035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                characteristic->GetService())->GetAdapter(),
8045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this);
8055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
8075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    observers_,
8085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    GattCharacteristicAdded(this, characteristic));
8095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
8105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothAdapterChromeOS::NotifyGattCharacteristicRemoved(
8125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    BluetoothRemoteGattCharacteristicChromeOS* characteristic) {
8135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
8145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                characteristic->GetService())->GetAdapter(),
8155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this);
8165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
8185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    observers_,
8195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    GattCharacteristicRemoved(this, characteristic));
8205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
8215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothAdapterChromeOS::NotifyGattDescriptorAdded(
8235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    BluetoothRemoteGattDescriptorChromeOS* descriptor) {
8245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
8255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                descriptor->GetCharacteristic()->GetService())->GetAdapter(),
8265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this);
8275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
8295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    observers_,
8305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    GattDescriptorAdded(this, descriptor));
8315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
8325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothAdapterChromeOS::NotifyGattDescriptorRemoved(
8345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    BluetoothRemoteGattDescriptorChromeOS* descriptor) {
8355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
8365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                descriptor->GetCharacteristic()->GetService())->GetAdapter(),
8375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this);
8385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
8405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    observers_,
8415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    GattDescriptorRemoved(this, descriptor));
8425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
8435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothAdapterChromeOS::NotifyGattCharacteristicValueChanged(
8455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    BluetoothRemoteGattCharacteristicChromeOS* characteristic,
8465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::vector<uint8>& value) {
8475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
8485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                characteristic->GetService())->GetAdapter(),
8495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this);
8505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  FOR_EACH_OBSERVER(
8525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      BluetoothAdapter::Observer,
8535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      observers_,
8545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      GattCharacteristicValueChanged(this, characteristic, value));
8555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
8565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void BluetoothAdapterChromeOS::NotifyGattDescriptorValueChanged(
8585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    BluetoothRemoteGattDescriptorChromeOS* descriptor,
8595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::vector<uint8>& value) {
8605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(static_cast<BluetoothRemoteGattServiceChromeOS*>(
8615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                descriptor->GetCharacteristic()->GetService())->GetAdapter(),
8625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            this);
8635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
8655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    observers_,
8665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    GattDescriptorValueChanged(this, descriptor, value));
8675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
8685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BluetoothAdapterChromeOS::OnSetDiscoverable(
8705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Closure& callback,
8715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ErrorCallback& error_callback,
8725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool success) {
8735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Set the discoverable_timeout property to zero so the adapter remains
8745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // discoverable forever.
8755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothAdapterClient()->
8765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      GetProperties(object_path_)->discoverable_timeout.Set(
8775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          0,
8785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::Bind(&BluetoothAdapterChromeOS::OnPropertyChangeCompleted,
8795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
8805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     callback,
8815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     error_callback));
8825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BluetoothAdapterChromeOS::OnPropertyChangeCompleted(
8855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Closure& callback,
8865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ErrorCallback& error_callback,
8875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool success) {
888c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (success)
889c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    callback.Run();
890c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  else
891c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    error_callback.Run();
892c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
893c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
894a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothAdapterChromeOS::AddDiscoverySession(
895a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const base::Closure& callback,
896a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const ErrorCallback& error_callback) {
897a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << __func__;
898a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (discovery_request_pending_) {
899a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // The pending request is either to stop a previous session or to start a
900a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // new one. Either way, queue this one.
901a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK(num_discovery_sessions_ == 1 || num_discovery_sessions_ == 0);
902a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    VLOG(1) << "Pending request to start/stop device discovery. Queueing "
903a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            << "request to start a new discovery session.";
904a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    discovery_request_queue_.push(std::make_pair(callback, error_callback));
905a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
906a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
907a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
908a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // The adapter is already discovering.
909a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (num_discovery_sessions_ > 0) {
910a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK(IsDiscovering());
911a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK(!discovery_request_pending_);
912a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    num_discovery_sessions_++;
913a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    callback.Run();
914a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
915a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
916a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
917a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // There are no active discovery sessions.
918a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(num_discovery_sessions_ == 0);
919a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
920a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // This is the first request to start device discovery.
921a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  discovery_request_pending_ = true;
922a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothAdapterClient()->
923a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      StartDiscovery(
924a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          object_path_,
925a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          base::Bind(&BluetoothAdapterChromeOS::OnStartDiscovery,
926a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
927a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     callback),
928a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          base::Bind(&BluetoothAdapterChromeOS::OnStartDiscoveryError,
929a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
930a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     callback,
931a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     error_callback));
932a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
933a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
934a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothAdapterChromeOS::RemoveDiscoverySession(
935a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const base::Closure& callback,
936a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const ErrorCallback& error_callback) {
937a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << __func__;
938a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // There are active sessions other than the one currently being removed.
939a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (num_discovery_sessions_ > 1) {
940a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK(IsDiscovering());
941a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK(!discovery_request_pending_);
942a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    num_discovery_sessions_--;
943a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    callback.Run();
944a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
945a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
946a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
947a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If there is a pending request to BlueZ, then queue this request.
948a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (discovery_request_pending_) {
949a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    VLOG(1) << "Pending request to start/stop device discovery. Queueing "
950a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            << "request to stop discovery session.";
951a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    error_callback.Run();
952a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
953a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
954a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
955a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // There are no active sessions. Return error.
956a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (num_discovery_sessions_ == 0) {
957a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // TODO(armansito): This should never happen once we have the
958a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // DiscoverySession API. Replace this case with an assert once it's
959a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // the deprecated methods have been removed. (See crbug.com/3445008).
960a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    VLOG(1) << "No active discovery sessions. Returning error.";
961a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    error_callback.Run();
962a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
963a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
964a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
965a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // There is exactly one active discovery session. Request BlueZ to stop
966a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // discovery.
967a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(num_discovery_sessions_ == 1);
968a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  discovery_request_pending_ = true;
969a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DBusThreadManager::Get()->GetBluetoothAdapterClient()->
970a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      StopDiscovery(
971a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          object_path_,
972a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          base::Bind(&BluetoothAdapterChromeOS::OnStopDiscovery,
973a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
974a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     callback),
975a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          base::Bind(&BluetoothAdapterChromeOS::OnStopDiscoveryError,
976a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
977a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     error_callback));
978a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
979a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
9807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::OnStartDiscovery(const base::Closure& callback) {
981a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Report success on the original request and increment the count.
982a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << __func__;
983a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(discovery_request_pending_);
984a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(num_discovery_sessions_ == 0);
985a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  discovery_request_pending_ = false;
986a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  num_discovery_sessions_++;
987c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  callback.Run();
988a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
989a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Try to add a new discovery session for each queued request.
990a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ProcessQueuedDiscoveryRequests();
991c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
992c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::OnStartDiscoveryError(
994a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const base::Closure& callback,
995c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ErrorCallback& error_callback,
996c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& error_name,
997c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& error_message) {
998c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  LOG(WARNING) << object_path_.value() << ": Failed to start discovery: "
999c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               << error_name << ": " << error_message;
1000a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1001a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Failed to start discovery. This can only happen if the count is at 0.
1002a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(num_discovery_sessions_ == 0);
1003a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(discovery_request_pending_);
1004a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  discovery_request_pending_ = false;
1005a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1006a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Discovery request may fail if discovery was previously initiated by Chrome,
1007a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // but the session were invalidated due to the discovery state unexpectedly
1008a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // changing to false and then back to true. In this case, report success.
1009a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (error_name == bluetooth_device::kErrorInProgress && IsDiscovering()) {
1010a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    VLOG(1) << "Discovery previously initiated. Reporting success.";
1011a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    num_discovery_sessions_++;
1012a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    callback.Run();
1013a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
1014a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    error_callback.Run();
1015a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
1016a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1017a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Try to add a new discovery session for each queued request.
1018a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ProcessQueuedDiscoveryRequests();
1019c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1020c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
10217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::OnStopDiscovery(const base::Closure& callback) {
1022a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Report success on the original request and decrement the count.
1023a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << __func__;
1024a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(discovery_request_pending_);
1025a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(num_discovery_sessions_ == 1);
1026a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  discovery_request_pending_ = false;
1027a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  num_discovery_sessions_--;
1028c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  callback.Run();
1029a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1030a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Try to add a new discovery session for each queued request.
1031a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ProcessQueuedDiscoveryRequests();
1032c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1033c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
10347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void BluetoothAdapterChromeOS::OnStopDiscoveryError(
1035c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const ErrorCallback& error_callback,
1036c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& error_name,
1037c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& error_message) {
1038c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  LOG(WARNING) << object_path_.value() << ": Failed to stop discovery: "
1039c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               << error_name << ": " << error_message;
1040a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1041a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Failed to stop discovery. This can only happen if the count is at 1.
1042a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(discovery_request_pending_);
1043a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(num_discovery_sessions_ == 1);
1044a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  discovery_request_pending_ = false;
1045c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  error_callback.Run();
1046a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1047a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Try to add a new discovery session for each queued request.
1048a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ProcessQueuedDiscoveryRequests();
1049a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
1050a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1051a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothAdapterChromeOS::ProcessQueuedDiscoveryRequests() {
1052a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  while (!discovery_request_queue_.empty()) {
1053a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    VLOG(1) << "Process queued discovery request.";
1054a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DiscoveryCallbackPair callbacks = discovery_request_queue_.front();
1055a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    discovery_request_queue_.pop();
1056a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    AddDiscoverySession(callbacks.first, callbacks.second);
1057a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1058a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // If the queued request resulted in a pending call, then let it
1059a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // asynchonously process the remaining queued requests once the pending
1060a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // call returns.
1061a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (discovery_request_pending_)
1062a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return;
1063a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
1064c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1065c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1066c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace chromeos
1067