15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/options/chromeos/bluetooth_options_handler.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/grit/generated_resources.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_ui.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "device/bluetooth/bluetooth_adapter.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "device/bluetooth/bluetooth_adapter_factory.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "device/bluetooth/bluetooth_device.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/cros_system_api/dbus/service_constants.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |UpdateDeviceCallback| takes a variable length list as an argument. The
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// value stored in each list element is indicated by the following constants.
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kUpdateDeviceAddressIndex = 0;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kUpdateDeviceCommandIndex = 1;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kUpdateDeviceAuthTokenIndex = 2;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |UpdateDeviceCallback| provides a command value of one of the following
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// constants that indicates what update it is providing to us.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kConnectCommand[] = "connect";
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kCancelCommand[] = "cancel";
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kAcceptCommand[] = "accept";
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kRejectCommand[] = "reject";
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kDisconnectCommand[] = "disconnect";
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kForgetCommand[] = "forget";
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |SendDeviceNotification| may include a pairing parameter whose value
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is one of the following constants instructing the UI to perform a certain
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// action.
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kStartConnecting[] = "bluetoothStartConnecting";
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kEnterPinCode[] = "bluetoothEnterPinCode";
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kEnterPasskey[] = "bluetoothEnterPasskey";
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kRemotePinCode[] = "bluetoothRemotePinCode";
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kRemotePasskey[] = "bluetoothRemotePasskey";
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kConfirmPasskey[] = "bluetoothConfirmPasskey";
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// An invalid |entered| value to represent the "undefined" value.
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kInvalidEntered = 0xFFFF;
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chromeos {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace options {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BluetoothOptionsHandler::BluetoothOptionsHandler()
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : should_run_device_discovery_(false),
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      pairing_device_passkey_(1000000),
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      pairing_device_entered_(kInvalidEntered),
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      weak_ptr_factory_(this) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BluetoothOptionsHandler::~BluetoothOptionsHandler() {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (adapter_.get())
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    adapter_->RemoveObserver(this);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::GetLocalizedValues(
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::DictionaryValue* localized_strings) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(localized_strings);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static OptionsStringResource resources[] = {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetooth", IDS_OPTIONS_SETTINGS_SECTION_TITLE_BLUETOOTH },
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "disableBluetooth", IDS_OPTIONS_SETTINGS_BLUETOOTH_DISABLE },
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "enableBluetooth", IDS_OPTIONS_SETTINGS_BLUETOOTH_ENABLE },
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "addBluetoothDevice", IDS_OPTIONS_SETTINGS_ADD_BLUETOOTH_DEVICE },
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothAddDeviceTitle",
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_ADD_DEVICE_TITLE },
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothOptionsPageTabTitle",
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_ADD_DEVICE_TITLE },
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "findBluetoothDevices", IDS_OPTIONS_SETTINGS_FIND_BLUETOOTH_DEVICES },
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothNoDevices", IDS_OPTIONS_SETTINGS_BLUETOOTH_NO_DEVICES },
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothNoDevicesFound",
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_NO_DEVICES_FOUND },
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    { "bluetoothScanning", IDS_OPTIONS_SETTINGS_BLUETOOTH_SCANNING },
86effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    { "bluetoothScanStopped", IDS_OPTIONS_SETTINGS_BLUETOOTH_SCAN_STOPPED },
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    { "bluetoothDeviceConnecting", IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECTING },
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothConnectDevice", IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT },
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothDisconnectDevice", IDS_OPTIONS_SETTINGS_BLUETOOTH_DISCONNECT },
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothForgetDevice", IDS_OPTIONS_SETTINGS_BLUETOOTH_FORGET },
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothCancel", IDS_OPTIONS_SETTINGS_BLUETOOTH_CANCEL },
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothEnterKey", IDS_OPTIONS_SETTINGS_BLUETOOTH_ENTER_KEY },
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothDismissError", IDS_OPTIONS_SETTINGS_BLUETOOTH_DISMISS_ERROR },
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Device connecting and pairing.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothStartConnecting",
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_START_CONNECTING },
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothAcceptPasskey",
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_ACCEPT_PASSKEY },
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothRejectPasskey",
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_REJECT_PASSKEY },
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothEnterPinCode",
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_ENTER_PIN_CODE_REQUEST },
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothEnterPasskey",
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_ENTER_PASSKEY_REQUEST },
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothRemotePinCode",
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_REMOTE_PIN_CODE_REQUEST },
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothRemotePasskey",
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_REMOTE_PASSKEY_REQUEST },
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothConfirmPasskey",
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_CONFIRM_PASSKEY_REQUEST },
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Error messages.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothStartDiscoveryFailed",
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_START_DISCOVERY_FAILED },
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothStopDiscoveryFailed",
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_STOP_DISCOVERY_FAILED },
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothChangePowerFailed",
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_CHANGE_POWER_FAILED },
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    { "bluetoothConnectUnknownError",
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_UNKNOWN_ERROR },
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    { "bluetoothConnectInProgress",
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_IN_PROGRESS },
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothConnectFailed",
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_FAILED },
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    { "bluetoothConnectAuthFailed",
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_AUTH_FAILED },
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    { "bluetoothConnectAuthCanceled",
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_AUTH_CANCELED },
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    { "bluetoothConnectAuthRejected",
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_AUTH_REJECTED },
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    { "bluetoothConnectAuthTimeout",
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_AUTH_TIMEOUT },
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    { "bluetoothConnectUnsupportedDevice",
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT_UNSUPPORTED_DEVICE },
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothDisconnectFailed",
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_DISCONNECT_FAILED },
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "bluetoothForgetFailed",
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IDS_OPTIONS_SETTINGS_BLUETOOTH_FORGET_FAILED }};
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegisterStrings(localized_strings, resources, arraysize(resources));
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(kevers): Reorder methods to match ordering in the header file.
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::AdapterPresentChanged(
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    device::BluetoothAdapter* adapter,
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool present) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(adapter == adapter_.get());
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (present) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_ui()->CallJavascriptFunction(
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "options.BrowserOptions.showBluetoothSettings");
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update the checkbox and visibility based on the powered state of the
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // new adapter.
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AdapterPoweredChanged(adapter_.get(), adapter_->IsPowered());
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_ui()->CallJavascriptFunction(
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "options.BrowserOptions.hideBluetoothSettings");
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::AdapterPoweredChanged(
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    device::BluetoothAdapter* adapter,
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool powered) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(adapter == adapter_.get());
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::FundamentalValue checked(powered);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui()->CallJavascriptFunction(
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "options.BrowserOptions.setBluetoothState", checked);
170effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
171effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // If the "Add device" overlay is visible, dismiss it.
172effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!powered) {
173effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    web_ui()->CallJavascriptFunction(
174effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        "options.BluetoothOptions.dismissOverlay");
175effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
176effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
177effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
178effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid BluetoothOptionsHandler::AdapterDiscoveringChanged(
179effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    device::BluetoothAdapter* adapter,
180effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    bool discovering) {
181effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(adapter == adapter_.get());
182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  base::FundamentalValue discovering_value(discovering);
183effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  web_ui()->CallJavascriptFunction(
184effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      "options.BluetoothOptions.updateDiscoveryState", discovering_value);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::RegisterMessages() {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui()->RegisterMessageCallback("bluetoothEnableChange",
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&BluetoothOptionsHandler::EnableChangeCallback,
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Unretained(this)));
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui()->RegisterMessageCallback("findBluetoothDevices",
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&BluetoothOptionsHandler::FindDevicesCallback,
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Unretained(this)));
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui()->RegisterMessageCallback("updateBluetoothDevice",
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&BluetoothOptionsHandler::UpdateDeviceCallback,
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Unretained(this)));
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui()->RegisterMessageCallback("stopBluetoothDeviceDiscovery",
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&BluetoothOptionsHandler::StopDiscoveryCallback,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Unretained(this)));
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui()->RegisterMessageCallback("getPairedBluetoothDevices",
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&BluetoothOptionsHandler::GetPairedDevicesCallback,
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Unretained(this)));
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::InitializeHandler() {
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  device::BluetoothAdapterFactory::GetAdapter(
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&BluetoothOptionsHandler::InitializeAdapter,
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()));
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::InitializePage() {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Show or hide the bluetooth settings and update the checkbox based
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // on the current present/powered state.
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AdapterPresentChanged(adapter_.get(), adapter_->IsPresent());
215effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Automatically start device discovery if the "Add Bluetooth Device"
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // overlay is visible.
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui()->CallJavascriptFunction(
219effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      "options.BluetoothOptions.startDeviceDiscovery");
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothOptionsHandler::InitializeAdapter(
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<device::BluetoothAdapter> adapter) {
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  adapter_ = adapter;
2257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  CHECK(adapter_.get());
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  adapter_->AddObserver(this);
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::EnableChangeCallback(
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::ListValue* args) {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool bluetooth_enabled;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->GetBoolean(0, &bluetooth_enabled);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  adapter_->SetPowered(bluetooth_enabled,
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       base::Bind(&base::DoNothing),
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       base::Bind(&BluetoothOptionsHandler::EnableChangeError,
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  weak_ptr_factory_.GetWeakPtr()));
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::EnableChangeError() {
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VLOG(1) << "Failed to change power state.";
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReportError("bluetoothChangePowerFailed", std::string());
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::FindDevicesCallback(
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::ListValue* args) {
247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (discovery_session_.get() && discovery_session_->IsActive()) {
248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    VLOG(1) << "Already have an active discovery session.";
249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  should_run_device_discovery_ = true;
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  adapter_->StartDiscoverySession(
253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&BluetoothOptionsHandler::OnStartDiscoverySession,
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()),
255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&BluetoothOptionsHandler::FindDevicesError,
256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()));
257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothOptionsHandler::OnStartDiscoverySession(
260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<device::BluetoothDiscoverySession> discovery_session) {
261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If the discovery session was returned after a request to stop discovery
262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // (e.g. the "Add Device" dialog was dismissed), don't claim the discovery
263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // session and let it clean up.
264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!should_run_device_discovery_)
265a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
266a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  discovery_session_ = discovery_session.Pass();
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::FindDevicesError() {
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VLOG(1) << "Failed to start discovery.";
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReportError("bluetoothStartDiscoveryFailed", std::string());
272effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!adapter_.get())
273effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
274effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  base::FundamentalValue discovering(adapter_->IsDiscovering());
275effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  web_ui()->CallJavascriptFunction(
276effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      "options.BluetoothOptions.updateDiscoveryState", discovering);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::UpdateDeviceCallback(
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::ListValue* args) {
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string address;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->GetString(kUpdateDeviceAddressIndex, &address);
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  device::BluetoothDevice* device = adapter_->GetDevice(address);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!device)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string command;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->GetString(kUpdateDeviceCommandIndex, &command);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (command == kConnectCommand) {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int size = args->GetSize();
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size > kUpdateDeviceAuthTokenIndex) {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // PIN code or Passkey entry during the pairing process.
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string auth_token;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      args->GetString(kUpdateDeviceAuthTokenIndex, &auth_token);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (device->ExpectingPinCode()) {
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        DeviceConnecting(device);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // PIN Code is an array of 1 to 16 8-bit bytes, the usual
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // interpretation, and the one shared by BlueZ, is a UTF-8 string
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // of as many characters that will fit in that space, thus we
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // can use the auth token from JavaScript unmodified.
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        VLOG(1) << "PIN Code supplied: " << address << ": " << auth_token;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        device->SetPinCode(auth_token);
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (device->ExpectingPasskey()) {
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        DeviceConnecting(device);
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Passkey is a numeric in the range 0-999999, in this case the
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // JavaScript code should have ensured the auth token string only
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // contains digits so a simple conversion is sufficient. In the
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // failure case, just use 0 since that's the most likely Passkey
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // anyway, and if it's refused the device will request a new one.
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unsigned passkey = 0;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::StringToUint(auth_token, &passkey);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        VLOG(1) << "Passkey supplied: " << address << ": " << passkey;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        device->SetPasskey(passkey);
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(WARNING) << "Auth token supplied after pairing ended: " << address
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     << ": " << auth_token;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Determine if the device supports pairing:
324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      PairingDelegate* delegate = NULL;
325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (device->IsPairable())
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        delegate = this;
327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Connection request.
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      VLOG(1) << "Connect: " << address;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      device->Connect(
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          delegate,
332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          base::Bind(&BluetoothOptionsHandler::Connected,
333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr()),
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&BluetoothOptionsHandler::ConnectError,
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr(),
336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     device->GetAddress()));
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (command == kCancelCommand) {
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Cancel pairing.
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    VLOG(1) << "Cancel pairing: " << address;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    device->CancelPairing();
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (command == kAcceptCommand) {
343a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DeviceConnecting(device);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Confirm displayed Passkey.
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    VLOG(1) << "Confirm pairing: " << address;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    device->ConfirmPairing();
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (command == kRejectCommand) {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Reject displayed Passkey.
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    VLOG(1) << "Reject pairing: " << address;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    device->RejectPairing();
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (command == kDisconnectCommand) {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Disconnect from device.
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    VLOG(1) << "Disconnect device: " << address;
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    device->Disconnect(
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&base::DoNothing),
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&BluetoothOptionsHandler::DisconnectError,
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr(),
358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   device->GetAddress()));
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (command == kForgetCommand) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Disconnect from device and delete pairing information.
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    VLOG(1) << "Forget device: " << address;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    device->Forget(base::Bind(&BluetoothOptionsHandler::ForgetError,
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              weak_ptr_factory_.GetWeakPtr(),
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              device->GetAddress()));
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Unknown updateBluetoothDevice command: " << command;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void BluetoothOptionsHandler::Connected() {
371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Invalidate the local cache.
372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  pairing_device_address_.clear();
373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  pairing_device_entered_ = kInvalidEntered;
374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  web_ui()->CallJavascriptFunction(
376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "options.BluetoothPairing.dismissDialog");
377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothOptionsHandler::ConnectError(
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& address,
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    device::BluetoothDevice::ConnectErrorCode error_code) {
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const char* error_name = NULL;
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Invalidate the local cache.
385c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  pairing_device_address_.clear();
386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  pairing_device_entered_ = kInvalidEntered;
387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VLOG(1) << "Failed to connect to device: " << address;
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (error_code) {
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case device::BluetoothDevice::ERROR_UNKNOWN:
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_name = "bluetoothConnectUnknownError";
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case device::BluetoothDevice::ERROR_INPROGRESS:
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_name = "bluetoothConnectInProgress";
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case device::BluetoothDevice::ERROR_FAILED:
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_name = "bluetoothConnectFailed";
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case device::BluetoothDevice::ERROR_AUTH_FAILED:
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_name = "bluetoothConnectAuthFailed";
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case device::BluetoothDevice::ERROR_AUTH_CANCELED:
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_name = "bluetoothConnectAuthCanceled";
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case device::BluetoothDevice::ERROR_AUTH_REJECTED:
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_name = "bluetoothConnectAuthRejected";
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case device::BluetoothDevice::ERROR_AUTH_TIMEOUT:
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_name = "bluetoothConnectAuthTimeout";
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case device::BluetoothDevice::ERROR_UNSUPPORTED_DEVICE:
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_name = "bluetoothConnectUnsupportedDevice";
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Report an error only if there's an error to report.
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (error_name)
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ReportError(error_name, address);
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::DisconnectError(const std::string& address) {
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VLOG(1) << "Failed to disconnect from device: " << address;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReportError("bluetoothDisconnectFailed", address);
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::ForgetError(const std::string& address) {
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VLOG(1) << "Failed to disconnect and unpair device: " << address;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReportError("bluetoothForgetFailed", address);
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::StopDiscoveryCallback(
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::ListValue* args) {
432a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  should_run_device_discovery_ = false;
433a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!discovery_session_.get() || !discovery_session_->IsActive()) {
434a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    VLOG(1) << "No active discovery session.";
435a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
437a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  discovery_session_->Stop(
438a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&base::DoNothing),
439a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&BluetoothOptionsHandler::StopDiscoveryError,
440a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()));
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::StopDiscoveryError() {
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VLOG(1) << "Failed to stop discovery.";
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReportError("bluetoothStopDiscoveryFailed", std::string());
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::GetPairedDevicesCallback(
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::ListValue* args) {
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  device::BluetoothAdapter::DeviceList devices = adapter_->GetDevices();
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (device::BluetoothAdapter::DeviceList::iterator iter = devices.begin();
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter != devices.end(); ++iter)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendDeviceNotification(*iter, NULL);
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::SendDeviceNotification(
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const device::BluetoothDevice* device,
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::DictionaryValue* params) {
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::DictionaryValue js_properties;
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  js_properties.SetString("name", device->GetName());
462c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  js_properties.SetString("address", device->GetAddress());
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  js_properties.SetBoolean("paired", device->IsPaired());
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  js_properties.SetBoolean("connected", device->IsConnected());
465c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  js_properties.SetBoolean("connecting", device->IsConnecting());
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  js_properties.SetBoolean("connectable", device->IsConnectable());
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (params)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    js_properties.MergeDictionary(params);
469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
470c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Use the cached values to update js_property.
471c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (device->GetAddress() == pairing_device_address_) {
472c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string pairing;
473c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!js_properties.GetString("pairing", &pairing)) {
474c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pairing = pairing_device_pairing_;
475c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      js_properties.SetString("pairing", pairing);
476c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
477c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (pairing == kRemotePinCode && !js_properties.HasKey("pincode"))
478c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      js_properties.SetString("pincode", pairing_device_pincode_);
479c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (pairing == kRemotePasskey && !js_properties.HasKey("passkey"))
480c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      js_properties.SetInteger("passkey", pairing_device_passkey_);
481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if ((pairing == kRemotePinCode || pairing == kRemotePasskey) &&
482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        !js_properties.HasKey("entered") &&
483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        pairing_device_entered_ != kInvalidEntered) {
484c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      js_properties.SetInteger("entered", pairing_device_entered_);
485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
486c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
488c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Update the cache with the new information.
489c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (js_properties.HasKey("pairing")) {
490c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    pairing_device_address_ = device->GetAddress();
491c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    js_properties.GetString("pairing", &pairing_device_pairing_);
492c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    js_properties.GetString("pincode", &pairing_device_pincode_);
493c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    js_properties.GetInteger("passkey", &pairing_device_passkey_);
494c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!js_properties.GetInteger("entered", &pairing_device_entered_))
495c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pairing_device_entered_ = kInvalidEntered;
496c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
497c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui()->CallJavascriptFunction(
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "options.BrowserOptions.addBluetoothDevice",
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      js_properties);
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::RequestPinCode(device::BluetoothDevice* device) {
5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue params;
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.SetString("pairing", kEnterPinCode);
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendDeviceNotification(device, &params);
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::RequestPasskey(device::BluetoothDevice* device) {
5105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue params;
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.SetString("pairing", kEnterPasskey);
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendDeviceNotification(device, &params);
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::DisplayPinCode(device::BluetoothDevice* device,
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             const std::string& pincode) {
5175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue params;
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.SetString("pairing", kRemotePinCode);
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.SetString("pincode", pincode);
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendDeviceNotification(device, &params);
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::DisplayPasskey(device::BluetoothDevice* device,
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             uint32 passkey) {
5255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue params;
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.SetString("pairing", kRemotePasskey);
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.SetInteger("passkey", passkey);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendDeviceNotification(device, &params);
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
531c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void BluetoothOptionsHandler::KeysEntered(device::BluetoothDevice* device,
532c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                          uint32 entered) {
5335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue params;
534c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  params.SetInteger("entered", entered);
535c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SendDeviceNotification(device, &params);
536c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
537c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::ConfirmPasskey(device::BluetoothDevice* device,
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             uint32 passkey) {
5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue params;
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.SetString("pairing", kConfirmPasskey);
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.SetInteger("passkey", passkey);
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendDeviceNotification(device, &params);
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
546a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void BluetoothOptionsHandler::AuthorizePairing(
547a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    device::BluetoothDevice* device) {
548a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // There is never any circumstance where this will be called, since the
549a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // options handler will only be used for outgoing pairing requests, but
550a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // play it safe.
551a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  device->ConfirmPairing();
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::ReportError(
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& error,
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& address) {
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::DictionaryValue properties;
5586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  properties.SetString("message", error);
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  properties.SetString("address", address);
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui()->CallJavascriptFunction(
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "options.BluetoothPairing.showMessage",
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      properties);
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::DeviceAdded(device::BluetoothAdapter* adapter,
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          device::BluetoothDevice* device) {
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(adapter == adapter_.get());
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(device);
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendDeviceNotification(device, NULL);
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::DeviceChanged(device::BluetoothAdapter* adapter,
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            device::BluetoothDevice* device) {
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(adapter == adapter_.get());
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(device);
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendDeviceNotification(device, NULL);
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BluetoothOptionsHandler::DeviceRemoved(device::BluetoothAdapter* adapter,
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            device::BluetoothDevice* device) {
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(adapter == adapter_.get());
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(device);
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
584c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Invalidate the local cache if the pairing device is removed.
585c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (pairing_device_address_ == device->GetAddress()) {
586c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    pairing_device_address_.clear();
587c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    pairing_device_entered_ = kInvalidEntered;
588c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
589c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
590c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::StringValue address(device->GetAddress());
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_ui()->CallJavascriptFunction(
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "options.BrowserOptions.removeBluetoothDevice",
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      address);
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void BluetoothOptionsHandler::DeviceConnecting(
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    device::BluetoothDevice* device) {
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(device);
5995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue params;
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  params.SetString("pairing", kStartConnecting);
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SendDeviceNotification(device, &params);
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace options
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chromeos
606