OLD | NEW |
---|---|
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 void BluetoothRemoteGattCharacteristic::StartNotifySession( | |
47 const NotifySessionCallback& callback, | |
48 const ErrorCallback& error_callback) { | |
49 NotifySessionCommand* command = | |
50 new NotifySessionCommandStart(this, callback, error_callback); | |
51 pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command)); | |
52 if (pending_notify_commands_.size() == 1) { | |
53 command->Execute(); | |
54 } | |
55 } | |
56 | |
57 BluetoothRemoteGattCharacteristic::NotifySessionCommand::NotifySessionCommand( | |
58 BluetoothRemoteGattCharacteristic* characteristic, | |
59 Type type) | |
60 : characteristic_(characteristic), type_(type) {} | |
61 | |
62 BluetoothRemoteGattCharacteristic::NotifySessionCommand:: | |
63 ~NotifySessionCommand() {} | |
64 | |
65 BluetoothRemoteGattCharacteristic::NotifySessionCommandStart:: | |
66 NotifySessionCommandStart(BluetoothRemoteGattCharacteristic* characteristic, | |
67 const NotifySessionCallback& callback, | |
68 const ErrorCallback& error_callback) | |
69 : NotifySessionCommand(characteristic, COMMAND_START), | |
70 callback_(callback), | |
71 error_callback_(error_callback) {} | |
72 | |
73 BluetoothRemoteGattCharacteristic::NotifySessionCommandStart:: | |
74 ~NotifySessionCommandStart() {} | |
75 | |
76 void BluetoothRemoteGattCharacteristic::NotifySessionCommandStart::Execute() { | |
77 Properties properties = characteristic_->GetProperties(); | |
78 | |
79 bool hasNotify = (properties & PROPERTY_NOTIFY) != 0; | |
80 bool hasIndicate = (properties & PROPERTY_INDICATE) != 0; | |
81 | |
82 if (!hasNotify && !hasIndicate) { | |
83 LOG(ERROR) << "Characteristic needs NOTIFY or INDICATE"; | |
84 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
85 FROM_HERE, | |
86 base::Bind(&BluetoothRemoteGattCharacteristic:: | |
87 NotifySessionCommandStart::OnError, | |
88 base::Unretained(this), | |
89 BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED)); | |
90 return; | |
91 } | |
92 | |
93 if (characteristic_->IsNotifying()) { | |
94 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
95 FROM_HERE, base::Bind(&BluetoothRemoteGattCharacteristic:: | |
96 NotifySessionCommandStart::OnSuccess, | |
97 base::Unretained(this))); | |
98 return; | |
99 } | |
100 | |
101 std::vector<BluetoothRemoteGattDescriptor*> ccc_descriptor = | |
ortuno
2016/08/02 01:56:32
Can you surround this with a #if !(defined(OS_CHRO
tommyt
2016/08/05 12:22:28
Done.
| |
102 characteristic_->GetDescriptorsByUUID( | |
103 BluetoothRemoteGattDescriptor:: | |
104 ClientCharacteristicConfigurationUuid()); | |
105 | |
106 if (ccc_descriptor.size() != 1u) { | |
107 LOG(ERROR) << "Found " << ccc_descriptor.size() | |
108 << " client characteristic configuration descriptors."; | |
109 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
110 FROM_HERE, | |
111 base::Bind(&BluetoothRemoteGattCharacteristic:: | |
112 NotifySessionCommandStart::OnError, | |
113 base::Unretained(this), | |
114 (ccc_descriptor.size() == 0) | |
115 ? BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED | |
116 : BluetoothRemoteGattService::GATT_ERROR_FAILED)); | |
117 return; | |
118 } | |
119 | |
120 characteristic_->SubscribeToNotifications( | |
121 ccc_descriptor[0], base::Bind(&BluetoothRemoteGattCharacteristic:: | |
122 NotifySessionCommandStart::OnSuccess, | |
123 base::Unretained(this)), | |
124 base::Bind(&BluetoothRemoteGattCharacteristic::NotifySessionCommandStart:: | |
125 OnError, | |
126 base::Unretained(this))); | |
127 } | |
128 | |
129 void BluetoothRemoteGattCharacteristic::NotifySessionCommandStart::Cancel() { | |
130 std::unique_ptr<NotifySessionCommand> command = | |
131 std::move(characteristic_->pending_notify_commands_.front()); | |
132 DCHECK_EQ(command.get(), this); | |
133 characteristic_->pending_notify_commands_.pop(); | |
134 error_callback_.Run(BluetoothRemoteGattService::GATT_ERROR_FAILED); | |
135 } | |
136 | |
137 void BluetoothRemoteGattCharacteristic::NotifySessionCommandStart::OnSuccess() { | |
138 std::unique_ptr<NotifySessionCommand> command = | |
139 std::move(characteristic_->pending_notify_commands_.front()); | |
140 DCHECK_EQ(command.get(), this); | |
141 characteristic_->pending_notify_commands_.pop(); | |
142 | |
143 std::unique_ptr<device::BluetoothGattNotifySession> notify_session( | |
144 new BluetoothGattNotifySession( | |
145 characteristic_->weak_ptr_factory_.GetWeakPtr())); | |
146 characteristic_->notify_sessions_.insert(notify_session.get()); | |
147 callback_.Run(std::move(notify_session)); | |
148 | |
149 if (!characteristic_->pending_notify_commands_.empty()) { | |
150 NotifySessionCommand* next = | |
151 characteristic_->pending_notify_commands_.front().get(); | |
152 if (next->type_ == COMMAND_START) { | |
153 characteristic_->pending_notify_commands_.front()->OnSuccess(); | |
154 } else { | |
155 characteristic_->pending_notify_commands_.front()->Execute(); | |
156 } | |
157 } | |
158 } | |
159 | |
160 void BluetoothRemoteGattCharacteristic::NotifySessionCommandStart::OnError( | |
161 BluetoothRemoteGattService::GattErrorCode error) { | |
162 std::unique_ptr<NotifySessionCommand> command = | |
163 std::move(characteristic_->pending_notify_commands_.front()); | |
164 DCHECK_EQ(command.get(), this); | |
165 characteristic_->pending_notify_commands_.pop(); | |
166 | |
167 error_callback_.Run(error); | |
168 | |
169 if (!characteristic_->pending_notify_commands_.empty()) { | |
170 NotifySessionCommand* next = | |
171 characteristic_->pending_notify_commands_.front().get(); | |
172 if (next->type_ == COMMAND_START) { | |
173 characteristic_->pending_notify_commands_.front()->OnError(error); | |
174 } else { | |
175 characteristic_->pending_notify_commands_.front()->Execute(); | |
176 } | |
177 } | |
178 } | |
179 | |
180 void BluetoothRemoteGattCharacteristic::StopNotifySession( | |
181 BluetoothGattNotifySession* session, | |
182 const base::Closure& callback) { | |
183 NotifySessionCommand* command = | |
184 new NotifySessionCommandStop(this, session, callback); | |
185 pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command)); | |
186 if (pending_notify_commands_.size() == 1) { | |
187 command->Execute(); | |
188 } | |
189 } | |
190 | |
191 BluetoothRemoteGattCharacteristic::NotifySessionCommandStop:: | |
192 NotifySessionCommandStop(BluetoothRemoteGattCharacteristic* characteristic, | |
193 BluetoothGattNotifySession* session, | |
194 const base::Closure& callback) | |
195 : NotifySessionCommand(characteristic, COMMAND_STOP), | |
196 session_(session), | |
197 callback_(callback) {} | |
198 | |
199 BluetoothRemoteGattCharacteristic::NotifySessionCommandStop:: | |
200 ~NotifySessionCommandStop() {} | |
201 | |
202 void BluetoothRemoteGattCharacteristic::NotifySessionCommandStop::Execute() { | |
203 std::set<BluetoothGattNotifySession*>::iterator session_iterator = | |
204 characteristic_->notify_sessions_.find(session_); | |
205 | |
206 // If the session does not even belong to this characteristic, we return an | |
207 // error right away. | |
208 if (session_iterator == characteristic_->notify_sessions_.end()) { | |
209 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
210 FROM_HERE, | |
211 base::Bind(&BluetoothRemoteGattCharacteristic:: | |
212 NotifySessionCommandStop::OnError, | |
213 base::Unretained(this), | |
214 device::BluetoothRemoteGattService::GATT_ERROR_FAILED)); | |
215 return; | |
216 } | |
217 | |
218 characteristic_->notify_sessions_.erase(session_); | |
219 | |
220 // If there are more active sessions, then we return right away. | |
221 if (characteristic_->notify_sessions_.size() > 0) { | |
222 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
223 FROM_HERE, base::Bind(&BluetoothRemoteGattCharacteristic:: | |
224 NotifySessionCommandStop::OnSuccess, | |
225 base::Unretained(this))); | |
226 return; | |
227 } | |
228 | |
229 std::vector<BluetoothRemoteGattDescriptor*> ccc_descriptor = | |
230 characteristic_->GetDescriptorsByUUID( | |
231 BluetoothRemoteGattDescriptor:: | |
232 ClientCharacteristicConfigurationUuid()); | |
233 | |
234 if (ccc_descriptor.size() != 1u) { | |
235 LOG(ERROR) << "Found " << ccc_descriptor.size() | |
236 << " client characteristic configuration descriptors."; | |
237 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
238 FROM_HERE, | |
239 base::Bind(&BluetoothRemoteGattCharacteristic:: | |
240 NotifySessionCommandStop::OnError, | |
241 base::Unretained(this), | |
242 device::BluetoothRemoteGattService::GATT_ERROR_FAILED)); | |
243 return; | |
244 } | |
245 | |
246 characteristic_->UnsubscribeFromNotifications( | |
247 ccc_descriptor[0], base::Bind(&BluetoothRemoteGattCharacteristic:: | |
248 NotifySessionCommandStop::OnSuccess, | |
249 base::Unretained(this)), | |
250 base::Bind( | |
251 &BluetoothRemoteGattCharacteristic::NotifySessionCommandStop::OnError, | |
252 base::Unretained(this))); | |
253 } | |
254 | |
255 void BluetoothRemoteGattCharacteristic::NotifySessionCommandStop::Cancel() { | |
256 std::unique_ptr<NotifySessionCommand> command = | |
257 std::move(characteristic_->pending_notify_commands_.front()); | |
258 DCHECK_EQ(command.get(), this); | |
259 characteristic_->pending_notify_commands_.pop(); | |
260 callback_.Run(); | |
261 } | |
262 | |
263 void BluetoothRemoteGattCharacteristic::NotifySessionCommandStop::OnSuccess() { | |
264 std::unique_ptr<NotifySessionCommand> command = | |
265 std::move(characteristic_->pending_notify_commands_.front()); | |
266 DCHECK_EQ(command.get(), this); | |
267 characteristic_->pending_notify_commands_.pop(); | |
268 | |
269 callback_.Run(); | |
270 | |
271 if (!characteristic_->pending_notify_commands_.empty()) { | |
272 characteristic_->pending_notify_commands_.front()->Execute(); | |
273 } | |
274 } | |
275 | |
276 void BluetoothRemoteGattCharacteristic::NotifySessionCommandStop::OnError( | |
277 BluetoothRemoteGattService::GattErrorCode error) { | |
278 std::unique_ptr<NotifySessionCommand> command = | |
279 std::move(characteristic_->pending_notify_commands_.front()); | |
280 DCHECK_EQ(command.get(), this); | |
281 characteristic_->pending_notify_commands_.pop(); | |
282 | |
283 callback_.Run(); | |
284 | |
285 if (!characteristic_->pending_notify_commands_.empty()) { | |
286 characteristic_->pending_notify_commands_.front()->Execute(); | |
287 } | |
288 } | |
289 | |
27 } // namespace device | 290 } // namespace device |
OLD | NEW |