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 |