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

Unified 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 side-by-side diff with in-line comments
Download patch
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..16ae1e5953f57e837a99dd944e02e804c6a9e456 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,290 @@ BluetoothRemoteGattCharacteristic::GetDescriptorsByUUID(
return descriptors;
}
+base::WeakPtr<device::BluetoothRemoteGattCharacteristic>
+BluetoothRemoteGattCharacteristic::GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
+bool BluetoothRemoteGattCharacteristic::IsNotifying() const {
+ return !notify_sessions_.empty();
+}
+
+BluetoothRemoteGattCharacteristic::NotifySessionCommand::NotifySessionCommand(
+ const base::Closure& execute_callback,
+ const base::Closure& cancel_callback)
+ : execute_callback_(execute_callback), cancel_callback_(cancel_callback) {}
+
+BluetoothRemoteGattCharacteristic::NotifySessionCommand::
+ ~NotifySessionCommand() {}
+
+void BluetoothRemoteGattCharacteristic::NotifySessionCommand::Execute() {
+ execute_callback_.Run();
+}
+
+void BluetoothRemoteGattCharacteristic::NotifySessionCommand::Cancel() {
+ cancel_callback_.Run();
+}
+
+void BluetoothRemoteGattCharacteristic::StartNotifySession(
+ const NotifySessionCallback& callback,
+ const ErrorCallback& error_callback) {
+ NotifySessionCommand* command = new NotifySessionCommand(
+ base::Bind(&BluetoothRemoteGattCharacteristic::ExecuteStartNotifySession,
+ 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
+ base::Bind(&BluetoothRemoteGattCharacteristic::CancelStartNotifySession,
+ base::Unretained(this),
+ base::Bind(error_callback,
+ BluetoothRemoteGattService::GATT_ERROR_FAILED)));
+
+ pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command));
+ if (pending_notify_commands_.size() == 1) {
+ command->Execute();
+ }
+}
+
+void BluetoothRemoteGattCharacteristic::ExecuteStartNotifySession(
+ NotifySessionCallback callback,
+ ErrorCallback error_callback) {
+ // If the command that was resolved immediately before this command was run,
+ // this command should be resolved with the same result.
+ if (previous_command_type_ == NotifySessionCommand::COMMAND_START) {
+ if (previous_command_result_ == NotifySessionCommand::RESULT_SUCCESS) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &BluetoothRemoteGattCharacteristic::StartNotifySessionSuccess,
+ base::Unretained(this), callback));
+ return;
+ } else {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &BluetoothRemoteGattCharacteristic::StartNotifySessionError,
+ base::Unretained(this), error_callback,
+ previous_command_error_code_));
+ return;
+ }
+ }
+
+ 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
+
+ bool hasNotify = (properties & PROPERTY_NOTIFY) != 0;
+ bool hasIndicate = (properties & PROPERTY_INDICATE) != 0;
+
+ if (!hasNotify && !hasIndicate) {
+ LOG(ERROR) << "Characteristic needs NOTIFY or INDICATE";
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothRemoteGattCharacteristic::StartNotifySessionError,
+ base::Unretained(this), error_callback,
+ BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED));
+ return;
+ }
+
+ if (IsNotifying()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &BluetoothRemoteGattCharacteristic::StartNotifySessionSuccess,
+ base::Unretained(this), callback));
+ return;
+ }
+
+#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
+ defined(OS_WIN)
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothRemoteGattCharacteristic::StartNotifySessionError,
+ base::Unretained(this), error_callback,
+ BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED));
+#else
ortuno 2016/08/09 21:57:56 nit: // !(defined(OS_CHROMEOS) && defined(OS_LINU
tommyt 2016/08/10 12:07:19 Done
+ std::vector<BluetoothRemoteGattDescriptor*> ccc_descriptor =
+ GetDescriptorsByUUID(BluetoothRemoteGattDescriptor::
+ ClientCharacteristicConfigurationUuid());
+
+ if (ccc_descriptor.size() != 1u) {
+ LOG(ERROR) << "Found " << ccc_descriptor.size()
+ << " client characteristic configuration descriptors.";
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothRemoteGattCharacteristic::StartNotifySessionError,
+ base::Unretained(this), error_callback,
+ (ccc_descriptor.size() == 0)
+ ? BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED
+ : BluetoothRemoteGattService::GATT_ERROR_FAILED));
+ return;
+ }
+
+ SubscribeToNotifications(
+ ccc_descriptor[0],
+ base::Bind(&BluetoothRemoteGattCharacteristic::StartNotifySessionSuccess,
+ base::Unretained(this), callback),
+ base::Bind(&BluetoothRemoteGattCharacteristic::StartNotifySessionError,
+ base::Unretained(this), error_callback));
+#endif
ortuno 2016/08/09 21:57:56 nit: // defined(OS_CHROMEOS) || defined(OS_LINUX)
tommyt 2016/08/10 12:07:19 Done
+}
+
+void BluetoothRemoteGattCharacteristic::CancelStartNotifySession(
+ base::Closure callback) {
+ std::unique_ptr<NotifySessionCommand> command =
+ std::move(pending_notify_commands_.front());
+ pending_notify_commands_.pop();
+ previous_command_type_ = NotifySessionCommand::COMMAND_NONE;
+ callback.Run();
+}
+
+void BluetoothRemoteGattCharacteristic::StartNotifySessionSuccess(
+ NotifySessionCallback callback) {
+ std::unique_ptr<NotifySessionCommand> command =
+ std::move(pending_notify_commands_.front());
+
+ std::unique_ptr<device::BluetoothGattNotifySession> notify_session(
+ new BluetoothGattNotifySession(weak_ptr_factory_.GetWeakPtr()));
+ notify_sessions_.insert(notify_session.get());
+ callback.Run(std::move(notify_session));
+
+ pending_notify_commands_.pop();
+ if (!pending_notify_commands_.empty()) {
+ previous_command_type_ = NotifySessionCommand::COMMAND_START;
+ previous_command_result_ = NotifySessionCommand::RESULT_SUCCESS;
+ pending_notify_commands_.front()->Execute();
+ } else {
+ previous_command_type_ = NotifySessionCommand::COMMAND_NONE;
+ }
+}
+
+void BluetoothRemoteGattCharacteristic::StartNotifySessionError(
+ ErrorCallback error_callback,
+ BluetoothRemoteGattService::GattErrorCode error) {
+ std::unique_ptr<NotifySessionCommand> command =
+ std::move(pending_notify_commands_.front());
+
+ error_callback.Run(error);
+
+ pending_notify_commands_.pop();
+ if (!pending_notify_commands_.empty()) {
+ 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
+ previous_command_result_ = NotifySessionCommand::RESULT_ERROR;
+ previous_command_error_code_ = error;
+ pending_notify_commands_.front()->Execute();
+ } else {
+ previous_command_type_ = NotifySessionCommand::COMMAND_NONE;
+ }
+}
+
+void BluetoothRemoteGattCharacteristic::StopNotifySession(
+ BluetoothGattNotifySession* session,
+ const base::Closure& callback) {
+ NotifySessionCommand* command = new NotifySessionCommand(
+ base::Bind(&BluetoothRemoteGattCharacteristic::ExecuteStopNotifySession,
+ base::Unretained(this), session, callback),
+ callback);
ortuno 2016/08/09 21:57:56 nit: callback /* cancel_callback */);
tommyt 2016/08/10 12:07:18 Done.
+
+ pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command));
+ if (pending_notify_commands_.size() == 1) {
+ command->Execute();
+ }
+}
+
+void BluetoothRemoteGattCharacteristic::ExecuteStopNotifySession(
+ 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,
+ base::Closure callback) {
+ std::set<BluetoothGattNotifySession*>::iterator session_iterator =
+ notify_sessions_.find(session);
+
+ // If the session does not even belong to this characteristic, we return an
+ // error right away.
+ if (session_iterator == notify_sessions_.end()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothRemoteGattCharacteristic::StopNotifySessionError,
+ base::Unretained(this), session, callback,
+ BluetoothRemoteGattService::GATT_ERROR_FAILED));
+ return;
+ }
+
+ // If there are more active sessions, then we return right away.
+ if (notify_sessions_.size() > 1) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothRemoteGattCharacteristic::StopNotifySessionSuccess,
+ base::Unretained(this), session, callback));
+ return;
+ }
+
+ 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.
+ GetDescriptorsByUUID(BluetoothRemoteGattDescriptor::
+ ClientCharacteristicConfigurationUuid());
+
+ if (ccc_descriptor.size() != 1u) {
+ LOG(ERROR) << "Found " << ccc_descriptor.size()
+ << " client characteristic configuration descriptors.";
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&BluetoothRemoteGattCharacteristic::StopNotifySessionError,
+ base::Unretained(this), session, callback,
+ BluetoothRemoteGattService::GATT_ERROR_FAILED));
+ return;
+ }
+
+ UnsubscribeFromNotifications(
+ ccc_descriptor[0],
+ base::Bind(&BluetoothRemoteGattCharacteristic::StopNotifySessionSuccess,
+ base::Unretained(this), session, callback),
+ base::Bind(&BluetoothRemoteGattCharacteristic::StopNotifySessionError,
+ base::Unretained(this), session, callback));
+}
+
+void BluetoothRemoteGattCharacteristic::CancelStopNotifySession(
+ base::Closure callback) {
+ std::unique_ptr<NotifySessionCommand> command =
+ std::move(pending_notify_commands_.front());
+ pending_notify_commands_.pop();
+ previous_command_type_ = NotifySessionCommand::COMMAND_NONE;
+ callback.Run();
+}
+
+void BluetoothRemoteGattCharacteristic::StopNotifySessionSuccess(
+ BluetoothGattNotifySession* session,
+ base::Closure callback) {
+ std::unique_ptr<NotifySessionCommand> command =
+ std::move(pending_notify_commands_.front());
+
+ notify_sessions_.erase(session);
+
+ callback.Run();
+
+ pending_notify_commands_.pop();
+ if (!pending_notify_commands_.empty()) {
+ previous_command_type_ = NotifySessionCommand::COMMAND_STOP;
+ previous_command_result_ = NotifySessionCommand::RESULT_SUCCESS;
+ pending_notify_commands_.front()->Execute();
+ } else {
+ previous_command_type_ = NotifySessionCommand::COMMAND_NONE;
+ }
+}
+
+void BluetoothRemoteGattCharacteristic::StopNotifySessionError(
+ BluetoothGattNotifySession* session,
+ base::Closure callback,
+ BluetoothRemoteGattService::GattErrorCode error) {
+ std::unique_ptr<NotifySessionCommand> command =
+ std::move(pending_notify_commands_.front());
+
+ notify_sessions_.erase(session);
+
+ callback.Run();
+
+ pending_notify_commands_.pop();
+ if (!pending_notify_commands_.empty()) {
+ previous_command_type_ = NotifySessionCommand::COMMAND_STOP;
+ previous_command_result_ = NotifySessionCommand::RESULT_ERROR;
+ previous_command_error_code_ = error;
+ pending_notify_commands_.front()->Execute();
+ } else {
+ previous_command_type_ = NotifySessionCommand::COMMAND_NONE;
+ }
+}
+
} // namespace device

Powered by Google App Engine
This is Rietveld 408576698