| Index: ash/system/chromeos/bluetooth/bluetooth_notification_controller.cc
|
| diff --git a/ash/system/chromeos/bluetooth/bluetooth_notification_controller.cc b/ash/system/chromeos/bluetooth/bluetooth_notification_controller.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1f2fd66a9eb294b37ca6783e003433edbbff5e2d
|
| --- /dev/null
|
| +++ b/ash/system/chromeos/bluetooth/bluetooth_notification_controller.cc
|
| @@ -0,0 +1,291 @@
|
| +// Copyright (c) 2014 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/chromeos/bluetooth/bluetooth_notification_controller.h"
|
| +
|
| +#include "ash/system/system_notifier.h"
|
| +#include "base/bind.h"
|
| +#include "base/callback.h"
|
| +#include "base/logging.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/strings/stringprintf.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "device/bluetooth/bluetooth_adapter_factory.h"
|
| +#include "device/bluetooth/bluetooth_device.h"
|
| +#include "grit/ash_resources.h"
|
| +#include "grit/ash_strings.h"
|
| +#include "ui/base/l10n/l10n_util.h"
|
| +#include "ui/base/resource/resource_bundle.h"
|
| +#include "ui/message_center/message_center.h"
|
| +#include "ui/message_center/notification.h"
|
| +#include "ui/message_center/notification_delegate.h"
|
| +#include "ui/message_center/notification_types.h"
|
| +
|
| +using device::BluetoothAdapter;
|
| +using device::BluetoothAdapterFactory;
|
| +using device::BluetoothDevice;
|
| +using message_center::Notification;
|
| +
|
| +namespace {
|
| +
|
| +// Identifier for the pairing notification; the Bluetooth code ensures we
|
| +// only receive one pairing request at a time, so a single id is sufficient and
|
| +// means we "update" one notification if not handled rather than continually
|
| +// bugging the user.
|
| +const char kBluetoothDevicePairingNotificationId[] =
|
| + "chrome://settings/bluetooth/pairing";
|
| +
|
| +// The BluetoothPairingNotificationDelegate handles user interaction with the
|
| +// pairing notification and sending the confirmation, rejection or cancellation
|
| +// back to the underlying device.
|
| +class BluetoothPairingNotificationDelegate
|
| + : public message_center::NotificationDelegate {
|
| + public:
|
| + BluetoothPairingNotificationDelegate(scoped_refptr<BluetoothAdapter> adapter,
|
| + const std::string& address);
|
| +
|
| + protected:
|
| + virtual ~BluetoothPairingNotificationDelegate();
|
| +
|
| + // message_center::NotificationDelegate overrides.
|
| + virtual void Display() OVERRIDE;
|
| + virtual void Error() OVERRIDE;
|
| + virtual void Close(bool by_user) OVERRIDE;
|
| + virtual bool HasClickedListener() OVERRIDE;
|
| + virtual void Click() OVERRIDE;
|
| + virtual void ButtonClick(int button_index) OVERRIDE;
|
| +
|
| + private:
|
| + // Reference to the underlying Bluetooth Adapter, holding onto this
|
| + // reference ensures the adapter object doesn't go out of scope while we have
|
| + // a pending request and user interaction.
|
| + scoped_refptr<BluetoothAdapter> adapter_;
|
| +
|
| + // Address of the device being paired.
|
| + std::string address_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(BluetoothPairingNotificationDelegate);
|
| +};
|
| +
|
| +BluetoothPairingNotificationDelegate::BluetoothPairingNotificationDelegate(
|
| + scoped_refptr<BluetoothAdapter> adapter,
|
| + const std::string& address)
|
| + : adapter_(adapter),
|
| + address_(address) {
|
| +}
|
| +
|
| +BluetoothPairingNotificationDelegate::~BluetoothPairingNotificationDelegate() {
|
| +}
|
| +
|
| +void BluetoothPairingNotificationDelegate::Display() {
|
| +}
|
| +
|
| +void BluetoothPairingNotificationDelegate::Error() {
|
| +}
|
| +
|
| +void BluetoothPairingNotificationDelegate::Close(bool by_user) {
|
| + VLOG(1) << "Pairing notification closed. by_user = " << by_user;
|
| + // Ignore notification closes generated as a result of pairing completion.
|
| + if (!by_user)
|
| + return;
|
| +
|
| + // Cancel the pairing of the device, if the object still exists.
|
| + BluetoothDevice* device = adapter_->GetDevice(address_);
|
| + if (device)
|
| + device->CancelPairing();
|
| +}
|
| +
|
| +bool BluetoothPairingNotificationDelegate::HasClickedListener() {
|
| + return false;
|
| +}
|
| +
|
| +void BluetoothPairingNotificationDelegate::Click() {
|
| +}
|
| +
|
| +void BluetoothPairingNotificationDelegate::ButtonClick(int button_index) {
|
| + VLOG(1) << "Pairing notification, button click: " << button_index;
|
| + // If the device object still exists, send the appropriate response either
|
| + // confirming or rejecting the pairing.
|
| + BluetoothDevice* device = adapter_->GetDevice(address_);
|
| + if (device) {
|
| + switch (button_index) {
|
| + case 0:
|
| + device->ConfirmPairing();
|
| + break;
|
| + case 1:
|
| + device->RejectPairing();
|
| + break;
|
| + }
|
| + }
|
| +
|
| + // In any case, remove this pairing notification.
|
| + message_center::MessageCenter::Get()->RemoveNotification(
|
| + kBluetoothDevicePairingNotificationId, false /* by_user */);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +
|
| +namespace ash {
|
| +namespace internal {
|
| +
|
| +BluetoothNotificationController::BluetoothNotificationController()
|
| + : weak_ptr_factory_(this) {
|
| + BluetoothAdapterFactory::GetAdapter(
|
| + base::Bind(&BluetoothNotificationController::OnGetAdapter,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| +}
|
| +
|
| +BluetoothNotificationController::~BluetoothNotificationController() {
|
| + adapter_->RemoveObserver(this);
|
| + adapter_->RemovePairingDelegate(this);
|
| +}
|
| +
|
| +
|
| +void BluetoothNotificationController::DeviceAdded(BluetoothAdapter* adapter,
|
| + BluetoothDevice* device) {
|
| + if (device->IsPaired()) {
|
| + paired_devices_.insert(device->GetAddress());
|
| + NotifyPairedDevice(device);
|
| + }
|
| +}
|
| +
|
| +void BluetoothNotificationController::DeviceChanged(BluetoothAdapter* adapter,
|
| + BluetoothDevice* device) {
|
| + if (paired_devices_.find(device->GetAddress()) != paired_devices_.end())
|
| + return;
|
| +
|
| + if (device->IsPaired()) {
|
| + paired_devices_.insert(device->GetAddress());
|
| + NotifyPairedDevice(device);
|
| + }
|
| +}
|
| +
|
| +void BluetoothNotificationController::DeviceRemoved(BluetoothAdapter* adapter,
|
| + BluetoothDevice* device) {
|
| + paired_devices_.erase(device->GetAddress());
|
| +}
|
| +
|
| +
|
| +void BluetoothNotificationController::RequestPinCode(BluetoothDevice* device) {
|
| + // Cannot provide keyboard entry in a notification; these devices (old car
|
| + // audio systems for the most part) will need pairing to be initated from
|
| + // the Chromebook.
|
| + device->CancelPairing();
|
| +}
|
| +
|
| +void BluetoothNotificationController::RequestPasskey(BluetoothDevice* device) {
|
| + // Cannot provide keyboard entry in a notification; fortunately the spec
|
| + // doesn't allow for this to be an option when we're receiving the pairing
|
| + // request anyway.
|
| + device->CancelPairing();
|
| +}
|
| +
|
| +void BluetoothNotificationController::DisplayPinCode(
|
| + BluetoothDevice* device,
|
| + const std::string& pincode) {
|
| + base::string16 message = l10n_util::GetStringFUTF16(
|
| + IDS_ASH_STATUS_TRAY_BLUETOOTH_DISPLAY_PINCODE,
|
| + device->GetName(), base::UTF8ToUTF16(pincode));
|
| +
|
| + NotifyPairing(device, message, false);
|
| +}
|
| +
|
| +void BluetoothNotificationController::DisplayPasskey(BluetoothDevice* device,
|
| + uint32 passkey) {
|
| + base::string16 message = l10n_util::GetStringFUTF16(
|
| + IDS_ASH_STATUS_TRAY_BLUETOOTH_DISPLAY_PASSKEY,
|
| + device->GetName(), base::UTF8ToUTF16(
|
| + base::StringPrintf("%06i", passkey)));
|
| +
|
| + NotifyPairing(device, message, false);
|
| +}
|
| +
|
| +void BluetoothNotificationController::KeysEntered(BluetoothDevice* device,
|
| + uint32 entered) {
|
| + // Ignored since we don't have CSS in the notification to update.
|
| +}
|
| +
|
| +void BluetoothNotificationController::ConfirmPasskey(BluetoothDevice* device,
|
| + uint32 passkey) {
|
| + base::string16 message = l10n_util::GetStringFUTF16(
|
| + IDS_ASH_STATUS_TRAY_BLUETOOTH_CONFIRM_PASSKEY,
|
| + device->GetName(), base::UTF8ToUTF16(
|
| + base::StringPrintf("%06i", passkey)));
|
| +
|
| + NotifyPairing(device, message, true);
|
| +}
|
| +
|
| +void BluetoothNotificationController::AuthorizePairing(
|
| + BluetoothDevice* device) {
|
| + base::string16 message = l10n_util::GetStringFUTF16(
|
| + IDS_ASH_STATUS_TRAY_BLUETOOTH_AUTHORIZE_PAIRING,
|
| + device->GetName());
|
| +
|
| + NotifyPairing(device, message, true);
|
| +}
|
| +
|
| +
|
| +void BluetoothNotificationController::OnGetAdapter(
|
| + scoped_refptr<BluetoothAdapter> adapter) {
|
| + adapter_ = adapter;
|
| + adapter_->AddObserver(this);
|
| + adapter_->AddPairingDelegate(this,
|
| + BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW);
|
| +
|
| + // Build a list of the currently paired devices; these don't receive
|
| + // notifications since it's assumed they were previously notified.
|
| + BluetoothAdapter::DeviceList devices = adapter_->GetDevices();
|
| + for (BluetoothAdapter::DeviceList::const_iterator iter = devices.begin();
|
| + iter != devices.end(); ++iter) {
|
| + const BluetoothDevice* device = *iter;
|
| + if (device->IsPaired())
|
| + paired_devices_.insert(device->GetAddress());
|
| + }
|
| +}
|
| +
|
| +
|
| +void BluetoothNotificationController::NotifyPairing(
|
| + BluetoothDevice* device,
|
| + const base::string16& message,
|
| + bool with_buttons) {
|
| + message_center::RichNotificationData optional;
|
| + if (with_buttons) {
|
| + optional.buttons.push_back(message_center::ButtonInfo(
|
| + l10n_util::GetStringUTF16(
|
| + IDS_ASH_STATUS_TRAY_BLUETOOTH_ACCEPT)));
|
| + optional.buttons.push_back(message_center::ButtonInfo(
|
| + l10n_util::GetStringUTF16(
|
| + IDS_ASH_STATUS_TRAY_BLUETOOTH_REJECT)));
|
| + }
|
| +
|
| + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
|
| +
|
| + scoped_ptr<Notification> notification(new Notification(
|
| + message_center::NOTIFICATION_TYPE_SIMPLE,
|
| + kBluetoothDevicePairingNotificationId,
|
| + base::string16() /* title */,
|
| + message,
|
| + bundle.GetImageNamed(IDR_AURA_UBER_TRAY_BLUETOOTH),
|
| + base::string16() /* display source */,
|
| + message_center::NotifierId(
|
| + message_center::NotifierId::SYSTEM_COMPONENT,
|
| + system_notifier::kNotifierBluetooth),
|
| + optional,
|
| + new BluetoothPairingNotificationDelegate(adapter_,
|
| + device->GetAddress())));
|
| + message_center::MessageCenter::Get()->AddNotification(notification.Pass());
|
| +}
|
| +
|
| +void BluetoothNotificationController::NotifyPairedDevice(
|
| + BluetoothDevice* device) {
|
| + // Remove the currently presented pairing notification; since only one
|
| + // pairing request is queued at a time, this is guaranteed to be the device
|
| + // that just became paired.
|
| + message_center::MessageCenter::Get()->RemoveNotification(
|
| + kBluetoothDevicePairingNotificationId, false /* by_user */);
|
| +}
|
| +
|
| +} // namespace internal
|
| +} // namespace ash
|
|
|