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..ddbfe71ee31d80a608ed0632631d41b08d412d70 |
--- /dev/null |
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.cpp |
@@ -0,0 +1,201 @@ |
+// Copyright 2016 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 { |
+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( |
+ std::unique_ptr<WebBluetoothRemoteGATTDescriptorInit> webDescriptor, |
+ BluetoothRemoteGATTCharacteristic* characteristic) |
+ : m_webDescriptor(std::move(webDescriptor)), |
+ m_characteristic(characteristic) {} |
+ |
+BluetoothRemoteGATTDescriptor* BluetoothRemoteGATTDescriptor::take( |
+ std::unique_ptr<WebBluetoothRemoteGATTDescriptorInit> webDescriptor, |
+ BluetoothRemoteGATTCharacteristic* characteristic) { |
+ if (!webDescriptor) { |
+ return nullptr; |
+ } |
+ BluetoothRemoteGATTDescriptor* descriptor = new BluetoothRemoteGATTDescriptor( |
+ std::move(webDescriptor), characteristic); |
+ return descriptor; |
+} |
+ |
+void BluetoothRemoteGATTDescriptor::setValue(DOMDataView* domDataView) { |
+ m_value = domDataView; |
+} |
+ |
+class DescriptorReadValueCallback : public WebBluetoothReadValueCallbacks { |
+ public: |
+ DescriptorReadValueCallback(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->getGatt()->connected()); |
+ m_descriptor->getGatt()->AddToActiveAlgorithms(m_resolver.get()); |
+ } |
+ |
+ void onSuccess(const WebVector<uint8_t>& value) override { |
+ if (!m_resolver->getExecutionContext() || |
+ m_resolver->getExecutionContext()->activeDOMObjectsAreStopped()) |
+ return; |
+ |
+ if (!m_descriptor->getGatt()->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->getGatt()->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 (!getGatt()->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 DescriptorReadValueCallback(this, resolver)); |
+ return promise; |
+} |
+ |
+class DescriptorWriteValueCallback : public WebBluetoothWriteValueCallbacks { |
+ public: |
+ DescriptorWriteValueCallback(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 DescriptorWriteValueCallback(this, resolver)); |
+ |
+ return promise; |
+} |
+ |
+DEFINE_TRACE(BluetoothRemoteGATTDescriptor) { |
+ visitor->trace(m_characteristic); |
+ visitor->trace(m_value); |
+} |
+ |
+} // namespace blink |