Index: device/bluetooth/bluetooth_remote_gatt_characteristic.cc |
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic.cc |
index fa96a9b984152d6c57ad23a0b17cd390ce434e7c..174512281f155e25bb4b7af3885681f1e1a100ad 100644 |
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic.cc |
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic.cc |
@@ -4,17 +4,27 @@ |
#include "device/bluetooth/bluetooth_remote_gatt_characteristic.h" |
+#include "base/bind.h" |
+#include "base/location.h" |
+#include "base/single_thread_task_runner.h" |
+#include "base/threading/thread_task_runner_handle.h" |
+#include "device/bluetooth/bluetooth_gatt_notify_session.h" |
#include "device/bluetooth/bluetooth_remote_gatt_descriptor.h" |
namespace device { |
-BluetoothRemoteGattCharacteristic::BluetoothRemoteGattCharacteristic() {} |
+BluetoothRemoteGattCharacteristic::BluetoothRemoteGattCharacteristic() |
+ : weak_ptr_factory_(this) {} |
-BluetoothRemoteGattCharacteristic::~BluetoothRemoteGattCharacteristic() {} |
+BluetoothRemoteGattCharacteristic::~BluetoothRemoteGattCharacteristic() { |
+ while (!pending_notify_commands_.empty()) { |
+ pending_notify_commands_.front()->Cancel(); |
+ } |
+} |
std::vector<BluetoothRemoteGattDescriptor*> |
BluetoothRemoteGattCharacteristic::GetDescriptorsByUUID( |
- const BluetoothUUID& uuid) { |
+ const BluetoothUUID& uuid) const { |
std::vector<BluetoothRemoteGattDescriptor*> descriptors; |
for (BluetoothRemoteGattDescriptor* descriptor : GetDescriptors()) { |
if (descriptor->GetUUID() == uuid) { |
@@ -24,4 +34,221 @@ BluetoothRemoteGattCharacteristic::GetDescriptorsByUUID( |
return descriptors; |
} |
+base::WeakPtr<device::BluetoothRemoteGattCharacteristic> |
+BluetoothRemoteGattCharacteristic::GetWeakPtr() { |
+ return weak_ptr_factory_.GetWeakPtr(); |
+} |
+ |
+bool BluetoothRemoteGattCharacteristic::IsNotifying() const { |
+ return !notify_sessions_.empty(); |
+} |
+ |
+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.
|
+ const NotifySessionCallback& callback, |
+ const ErrorCallback& error_callback) { |
+ NotifySessionCommand* command = |
+ new NotifySessionCommandStart(this, callback, error_callback); |
+ pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command)); |
+ if (pending_notify_commands_.size() == 1) { |
+ command->Execute(); |
+ } |
+} |
+ |
+BluetoothRemoteGattCharacteristic::NotifySessionCommand::NotifySessionCommand( |
+ BluetoothRemoteGattCharacteristic* characteristic, |
+ Type type) |
+ : characteristic_(characteristic), type_(type) {} |
+ |
+BluetoothRemoteGattCharacteristic::NotifySessionCommand:: |
+ ~NotifySessionCommand() {} |
+ |
+BluetoothRemoteGattCharacteristic::NotifySessionCommandStart:: |
+ NotifySessionCommandStart(BluetoothRemoteGattCharacteristic* characteristic, |
+ const NotifySessionCallback& callback, |
+ const ErrorCallback& error_callback) |
+ : NotifySessionCommand(characteristic, COMMAND_START), |
+ callback_(callback), |
+ error_callback_(error_callback) {} |
+ |
+BluetoothRemoteGattCharacteristic::NotifySessionCommandStart:: |
+ ~NotifySessionCommandStart() {} |
+ |
+void BluetoothRemoteGattCharacteristic::NotifySessionCommandStart::Execute() { |
+ Properties properties = characteristic_->GetProperties(); |
+ |
+ bool hasNotify = (properties & PROPERTY_NOTIFY) != 0; |
+ bool hasIndicate = (properties & PROPERTY_INDICATE) != 0; |
+ |
+ 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
|
+ LOG(ERROR) << "Characteristic needs NOTIFY or INDICATE"; |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&BluetoothRemoteGattCharacteristic:: |
+ NotifySessionCommandStart::OnError, |
+ base::Unretained(this), |
+ BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED)); |
+ return; |
+ } |
+ |
+ if (characteristic_->IsNotifying()) { |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::Bind(&BluetoothRemoteGattCharacteristic:: |
+ NotifySessionCommandStart::OnSuccess, |
+ base::Unretained(this))); |
+ return; |
+ } |
+ |
+ characteristic_->SubscribeToNotifications( |
+ base::Bind(&BluetoothRemoteGattCharacteristic::NotifySessionCommandStart:: |
+ OnSuccess, |
+ base::Unretained(this)), |
+ base::Bind(&BluetoothRemoteGattCharacteristic::NotifySessionCommandStart:: |
+ OnError, |
+ base::Unretained(this))); |
+} |
+ |
+void BluetoothRemoteGattCharacteristic::NotifySessionCommandStart::Cancel() { |
+ std::unique_ptr<NotifySessionCommand> command = |
+ std::move(characteristic_->pending_notify_commands_.front()); |
+ DCHECK_EQ(command.get(), this); |
+ characteristic_->pending_notify_commands_.pop(); |
+ error_callback_.Run(BluetoothRemoteGattService::GATT_ERROR_FAILED); |
+} |
+ |
+void BluetoothRemoteGattCharacteristic::NotifySessionCommandStart::OnSuccess() { |
+ std::unique_ptr<NotifySessionCommand> command = |
+ std::move(characteristic_->pending_notify_commands_.front()); |
+ DCHECK_EQ(command.get(), this); |
+ characteristic_->pending_notify_commands_.pop(); |
+ |
+ std::unique_ptr<device::BluetoothGattNotifySession> notify_session( |
+ new BluetoothGattNotifySession( |
+ characteristic_->weak_ptr_factory_.GetWeakPtr())); |
+ characteristic_->notify_sessions_.insert(notify_session.get()); |
+ callback_.Run(std::move(notify_session)); |
+ |
+ if (!characteristic_->pending_notify_commands_.empty()) { |
+ NotifySessionCommand* next = |
+ characteristic_->pending_notify_commands_.front().get(); |
+ if (next->type_ == COMMAND_START) { |
+ characteristic_->pending_notify_commands_.front()->OnSuccess(); |
+ } else { |
+ characteristic_->pending_notify_commands_.front()->Execute(); |
+ } |
+ } |
+} |
+ |
+void BluetoothRemoteGattCharacteristic::NotifySessionCommandStart::OnError( |
+ BluetoothRemoteGattService::GattErrorCode error) { |
+ std::unique_ptr<NotifySessionCommand> command = |
+ std::move(characteristic_->pending_notify_commands_.front()); |
+ DCHECK_EQ(command.get(), this); |
+ characteristic_->pending_notify_commands_.pop(); |
+ |
+ error_callback_.Run(error); |
+ |
+ if (!characteristic_->pending_notify_commands_.empty()) { |
+ NotifySessionCommand* next = |
+ characteristic_->pending_notify_commands_.front().get(); |
+ 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
|
+ characteristic_->pending_notify_commands_.front()->OnError(error); |
+ } else { |
+ characteristic_->pending_notify_commands_.front()->Execute(); |
+ } |
+ } |
+} |
+ |
+void BluetoothRemoteGattCharacteristic::StopNotifySession( |
+ BluetoothGattNotifySession* session, |
+ const base::Closure& callback) { |
+ NotifySessionCommand* command = |
+ new NotifySessionCommandStop(this, session, callback); |
+ pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command)); |
+ if (pending_notify_commands_.size() == 1) { |
+ command->Execute(); |
+ } |
+} |
+ |
+BluetoothRemoteGattCharacteristic::NotifySessionCommandStop:: |
+ NotifySessionCommandStop(BluetoothRemoteGattCharacteristic* characteristic, |
+ BluetoothGattNotifySession* session, |
+ const base::Closure& callback) |
+ : NotifySessionCommand(characteristic, COMMAND_STOP), |
+ session_(session), |
+ callback_(callback) {} |
+ |
+BluetoothRemoteGattCharacteristic::NotifySessionCommandStop:: |
+ ~NotifySessionCommandStop() {} |
+ |
+void BluetoothRemoteGattCharacteristic::NotifySessionCommandStop::Execute() { |
+ std::set<BluetoothGattNotifySession*>::iterator session_iterator = |
+ characteristic_->notify_sessions_.find(session_); |
+ |
+ // If the session does not even belong to this characteristic, we return an |
+ // error right away. |
+ if (session_iterator == characteristic_->notify_sessions_.end()) { |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&BluetoothRemoteGattCharacteristic:: |
+ NotifySessionCommandStop::OnError, |
+ base::Unretained(this), |
+ device::BluetoothRemoteGattService::GATT_ERROR_FAILED)); |
+ return; |
+ } |
+ |
+ characteristic_->notify_sessions_.erase(session_); |
+ |
+ // If there are more active sessions, then we return right away. |
+ if (characteristic_->notify_sessions_.size() > 0) { |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::Bind(&BluetoothRemoteGattCharacteristic:: |
+ NotifySessionCommandStop::OnSuccess, |
+ base::Unretained(this))); |
+ return; |
+ } |
+ |
+ characteristic_->UnsubscribeFromNotifications( |
+ base::Bind(&BluetoothRemoteGattCharacteristic::NotifySessionCommandStop:: |
+ OnSuccess, |
+ base::Unretained(this)), |
+ base::Bind( |
+ &BluetoothRemoteGattCharacteristic::NotifySessionCommandStop::OnError, |
+ base::Unretained(this))); |
+} |
+ |
+void BluetoothRemoteGattCharacteristic::NotifySessionCommandStop::Cancel() { |
+ std::unique_ptr<NotifySessionCommand> command = |
+ std::move(characteristic_->pending_notify_commands_.front()); |
+ DCHECK_EQ(command.get(), this); |
+ characteristic_->pending_notify_commands_.pop(); |
+ callback_.Run(); |
+} |
+ |
+void BluetoothRemoteGattCharacteristic::NotifySessionCommandStop::OnSuccess() { |
+ std::unique_ptr<NotifySessionCommand> command = |
+ std::move(characteristic_->pending_notify_commands_.front()); |
+ DCHECK_EQ(command.get(), this); |
+ characteristic_->pending_notify_commands_.pop(); |
+ |
+ callback_.Run(); |
+ |
+ if (!characteristic_->pending_notify_commands_.empty()) { |
+ characteristic_->pending_notify_commands_.front()->Execute(); |
+ } |
+} |
+ |
+void BluetoothRemoteGattCharacteristic::NotifySessionCommandStop::OnError( |
+ BluetoothRemoteGattService::GattErrorCode error) { |
+ std::unique_ptr<NotifySessionCommand> command = |
+ std::move(characteristic_->pending_notify_commands_.front()); |
+ DCHECK_EQ(command.get(), this); |
+ characteristic_->pending_notify_commands_.pop(); |
+ |
+ callback_.Run(); |
+ |
+ if (!characteristic_->pending_notify_commands_.empty()) { |
+ characteristic_->pending_notify_commands_.front()->Execute(); |
+ } |
+} |
+ |
} // namespace device |