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

Unified Diff: third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.cpp

Issue 2466223002: Implement WebBluetooth getDescriptor[s] (Closed)
Patch Set: Ensure that we throw a kGattServerNotConnected error if getDescriptor[s] is called while not connec… Created 4 years, 1 month 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: third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.cpp
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5ebd7daf14252c8cd69ef80e2efa27208737c216
--- /dev/null
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.cpp
@@ -0,0 +1,260 @@
+// Copyright 2015 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 "modules/bluetooth/BluetoothRemoteGATTDescriptor.h"
+
+#include "bindings/core/v8/CallbackPromiseAdapter.h"
+#include "bindings/core/v8/ScriptPromise.h"
+#include "bindings/core/v8/ScriptPromiseResolver.h"
+#include "core/dom/DOMDataView.h"
+#include "core/dom/DOMException.h"
+#include "core/dom/ExceptionCode.h"
+#include "core/events/Event.h"
+#include "core/inspector/ConsoleMessage.h"
+#include "modules/bluetooth/BluetoothError.h"
+#include "modules/bluetooth/BluetoothRemoteGATTService.h"
+#include "modules/bluetooth/BluetoothSupplement.h"
+#include "public/platform/modules/bluetooth/WebBluetooth.h"
+#include <memory>
+
+namespace blink {
+
+namespace {
+
+// TODO dft move to some utility!
+
+const char kGATTServerDisconnected[] =
+ "GATT Server disconnected while performing a GATT operation.";
+const char kGATTServerNotConnected[] =
+ "GATT Server is disconnected. Cannot perform GATT operations.";
+
+DOMDataView* ConvertWebVectorToDataView(const WebVector<uint8_t>& webVector) {
+ static_assert(sizeof(*webVector.data()) == 1,
+ "uint8_t should be a single byte");
+ DOMArrayBuffer* domBuffer =
+ DOMArrayBuffer::create(webVector.data(), webVector.size());
+ return DOMDataView::create(domBuffer, 0, webVector.size());
+}
+
+} // anonymous namespace
+
+BluetoothRemoteGATTDescriptor::BluetoothRemoteGATTDescriptor(
+ ExecutionContext* context,
+ std::unique_ptr<WebBluetoothRemoteGATTDescriptorInit> webDescriptor,
+ BluetoothRemoteGATTService* service)
+ : ActiveDOMObject(context),
+ m_webDescriptor(std::move(webDescriptor)),
+ m_service(service),
+ m_stopped(false) {
+ // See example in Source/platform/heap/ThreadState.h
+ ThreadState::current()->registerPreFinalizer(this);
+}
+
+BluetoothRemoteGATTDescriptor* BluetoothRemoteGATTDescriptor::take(
+ ScriptPromiseResolver* resolver,
+ std::unique_ptr<WebBluetoothRemoteGATTDescriptorInit> webDescriptor,
+ BluetoothRemoteGATTService* service) {
+ if (!webDescriptor) {
+ return nullptr;
+ }
+ BluetoothRemoteGATTDescriptor* descriptor = new BluetoothRemoteGATTDescriptor(
+ resolver->getExecutionContext(), std::move(webDescriptor), service);
+ // See note in ActiveDOMObject about suspendIfNeeded.
+ descriptor->suspendIfNeeded();
+ return descriptor;
+}
+
+void BluetoothRemoteGATTDescriptor::setValue(DOMDataView* domDataView) {
+ m_value = domDataView;
+}
+
+void BluetoothRemoteGATTDescriptor::dispatchDescriptorValueChanged(
+ const WebVector<uint8_t>& value) {
+ this->setValue(ConvertWebVectorToDataView(value));
+ dispatchEvent(Event::create(EventTypeNames::descriptorvaluechanged));
+}
+
+void BluetoothRemoteGATTDescriptor::contextDestroyed() {
+ notifyDescriptorObjectRemoved();
+}
+
+void BluetoothRemoteGATTDescriptor::dispose() {
+ notifyDescriptorObjectRemoved();
+}
+
+void BluetoothRemoteGATTDescriptor::notifyDescriptorObjectRemoved() {
+ if (!m_stopped) {
+ m_stopped = true;
+ WebBluetooth* webbluetooth = BluetoothSupplement::fromExecutionContext(
+ ActiveDOMObject::getExecutionContext());
+ webbluetooth->descriptorObjectRemoved(m_webDescriptor->descriptorInstanceID,
+ this);
+ }
+}
+
+const WTF::AtomicString& BluetoothRemoteGATTDescriptor::interfaceName() const {
+ return EventTargetNames::BluetoothRemoteGATTDescriptor;
+}
+
+ExecutionContext* BluetoothRemoteGATTDescriptor::getExecutionContext() const {
+ return ActiveDOMObject::getExecutionContext();
+}
+
+void BluetoothRemoteGATTDescriptor::addedEventListener(
+ const AtomicString& eventType,
+ RegisteredEventListener& registeredListener) {
+ EventTargetWithInlineData::addedEventListener(eventType, registeredListener);
+ // We will also need to unregister a descriptor once all the event
+ // listeners have been removed. See http://crbug.com/541390
+ if (eventType == EventTypeNames::descriptorvaluechanged) {
+ WebBluetooth* webbluetooth =
+ BluetoothSupplement::fromExecutionContext(getExecutionContext());
+ webbluetooth->registerDescriptorObject(
+ m_webDescriptor->descriptorInstanceID, this);
+ }
+}
+
+// TODO dft -- can we move out into a utility
+class ReadValueCallback : public WebBluetoothReadValueCallbacks {
+ public:
+ ReadValueCallback(BluetoothRemoteGATTDescriptor* descriptor,
+ ScriptPromiseResolver* resolver)
+ : m_descriptor(descriptor), m_resolver(resolver) {
+ // We always check that the device is connected before constructing this
+ // object.
+ CHECK(m_descriptor->gatt()->connected());
+ m_descriptor->gatt()->AddToActiveAlgorithms(m_resolver.get());
+ }
+
+ void onSuccess(const WebVector<uint8_t>& value) override {
+ if (!m_resolver->getExecutionContext() ||
+ m_resolver->getExecutionContext()->activeDOMObjectsAreStopped())
+ return;
+
+ if (!m_descriptor->gatt()->RemoveFromActiveAlgorithms(m_resolver.get())) {
+ m_resolver->reject(
+ DOMException::create(NetworkError, kGATTServerDisconnected));
+ return;
+ }
+
+ DOMDataView* domDataView = ConvertWebVectorToDataView(value);
+ if (m_descriptor)
+ m_descriptor->setValue(domDataView);
+
+ m_resolver->resolve(domDataView);
+ }
+
+ void onError(
+ int32_t
+ error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */)
+ override {
+ if (!m_resolver->getExecutionContext() ||
+ m_resolver->getExecutionContext()->activeDOMObjectsAreStopped())
+ return;
+
+ if (!m_descriptor->gatt()->RemoveFromActiveAlgorithms(m_resolver.get())) {
+ m_resolver->reject(
+ DOMException::create(NetworkError, kGATTServerDisconnected));
+ return;
+ }
+
+ m_resolver->reject(BluetoothError::take(m_resolver, error));
+ }
+
+ private:
+ WeakPersistent<BluetoothRemoteGATTDescriptor> m_descriptor;
+ Persistent<ScriptPromiseResolver> m_resolver;
+};
+
+ScriptPromise BluetoothRemoteGATTDescriptor::readValue(
+ ScriptState* scriptState) {
+ if (!gatt()->connected()) {
+ return ScriptPromise::rejectWithDOMException(
+ scriptState,
+ DOMException::create(NetworkError, kGATTServerNotConnected));
+ }
+
+ WebBluetooth* webbluetooth =
+ BluetoothSupplement::fromScriptState(scriptState);
+
+ ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
+ ScriptPromise promise = resolver->promise();
+
+ webbluetooth->descriptorReadValue(m_webDescriptor->descriptorInstanceID,
+ new ReadValueCallback(this, resolver));
+ return promise;
+}
+
+class WriteValueCallback : public WebBluetoothWriteValueCallbacks {
+ public:
+ WriteValueCallback(BluetoothRemoteGATTDescriptor* descriptor,
+ ScriptPromiseResolver* resolver)
+ : m_webDescriptor(descriptor), m_resolver(resolver) {}
+
+ void onSuccess(const WebVector<uint8_t>& value) override {
+ if (!m_resolver->getExecutionContext() ||
+ m_resolver->getExecutionContext()->activeDOMObjectsAreStopped())
+ return;
+
+ if (m_webDescriptor) {
+ m_webDescriptor->setValue(ConvertWebVectorToDataView(value));
+ }
+ m_resolver->resolve();
+ }
+
+ void onError(
+ int32_t
+ error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */)
+ override {
+ if (!m_resolver->getExecutionContext() ||
+ m_resolver->getExecutionContext()->activeDOMObjectsAreStopped())
+ return;
+ m_resolver->reject(BluetoothError::take(m_resolver, error));
+ }
+
+ private:
+ WeakPersistent<BluetoothRemoteGATTDescriptor> m_webDescriptor;
+ Persistent<ScriptPromiseResolver> m_resolver;
+};
+
+ScriptPromise BluetoothRemoteGATTDescriptor::writeValue(
+ ScriptState* scriptState,
+ const DOMArrayPiece& value) {
+ WebBluetooth* webbluetooth =
+ BluetoothSupplement::fromScriptState(scriptState);
+
+ // Partial implementation of writeValue algorithm:
+ // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothgattdescriptor-writevalue
+
+ // If bytes is more than 512 bytes long (the maximum length of an attribute
+ // value, per Long Attribute Values) return a promise rejected with an
+ // InvalidModificationError and abort.
+ if (value.byteLength() > 512) {
+ return ScriptPromise::rejectWithDOMException(
+ scriptState, DOMException::create(InvalidModificationError,
+ "Value can't exceed 512 bytes."));
+ }
+
+ // Let valueVector be a copy of the bytes held by value.
+ WebVector<uint8_t> valueVector(value.bytes(), value.byteLength());
+
+ ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
+
+ ScriptPromise promise = resolver->promise();
+ webbluetooth->descriptorWriteValue(m_webDescriptor->descriptorInstanceID,
+ valueVector,
+ new WriteValueCallback(this, resolver));
+
+ return promise;
+}
+
+DEFINE_TRACE(BluetoothRemoteGATTDescriptor) {
+ visitor->trace(m_service);
+ visitor->trace(m_characteristic);
+ visitor->trace(m_value);
+ EventTargetWithInlineData::trace(visitor);
+ ActiveDOMObject::trace(visitor);
+}
+
+} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698