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