blob: 56e85147f9613fc6d87e62fa772b0447493a96f8 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/bluetooth/tray_bluetooth_helper.h"
#include "ash/shell.h"
#include "ash/system/tray/system_tray_controller.h"
#include "ash/system/tray/system_tray_notifier.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/metrics/user_metrics.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_discovery_session.h"
namespace ash {
namespace {
// System tray shows a limited number of bluetooth devices.
const int kMaximumDevicesShown = 50;
void BluetoothSetDiscoveringError() {
LOG(ERROR) << "BluetoothSetDiscovering failed.";
}
void BluetoothDeviceConnectError(
device::BluetoothDevice::ConnectErrorCode error_code) {}
ash::SystemTrayNotifier* GetSystemTrayNotifier() {
return Shell::Get()->system_tray_notifier();
}
BluetoothDeviceInfo GetBluetoothDeviceInfo(device::BluetoothDevice* device) {
BluetoothDeviceInfo info;
info.address = device->GetAddress();
info.display_name = device->GetNameForDisplay();
info.connected = device->IsConnected();
info.connecting = device->IsConnecting();
info.paired = device->IsPaired();
info.device_type = device->GetDeviceType();
return info;
}
} // namespace
BluetoothDeviceInfo::BluetoothDeviceInfo()
: connected(false), connecting(false), paired(false) {}
BluetoothDeviceInfo::BluetoothDeviceInfo(const BluetoothDeviceInfo& other) =
default;
BluetoothDeviceInfo::~BluetoothDeviceInfo() = default;
TrayBluetoothHelper::TrayBluetoothHelper() : weak_ptr_factory_(this) {}
TrayBluetoothHelper::~TrayBluetoothHelper() {
if (adapter_)
adapter_->RemoveObserver(this);
}
void TrayBluetoothHelper::Initialize() {
device::BluetoothAdapterFactory::GetAdapter(
base::Bind(&TrayBluetoothHelper::InitializeOnAdapterReady,
weak_ptr_factory_.GetWeakPtr()));
}
void TrayBluetoothHelper::InitializeOnAdapterReady(
scoped_refptr<device::BluetoothAdapter> adapter) {
adapter_ = adapter;
CHECK(adapter_);
adapter_->AddObserver(this);
}
BluetoothDeviceList TrayBluetoothHelper::GetAvailableBluetoothDevices() const {
BluetoothDeviceList device_list;
device::BluetoothAdapter::DeviceList devices = adapter_->GetDevices();
for (device::BluetoothDevice* device : devices) {
if (device_list.size() == kMaximumDevicesShown)
break;
if (device->IsPaired() || device->IsConnecting())
device_list.push_back(GetBluetoothDeviceInfo(device));
}
for (device::BluetoothDevice* device : devices) {
if (device_list.size() == kMaximumDevicesShown)
break;
if (!device->IsPaired() && !device->IsConnecting())
device_list.push_back(GetBluetoothDeviceInfo(device));
}
return device_list;
}
void TrayBluetoothHelper::StartBluetoothDiscovering() {
if (HasBluetoothDiscoverySession()) {
LOG(WARNING) << "Already have active Bluetooth device discovery session.";
return;
}
VLOG(1) << "Requesting new Bluetooth device discovery session.";
should_run_discovery_ = true;
adapter_->StartDiscoverySession(
base::Bind(&TrayBluetoothHelper::OnStartDiscoverySession,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&BluetoothSetDiscoveringError));
}
void TrayBluetoothHelper::StopBluetoothDiscovering() {
should_run_discovery_ = false;
if (!HasBluetoothDiscoverySession()) {
LOG(WARNING) << "No active Bluetooth device discovery session.";
return;
}
VLOG(1) << "Stopping Bluetooth device discovery session.";
discovery_session_->Stop(base::Bind(&base::DoNothing),
base::Bind(&BluetoothSetDiscoveringError));
}
void TrayBluetoothHelper::ConnectToBluetoothDevice(const std::string& address) {
device::BluetoothDevice* device = adapter_->GetDevice(address);
if (!device || device->IsConnecting() ||
(device->IsConnected() && device->IsPaired())) {
return;
}
if (device->IsPaired() && !device->IsConnectable())
return;
if (device->IsPaired() || !device->IsPairable()) {
base::RecordAction(
base::UserMetricsAction("StatusArea_Bluetooth_Connect_Known"));
device->Connect(NULL, base::Bind(&base::DoNothing),
base::Bind(&BluetoothDeviceConnectError));
return;
}
// Show pairing dialog for the unpaired device.
Shell::Get()->system_tray_controller()->ShowBluetoothPairingDialog(
device->GetAddress(), device->GetNameForDisplay(), device->IsPaired(),
device->IsConnected());
}
bool TrayBluetoothHelper::GetBluetoothAvailable() {
return adapter_ && adapter_->IsPresent();
}
bool TrayBluetoothHelper::GetBluetoothEnabled() {
return adapter_ && adapter_->IsPowered();
}
bool TrayBluetoothHelper::HasBluetoothDiscoverySession() {
return discovery_session_ && discovery_session_->IsActive();
}
////////////////////////////////////////////////////////////////////////////////
// BluetoothAdapter::Observer:
void TrayBluetoothHelper::AdapterPresentChanged(
device::BluetoothAdapter* adapter,
bool present) {
GetSystemTrayNotifier()->NotifyRefreshBluetooth();
}
void TrayBluetoothHelper::AdapterPoweredChanged(
device::BluetoothAdapter* adapter,
bool powered) {
GetSystemTrayNotifier()->NotifyRefreshBluetooth();
}
void TrayBluetoothHelper::AdapterDiscoveringChanged(
device::BluetoothAdapter* adapter,
bool discovering) {
GetSystemTrayNotifier()->NotifyBluetoothDiscoveringChanged();
}
void TrayBluetoothHelper::DeviceAdded(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) {
GetSystemTrayNotifier()->NotifyRefreshBluetooth();
}
void TrayBluetoothHelper::DeviceChanged(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) {
GetSystemTrayNotifier()->NotifyRefreshBluetooth();
}
void TrayBluetoothHelper::DeviceRemoved(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) {
GetSystemTrayNotifier()->NotifyRefreshBluetooth();
}
void TrayBluetoothHelper::OnStartDiscoverySession(
std::unique_ptr<device::BluetoothDiscoverySession> discovery_session) {
// If the discovery session was returned after a request to stop discovery
// (e.g. the user dismissed the Bluetooth detailed view before the call
// returned), don't claim the discovery session and let it clean up.
if (!should_run_discovery_)
return;
VLOG(1) << "Claiming new Bluetooth device discovery session.";
discovery_session_ = std::move(discovery_session);
GetSystemTrayNotifier()->NotifyBluetoothDiscoveringChanged();
}
} // namespace ash