This source file includes following definitions.
- weak_ptr_factory_
- GetLocalizedValues
- AdapterPresentChanged
- AdapterPoweredChanged
- AdapterDiscoveringChanged
- RegisterMessages
- InitializeHandler
- InitializePage
- InitializeAdapter
- EnableChangeCallback
- EnableChangeError
- FindDevicesCallback
- OnStartDiscoverySession
- FindDevicesError
- UpdateDeviceCallback
- Connected
- ConnectError
- DisconnectError
- ForgetError
- StopDiscoveryCallback
- StopDiscoveryError
- GetPairedDevicesCallback
- SendDeviceNotification
- RequestPinCode
- RequestPasskey
- DisplayPinCode
- DisplayPasskey
- KeysEntered
- ConfirmPasskey
- AuthorizePairing
- ReportError
- DeviceAdded
- DeviceChanged
- DeviceRemoved
- DeviceConnecting
#include "chrome/browser/ui/webui/options/chromeos/bluetooth_options_handler.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/public/browser/web_ui.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_device.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "ui/base/l10n/l10n_util.h"
namespace {
const int kUpdateDeviceAddressIndex = 0;
const int kUpdateDeviceCommandIndex = 1;
const int kUpdateDeviceAuthTokenIndex = 2;
const char kConnectCommand[] = "connect";
const char kCancelCommand[] = "cancel";
const char kAcceptCommand[] = "accept";
const char kRejectCommand[] = "reject";
const char kDisconnectCommand[] = "disconnect";
const char kForgetCommand[] = "forget";
const char kStartConnecting[] = "bluetoothStartConnecting";
const char kEnterPinCode[] = "bluetoothEnterPinCode";
const char kEnterPasskey[] = "bluetoothEnterPasskey";
const char kRemotePinCode[] = "bluetoothRemotePinCode";
const char kRemotePasskey[] = "bluetoothRemotePasskey";
const char kConfirmPasskey[] = "bluetoothConfirmPasskey";
const int kInvalidEntered = 0xFFFF;
}
namespace chromeos {
namespace options {
BluetoothOptionsHandler::BluetoothOptionsHandler()
: should_run_device_discovery_(false),
pairing_device_passkey_(1000000),
pairing_device_entered_(kInvalidEntered),
weak_ptr_factory_(this) {
}
BluetoothOptionsHandler::~BluetoothOptionsHandler() {
if (adapter_.get())
adapter_->RemoveObserver(this);
}
void BluetoothOptionsHandler::GetLocalizedValues(
base::DictionaryValue* localized_strings) {
DCHECK(localized_strings);
static OptionsStringResource resources[] = {
{ "bluetooth", IDS_OPTIONS_SETTINGS_SECTION_TITLE_BLUETOOTH },
{ "disableBluetooth", IDS_OPTIONS_SETTINGS_BLUETOOTH_DISABLE },
{ "enableBluetooth", IDS_OPTIONS_SETTINGS_BLUETOOTH_ENABLE },
{ "addBluetoothDevice", IDS_OPTIONS_SETTINGS_ADD_BLUETOOTH_DEVICE },
{ "bluetoothAddDeviceTitle",
IDS_OPTIONS_SETTINGS_BLUETOOTH_ADD_DEVICE_TITLE },
{ "bluetoothOptionsPageTabTitle",
IDS_OPTIONS_SETTINGS_BLUETOOTH_ADD_DEVICE_TITLE },
{ "findBluetoothDevices", IDS_OPTIONS_SETTINGS_FIND_BLUETOOTH_DEVICES },
{ "bluetoothNoDevices", IDS_OPTIONS_SETTINGS_BLUETOOTH_NO_DEVICES },
{ "bluetoothNoDevicesFound",
IDS_OPTIONS_SETTINGS_BLUETOOTH_NO_DEVICES_FOUND },
{ "bluetoothScanning", IDS_OPTIONS_SETTINGS_BLUETOOTH_SCANNING },
{ "bluetoothScanStopped", IDS_OPTIONS_SETTINGS_BLUETOOTH_SCAN_STOPPED },
{ "bluetoothDeviceConnecting", IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECTING },
{ "bluetoothConnectDevice", IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT },
{ "bluetoothDisconnectDevice", IDS_OPTIONS_SETTINGS_BLUETOOTH_DISCONNECT },
{ "bluetoothForgetDevice", IDS_OPTIONS_SETTINGS_BLUETOOTH_FORGET },
{ "bluetoothCancel", IDS_OPTIONS_SETTINGS_BLUETOOTH_CANCEL },
{ "bluetoothEnterKey", IDS_OPTIONS_SETTINGS_BLUETOOTH_ENTER_KEY },
{ "bluetoothDismissError", IDS_OPTIONS_SETTINGS_BLUETOOTH_DISMISS_ERROR },
{ "bluetoothStartConnecting",
IDS_OPTIONS_SETTINGS_BLUETOOTH_START_CONNECTING },
{ "bluetoothAcceptPasskey",
IDS_OPTIONS_SETTINGS_BLUETOOTH_ACCEPT_PASSKEY },
{ "bluetoothRejectPasskey",
IDS_OPTIONS_SETTINGS_BLUETOOTH_REJECT_PASSKEY },
{ "bluetoothEnterPinCode",
IDS_OPTIONS_SETTINGS_BLUETOOTH_ENTER_PIN_CODE_REQUEST },
{ "bluetoothEnterPasskey",
IDS_OPTIONS_SETTINGS_BLUETOOTH_ENTER_PASSKEY_REQUEST },
{ "bluetoothRemotePinCode",
IDS_OPTIONS_SETTINGS_BLUETOOTH_REMOTE_PIN_CODE_REQUEST },
{ "bluetoothRemotePasskey",
IDS_OPTIONS_SETTINGS_BLUETOOTH_REMOTE_PASSKEY_REQUEST },
{ "bluetoothConfirmPasskey",
IDS_OPTIONS_SETTINGS_BLUETOOTH_CONFIRM_PASSKEY_REQUEST },
{ "bluetoothStartDiscoveryFailed",
IDS_OPTIONS_SETTINGS_BLUETOOTH_START_DISCOVERY_FAILED },
{ "bluetoothStopDiscoveryFailed",
IDS_OPTIONS_SETTINGS_BLUETOOTH_STOP_DISCOVERY_FAILED },
{ "bluetoothChangePowerFailed",
IDS_OPTIONS_SETTINGS_BLUETOOTH_CHANGE_POWER_FAILED },
{ "bluetoothConnectUnknownError",
IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_UNKNOWN_ERROR },
{ "bluetoothConnectInProgress",
IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_IN_PROGRESS },
{ "bluetoothConnectFailed",
IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_FAILED },
{ "bluetoothConnectAuthFailed",
IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_AUTH_FAILED },
{ "bluetoothConnectAuthCanceled",
IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_AUTH_CANCELED },
{ "bluetoothConnectAuthRejected",
IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_AUTH_REJECTED },
{ "bluetoothConnectAuthTimeout",
IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_AUTH_TIMEOUT },
{ "bluetoothConnectUnsupportedDevice",
IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_UNSUPPORTED_DEVICE },
{ "bluetoothDisconnectFailed",
IDS_OPTIONS_SETTINGS_BLUETOOTH_DISCONNECT_FAILED },
{ "bluetoothForgetFailed",
IDS_OPTIONS_SETTINGS_BLUETOOTH_FORGET_FAILED }};
RegisterStrings(localized_strings, resources, arraysize(resources));
}
void BluetoothOptionsHandler::AdapterPresentChanged(
device::BluetoothAdapter* adapter,
bool present) {
DCHECK(adapter == adapter_.get());
if (present) {
web_ui()->CallJavascriptFunction(
"options.BrowserOptions.showBluetoothSettings");
AdapterPoweredChanged(adapter_.get(), adapter_->IsPowered());
} else {
web_ui()->CallJavascriptFunction(
"options.BrowserOptions.hideBluetoothSettings");
}
}
void BluetoothOptionsHandler::AdapterPoweredChanged(
device::BluetoothAdapter* adapter,
bool powered) {
DCHECK(adapter == adapter_.get());
base::FundamentalValue checked(powered);
web_ui()->CallJavascriptFunction(
"options.BrowserOptions.setBluetoothState", checked);
if (!powered) {
web_ui()->CallJavascriptFunction(
"options.BluetoothOptions.dismissOverlay");
}
}
void BluetoothOptionsHandler::AdapterDiscoveringChanged(
device::BluetoothAdapter* adapter,
bool discovering) {
DCHECK(adapter == adapter_.get());
base::FundamentalValue discovering_value(discovering);
web_ui()->CallJavascriptFunction(
"options.BluetoothOptions.updateDiscoveryState", discovering_value);
}
void BluetoothOptionsHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback("bluetoothEnableChange",
base::Bind(&BluetoothOptionsHandler::EnableChangeCallback,
base::Unretained(this)));
web_ui()->RegisterMessageCallback("findBluetoothDevices",
base::Bind(&BluetoothOptionsHandler::FindDevicesCallback,
base::Unretained(this)));
web_ui()->RegisterMessageCallback("updateBluetoothDevice",
base::Bind(&BluetoothOptionsHandler::UpdateDeviceCallback,
base::Unretained(this)));
web_ui()->RegisterMessageCallback("stopBluetoothDeviceDiscovery",
base::Bind(&BluetoothOptionsHandler::StopDiscoveryCallback,
base::Unretained(this)));
web_ui()->RegisterMessageCallback("getPairedBluetoothDevices",
base::Bind(&BluetoothOptionsHandler::GetPairedDevicesCallback,
base::Unretained(this)));
}
void BluetoothOptionsHandler::InitializeHandler() {
device::BluetoothAdapterFactory::GetAdapter(
base::Bind(&BluetoothOptionsHandler::InitializeAdapter,
weak_ptr_factory_.GetWeakPtr()));
}
void BluetoothOptionsHandler::InitializePage() {
AdapterPresentChanged(adapter_.get(), adapter_->IsPresent());
web_ui()->CallJavascriptFunction(
"options.BluetoothOptions.startDeviceDiscovery");
}
void BluetoothOptionsHandler::InitializeAdapter(
scoped_refptr<device::BluetoothAdapter> adapter) {
adapter_ = adapter;
CHECK(adapter_.get());
adapter_->AddObserver(this);
}
void BluetoothOptionsHandler::EnableChangeCallback(
const base::ListValue* args) {
bool bluetooth_enabled;
args->GetBoolean(0, &bluetooth_enabled);
adapter_->SetPowered(bluetooth_enabled,
base::Bind(&base::DoNothing),
base::Bind(&BluetoothOptionsHandler::EnableChangeError,
weak_ptr_factory_.GetWeakPtr()));
}
void BluetoothOptionsHandler::EnableChangeError() {
VLOG(1) << "Failed to change power state.";
ReportError("bluetoothChangePowerFailed", std::string());
}
void BluetoothOptionsHandler::FindDevicesCallback(
const base::ListValue* args) {
if (discovery_session_.get() && discovery_session_->IsActive()) {
VLOG(1) << "Already have an active discovery session.";
return;
}
should_run_device_discovery_ = true;
adapter_->StartDiscoverySession(
base::Bind(&BluetoothOptionsHandler::OnStartDiscoverySession,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&BluetoothOptionsHandler::FindDevicesError,
weak_ptr_factory_.GetWeakPtr()));
}
void BluetoothOptionsHandler::OnStartDiscoverySession(
scoped_ptr<device::BluetoothDiscoverySession> discovery_session) {
if (!should_run_device_discovery_)
return;
discovery_session_ = discovery_session.Pass();
}
void BluetoothOptionsHandler::FindDevicesError() {
VLOG(1) << "Failed to start discovery.";
ReportError("bluetoothStartDiscoveryFailed", std::string());
if (!adapter_.get())
return;
base::FundamentalValue discovering(adapter_->IsDiscovering());
web_ui()->CallJavascriptFunction(
"options.BluetoothOptions.updateDiscoveryState", discovering);
}
void BluetoothOptionsHandler::UpdateDeviceCallback(
const base::ListValue* args) {
std::string address;
args->GetString(kUpdateDeviceAddressIndex, &address);
device::BluetoothDevice* device = adapter_->GetDevice(address);
if (!device)
return;
std::string command;
args->GetString(kUpdateDeviceCommandIndex, &command);
if (command == kConnectCommand) {
int size = args->GetSize();
if (size > kUpdateDeviceAuthTokenIndex) {
std::string auth_token;
args->GetString(kUpdateDeviceAuthTokenIndex, &auth_token);
if (device->ExpectingPinCode()) {
DeviceConnecting(device);
VLOG(1) << "PIN Code supplied: " << address << ": " << auth_token;
device->SetPinCode(auth_token);
} else if (device->ExpectingPasskey()) {
DeviceConnecting(device);
unsigned passkey = 0;
base::StringToUint(auth_token, &passkey);
VLOG(1) << "Passkey supplied: " << address << ": " << passkey;
device->SetPasskey(passkey);
} else {
LOG(WARNING) << "Auth token supplied after pairing ended: " << address
<< ": " << auth_token;
}
} else {
PairingDelegate* delegate = NULL;
if (device->IsPairable())
delegate = this;
VLOG(1) << "Connect: " << address;
device->Connect(
delegate,
base::Bind(&BluetoothOptionsHandler::Connected,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&BluetoothOptionsHandler::ConnectError,
weak_ptr_factory_.GetWeakPtr(),
device->GetAddress()));
}
} else if (command == kCancelCommand) {
VLOG(1) << "Cancel pairing: " << address;
device->CancelPairing();
} else if (command == kAcceptCommand) {
DeviceConnecting(device);
VLOG(1) << "Confirm pairing: " << address;
device->ConfirmPairing();
} else if (command == kRejectCommand) {
VLOG(1) << "Reject pairing: " << address;
device->RejectPairing();
} else if (command == kDisconnectCommand) {
VLOG(1) << "Disconnect device: " << address;
device->Disconnect(
base::Bind(&base::DoNothing),
base::Bind(&BluetoothOptionsHandler::DisconnectError,
weak_ptr_factory_.GetWeakPtr(),
device->GetAddress()));
} else if (command == kForgetCommand) {
VLOG(1) << "Forget device: " << address;
device->Forget(base::Bind(&BluetoothOptionsHandler::ForgetError,
weak_ptr_factory_.GetWeakPtr(),
device->GetAddress()));
} else {
LOG(WARNING) << "Unknown updateBluetoothDevice command: " << command;
}
}
void BluetoothOptionsHandler::Connected() {
pairing_device_address_.clear();
pairing_device_entered_ = kInvalidEntered;
web_ui()->CallJavascriptFunction(
"options.BluetoothPairing.dismissDialog");
}
void BluetoothOptionsHandler::ConnectError(
const std::string& address,
device::BluetoothDevice::ConnectErrorCode error_code) {
const char* error_name = NULL;
pairing_device_address_.clear();
pairing_device_entered_ = kInvalidEntered;
VLOG(1) << "Failed to connect to device: " << address;
switch (error_code) {
case device::BluetoothDevice::ERROR_UNKNOWN:
error_name = "bluetoothConnectUnknownError";
break;
case device::BluetoothDevice::ERROR_INPROGRESS:
error_name = "bluetoothConnectInProgress";
break;
case device::BluetoothDevice::ERROR_FAILED:
error_name = "bluetoothConnectFailed";
break;
case device::BluetoothDevice::ERROR_AUTH_FAILED:
error_name = "bluetoothConnectAuthFailed";
break;
case device::BluetoothDevice::ERROR_AUTH_CANCELED:
error_name = "bluetoothConnectAuthCanceled";
break;
case device::BluetoothDevice::ERROR_AUTH_REJECTED:
error_name = "bluetoothConnectAuthRejected";
break;
case device::BluetoothDevice::ERROR_AUTH_TIMEOUT:
error_name = "bluetoothConnectAuthTimeout";
break;
case device::BluetoothDevice::ERROR_UNSUPPORTED_DEVICE:
error_name = "bluetoothConnectUnsupportedDevice";
break;
}
if (error_name)
ReportError(error_name, address);
}
void BluetoothOptionsHandler::DisconnectError(const std::string& address) {
VLOG(1) << "Failed to disconnect from device: " << address;
ReportError("bluetoothDisconnectFailed", address);
}
void BluetoothOptionsHandler::ForgetError(const std::string& address) {
VLOG(1) << "Failed to disconnect and unpair device: " << address;
ReportError("bluetoothForgetFailed", address);
}
void BluetoothOptionsHandler::StopDiscoveryCallback(
const base::ListValue* args) {
should_run_device_discovery_ = false;
if (!discovery_session_.get() || !discovery_session_->IsActive()) {
VLOG(1) << "No active discovery session.";
return;
}
discovery_session_->Stop(
base::Bind(&base::DoNothing),
base::Bind(&BluetoothOptionsHandler::StopDiscoveryError,
weak_ptr_factory_.GetWeakPtr()));
}
void BluetoothOptionsHandler::StopDiscoveryError() {
VLOG(1) << "Failed to stop discovery.";
ReportError("bluetoothStopDiscoveryFailed", std::string());
}
void BluetoothOptionsHandler::GetPairedDevicesCallback(
const base::ListValue* args) {
device::BluetoothAdapter::DeviceList devices = adapter_->GetDevices();
for (device::BluetoothAdapter::DeviceList::iterator iter = devices.begin();
iter != devices.end(); ++iter)
SendDeviceNotification(*iter, NULL);
}
void BluetoothOptionsHandler::SendDeviceNotification(
const device::BluetoothDevice* device,
base::DictionaryValue* params) {
base::DictionaryValue js_properties;
js_properties.SetString("name", device->GetName());
js_properties.SetString("address", device->GetAddress());
js_properties.SetBoolean("paired", device->IsPaired());
js_properties.SetBoolean("connected", device->IsConnected());
js_properties.SetBoolean("connecting", device->IsConnecting());
js_properties.SetBoolean("connectable", device->IsConnectable());
if (params)
js_properties.MergeDictionary(params);
if (device->GetAddress() == pairing_device_address_) {
std::string pairing;
if (!js_properties.GetString("pairing", &pairing)) {
pairing = pairing_device_pairing_;
js_properties.SetString("pairing", pairing);
}
if (pairing == kRemotePinCode && !js_properties.HasKey("pincode"))
js_properties.SetString("pincode", pairing_device_pincode_);
if (pairing == kRemotePasskey && !js_properties.HasKey("passkey"))
js_properties.SetInteger("passkey", pairing_device_passkey_);
if ((pairing == kRemotePinCode || pairing == kRemotePasskey) &&
!js_properties.HasKey("entered") &&
pairing_device_entered_ != kInvalidEntered) {
js_properties.SetInteger("entered", pairing_device_entered_);
}
}
if (js_properties.HasKey("pairing")) {
pairing_device_address_ = device->GetAddress();
js_properties.GetString("pairing", &pairing_device_pairing_);
js_properties.GetString("pincode", &pairing_device_pincode_);
js_properties.GetInteger("passkey", &pairing_device_passkey_);
if (!js_properties.GetInteger("entered", &pairing_device_entered_))
pairing_device_entered_ = kInvalidEntered;
}
web_ui()->CallJavascriptFunction(
"options.BrowserOptions.addBluetoothDevice",
js_properties);
}
void BluetoothOptionsHandler::RequestPinCode(device::BluetoothDevice* device) {
base::DictionaryValue params;
params.SetString("pairing", kEnterPinCode);
SendDeviceNotification(device, ¶ms);
}
void BluetoothOptionsHandler::RequestPasskey(device::BluetoothDevice* device) {
base::DictionaryValue params;
params.SetString("pairing", kEnterPasskey);
SendDeviceNotification(device, ¶ms);
}
void BluetoothOptionsHandler::DisplayPinCode(device::BluetoothDevice* device,
const std::string& pincode) {
base::DictionaryValue params;
params.SetString("pairing", kRemotePinCode);
params.SetString("pincode", pincode);
SendDeviceNotification(device, ¶ms);
}
void BluetoothOptionsHandler::DisplayPasskey(device::BluetoothDevice* device,
uint32 passkey) {
base::DictionaryValue params;
params.SetString("pairing", kRemotePasskey);
params.SetInteger("passkey", passkey);
SendDeviceNotification(device, ¶ms);
}
void BluetoothOptionsHandler::KeysEntered(device::BluetoothDevice* device,
uint32 entered) {
base::DictionaryValue params;
params.SetInteger("entered", entered);
SendDeviceNotification(device, ¶ms);
}
void BluetoothOptionsHandler::ConfirmPasskey(device::BluetoothDevice* device,
uint32 passkey) {
base::DictionaryValue params;
params.SetString("pairing", kConfirmPasskey);
params.SetInteger("passkey", passkey);
SendDeviceNotification(device, ¶ms);
}
void BluetoothOptionsHandler::AuthorizePairing(
device::BluetoothDevice* device) {
device->ConfirmPairing();
}
void BluetoothOptionsHandler::ReportError(
const std::string& error,
const std::string& address) {
base::DictionaryValue properties;
properties.SetString("label", error);
properties.SetString("address", address);
web_ui()->CallJavascriptFunction(
"options.BluetoothPairing.showMessage",
properties);
}
void BluetoothOptionsHandler::DeviceAdded(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) {
DCHECK(adapter == adapter_.get());
DCHECK(device);
SendDeviceNotification(device, NULL);
}
void BluetoothOptionsHandler::DeviceChanged(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) {
DCHECK(adapter == adapter_.get());
DCHECK(device);
SendDeviceNotification(device, NULL);
}
void BluetoothOptionsHandler::DeviceRemoved(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) {
DCHECK(adapter == adapter_.get());
DCHECK(device);
if (pairing_device_address_ == device->GetAddress()) {
pairing_device_address_.clear();
pairing_device_entered_ = kInvalidEntered;
}
base::StringValue address(device->GetAddress());
web_ui()->CallJavascriptFunction(
"options.BrowserOptions.removeBluetoothDevice",
address);
}
void BluetoothOptionsHandler::DeviceConnecting(
device::BluetoothDevice* device) {
DCHECK(device);
base::DictionaryValue params;
params.SetString("pairing", kStartConnecting);
SendDeviceNotification(device, ¶ms);
}
}
}