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( | |
ortuno
2016/07/28 21:59:30
This looks very similar to what I first wrote for
tommyt
2016/08/01 11:39:21
I really like this approach, and I agree that the
ortuno
2016/08/02 01:56:31
Hmm maybe I'm missing something, but I don't think
ortuno
2016/08/03 16:55:42
Ah I see what you mean now. You could still just s
tommyt
2016/08/08 13:55:08
Done.
| |
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) { | |
ortuno
2016/07/28 21:59:30
I think you can move this logic into SubscribeToNo
tommyt
2016/08/01 11:39:21
Actually, I'll be moving more functionality into t
ortuno
2016/08/02 01:56:31
I'm a bit hesitant to put low level concepts like
tommyt
2016/08/08 13:55:08
This has been changed a bit in the latest changese
| |
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 characteristic_->SubscribeToNotifications( | |
102 base::Bind(&BluetoothRemoteGattCharacteristic::NotifySessionCommandStart:: | |
103 OnSuccess, | |
104 base::Unretained(this)), | |
105 base::Bind(&BluetoothRemoteGattCharacteristic::NotifySessionCommandStart:: | |
106 OnError, | |
107 base::Unretained(this))); | |
108 } | |
109 | |
110 void BluetoothRemoteGattCharacteristic::NotifySessionCommandStart::Cancel() { | |
111 std::unique_ptr<NotifySessionCommand> command = | |
112 std::move(characteristic_->pending_notify_commands_.front()); | |
113 DCHECK_EQ(command.get(), this); | |
114 characteristic_->pending_notify_commands_.pop(); | |
115 error_callback_.Run(BluetoothRemoteGattService::GATT_ERROR_FAILED); | |
116 } | |
117 | |
118 void BluetoothRemoteGattCharacteristic::NotifySessionCommandStart::OnSuccess() { | |
119 std::unique_ptr<NotifySessionCommand> command = | |
120 std::move(characteristic_->pending_notify_commands_.front()); | |
121 DCHECK_EQ(command.get(), this); | |
122 characteristic_->pending_notify_commands_.pop(); | |
123 | |
124 std::unique_ptr<device::BluetoothGattNotifySession> notify_session( | |
125 new BluetoothGattNotifySession( | |
126 characteristic_->weak_ptr_factory_.GetWeakPtr())); | |
127 characteristic_->notify_sessions_.insert(notify_session.get()); | |
128 callback_.Run(std::move(notify_session)); | |
129 | |
130 if (!characteristic_->pending_notify_commands_.empty()) { | |
131 NotifySessionCommand* next = | |
132 characteristic_->pending_notify_commands_.front().get(); | |
133 if (next->type_ == COMMAND_START) { | |
134 characteristic_->pending_notify_commands_.front()->OnSuccess(); | |
135 } else { | |
136 characteristic_->pending_notify_commands_.front()->Execute(); | |
137 } | |
138 } | |
139 } | |
140 | |
141 void BluetoothRemoteGattCharacteristic::NotifySessionCommandStart::OnError( | |
142 BluetoothRemoteGattService::GattErrorCode error) { | |
143 std::unique_ptr<NotifySessionCommand> command = | |
144 std::move(characteristic_->pending_notify_commands_.front()); | |
145 DCHECK_EQ(command.get(), this); | |
146 characteristic_->pending_notify_commands_.pop(); | |
147 | |
148 error_callback_.Run(error); | |
149 | |
150 if (!characteristic_->pending_notify_commands_.empty()) { | |
151 NotifySessionCommand* next = | |
152 characteristic_->pending_notify_commands_.front().get(); | |
153 if (next->type_ == COMMAND_START) { | |
ortuno
2016/07/28 21:59:30
Do you do this for any other reason that optimizin
tommyt
2016/08/01 11:39:21
Yes, if we have multiple StartNotifySession comman
| |
154 characteristic_->pending_notify_commands_.front()->OnError(error); | |
155 } else { | |
156 characteristic_->pending_notify_commands_.front()->Execute(); | |
157 } | |
158 } | |
159 } | |
160 | |
161 void BluetoothRemoteGattCharacteristic::StopNotifySession( | |
162 BluetoothGattNotifySession* session, | |
163 const base::Closure& callback) { | |
164 NotifySessionCommand* command = | |
165 new NotifySessionCommandStop(this, session, callback); | |
166 pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command)); | |
167 if (pending_notify_commands_.size() == 1) { | |
168 command->Execute(); | |
169 } | |
170 } | |
171 | |
172 BluetoothRemoteGattCharacteristic::NotifySessionCommandStop:: | |
173 NotifySessionCommandStop(BluetoothRemoteGattCharacteristic* characteristic, | |
174 BluetoothGattNotifySession* session, | |
175 const base::Closure& callback) | |
176 : NotifySessionCommand(characteristic, COMMAND_STOP), | |
177 session_(session), | |
178 callback_(callback) {} | |
179 | |
180 BluetoothRemoteGattCharacteristic::NotifySessionCommandStop:: | |
181 ~NotifySessionCommandStop() {} | |
182 | |
183 void BluetoothRemoteGattCharacteristic::NotifySessionCommandStop::Execute() { | |
184 std::set<BluetoothGattNotifySession*>::iterator session_iterator = | |
185 characteristic_->notify_sessions_.find(session_); | |
186 | |
187 // If the session does not even belong to this characteristic, we return an | |
188 // error right away. | |
189 if (session_iterator == characteristic_->notify_sessions_.end()) { | |
190 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
191 FROM_HERE, | |
192 base::Bind(&BluetoothRemoteGattCharacteristic:: | |
193 NotifySessionCommandStop::OnError, | |
194 base::Unretained(this), | |
195 device::BluetoothRemoteGattService::GATT_ERROR_FAILED)); | |
196 return; | |
197 } | |
198 | |
199 characteristic_->notify_sessions_.erase(session_); | |
200 | |
201 // If there are more active sessions, then we return right away. | |
202 if (characteristic_->notify_sessions_.size() > 0) { | |
203 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
204 FROM_HERE, base::Bind(&BluetoothRemoteGattCharacteristic:: | |
205 NotifySessionCommandStop::OnSuccess, | |
206 base::Unretained(this))); | |
207 return; | |
208 } | |
209 | |
210 characteristic_->UnsubscribeFromNotifications( | |
211 base::Bind(&BluetoothRemoteGattCharacteristic::NotifySessionCommandStop:: | |
212 OnSuccess, | |
213 base::Unretained(this)), | |
214 base::Bind( | |
215 &BluetoothRemoteGattCharacteristic::NotifySessionCommandStop::OnError, | |
216 base::Unretained(this))); | |
217 } | |
218 | |
219 void BluetoothRemoteGattCharacteristic::NotifySessionCommandStop::Cancel() { | |
220 std::unique_ptr<NotifySessionCommand> command = | |
221 std::move(characteristic_->pending_notify_commands_.front()); | |
222 DCHECK_EQ(command.get(), this); | |
223 characteristic_->pending_notify_commands_.pop(); | |
224 callback_.Run(); | |
225 } | |
226 | |
227 void BluetoothRemoteGattCharacteristic::NotifySessionCommandStop::OnSuccess() { | |
228 std::unique_ptr<NotifySessionCommand> command = | |
229 std::move(characteristic_->pending_notify_commands_.front()); | |
230 DCHECK_EQ(command.get(), this); | |
231 characteristic_->pending_notify_commands_.pop(); | |
232 | |
233 callback_.Run(); | |
234 | |
235 if (!characteristic_->pending_notify_commands_.empty()) { | |
236 characteristic_->pending_notify_commands_.front()->Execute(); | |
237 } | |
238 } | |
239 | |
240 void BluetoothRemoteGattCharacteristic::NotifySessionCommandStop::OnError( | |
241 BluetoothRemoteGattService::GattErrorCode error) { | |
242 std::unique_ptr<NotifySessionCommand> command = | |
243 std::move(characteristic_->pending_notify_commands_.front()); | |
244 DCHECK_EQ(command.get(), this); | |
245 characteristic_->pending_notify_commands_.pop(); | |
246 | |
247 callback_.Run(); | |
248 | |
249 if (!characteristic_->pending_notify_commands_.empty()) { | |
250 characteristic_->pending_notify_commands_.front()->Execute(); | |
251 } | |
252 } | |
253 | |
27 } // namespace device | 254 } // namespace device |
OLD | NEW |