| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "ash/common/system/chromeos/bluetooth/bluetooth_notification_controller
.h" | |
| 6 | |
| 7 #include <memory> | |
| 8 #include <utility> | |
| 9 | |
| 10 #include "ash/common/system/system_notifier.h" | |
| 11 #include "ash/resources/grit/ash_resources.h" | |
| 12 #include "ash/strings/grit/ash_strings.h" | |
| 13 #include "base/bind.h" | |
| 14 #include "base/callback.h" | |
| 15 #include "base/logging.h" | |
| 16 #include "base/strings/stringprintf.h" | |
| 17 #include "base/strings/utf_string_conversions.h" | |
| 18 #include "device/bluetooth/bluetooth_adapter_factory.h" | |
| 19 #include "device/bluetooth/bluetooth_device.h" | |
| 20 #include "ui/base/l10n/l10n_util.h" | |
| 21 #include "ui/base/resource/resource_bundle.h" | |
| 22 #include "ui/message_center/message_center.h" | |
| 23 #include "ui/message_center/notification.h" | |
| 24 #include "ui/message_center/notification_delegate.h" | |
| 25 #include "ui/message_center/notification_types.h" | |
| 26 | |
| 27 using device::BluetoothAdapter; | |
| 28 using device::BluetoothAdapterFactory; | |
| 29 using device::BluetoothDevice; | |
| 30 using message_center::Notification; | |
| 31 | |
| 32 namespace { | |
| 33 | |
| 34 // Identifier for the discoverable notification. | |
| 35 const char kBluetoothDeviceDiscoverableNotificationId[] = | |
| 36 "chrome://settings/bluetooth/discoverable"; | |
| 37 | |
| 38 // Identifier for the pairing notification; the Bluetooth code ensures we | |
| 39 // only receive one pairing request at a time, so a single id is sufficient and | |
| 40 // means we "update" one notification if not handled rather than continually | |
| 41 // bugging the user. | |
| 42 const char kBluetoothDevicePairingNotificationId[] = | |
| 43 "chrome://settings/bluetooth/pairing"; | |
| 44 | |
| 45 // Identifier for the notification that a device has been paired with the | |
| 46 // system. | |
| 47 const char kBluetoothDevicePairedNotificationId[] = | |
| 48 "chrome://settings/bluetooth/paired"; | |
| 49 | |
| 50 // The BluetoothPairingNotificationDelegate handles user interaction with the | |
| 51 // pairing notification and sending the confirmation, rejection or cancellation | |
| 52 // back to the underlying device. | |
| 53 class BluetoothPairingNotificationDelegate | |
| 54 : public message_center::NotificationDelegate { | |
| 55 public: | |
| 56 BluetoothPairingNotificationDelegate(scoped_refptr<BluetoothAdapter> adapter, | |
| 57 const std::string& address); | |
| 58 | |
| 59 protected: | |
| 60 ~BluetoothPairingNotificationDelegate() override; | |
| 61 | |
| 62 // message_center::NotificationDelegate overrides. | |
| 63 void Close(bool by_user) override; | |
| 64 void ButtonClick(int button_index) override; | |
| 65 | |
| 66 private: | |
| 67 // Buttons that appear in notifications. | |
| 68 enum Button { BUTTON_ACCEPT, BUTTON_REJECT }; | |
| 69 | |
| 70 // Reference to the underlying Bluetooth Adapter, holding onto this | |
| 71 // reference ensures the adapter object doesn't go out of scope while we have | |
| 72 // a pending request and user interaction. | |
| 73 scoped_refptr<BluetoothAdapter> adapter_; | |
| 74 | |
| 75 // Address of the device being paired. | |
| 76 const std::string address_; | |
| 77 | |
| 78 DISALLOW_COPY_AND_ASSIGN(BluetoothPairingNotificationDelegate); | |
| 79 }; | |
| 80 | |
| 81 BluetoothPairingNotificationDelegate::BluetoothPairingNotificationDelegate( | |
| 82 scoped_refptr<BluetoothAdapter> adapter, | |
| 83 const std::string& address) | |
| 84 : adapter_(adapter), address_(address) {} | |
| 85 | |
| 86 BluetoothPairingNotificationDelegate::~BluetoothPairingNotificationDelegate() {} | |
| 87 | |
| 88 void BluetoothPairingNotificationDelegate::Close(bool by_user) { | |
| 89 VLOG(1) << "Pairing notification closed. by_user = " << by_user; | |
| 90 // Ignore notification closes generated as a result of pairing completion. | |
| 91 if (!by_user) | |
| 92 return; | |
| 93 | |
| 94 // Cancel the pairing of the device, if the object still exists. | |
| 95 BluetoothDevice* device = adapter_->GetDevice(address_); | |
| 96 if (device) | |
| 97 device->CancelPairing(); | |
| 98 } | |
| 99 | |
| 100 void BluetoothPairingNotificationDelegate::ButtonClick(int button_index) { | |
| 101 VLOG(1) << "Pairing notification, button click: " << button_index; | |
| 102 // If the device object still exists, send the appropriate response either | |
| 103 // confirming or rejecting the pairing. | |
| 104 BluetoothDevice* device = adapter_->GetDevice(address_); | |
| 105 if (device) { | |
| 106 switch (button_index) { | |
| 107 case BUTTON_ACCEPT: | |
| 108 device->ConfirmPairing(); | |
| 109 break; | |
| 110 case BUTTON_REJECT: | |
| 111 device->RejectPairing(); | |
| 112 break; | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 // In any case, remove this pairing notification. | |
| 117 message_center::MessageCenter::Get()->RemoveNotification( | |
| 118 kBluetoothDevicePairingNotificationId, false /* by_user */); | |
| 119 } | |
| 120 | |
| 121 } // namespace | |
| 122 | |
| 123 namespace ash { | |
| 124 | |
| 125 BluetoothNotificationController::BluetoothNotificationController() | |
| 126 : weak_ptr_factory_(this) { | |
| 127 BluetoothAdapterFactory::GetAdapter( | |
| 128 base::Bind(&BluetoothNotificationController::OnGetAdapter, | |
| 129 weak_ptr_factory_.GetWeakPtr())); | |
| 130 } | |
| 131 | |
| 132 BluetoothNotificationController::~BluetoothNotificationController() { | |
| 133 if (adapter_.get()) { | |
| 134 adapter_->RemoveObserver(this); | |
| 135 adapter_->RemovePairingDelegate(this); | |
| 136 adapter_ = NULL; | |
| 137 } | |
| 138 } | |
| 139 | |
| 140 void BluetoothNotificationController::AdapterDiscoverableChanged( | |
| 141 BluetoothAdapter* adapter, | |
| 142 bool discoverable) { | |
| 143 if (discoverable) { | |
| 144 NotifyAdapterDiscoverable(); | |
| 145 } else { | |
| 146 // Clear any previous discoverable notification. | |
| 147 message_center::MessageCenter::Get()->RemoveNotification( | |
| 148 kBluetoothDeviceDiscoverableNotificationId, false /* by_user */); | |
| 149 } | |
| 150 } | |
| 151 | |
| 152 void BluetoothNotificationController::DeviceAdded(BluetoothAdapter* adapter, | |
| 153 BluetoothDevice* device) { | |
| 154 // Add the new device to the list of currently paired devices; it doesn't | |
| 155 // receive a notification since it's assumed it was previously notified. | |
| 156 if (device->IsPaired()) | |
| 157 paired_devices_.insert(device->GetAddress()); | |
| 158 } | |
| 159 | |
| 160 void BluetoothNotificationController::DeviceChanged(BluetoothAdapter* adapter, | |
| 161 BluetoothDevice* device) { | |
| 162 // If the device is already in the list of paired devices, then don't | |
| 163 // notify. | |
| 164 if (paired_devices_.find(device->GetAddress()) != paired_devices_.end()) | |
| 165 return; | |
| 166 | |
| 167 // Otherwise if it's marked as paired then it must be newly paired, so | |
| 168 // notify the user about that. | |
| 169 if (device->IsPaired()) { | |
| 170 paired_devices_.insert(device->GetAddress()); | |
| 171 NotifyPairedDevice(device); | |
| 172 } | |
| 173 } | |
| 174 | |
| 175 void BluetoothNotificationController::DeviceRemoved(BluetoothAdapter* adapter, | |
| 176 BluetoothDevice* device) { | |
| 177 paired_devices_.erase(device->GetAddress()); | |
| 178 } | |
| 179 | |
| 180 void BluetoothNotificationController::RequestPinCode(BluetoothDevice* device) { | |
| 181 // Cannot provide keyboard entry in a notification; these devices (old car | |
| 182 // audio systems for the most part) will need pairing to be initiated from | |
| 183 // the Chromebook. | |
| 184 device->CancelPairing(); | |
| 185 } | |
| 186 | |
| 187 void BluetoothNotificationController::RequestPasskey(BluetoothDevice* device) { | |
| 188 // Cannot provide keyboard entry in a notification; fortunately the spec | |
| 189 // doesn't allow for this to be an option when we're receiving the pairing | |
| 190 // request anyway. | |
| 191 device->CancelPairing(); | |
| 192 } | |
| 193 | |
| 194 void BluetoothNotificationController::DisplayPinCode( | |
| 195 BluetoothDevice* device, | |
| 196 const std::string& pincode) { | |
| 197 base::string16 message = l10n_util::GetStringFUTF16( | |
| 198 IDS_ASH_STATUS_TRAY_BLUETOOTH_DISPLAY_PINCODE, | |
| 199 device->GetNameForDisplay(), base::UTF8ToUTF16(pincode)); | |
| 200 | |
| 201 NotifyPairing(device, message, false); | |
| 202 } | |
| 203 | |
| 204 void BluetoothNotificationController::DisplayPasskey(BluetoothDevice* device, | |
| 205 uint32_t passkey) { | |
| 206 base::string16 message = l10n_util::GetStringFUTF16( | |
| 207 IDS_ASH_STATUS_TRAY_BLUETOOTH_DISPLAY_PASSKEY, | |
| 208 device->GetNameForDisplay(), | |
| 209 base::UTF8ToUTF16(base::StringPrintf("%06i", passkey))); | |
| 210 | |
| 211 NotifyPairing(device, message, false); | |
| 212 } | |
| 213 | |
| 214 void BluetoothNotificationController::KeysEntered(BluetoothDevice* device, | |
| 215 uint32_t entered) { | |
| 216 // Ignored since we don't have CSS in the notification to update. | |
| 217 } | |
| 218 | |
| 219 void BluetoothNotificationController::ConfirmPasskey(BluetoothDevice* device, | |
| 220 uint32_t passkey) { | |
| 221 base::string16 message = l10n_util::GetStringFUTF16( | |
| 222 IDS_ASH_STATUS_TRAY_BLUETOOTH_CONFIRM_PASSKEY, | |
| 223 device->GetNameForDisplay(), | |
| 224 base::UTF8ToUTF16(base::StringPrintf("%06i", passkey))); | |
| 225 | |
| 226 NotifyPairing(device, message, true); | |
| 227 } | |
| 228 | |
| 229 void BluetoothNotificationController::AuthorizePairing( | |
| 230 BluetoothDevice* device) { | |
| 231 base::string16 message = l10n_util::GetStringFUTF16( | |
| 232 IDS_ASH_STATUS_TRAY_BLUETOOTH_AUTHORIZE_PAIRING, | |
| 233 device->GetNameForDisplay()); | |
| 234 | |
| 235 NotifyPairing(device, message, true); | |
| 236 } | |
| 237 | |
| 238 void BluetoothNotificationController::OnGetAdapter( | |
| 239 scoped_refptr<BluetoothAdapter> adapter) { | |
| 240 DCHECK(!adapter_.get()); | |
| 241 adapter_ = adapter; | |
| 242 adapter_->AddObserver(this); | |
| 243 adapter_->AddPairingDelegate(this, | |
| 244 BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW); | |
| 245 | |
| 246 // Notify a user if the adapter is already in the discoverable state. | |
| 247 if (adapter_->IsDiscoverable()) | |
| 248 NotifyAdapterDiscoverable(); | |
| 249 | |
| 250 // Build a list of the currently paired devices; these don't receive | |
| 251 // notifications since it's assumed they were previously notified. | |
| 252 BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); | |
| 253 for (BluetoothAdapter::DeviceList::const_iterator iter = devices.begin(); | |
| 254 iter != devices.end(); ++iter) { | |
| 255 const BluetoothDevice* device = *iter; | |
| 256 if (device->IsPaired()) | |
| 257 paired_devices_.insert(device->GetAddress()); | |
| 258 } | |
| 259 } | |
| 260 | |
| 261 void BluetoothNotificationController::NotifyAdapterDiscoverable() { | |
| 262 message_center::RichNotificationData optional; | |
| 263 | |
| 264 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); | |
| 265 | |
| 266 std::unique_ptr<Notification> notification(new Notification( | |
| 267 message_center::NOTIFICATION_TYPE_SIMPLE, | |
| 268 kBluetoothDeviceDiscoverableNotificationId, base::string16() /* title */, | |
| 269 l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_BLUETOOTH_DISCOVERABLE, | |
| 270 base::UTF8ToUTF16(adapter_->GetName()), | |
| 271 base::UTF8ToUTF16(adapter_->GetAddress())), | |
| 272 bundle.GetImageNamed(IDR_AURA_NOTIFICATION_BLUETOOTH), | |
| 273 base::string16() /* display source */, GURL(), | |
| 274 message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, | |
| 275 system_notifier::kNotifierBluetooth), | |
| 276 optional, NULL)); | |
| 277 message_center::MessageCenter::Get()->AddNotification( | |
| 278 std::move(notification)); | |
| 279 } | |
| 280 | |
| 281 void BluetoothNotificationController::NotifyPairing( | |
| 282 BluetoothDevice* device, | |
| 283 const base::string16& message, | |
| 284 bool with_buttons) { | |
| 285 message_center::RichNotificationData optional; | |
| 286 if (with_buttons) { | |
| 287 optional.buttons.push_back(message_center::ButtonInfo( | |
| 288 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BLUETOOTH_ACCEPT))); | |
| 289 optional.buttons.push_back(message_center::ButtonInfo( | |
| 290 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BLUETOOTH_REJECT))); | |
| 291 } | |
| 292 | |
| 293 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); | |
| 294 | |
| 295 std::unique_ptr<Notification> notification(new Notification( | |
| 296 message_center::NOTIFICATION_TYPE_SIMPLE, | |
| 297 kBluetoothDevicePairingNotificationId, base::string16() /* title */, | |
| 298 message, bundle.GetImageNamed(IDR_AURA_NOTIFICATION_BLUETOOTH), | |
| 299 base::string16() /* display source */, GURL(), | |
| 300 message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, | |
| 301 system_notifier::kNotifierBluetooth), | |
| 302 optional, new BluetoothPairingNotificationDelegate( | |
| 303 adapter_, device->GetAddress()))); | |
| 304 message_center::MessageCenter::Get()->AddNotification( | |
| 305 std::move(notification)); | |
| 306 } | |
| 307 | |
| 308 void BluetoothNotificationController::NotifyPairedDevice( | |
| 309 BluetoothDevice* device) { | |
| 310 // Remove the currently presented pairing notification; since only one | |
| 311 // pairing request is queued at a time, this is guaranteed to be the device | |
| 312 // that just became paired. | |
| 313 message_center::MessageCenter::Get()->RemoveNotification( | |
| 314 kBluetoothDevicePairingNotificationId, false /* by_user */); | |
| 315 | |
| 316 message_center::RichNotificationData optional; | |
| 317 | |
| 318 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); | |
| 319 | |
| 320 std::unique_ptr<Notification> notification(new Notification( | |
| 321 message_center::NOTIFICATION_TYPE_SIMPLE, | |
| 322 kBluetoothDevicePairedNotificationId, base::string16() /* title */, | |
| 323 l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_BLUETOOTH_PAIRED, | |
| 324 device->GetNameForDisplay()), | |
| 325 bundle.GetImageNamed(IDR_AURA_NOTIFICATION_BLUETOOTH), | |
| 326 base::string16() /* display source */, GURL(), | |
| 327 message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, | |
| 328 system_notifier::kNotifierBluetooth), | |
| 329 optional, NULL)); | |
| 330 message_center::MessageCenter::Get()->AddNotification( | |
| 331 std::move(notification)); | |
| 332 } | |
| 333 | |
| 334 } // namespace ash | |
| OLD | NEW |