summaryrefslogtreecommitdiffstats
path: root/ash/system/chromeos
diff options
context:
space:
mode:
authorkeybuk@chromium.org <keybuk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-04 06:59:50 +0000
committerkeybuk@chromium.org <keybuk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-04 06:59:50 +0000
commitb314272591420e941281d56e96079756b334c404 (patch)
tree41ab73dbaf890dd87f1610c707defff67a50a857 /ash/system/chromeos
parent90be8cd625f609af86d135ef4e54503360699efa (diff)
downloadchromium_src-b314272591420e941281d56e96079756b334c404.zip
chromium_src-b314272591420e941281d56e96079756b334c404.tar.gz
chromium_src-b314272591420e941281d56e96079756b334c404.tar.bz2
Bluetooth: notify user of incoming pairing requests
Implement a low-priority pairing delegate in the form of an Aura Status Tray Notification Controller that displays a rich notification when an incoming pairing request is received and allows the user to accept or reject it when appropriate. BUG=345535 TESTS=chromeos=1 on Linux presents fake pairing requests Review URL: https://codereview.chromium.org/183853010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@254697 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash/system/chromeos')
-rw-r--r--ash/system/chromeos/bluetooth/bluetooth_notification_controller.cc301
-rw-r--r--ash/system/chromeos/bluetooth/bluetooth_notification_controller.h89
2 files changed, 390 insertions, 0 deletions
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 0000000..1a3aae3
--- /dev/null
+++ b/ash/system/chromeos/bluetooth/bluetooth_notification_controller.cc
@@ -0,0 +1,301 @@
+// Copyright 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:
+ // Buttons that appear in notifications.
+ enum Button {
+ BUTTON_ACCEPT,
+ BUTTON_REJECT
+ };
+
+ // 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.
+ const 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 BUTTON_ACCEPT:
+ device->ConfirmPairing();
+ break;
+ case BUTTON_REJECT:
+ 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() {
+ if (adapter_.get()) {
+ adapter_->RemoveObserver(this);
+ adapter_->RemovePairingDelegate(this);
+ adapter_ = NULL;
+ }
+}
+
+
+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 initiated 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) {
+ DCHECK(!adapter_.get());
+ 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
diff --git a/ash/system/chromeos/bluetooth/bluetooth_notification_controller.h b/ash/system/chromeos/bluetooth/bluetooth_notification_controller.h
new file mode 100644
index 0000000..dde8692
--- /dev/null
+++ b/ash/system/chromeos/bluetooth/bluetooth_notification_controller.h
@@ -0,0 +1,89 @@
+// Copyright 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.
+
+#ifndef ASH_SYSTEM_CHROMEOS_BLUETOOTH_BLUETOOTH_NOTIFICATION_CONTROLLER_H_
+#define ASH_SYSTEM_CHROMEOS_BLUETOOTH_BLUETOOTH_NOTIFICATION_CONTROLLER_H_
+
+#include <set>
+
+#include "ash/ash_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string16.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_device.h"
+
+namespace ash {
+namespace internal {
+
+// The BluetoothNotificationController receives incoming pairing requests from
+// the BluetoothAdapter, and notifications of changes to the adapter state and
+// set of paired devices. It presents incoming pairing requests in the form of
+// rich notifications that the user can interact with to approve the request.
+class ASH_EXPORT BluetoothNotificationController
+ : public device::BluetoothAdapter::Observer,
+ public device::BluetoothDevice::PairingDelegate {
+ public:
+ BluetoothNotificationController();
+ virtual ~BluetoothNotificationController();
+
+ // device::BluetoothAdapter::Observer override.
+ virtual void DeviceAdded(device::BluetoothAdapter* adapter,
+ device::BluetoothDevice* device) OVERRIDE;
+ virtual void DeviceChanged(device::BluetoothAdapter* adapter,
+ device::BluetoothDevice* device) OVERRIDE;
+ virtual void DeviceRemoved(device::BluetoothAdapter* adapter,
+ device::BluetoothDevice* device) OVERRIDE;
+
+ // device::BluetoothDevice::PairingDelegate override.
+ virtual void RequestPinCode(device::BluetoothDevice* device) OVERRIDE;
+ virtual void RequestPasskey(device::BluetoothDevice* device) OVERRIDE;
+ virtual void DisplayPinCode(device::BluetoothDevice* device,
+ const std::string& pincode) OVERRIDE;
+ virtual void DisplayPasskey(device::BluetoothDevice* device,
+ uint32 passkey) OVERRIDE;
+ virtual void KeysEntered(device::BluetoothDevice* device,
+ uint32 entered) OVERRIDE;
+ virtual void ConfirmPasskey(device::BluetoothDevice* device,
+ uint32 passkey) OVERRIDE;
+ virtual void AuthorizePairing(device::BluetoothDevice* device) OVERRIDE;
+
+ private:
+ // Internal method called by BluetoothAdapterFactory to provide the adapter
+ // object.
+ void OnGetAdapter(scoped_refptr<device::BluetoothAdapter> adapter);
+
+ // Presents a notification to the user that a device |device| is making a
+ // pairing request. The exact message to display is given in |message| and
+ // should include all relevant instructions, if |with_buttons| is true then
+ // the notification will have Accept and Reject buttons, if false only the
+ // usual cancel/dismiss button will be present on the notification.
+ void NotifyPairing(device::BluetoothDevice* device,
+ const base::string16& message,
+ bool with_buttons);
+
+ // Clears any shown pairing notification now that the device has been paired.
+ void NotifyPairedDevice(device::BluetoothDevice* device);
+
+ // Reference to the underlying BluetoothAdapter object, holding this reference
+ // ensures we stay around as the pairing delegate for that adapter.
+ scoped_refptr<device::BluetoothAdapter> adapter_;
+
+ // Set of currently paired devices, stored by Bluetooth address, used to
+ // filter out property changes for devices that were previously paired.
+ std::set<std::string> paired_devices_;
+
+ // Note: This should remain the last member so it'll be destroyed and
+ // invalidate its weak pointers before any other members are destroyed.
+ base::WeakPtrFactory<BluetoothNotificationController> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothNotificationController);
+};
+
+} // namespace internal
+} // namespace ash
+
+#endif // ASH_SYSTEM_CHROMEOS_BLUETOOTH_BLUETOOTH_NOTIFICATION_CONTROLLER_H_