blob: 82bad22cb0993b98088c0f0bcf98e5f4d63f24cb [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/bluetooth/bluetooth_dispatcher.h"
#include <stddef.h>
#include "base/lazy_instance.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/thread_task_runner_handle.h"
#include "content/child/thread_safe_sender.h"
#include "content/common/bluetooth/bluetooth_messages.h"
#include "device/bluetooth/bluetooth_uuid.h"
#include "third_party/WebKit/public/platform/WebPassOwnPtr.h"
#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.h"
#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothError.h"
#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTCharacteristic.h"
#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTCharacteristicInit.h"
#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTRemoteServer.h"
#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTService.h"
#include "third_party/WebKit/public/platform/modules/bluetooth/WebRequestDeviceOptions.h"
using blink::WebBluetoothConnectGATTCallbacks;
using blink::WebBluetoothDevice;
using blink::WebBluetoothError;
using blink::WebBluetoothGATTCharacteristicInit;
using blink::WebBluetoothGATTRemoteServer;
using blink::WebBluetoothGATTService;
using blink::WebBluetoothReadValueCallbacks;
using blink::WebBluetoothRequestDeviceCallbacks;
using blink::WebBluetoothScanFilter;
using blink::WebRequestDeviceOptions;
using blink::WebString;
using blink::WebVector;
using NotificationsRequestType =
content::BluetoothDispatcher::NotificationsRequestType;
struct BluetoothPrimaryServiceRequest {
BluetoothPrimaryServiceRequest(
blink::WebString device_id,
blink::WebString service_uuid,
blink::WebBluetoothGetPrimaryServiceCallbacks* callbacks)
: device_id(device_id),
service_uuid(service_uuid),
callbacks(callbacks) {}
~BluetoothPrimaryServiceRequest() {}
blink::WebString device_id;
blink::WebString service_uuid;
scoped_ptr<blink::WebBluetoothGetPrimaryServiceCallbacks> callbacks;
};
struct BluetoothCharacteristicRequest {
BluetoothCharacteristicRequest(
blink::WebString service_instance_id,
blink::WebString characteristic_uuid,
blink::WebBluetoothGetCharacteristicCallbacks* callbacks)
: service_instance_id(service_instance_id),
characteristic_uuid(characteristic_uuid),
callbacks(callbacks) {}
~BluetoothCharacteristicRequest() {}
blink::WebString service_instance_id;
blink::WebString characteristic_uuid;
scoped_ptr<blink::WebBluetoothGetCharacteristicCallbacks> callbacks;
};
// Struct that holds a pending Start/StopNotifications request.
struct BluetoothNotificationsRequest {
BluetoothNotificationsRequest(
const std::string characteristic_instance_id,
blink::WebBluetoothGATTCharacteristic* characteristic,
blink::WebBluetoothNotificationsCallbacks* callbacks,
NotificationsRequestType type)
: characteristic_instance_id(characteristic_instance_id),
characteristic(characteristic),
callbacks(callbacks),
type(type) {}
~BluetoothNotificationsRequest() {}
const std::string characteristic_instance_id;
// The characteristic object is owned by the execution context on
// the blink side which can destroy the object at any point. Since the
// object implements ActiveDOMObject, the object calls Stop when is getting
// destroyed, which in turn calls characteristicObjectRemoved.
// characteristicObjectRemoved will null any pointers to the object
// and queue a stop notifications request if necessary.
blink::WebBluetoothGATTCharacteristic* characteristic;
scoped_ptr<blink::WebBluetoothNotificationsCallbacks> callbacks;
NotificationsRequestType type;
};
namespace content {
namespace {
base::LazyInstance<base::ThreadLocalPointer<void>>::Leaky g_dispatcher_tls =
LAZY_INSTANCE_INITIALIZER;
void* const kHasBeenDeleted = reinterpret_cast<void*>(0x1);
int CurrentWorkerId() {
return WorkerThread::GetCurrentId();
}
WebBluetoothDevice::VendorIDSource GetWebVendorIdSource(
device::BluetoothDevice::VendorIDSource vendor_id_source) {
switch (vendor_id_source) {
case device::BluetoothDevice::VENDOR_ID_UNKNOWN:
return WebBluetoothDevice::VendorIDSource::Unknown;
case device::BluetoothDevice::VENDOR_ID_BLUETOOTH:
return WebBluetoothDevice::VendorIDSource::Bluetooth;
case device::BluetoothDevice::VENDOR_ID_USB:
return WebBluetoothDevice::VendorIDSource::USB;
}
NOTREACHED();
return WebBluetoothDevice::VendorIDSource::Unknown;
}
} // namespace
BluetoothDispatcher::BluetoothDispatcher(ThreadSafeSender* sender)
: thread_safe_sender_(sender) {
g_dispatcher_tls.Pointer()->Set(static_cast<void*>(this));
}
BluetoothDispatcher::~BluetoothDispatcher() {
g_dispatcher_tls.Pointer()->Set(kHasBeenDeleted);
}
BluetoothDispatcher* BluetoothDispatcher::GetOrCreateThreadSpecificInstance(
ThreadSafeSender* thread_safe_sender) {
if (g_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted) {
NOTREACHED() << "Re-instantiating TLS BluetoothDispatcher.";
g_dispatcher_tls.Pointer()->Set(NULL);
}
if (g_dispatcher_tls.Pointer()->Get())
return static_cast<BluetoothDispatcher*>(g_dispatcher_tls.Pointer()->Get());
BluetoothDispatcher* dispatcher = new BluetoothDispatcher(thread_safe_sender);
if (CurrentWorkerId())
WorkerThread::AddObserver(dispatcher);
return dispatcher;
}
bool BluetoothDispatcher::Send(IPC::Message* msg) {
return thread_safe_sender_->Send(msg);
}
void BluetoothDispatcher::OnMessageReceived(const IPC::Message& msg) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(BluetoothDispatcher, msg)
IPC_MESSAGE_HANDLER(BluetoothMsg_RequestDeviceSuccess,
OnRequestDeviceSuccess);
IPC_MESSAGE_HANDLER(BluetoothMsg_RequestDeviceError, OnRequestDeviceError);
IPC_MESSAGE_HANDLER(BluetoothMsg_ConnectGATTSuccess, OnConnectGATTSuccess);
IPC_MESSAGE_HANDLER(BluetoothMsg_ConnectGATTError, OnConnectGATTError);
IPC_MESSAGE_HANDLER(BluetoothMsg_GetPrimaryServiceSuccess,
OnGetPrimaryServiceSuccess);
IPC_MESSAGE_HANDLER(BluetoothMsg_GetPrimaryServiceError,
OnGetPrimaryServiceError);
IPC_MESSAGE_HANDLER(BluetoothMsg_GetCharacteristicSuccess,
OnGetCharacteristicSuccess);
IPC_MESSAGE_HANDLER(BluetoothMsg_GetCharacteristicError,
OnGetCharacteristicError);
IPC_MESSAGE_HANDLER(BluetoothMsg_ReadCharacteristicValueSuccess,
OnReadValueSuccess);
IPC_MESSAGE_HANDLER(BluetoothMsg_ReadCharacteristicValueError,
OnReadValueError);
IPC_MESSAGE_HANDLER(BluetoothMsg_WriteCharacteristicValueSuccess,
OnWriteValueSuccess);
IPC_MESSAGE_HANDLER(BluetoothMsg_WriteCharacteristicValueError,
OnWriteValueError);
IPC_MESSAGE_HANDLER(BluetoothMsg_StartNotificationsSuccess,
OnStartNotificationsSuccess)
IPC_MESSAGE_HANDLER(BluetoothMsg_StartNotificationsError,
OnStartNotificationsError)
IPC_MESSAGE_HANDLER(BluetoothMsg_StopNotificationsSuccess,
OnStopNotificationsSuccess)
IPC_MESSAGE_HANDLER(BluetoothMsg_CharacteristicValueChanged,
OnCharacteristicValueChanged)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
DCHECK(handled) << "Unhandled message:" << msg.type();
}
void BluetoothDispatcher::requestDevice(
int frame_routing_id,
const WebRequestDeviceOptions& options,
blink::WebBluetoothRequestDeviceCallbacks* callbacks) {
int request_id = pending_requests_.Add(callbacks);
// Convert |options| to its IPC form.
std::vector<content::BluetoothScanFilter> filters(options.filters.size());
for (size_t i = 0; i < options.filters.size(); ++i) {
const WebBluetoothScanFilter& web_filter = options.filters[i];
BluetoothScanFilter& filter = filters[i];
filter.services.reserve(web_filter.services.size());
for (const WebString& service : web_filter.services) {
filter.services.push_back(device::BluetoothUUID(service.utf8()));
}
filter.name = web_filter.name.utf8();
filter.namePrefix = web_filter.namePrefix.utf8();
}
std::vector<device::BluetoothUUID> optional_services;
optional_services.reserve(options.optionalServices.size());
for (const WebString& optional_service : options.optionalServices) {
optional_services.push_back(device::BluetoothUUID(optional_service.utf8()));
}
Send(new BluetoothHostMsg_RequestDevice(CurrentWorkerId(), request_id,
frame_routing_id, filters,
optional_services));
}
void BluetoothDispatcher::connectGATT(
const blink::WebString& device_id,
blink::WebBluetoothConnectGATTCallbacks* callbacks) {
int request_id = pending_connect_requests_.Add(callbacks);
Send(new BluetoothHostMsg_ConnectGATT(CurrentWorkerId(), request_id,
device_id.utf8()));
}
void BluetoothDispatcher::getPrimaryService(
const blink::WebString& device_id,
const blink::WebString& service_uuid,
blink::WebBluetoothGetPrimaryServiceCallbacks* callbacks) {
int request_id = pending_primary_service_requests_.Add(
new BluetoothPrimaryServiceRequest(device_id, service_uuid, callbacks));
Send(new BluetoothHostMsg_GetPrimaryService(
CurrentWorkerId(), request_id, device_id.utf8(), service_uuid.utf8()));
}
void BluetoothDispatcher::getCharacteristic(
const blink::WebString& service_instance_id,
const blink::WebString& characteristic_uuid,
blink::WebBluetoothGetCharacteristicCallbacks* callbacks) {
int request_id =
pending_characteristic_requests_.Add(new BluetoothCharacteristicRequest(
service_instance_id, characteristic_uuid, callbacks));
Send(new BluetoothHostMsg_GetCharacteristic(CurrentWorkerId(), request_id,
service_instance_id.utf8(),
characteristic_uuid.utf8()));
}
void BluetoothDispatcher::readValue(
const blink::WebString& characteristic_instance_id,
blink::WebBluetoothReadValueCallbacks* callbacks) {
int request_id = pending_read_value_requests_.Add(callbacks);
Send(new BluetoothHostMsg_ReadValue(CurrentWorkerId(), request_id,
characteristic_instance_id.utf8()));
}
void BluetoothDispatcher::writeValue(
const blink::WebString& characteristic_instance_id,
const blink::WebVector<uint8_t>& value,
blink::WebBluetoothWriteValueCallbacks* callbacks) {
int request_id = pending_write_value_requests_.Add(callbacks);
Send(new BluetoothHostMsg_WriteValue(
CurrentWorkerId(), request_id, characteristic_instance_id.utf8(),
std::vector<uint8_t>(value.begin(), value.end())));
}
void BluetoothDispatcher::startNotifications(
const blink::WebString& characteristic_instance_id,
blink::WebBluetoothGATTCharacteristic* characteristic,
blink::WebBluetoothNotificationsCallbacks* callbacks) {
int request_id = QueueNotificationRequest(characteristic_instance_id.utf8(),
characteristic, callbacks,
NotificationsRequestType::START);
// The Notification subscription's state can change after a request
// finishes. To avoid resolving with a soon-to-be-invalid state we queue
// requests.
if (HasNotificationRequestResponsePending(
characteristic_instance_id.utf8())) {
return;
}
ResolveOrSendStartNotificationRequest(request_id);
}
void BluetoothDispatcher::stopNotifications(
const blink::WebString& characteristic_instance_id,
blink::WebBluetoothGATTCharacteristic* characteristic,
blink::WebBluetoothNotificationsCallbacks* callbacks) {
int request_id = QueueNotificationRequest(characteristic_instance_id.utf8(),
characteristic, callbacks,
NotificationsRequestType::STOP);
if (HasNotificationRequestResponsePending(
characteristic_instance_id.utf8())) {
return;
}
ResolveOrSendStopNotificationsRequest(request_id);
}
void BluetoothDispatcher::characteristicObjectRemoved(
const blink::WebString& characteristic_instance_id,
blink::WebBluetoothGATTCharacteristic* characteristic) {
// We need to remove references to the object from the following:
// 1) The set of active characteristics
// 2) The queue waiting for a response
// 3) The set of active notifications
// 1
// TODO(ortuno): We should only unregister a characteristic once
// there are no characteristic objects that have listeners attached.
// https://crbug.com/541388
UnregisterCharacteristicObject(characteristic_instance_id);
// 2
// If the object is in the queue we null the characteristic. If this is the
// first object waiting for a response OnStartNotificationsSuccess will make
// sure not to add the characteristic to the map and it will queue a Stop
// request. Otherwise ResolveOrSendStartNotificationRequest will make sure not
// to add it to active notification subscriptions.
bool found = false;
for (IDMap<BluetoothNotificationsRequest, IDMapOwnPointer>::iterator iter(
&pending_notifications_requests_);
!iter.IsAtEnd(); iter.Advance()) {
if (iter.GetCurrentValue()->characteristic == characteristic) {
found = true;
iter.GetCurrentValue()->characteristic = nullptr;
}
}
if (found) {
// A characteristic will never be in the set of active notifications
// and in the queue at the same time.
auto subscriptions_iter = active_notification_subscriptions_.find(
characteristic_instance_id.utf8());
if (subscriptions_iter != active_notification_subscriptions_.end()) {
DCHECK(!ContainsKey(subscriptions_iter->second, characteristic));
}
return;
}
// 3
// If the object is not in the queue then:
// 1. The subscription was inactive already: this characteristic
// object didn't subscribe to notifications.
// 2. The subscription will become inactive: the characteristic
// object that subscribed to notifications is getting destroyed.
// 3. The subscription will still be active: there are other
// characteristic objects subscribed to notifications.
if (!HasActiveNotificationSubscription(characteristic_instance_id.utf8())) {
return;
}
// For 2 and 3 calling ResolveOrSendStopNotificationsRequest ensures the
// notification subscription is released.
// We pass in the characteristic so that ResolveOrSendStopNotificationsRequest
// can remove the characteristic from ActiveNotificationSubscriptions.
ResolveOrSendStopNotificationsRequest(QueueNotificationRequest(
characteristic_instance_id.utf8(), characteristic,
nullptr /* callbacks */, NotificationsRequestType::STOP));
}
void BluetoothDispatcher::registerCharacteristicObject(
const blink::WebString& characteristic_instance_id,
blink::WebBluetoothGATTCharacteristic* characteristic) {
// TODO(ortuno): After the Object manager is implemented, there will
// only be one object per characteristic. But for now we remove
// the previous object.
// https://crbug.com/495270
active_characteristics_.erase(characteristic_instance_id.utf8());
active_characteristics_.insert(
std::make_pair(characteristic_instance_id.utf8(), characteristic));
Send(new BluetoothHostMsg_RegisterCharacteristic(
CurrentWorkerId(), characteristic_instance_id.utf8()));
}
void BluetoothDispatcher::WillStopCurrentWorkerThread() {
delete this;
}
int BluetoothDispatcher::QueueNotificationRequest(
const std::string& characteristic_instance_id,
blink::WebBluetoothGATTCharacteristic* characteristic,
blink::WebBluetoothNotificationsCallbacks* callbacks,
NotificationsRequestType type) {
int request_id =
pending_notifications_requests_.Add(new BluetoothNotificationsRequest(
characteristic_instance_id, characteristic, callbacks, type));
notification_requests_queues_[characteristic_instance_id].push(request_id);
return request_id;
}
void BluetoothDispatcher::PopNotificationRequestQueueAndProcessNext(
int request_id) {
BluetoothNotificationsRequest* old_request =
pending_notifications_requests_.Lookup(request_id);
auto queue_iter = notification_requests_queues_.find(
old_request->characteristic_instance_id);
CHECK(queue_iter != notification_requests_queues_.end());
std::queue<int>& request_queue = queue_iter->second;
DCHECK(request_queue.front() == request_id);
// Remove old request and clean map if necessary.
request_queue.pop();
pending_notifications_requests_.Remove(request_id);
if (request_queue.empty()) {
notification_requests_queues_.erase(queue_iter);
return;
}
int next_request_id = request_queue.front();
BluetoothNotificationsRequest* next_request =
pending_notifications_requests_.Lookup(next_request_id);
switch (next_request->type) {
case NotificationsRequestType::START:
ResolveOrSendStartNotificationRequest(next_request_id);
return;
case NotificationsRequestType::STOP:
ResolveOrSendStopNotificationsRequest(next_request_id);
return;
}
}
bool BluetoothDispatcher::HasNotificationRequestResponsePending(
const std::string& characteristic_instance_id) {
return ContainsKey(notification_requests_queues_,
characteristic_instance_id) &&
(notification_requests_queues_[characteristic_instance_id].size() > 1);
}
bool BluetoothDispatcher::HasActiveNotificationSubscription(
const std::string& characteristic_instance_id) {
return ContainsKey(active_notification_subscriptions_,
characteristic_instance_id);
}
void BluetoothDispatcher::AddToActiveNotificationSubscriptions(
const std::string& characteristic_instance_id,
blink::WebBluetoothGATTCharacteristic* characteristic) {
active_notification_subscriptions_[characteristic_instance_id].insert(
characteristic);
}
bool BluetoothDispatcher::RemoveFromActiveNotificationSubscriptions(
const std::string& characteristic_instance_id,
blink::WebBluetoothGATTCharacteristic* characteristic) {
auto active_map =
active_notification_subscriptions_.find(characteristic_instance_id);
if (active_map == active_notification_subscriptions_.end()) {
return false;
}
active_map->second.erase(characteristic);
if (active_map->second.empty()) {
active_notification_subscriptions_.erase(active_map);
DCHECK(!HasActiveNotificationSubscription(characteristic_instance_id));
return true;
}
return false;
}
void BluetoothDispatcher::ResolveOrSendStartNotificationRequest(
int request_id) {
BluetoothNotificationsRequest* request =
pending_notifications_requests_.Lookup(request_id);
const std::string& characteristic_instance_id =
request->characteristic_instance_id;
blink::WebBluetoothGATTCharacteristic* characteristic =
request->characteristic;
blink::WebBluetoothNotificationsCallbacks* callbacks =
request->callbacks.get();
// If an object is already subscribed to notifications from the characteristic
// no need to send an IPC again.
if (HasActiveNotificationSubscription(characteristic_instance_id)) {
// The object could have been destroyed while we waited.
if (characteristic != nullptr) {
AddToActiveNotificationSubscriptions(characteristic_instance_id,
characteristic);
}
callbacks->onSuccess();
PopNotificationRequestQueueAndProcessNext(request_id);
return;
}
Send(new BluetoothHostMsg_StartNotifications(CurrentWorkerId(), request_id,
characteristic_instance_id));
}
void BluetoothDispatcher::ResolveOrSendStopNotificationsRequest(
int request_id) {
// The Notification subscription's state can change after a request
// finishes. To avoid resolving with a soon-to-be-invalid state we queue
// requests.
BluetoothNotificationsRequest* request =
pending_notifications_requests_.Lookup(request_id);
const std::string& characteristic_instance_id =
request->characteristic_instance_id;
blink::WebBluetoothGATTCharacteristic* characteristic =
request->characteristic;
blink::WebBluetoothNotificationsCallbacks* callbacks =
request->callbacks.get();
// If removing turns the subscription inactive then stop.
if (RemoveFromActiveNotificationSubscriptions(characteristic_instance_id,
characteristic)) {
Send(new BluetoothHostMsg_StopNotifications(CurrentWorkerId(), request_id,
characteristic_instance_id));
return;
}
// We could be processing a request with nullptr callbacks due to:
// 1) OnStartNotificationSuccess queues a Stop request because the object
// got destroyed in characteristicObjectRemoved.
// 2) The last characteristic object that held this subscription got
// destroyed in characteristicObjectRemoved.
if (callbacks != nullptr) {
callbacks->onSuccess();
}
PopNotificationRequestQueueAndProcessNext(request_id);
}
void BluetoothDispatcher::UnregisterCharacteristicObject(
const blink::WebString& characteristic_instance_id) {
int removed =
active_characteristics_.erase(characteristic_instance_id.utf8());
if (removed != 0) {
Send(new BluetoothHostMsg_UnregisterCharacteristic(
CurrentWorkerId(), characteristic_instance_id.utf8()));
}
}
void BluetoothDispatcher::OnRequestDeviceSuccess(
int thread_id,
int request_id,
const BluetoothDevice& device) {
DCHECK(pending_requests_.Lookup(request_id)) << request_id;
WebVector<WebString> uuids(device.uuids.size());
for (size_t i = 0; i < device.uuids.size(); ++i)
uuids[i] = WebString::fromUTF8(device.uuids[i].c_str());
pending_requests_.Lookup(request_id)
->onSuccess(blink::adoptWebPtr(new WebBluetoothDevice(
WebString::fromUTF8(device.id), WebString(device.name),
device.tx_power, device.rssi, device.device_class,
GetWebVendorIdSource(device.vendor_id_source), device.vendor_id,
device.product_id, device.product_version, uuids)));
pending_requests_.Remove(request_id);
}
void BluetoothDispatcher::OnRequestDeviceError(int thread_id,
int request_id,
WebBluetoothError error) {
DCHECK(pending_requests_.Lookup(request_id)) << request_id;
pending_requests_.Lookup(request_id)->onError(WebBluetoothError(error));
pending_requests_.Remove(request_id);
}
void BluetoothDispatcher::OnConnectGATTSuccess(int thread_id,
int request_id,
const std::string& device_id) {
DCHECK(pending_connect_requests_.Lookup(request_id)) << request_id;
pending_connect_requests_.Lookup(request_id)
->onSuccess(blink::adoptWebPtr(new WebBluetoothGATTRemoteServer(
WebString::fromUTF8(device_id), true /* connected */)));
pending_connect_requests_.Remove(request_id);
}
void BluetoothDispatcher::OnConnectGATTError(int thread_id,
int request_id,
WebBluetoothError error) {
DCHECK(pending_connect_requests_.Lookup(request_id)) << request_id;
pending_connect_requests_.Lookup(request_id)
->onError(WebBluetoothError(error));
pending_connect_requests_.Remove(request_id);
}
void BluetoothDispatcher::OnGetPrimaryServiceSuccess(
int thread_id,
int request_id,
const std::string& service_instance_id) {
DCHECK(pending_primary_service_requests_.Lookup(request_id)) << request_id;
BluetoothPrimaryServiceRequest* request =
pending_primary_service_requests_.Lookup(request_id);
request->callbacks->onSuccess(blink::adoptWebPtr(new WebBluetoothGATTService(
WebString::fromUTF8(service_instance_id), request->service_uuid,
true /* isPrimary */, request->device_id)));
pending_primary_service_requests_.Remove(request_id);
}
void BluetoothDispatcher::OnGetPrimaryServiceError(int thread_id,
int request_id,
WebBluetoothError error) {
DCHECK(pending_primary_service_requests_.Lookup(request_id)) << request_id;
pending_primary_service_requests_.Lookup(request_id)
->callbacks->onError(WebBluetoothError(error));
pending_primary_service_requests_.Remove(request_id);
}
void BluetoothDispatcher::OnGetCharacteristicSuccess(
int thread_id,
int request_id,
const std::string& characteristic_instance_id,
uint32_t characteristic_properties) {
DCHECK(pending_characteristic_requests_.Lookup(request_id)) << request_id;
BluetoothCharacteristicRequest* request =
pending_characteristic_requests_.Lookup(request_id);
request->callbacks->onSuccess(
blink::adoptWebPtr(new WebBluetoothGATTCharacteristicInit(
WebString::fromUTF8(characteristic_instance_id),
request->service_instance_id, request->characteristic_uuid,
characteristic_properties)));
pending_characteristic_requests_.Remove(request_id);
}
void BluetoothDispatcher::OnGetCharacteristicError(int thread_id,
int request_id,
WebBluetoothError error) {
DCHECK(pending_characteristic_requests_.Lookup(request_id)) << request_id;
pending_characteristic_requests_.Lookup(request_id)
->callbacks->onError(WebBluetoothError(error));
pending_characteristic_requests_.Remove(request_id);
}
void BluetoothDispatcher::OnReadValueSuccess(
int thread_id,
int request_id,
const std::vector<uint8_t>& value) {
DCHECK(pending_read_value_requests_.Lookup(request_id)) << request_id;
// WebArrayBuffer is not accessible from Source/modules so we pass a
// WebVector instead.
pending_read_value_requests_.Lookup(request_id)->onSuccess(value);
pending_read_value_requests_.Remove(request_id);
}
void BluetoothDispatcher::OnReadValueError(int thread_id,
int request_id,
WebBluetoothError error) {
DCHECK(pending_read_value_requests_.Lookup(request_id)) << request_id;
pending_read_value_requests_.Lookup(request_id)
->onError(WebBluetoothError(error));
pending_read_value_requests_.Remove(request_id);
}
void BluetoothDispatcher::OnWriteValueSuccess(int thread_id, int request_id) {
DCHECK(pending_write_value_requests_.Lookup(request_id)) << request_id;
pending_write_value_requests_.Lookup(request_id)->onSuccess();
pending_write_value_requests_.Remove(request_id);
}
void BluetoothDispatcher::OnWriteValueError(int thread_id,
int request_id,
WebBluetoothError error) {
DCHECK(pending_write_value_requests_.Lookup(request_id)) << request_id;
pending_write_value_requests_.Lookup(request_id)
->onError(WebBluetoothError(error));
pending_write_value_requests_.Remove(request_id);
}
void BluetoothDispatcher::OnStartNotificationsSuccess(int thread_id,
int request_id) {
DCHECK(pending_notifications_requests_.Lookup(request_id)) << request_id;
BluetoothNotificationsRequest* request =
pending_notifications_requests_.Lookup(request_id);
DCHECK(notification_requests_queues_[request->characteristic_instance_id]
.front() == request_id);
// We only send an IPC for inactive notifications.
DCHECK(
!HasActiveNotificationSubscription(request->characteristic_instance_id));
AddToActiveNotificationSubscriptions(request->characteristic_instance_id,
request->characteristic);
// The object requesting the notification could have been destroyed
// while waiting for the subscription. characteristicRemoved
// nulls the characteristic when the corresponding js object gets destroyed.
// A Stop request must be issued as the subscription is no longer needed.
// The Stop requets is added to the end of the queue in case another
// Start request exists in the queue from another characteristic object,
// which would result in the subscription continuing.
if (request->characteristic == nullptr) {
QueueNotificationRequest(
request->characteristic_instance_id, nullptr /* characteristic */,
nullptr /* callbacks */, NotificationsRequestType::STOP);
}
request->callbacks->onSuccess();
PopNotificationRequestQueueAndProcessNext(request_id);
}
void BluetoothDispatcher::OnStartNotificationsError(int thread_id,
int request_id,
WebBluetoothError error) {
DCHECK(pending_notifications_requests_.Lookup(request_id)) << request_id;
BluetoothNotificationsRequest* request =
pending_notifications_requests_.Lookup(request_id);
DCHECK(notification_requests_queues_[request->characteristic_instance_id]
.front() == request_id);
// We only send an IPC for inactive notifications.
DCHECK(
!HasActiveNotificationSubscription(request->characteristic_instance_id));
request->callbacks->onError(error);
PopNotificationRequestQueueAndProcessNext(request_id);
}
void BluetoothDispatcher::OnStopNotificationsSuccess(int thread_id,
int request_id) {
DCHECK(pending_notifications_requests_.Lookup(request_id)) << request_id;
BluetoothNotificationsRequest* request =
pending_notifications_requests_.Lookup(request_id);
DCHECK(notification_requests_queues_[request->characteristic_instance_id]
.front() == request_id);
// We only send an IPC for inactive notifications.
DCHECK(
!HasActiveNotificationSubscription(request->characteristic_instance_id));
if (request->callbacks != nullptr) {
request->callbacks->onSuccess();
}
PopNotificationRequestQueueAndProcessNext(request_id);
}
void BluetoothDispatcher::OnCharacteristicValueChanged(
int thread_id,
const std::string& characteristic_instance_id,
const std::vector<uint8_t> new_value) {
auto active_iter = active_characteristics_.find(characteristic_instance_id);
if (active_iter != active_characteristics_.end()) {
active_iter->second->dispatchCharacteristicValueChanged(new_value);
}
}
} // namespace content