Chromium Code Reviews| 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 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 |
| OLD | NEW |