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

Side by Side Diff: device/bluetooth/bluetooth_remote_gatt_characteristic.cc

Issue 2051333004: Implement BluetoothGattNotifySession::Stop on Android, 2nd attempt (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address new review comments Created 4 years, 4 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 unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h" 5 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
6 6
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/threading/thread_task_runner_handle.h"
11 #include "device/bluetooth/bluetooth_gatt_notify_session.h"
7 #include "device/bluetooth/bluetooth_remote_gatt_descriptor.h" 12 #include "device/bluetooth/bluetooth_remote_gatt_descriptor.h"
8 13
9 namespace device { 14 namespace device {
10 15
11 BluetoothRemoteGattCharacteristic::BluetoothRemoteGattCharacteristic() {} 16 BluetoothRemoteGattCharacteristic::BluetoothRemoteGattCharacteristic()
17 : weak_ptr_factory_(this) {}
12 18
13 BluetoothRemoteGattCharacteristic::~BluetoothRemoteGattCharacteristic() {} 19 BluetoothRemoteGattCharacteristic::~BluetoothRemoteGattCharacteristic() {
20 while (!pending_notify_commands_.empty()) {
21 pending_notify_commands_.front()->Cancel();
22 }
23 }
14 24
15 std::vector<BluetoothRemoteGattDescriptor*> 25 std::vector<BluetoothRemoteGattDescriptor*>
16 BluetoothRemoteGattCharacteristic::GetDescriptorsByUUID( 26 BluetoothRemoteGattCharacteristic::GetDescriptorsByUUID(
17 const BluetoothUUID& uuid) { 27 const BluetoothUUID& uuid) const {
18 std::vector<BluetoothRemoteGattDescriptor*> descriptors; 28 std::vector<BluetoothRemoteGattDescriptor*> descriptors;
19 for (BluetoothRemoteGattDescriptor* descriptor : GetDescriptors()) { 29 for (BluetoothRemoteGattDescriptor* descriptor : GetDescriptors()) {
20 if (descriptor->GetUUID() == uuid) { 30 if (descriptor->GetUUID() == uuid) {
21 descriptors.push_back(descriptor); 31 descriptors.push_back(descriptor);
22 } 32 }
23 } 33 }
24 return descriptors; 34 return descriptors;
25 } 35 }
26 36
37 base::WeakPtr<device::BluetoothRemoteGattCharacteristic>
38 BluetoothRemoteGattCharacteristic::GetWeakPtr() {
39 return weak_ptr_factory_.GetWeakPtr();
40 }
41
42 bool BluetoothRemoteGattCharacteristic::IsNotifying() const {
43 return !notify_sessions_.empty();
44 }
45
46 BluetoothRemoteGattCharacteristic::NotifySessionCommand::NotifySessionCommand(
47 const ExecuteCallback& execute_callback,
48 const base::Closure& cancel_callback)
49 : execute_callback_(execute_callback), cancel_callback_(cancel_callback) {}
50
51 BluetoothRemoteGattCharacteristic::NotifySessionCommand::
52 ~NotifySessionCommand() {}
53
54 void BluetoothRemoteGattCharacteristic::NotifySessionCommand::Execute() {
55 execute_callback_.Run(COMMAND_NONE, RESULT_SUCCESS,
56 BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
57 }
58
59 void BluetoothRemoteGattCharacteristic::NotifySessionCommand::Execute(
60 Type previous_command_type,
61 Result previous_command_result,
62 BluetoothRemoteGattService::GattErrorCode previous_command_error_code) {
63 execute_callback_.Run(previous_command_type, previous_command_result,
64 previous_command_error_code);
65 }
66
67 void BluetoothRemoteGattCharacteristic::NotifySessionCommand::Cancel() {
68 cancel_callback_.Run();
69 }
70
71 void BluetoothRemoteGattCharacteristic::StartNotifySession(
72 const NotifySessionCallback& callback,
73 const ErrorCallback& error_callback) {
74 NotifySessionCommand* command = new NotifySessionCommand(
75 base::Bind(&BluetoothRemoteGattCharacteristic::ExecuteStartNotifySession,
76 GetWeakPtr(), callback, error_callback),
77 base::Bind(&BluetoothRemoteGattCharacteristic::CancelStartNotifySession,
78 GetWeakPtr(),
79 base::Bind(error_callback,
80 BluetoothRemoteGattService::GATT_ERROR_FAILED)));
81
82 pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command));
83 if (pending_notify_commands_.size() == 1) {
84 command->Execute();
85 }
86 }
87
88 void BluetoothRemoteGattCharacteristic::ExecuteStartNotifySession(
89 NotifySessionCallback callback,
90 ErrorCallback error_callback,
91 NotifySessionCommand::Type previous_command_type,
92 NotifySessionCommand::Result previous_command_result,
93 BluetoothRemoteGattService::GattErrorCode previous_command_error_code) {
94 // If the command that was resolved immediately before this command was run,
95 // this command should be resolved with the same result.
96 if (previous_command_type == NotifySessionCommand::COMMAND_START) {
97 if (previous_command_result == NotifySessionCommand::RESULT_SUCCESS) {
98 base::ThreadTaskRunnerHandle::Get()->PostTask(
99 FROM_HERE,
100 base::Bind(
101 &BluetoothRemoteGattCharacteristic::OnStartNotifySessionSuccess,
102 GetWeakPtr(), callback));
103 return;
104 } else {
105 base::ThreadTaskRunnerHandle::Get()->PostTask(
106 FROM_HERE,
107 base::Bind(
108 &BluetoothRemoteGattCharacteristic::OnStartNotifySessionError,
109 GetWeakPtr(), error_callback, previous_command_error_code));
110 return;
111 }
112 }
113
114 // Check that the characteristic supports either notifications or
115 // indications.
116 Properties properties = GetProperties();
117 bool hasNotify = (properties & PROPERTY_NOTIFY) != 0;
118 bool hasIndicate = (properties & PROPERTY_INDICATE) != 0;
119
120 if (!hasNotify && !hasIndicate) {
121 LOG(ERROR) << "Characteristic needs NOTIFY or INDICATE";
122 base::ThreadTaskRunnerHandle::Get()->PostTask(
123 FROM_HERE,
124 base::Bind(
125 &BluetoothRemoteGattCharacteristic::OnStartNotifySessionError,
126 GetWeakPtr(), error_callback,
127 BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED));
128 return;
129 }
130
131 // If the characteristic is already notifying, then we don't need to
132 // subscribe again. All we need to do is call the success callback, which
133 // will create and return a session object to the caller.
134 if (IsNotifying()) {
135 base::ThreadTaskRunnerHandle::Get()->PostTask(
136 FROM_HERE,
137 base::Bind(
138 &BluetoothRemoteGattCharacteristic::OnStartNotifySessionSuccess,
139 GetWeakPtr(), callback));
140 return;
141 }
142
143 // After we migrate each platform to the new way of starting and stopping
144 // notifications, we can remove them from this #if check. The goal is to get
145 // rid of the entire check, and run SubscribeToNotifications on all
146 // platforms.
147 //
148 // TODO(http://crbug.com/633191): Remove OS_MACOSX from this check.
149 // TODO(http://crbug.com/636270): Remove OS_WIN from this check.
150 // TODO(http://crbug.com/636275): Remove OS_CHROMEOS and OS_LINUX from this
151 // check.
152 #if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) || \
153 defined(OS_WIN)
154 base::ThreadTaskRunnerHandle::Get()->PostTask(
155 FROM_HERE,
156 base::Bind(&BluetoothRemoteGattCharacteristic::OnStartNotifySessionError,
157 GetWeakPtr(), error_callback,
158 BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED));
159 #else // !(defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) ||
160 // defined(OS_WIN))
161 // Find the Client Characteristic Configuration descriptor.
162 std::vector<BluetoothRemoteGattDescriptor*> ccc_descriptor =
163 GetDescriptorsByUUID(BluetoothRemoteGattDescriptor::
164 ClientCharacteristicConfigurationUuid());
165
166 if (ccc_descriptor.size() != 1u) {
167 LOG(ERROR) << "Found " << ccc_descriptor.size()
168 << " client characteristic configuration descriptors.";
169 base::ThreadTaskRunnerHandle::Get()->PostTask(
170 FROM_HERE,
171 base::Bind(
172 &BluetoothRemoteGattCharacteristic::OnStartNotifySessionError,
173 GetWeakPtr(), error_callback,
174 (ccc_descriptor.size() == 0)
175 ? BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED
176 : BluetoothRemoteGattService::GATT_ERROR_FAILED));
177 return;
178 }
179
180 // Pass the Client Characteristic Configuration descriptor to
181 // SubscribetoNotifications, which will write the correct value to it, and
182 // do whatever else is needed to get the notifications flowing.
183 SubscribeToNotifications(
184 ccc_descriptor[0],
185 base::Bind(
186 &BluetoothRemoteGattCharacteristic::OnStartNotifySessionSuccess,
187 GetWeakPtr(), callback),
188 base::Bind(&BluetoothRemoteGattCharacteristic::OnStartNotifySessionError,
189 GetWeakPtr(), error_callback));
190 #endif // defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) ||
191 // defined(OS_WIN)
192 }
193
194 void BluetoothRemoteGattCharacteristic::CancelStartNotifySession(
195 base::Closure callback) {
196 std::unique_ptr<NotifySessionCommand> command =
197 std::move(pending_notify_commands_.front());
198 pending_notify_commands_.pop();
199 callback.Run();
200 }
201
202 void BluetoothRemoteGattCharacteristic::OnStartNotifySessionSuccess(
203 NotifySessionCallback callback) {
204 std::unique_ptr<NotifySessionCommand> command =
205 std::move(pending_notify_commands_.front());
206
207 std::unique_ptr<device::BluetoothGattNotifySession> notify_session(
208 new BluetoothGattNotifySession(weak_ptr_factory_.GetWeakPtr()));
209 notify_sessions_.insert(notify_session.get());
210 callback.Run(std::move(notify_session));
211
212 pending_notify_commands_.pop();
213 if (!pending_notify_commands_.empty()) {
214 pending_notify_commands_.front()->Execute(
215 NotifySessionCommand::COMMAND_START,
216 NotifySessionCommand::RESULT_SUCCESS,
217 BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
218 }
219 }
220
221 void BluetoothRemoteGattCharacteristic::OnStartNotifySessionError(
222 ErrorCallback error_callback,
223 BluetoothRemoteGattService::GattErrorCode error) {
224 std::unique_ptr<NotifySessionCommand> command =
225 std::move(pending_notify_commands_.front());
226
227 error_callback.Run(error);
228
229 pending_notify_commands_.pop();
230 if (!pending_notify_commands_.empty()) {
231 pending_notify_commands_.front()->Execute(
232 NotifySessionCommand::COMMAND_START, NotifySessionCommand::RESULT_ERROR,
233 error);
234 }
235 }
236
237 void BluetoothRemoteGattCharacteristic::StopNotifySession(
238 BluetoothGattNotifySession* session,
239 const base::Closure& callback) {
240 NotifySessionCommand* command = new NotifySessionCommand(
241 base::Bind(&BluetoothRemoteGattCharacteristic::ExecuteStopNotifySession,
242 GetWeakPtr(), session, callback),
243 callback /* cancel_callback */);
244
245 pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command));
246 if (pending_notify_commands_.size() == 1) {
247 command->Execute();
248 }
249 }
250
251 void BluetoothRemoteGattCharacteristic::ExecuteStopNotifySession(
252 BluetoothGattNotifySession* session,
253 base::Closure callback,
254 NotifySessionCommand::Type previous_command_type,
255 NotifySessionCommand::Result previous_command_result,
256 BluetoothRemoteGattService::GattErrorCode previous_command_error_code) {
257 std::set<BluetoothGattNotifySession*>::iterator session_iterator =
258 notify_sessions_.find(session);
259
260 // If the session does not even belong to this characteristic, we return an
261 // error right away.
262 if (session_iterator == notify_sessions_.end()) {
263 base::ThreadTaskRunnerHandle::Get()->PostTask(
264 FROM_HERE,
265 base::Bind(&BluetoothRemoteGattCharacteristic::OnStopNotifySessionError,
266 GetWeakPtr(), session, callback,
267 BluetoothRemoteGattService::GATT_ERROR_FAILED));
268 return;
269 }
270
271 // If there are more active sessions, then we return right away.
272 if (notify_sessions_.size() > 1) {
273 base::ThreadTaskRunnerHandle::Get()->PostTask(
274 FROM_HERE,
275 base::Bind(
276 &BluetoothRemoteGattCharacteristic::OnStopNotifySessionSuccess,
277 GetWeakPtr(), session, callback));
278 return;
279 }
280
281 // After we migrate each platform to the new way of starting and stopping
282 // notifications, we can remove them from this #if check. The goal is to get
283 // rid of the entire check, and run SubscribeToNotifications on all
284 // platforms.
285 //
286 // TODO(http://crbug.com/633191): Remove OS_MACOSX from this check.
287 // TODO(http://crbug.com/636270): Remove OS_WIN from this check.
288 // TODO(http://crbug.com/636275): Remove OS_CHROMEOS and OS_LINUX from this
289 // check.
290 #if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) || \
291 defined(OS_WIN)
292 base::ThreadTaskRunnerHandle::Get()->PostTask(
293 FROM_HERE,
294 base::Bind(&BluetoothRemoteGattCharacteristic::OnStopNotifySessionError,
295 GetWeakPtr(), session, callback,
296 BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED));
297 #else // !(defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) ||
298 // defined(OS_WIN))
299 // Find the Client Characteristic Configuration descriptor.
300 std::vector<BluetoothRemoteGattDescriptor*> ccc_descriptor =
301 GetDescriptorsByUUID(BluetoothRemoteGattDescriptor::
302 ClientCharacteristicConfigurationUuid());
303
304 if (ccc_descriptor.size() != 1u) {
305 LOG(ERROR) << "Found " << ccc_descriptor.size()
306 << " client characteristic configuration descriptors.";
307 base::ThreadTaskRunnerHandle::Get()->PostTask(
308 FROM_HERE,
309 base::Bind(&BluetoothRemoteGattCharacteristic::OnStopNotifySessionError,
310 GetWeakPtr(), session, callback,
311 BluetoothRemoteGattService::GATT_ERROR_FAILED));
312 return;
313 }
314
315 UnsubscribeFromNotifications(
316 ccc_descriptor[0],
317 base::Bind(&BluetoothRemoteGattCharacteristic::OnStopNotifySessionSuccess,
318 GetWeakPtr(), session, callback),
319 base::Bind(&BluetoothRemoteGattCharacteristic::OnStopNotifySessionError,
320 GetWeakPtr(), session, callback));
321 #endif // defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) ||
322 // defined(OS_WIN)
323 }
324
325 void BluetoothRemoteGattCharacteristic::CancelStopNotifySession(
326 base::Closure callback) {
327 std::unique_ptr<NotifySessionCommand> command =
328 std::move(pending_notify_commands_.front());
329 pending_notify_commands_.pop();
330 callback.Run();
331 }
332
333 void BluetoothRemoteGattCharacteristic::OnStopNotifySessionSuccess(
334 BluetoothGattNotifySession* session,
335 base::Closure callback) {
336 std::unique_ptr<NotifySessionCommand> command =
337 std::move(pending_notify_commands_.front());
338
339 notify_sessions_.erase(session);
340
341 callback.Run();
342
343 pending_notify_commands_.pop();
344 if (!pending_notify_commands_.empty()) {
345 pending_notify_commands_.front()->Execute(
346 NotifySessionCommand::COMMAND_STOP,
347 NotifySessionCommand::RESULT_SUCCESS,
348 BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
349 }
350 }
351
352 void BluetoothRemoteGattCharacteristic::OnStopNotifySessionError(
353 BluetoothGattNotifySession* session,
354 base::Closure callback,
355 BluetoothRemoteGattService::GattErrorCode error) {
356 std::unique_ptr<NotifySessionCommand> command =
357 std::move(pending_notify_commands_.front());
358
359 notify_sessions_.erase(session);
360
361 callback.Run();
362
363 pending_notify_commands_.pop();
364 if (!pending_notify_commands_.empty()) {
365 pending_notify_commands_.front()->Execute(
366 NotifySessionCommand::COMMAND_STOP, NotifySessionCommand::RESULT_ERROR,
367 error);
368 }
369 }
370
27 } // namespace device 371 } // namespace device
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698