Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Unified Diff: ash/system/chromeos/bluetooth/bluetooth_notification_controller.cc

Issue 183853010: Bluetooth: notify user of incoming pairing requests (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fit nits, add unit tests dep Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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());
jennyz 2014/02/28 23:24:36 Is the insert redundant? device->GetAddress alread
keybuk 2014/02/28 23:28:18 You have the condition above backwards ... that ma
jennyz 2014/02/28 23:31:19 My blindness, I read it oppositely. You are right.
+ 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
jennyz 2014/02/28 23:24:36 nit: initated -> initiated
keybuk 2014/02/28 23:28:18 Done.
+ // 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

Powered by Google App Engine
This is Rietveld 408576698