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

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: Fix a silly mistake in commit e4725886 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 base::Closure& 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();
56 }
57
58 void BluetoothRemoteGattCharacteristic::NotifySessionCommand::Cancel() {
59 cancel_callback_.Run();
60 }
61
62 void BluetoothRemoteGattCharacteristic::StartNotifySession(
63 const NotifySessionCallback& callback,
64 const ErrorCallback& error_callback) {
65 NotifySessionCommand* command = new NotifySessionCommand(
66 base::Bind(&BluetoothRemoteGattCharacteristic::ExecuteStartNotifySession,
67 base::Unretained(this), callback, error_callback),
ortuno 2016/08/09 21:57:56 Unretained always raises some alarms. Either add a
tommyt 2016/08/10 12:07:18 I've replaced all instances of base::Unretained(th
68 base::Bind(&BluetoothRemoteGattCharacteristic::CancelStartNotifySession,
69 base::Unretained(this),
70 base::Bind(error_callback,
71 BluetoothRemoteGattService::GATT_ERROR_FAILED)));
72
73 pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command));
74 if (pending_notify_commands_.size() == 1) {
75 command->Execute();
76 }
77 }
78
79 void BluetoothRemoteGattCharacteristic::ExecuteStartNotifySession(
80 NotifySessionCallback callback,
81 ErrorCallback error_callback) {
82 // If the command that was resolved immediately before this command was run,
83 // this command should be resolved with the same result.
84 if (previous_command_type_ == NotifySessionCommand::COMMAND_START) {
85 if (previous_command_result_ == NotifySessionCommand::RESULT_SUCCESS) {
86 base::ThreadTaskRunnerHandle::Get()->PostTask(
87 FROM_HERE,
88 base::Bind(
89 &BluetoothRemoteGattCharacteristic::StartNotifySessionSuccess,
90 base::Unretained(this), callback));
91 return;
92 } else {
93 base::ThreadTaskRunnerHandle::Get()->PostTask(
94 FROM_HERE,
95 base::Bind(
96 &BluetoothRemoteGattCharacteristic::StartNotifySessionError,
97 base::Unretained(this), error_callback,
98 previous_command_error_code_));
99 return;
100 }
101 }
102
103 Properties properties = GetProperties();
ortuno 2016/08/09 21:57:56 optional nit: Would it make sense to put all this
tommyt 2016/08/10 12:07:18 Personally, I only think there is an advantage to
104
105 bool hasNotify = (properties & PROPERTY_NOTIFY) != 0;
106 bool hasIndicate = (properties & PROPERTY_INDICATE) != 0;
107
108 if (!hasNotify && !hasIndicate) {
109 LOG(ERROR) << "Characteristic needs NOTIFY or INDICATE";
110 base::ThreadTaskRunnerHandle::Get()->PostTask(
111 FROM_HERE,
112 base::Bind(&BluetoothRemoteGattCharacteristic::StartNotifySessionError,
113 base::Unretained(this), error_callback,
114 BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED));
115 return;
116 }
117
118 if (IsNotifying()) {
119 base::ThreadTaskRunnerHandle::Get()->PostTask(
120 FROM_HERE,
121 base::Bind(
122 &BluetoothRemoteGattCharacteristic::StartNotifySessionSuccess,
123 base::Unretained(this), callback));
124 return;
125 }
126
127 #if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) || \
ortuno 2016/08/09 21:57:56 Could you add a TODO explaining what needs to be d
tommyt 2016/08/10 12:07:18 Done
128 defined(OS_WIN)
129 base::ThreadTaskRunnerHandle::Get()->PostTask(
130 FROM_HERE,
131 base::Bind(&BluetoothRemoteGattCharacteristic::StartNotifySessionError,
132 base::Unretained(this), error_callback,
133 BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED));
134 #else
ortuno 2016/08/09 21:57:56 nit: // !(defined(OS_CHROMEOS) && defined(OS_LINU
tommyt 2016/08/10 12:07:19 Done
135 std::vector<BluetoothRemoteGattDescriptor*> ccc_descriptor =
136 GetDescriptorsByUUID(BluetoothRemoteGattDescriptor::
137 ClientCharacteristicConfigurationUuid());
138
139 if (ccc_descriptor.size() != 1u) {
140 LOG(ERROR) << "Found " << ccc_descriptor.size()
141 << " client characteristic configuration descriptors.";
142 base::ThreadTaskRunnerHandle::Get()->PostTask(
143 FROM_HERE,
144 base::Bind(&BluetoothRemoteGattCharacteristic::StartNotifySessionError,
145 base::Unretained(this), error_callback,
146 (ccc_descriptor.size() == 0)
147 ? BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED
148 : BluetoothRemoteGattService::GATT_ERROR_FAILED));
149 return;
150 }
151
152 SubscribeToNotifications(
153 ccc_descriptor[0],
154 base::Bind(&BluetoothRemoteGattCharacteristic::StartNotifySessionSuccess,
155 base::Unretained(this), callback),
156 base::Bind(&BluetoothRemoteGattCharacteristic::StartNotifySessionError,
157 base::Unretained(this), error_callback));
158 #endif
ortuno 2016/08/09 21:57:56 nit: // defined(OS_CHROMEOS) || defined(OS_LINUX)
tommyt 2016/08/10 12:07:19 Done
159 }
160
161 void BluetoothRemoteGattCharacteristic::CancelStartNotifySession(
162 base::Closure callback) {
163 std::unique_ptr<NotifySessionCommand> command =
164 std::move(pending_notify_commands_.front());
165 pending_notify_commands_.pop();
166 previous_command_type_ = NotifySessionCommand::COMMAND_NONE;
167 callback.Run();
168 }
169
170 void BluetoothRemoteGattCharacteristic::StartNotifySessionSuccess(
171 NotifySessionCallback callback) {
172 std::unique_ptr<NotifySessionCommand> command =
173 std::move(pending_notify_commands_.front());
174
175 std::unique_ptr<device::BluetoothGattNotifySession> notify_session(
176 new BluetoothGattNotifySession(weak_ptr_factory_.GetWeakPtr()));
177 notify_sessions_.insert(notify_session.get());
178 callback.Run(std::move(notify_session));
179
180 pending_notify_commands_.pop();
181 if (!pending_notify_commands_.empty()) {
182 previous_command_type_ = NotifySessionCommand::COMMAND_START;
183 previous_command_result_ = NotifySessionCommand::RESULT_SUCCESS;
184 pending_notify_commands_.front()->Execute();
185 } else {
186 previous_command_type_ = NotifySessionCommand::COMMAND_NONE;
187 }
188 }
189
190 void BluetoothRemoteGattCharacteristic::StartNotifySessionError(
191 ErrorCallback error_callback,
192 BluetoothRemoteGattService::GattErrorCode error) {
193 std::unique_ptr<NotifySessionCommand> command =
194 std::move(pending_notify_commands_.front());
195
196 error_callback.Run(error);
197
198 pending_notify_commands_.pop();
199 if (!pending_notify_commands_.empty()) {
200 previous_command_type_ = NotifySessionCommand::COMMAND_START;
ortuno 2016/08/09 21:57:56 optional nit: Would passing these directly to Exec
tommyt 2016/08/10 12:07:18 Maybe. I've done this in my latest patchset, and I
201 previous_command_result_ = NotifySessionCommand::RESULT_ERROR;
202 previous_command_error_code_ = error;
203 pending_notify_commands_.front()->Execute();
204 } else {
205 previous_command_type_ = NotifySessionCommand::COMMAND_NONE;
206 }
207 }
208
209 void BluetoothRemoteGattCharacteristic::StopNotifySession(
210 BluetoothGattNotifySession* session,
211 const base::Closure& callback) {
212 NotifySessionCommand* command = new NotifySessionCommand(
213 base::Bind(&BluetoothRemoteGattCharacteristic::ExecuteStopNotifySession,
214 base::Unretained(this), session, callback),
215 callback);
ortuno 2016/08/09 21:57:56 nit: callback /* cancel_callback */);
tommyt 2016/08/10 12:07:18 Done.
216
217 pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command));
218 if (pending_notify_commands_.size() == 1) {
219 command->Execute();
220 }
221 }
222
223 void BluetoothRemoteGattCharacteristic::ExecuteStopNotifySession(
224 BluetoothGattNotifySession* session,
ortuno 2016/08/09 21:57:56 It makes me nervous that we are passing a pointer
tommyt 2016/08/10 12:07:18 This session pointer is not dereferenced anywhere,
225 base::Closure callback) {
226 std::set<BluetoothGattNotifySession*>::iterator session_iterator =
227 notify_sessions_.find(session);
228
229 // If the session does not even belong to this characteristic, we return an
230 // error right away.
231 if (session_iterator == notify_sessions_.end()) {
232 base::ThreadTaskRunnerHandle::Get()->PostTask(
233 FROM_HERE,
234 base::Bind(&BluetoothRemoteGattCharacteristic::StopNotifySessionError,
235 base::Unretained(this), session, callback,
236 BluetoothRemoteGattService::GATT_ERROR_FAILED));
237 return;
238 }
239
240 // If there are more active sessions, then we return right away.
241 if (notify_sessions_.size() > 1) {
242 base::ThreadTaskRunnerHandle::Get()->PostTask(
243 FROM_HERE,
244 base::Bind(&BluetoothRemoteGattCharacteristic::StopNotifySessionSuccess,
245 base::Unretained(this), session, callback));
246 return;
247 }
248
249 std::vector<BluetoothRemoteGattDescriptor*> ccc_descriptor =
ortuno 2016/08/09 21:57:56 Do you need an "#if defined..." here?
tommyt 2016/08/10 12:07:19 Done.
250 GetDescriptorsByUUID(BluetoothRemoteGattDescriptor::
251 ClientCharacteristicConfigurationUuid());
252
253 if (ccc_descriptor.size() != 1u) {
254 LOG(ERROR) << "Found " << ccc_descriptor.size()
255 << " client characteristic configuration descriptors.";
256 base::ThreadTaskRunnerHandle::Get()->PostTask(
257 FROM_HERE,
258 base::Bind(&BluetoothRemoteGattCharacteristic::StopNotifySessionError,
259 base::Unretained(this), session, callback,
260 BluetoothRemoteGattService::GATT_ERROR_FAILED));
261 return;
262 }
263
264 UnsubscribeFromNotifications(
265 ccc_descriptor[0],
266 base::Bind(&BluetoothRemoteGattCharacteristic::StopNotifySessionSuccess,
267 base::Unretained(this), session, callback),
268 base::Bind(&BluetoothRemoteGattCharacteristic::StopNotifySessionError,
269 base::Unretained(this), session, callback));
270 }
271
272 void BluetoothRemoteGattCharacteristic::CancelStopNotifySession(
273 base::Closure callback) {
274 std::unique_ptr<NotifySessionCommand> command =
275 std::move(pending_notify_commands_.front());
276 pending_notify_commands_.pop();
277 previous_command_type_ = NotifySessionCommand::COMMAND_NONE;
278 callback.Run();
279 }
280
281 void BluetoothRemoteGattCharacteristic::StopNotifySessionSuccess(
282 BluetoothGattNotifySession* session,
283 base::Closure callback) {
284 std::unique_ptr<NotifySessionCommand> command =
285 std::move(pending_notify_commands_.front());
286
287 notify_sessions_.erase(session);
288
289 callback.Run();
290
291 pending_notify_commands_.pop();
292 if (!pending_notify_commands_.empty()) {
293 previous_command_type_ = NotifySessionCommand::COMMAND_STOP;
294 previous_command_result_ = NotifySessionCommand::RESULT_SUCCESS;
295 pending_notify_commands_.front()->Execute();
296 } else {
297 previous_command_type_ = NotifySessionCommand::COMMAND_NONE;
298 }
299 }
300
301 void BluetoothRemoteGattCharacteristic::StopNotifySessionError(
302 BluetoothGattNotifySession* session,
303 base::Closure callback,
304 BluetoothRemoteGattService::GattErrorCode error) {
305 std::unique_ptr<NotifySessionCommand> command =
306 std::move(pending_notify_commands_.front());
307
308 notify_sessions_.erase(session);
309
310 callback.Run();
311
312 pending_notify_commands_.pop();
313 if (!pending_notify_commands_.empty()) {
314 previous_command_type_ = NotifySessionCommand::COMMAND_STOP;
315 previous_command_result_ = NotifySessionCommand::RESULT_ERROR;
316 previous_command_error_code_ = error;
317 pending_notify_commands_.front()->Execute();
318 } else {
319 previous_command_type_ = NotifySessionCommand::COMMAND_NONE;
320 }
321 }
322
27 } // namespace device 323 } // namespace device
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698