| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 
|  | 2 // Use of this source code is governed by a BSD-style license that can be | 
|  | 3 // found in the LICENSE file. | 
|  | 4 | 
|  | 5 #include "modules/bluetooth/BluetoothRemoteGATTDescriptor.h" | 
|  | 6 | 
|  | 7 #include "bindings/core/v8/CallbackPromiseAdapter.h" | 
|  | 8 #include "bindings/core/v8/ScriptPromise.h" | 
|  | 9 #include "bindings/core/v8/ScriptPromiseResolver.h" | 
|  | 10 #include "core/dom/DOMDataView.h" | 
|  | 11 #include "core/dom/DOMException.h" | 
|  | 12 #include "core/dom/ExceptionCode.h" | 
|  | 13 #include "core/events/Event.h" | 
|  | 14 #include "core/inspector/ConsoleMessage.h" | 
|  | 15 #include "modules/bluetooth/BluetoothError.h" | 
|  | 16 #include "modules/bluetooth/BluetoothRemoteGATTService.h" | 
|  | 17 #include "modules/bluetooth/BluetoothSupplement.h" | 
|  | 18 #include "public/platform/modules/bluetooth/WebBluetooth.h" | 
|  | 19 #include <memory> | 
|  | 20 | 
|  | 21 namespace blink { | 
|  | 22 | 
|  | 23 namespace { | 
|  | 24 | 
|  | 25 // TODO dft move to some utility! | 
|  | 26 | 
|  | 27 const char kGATTServerDisconnected[] = | 
|  | 28     "GATT Server disconnected while performing a GATT operation."; | 
|  | 29 const char kGATTServerNotConnected[] = | 
|  | 30     "GATT Server is disconnected. Cannot perform GATT operations."; | 
|  | 31 | 
|  | 32 DOMDataView* ConvertWebVectorToDataView(const WebVector<uint8_t>& webVector) { | 
|  | 33   static_assert(sizeof(*webVector.data()) == 1, | 
|  | 34                 "uint8_t should be a single byte"); | 
|  | 35   DOMArrayBuffer* domBuffer = | 
|  | 36       DOMArrayBuffer::create(webVector.data(), webVector.size()); | 
|  | 37   return DOMDataView::create(domBuffer, 0, webVector.size()); | 
|  | 38 } | 
|  | 39 | 
|  | 40 }  // anonymous namespace | 
|  | 41 | 
|  | 42 BluetoothRemoteGATTDescriptor::BluetoothRemoteGATTDescriptor( | 
|  | 43     ExecutionContext* context, | 
|  | 44     std::unique_ptr<WebBluetoothRemoteGATTDescriptorInit> webDescriptor, | 
|  | 45     BluetoothRemoteGATTService* service) | 
|  | 46     : ActiveDOMObject(context), | 
|  | 47       m_webDescriptor(std::move(webDescriptor)), | 
|  | 48       m_service(service), | 
|  | 49       m_stopped(false) { | 
|  | 50   // See example in Source/platform/heap/ThreadState.h | 
|  | 51   ThreadState::current()->registerPreFinalizer(this); | 
|  | 52 } | 
|  | 53 | 
|  | 54 BluetoothRemoteGATTDescriptor* BluetoothRemoteGATTDescriptor::take( | 
|  | 55     ScriptPromiseResolver* resolver, | 
|  | 56     std::unique_ptr<WebBluetoothRemoteGATTDescriptorInit> webDescriptor, | 
|  | 57     BluetoothRemoteGATTService* service) { | 
|  | 58   if (!webDescriptor) { | 
|  | 59     return nullptr; | 
|  | 60   } | 
|  | 61   BluetoothRemoteGATTDescriptor* descriptor = new BluetoothRemoteGATTDescriptor( | 
|  | 62       resolver->getExecutionContext(), std::move(webDescriptor), service); | 
|  | 63   // See note in ActiveDOMObject about suspendIfNeeded. | 
|  | 64   descriptor->suspendIfNeeded(); | 
|  | 65   return descriptor; | 
|  | 66 } | 
|  | 67 | 
|  | 68 void BluetoothRemoteGATTDescriptor::setValue(DOMDataView* domDataView) { | 
|  | 69   m_value = domDataView; | 
|  | 70 } | 
|  | 71 | 
|  | 72 void BluetoothRemoteGATTDescriptor::dispatchDescriptorValueChanged( | 
|  | 73     const WebVector<uint8_t>& value) { | 
|  | 74   this->setValue(ConvertWebVectorToDataView(value)); | 
|  | 75   dispatchEvent(Event::create(EventTypeNames::descriptorvaluechanged)); | 
|  | 76 } | 
|  | 77 | 
|  | 78 void BluetoothRemoteGATTDescriptor::contextDestroyed() { | 
|  | 79   notifyDescriptorObjectRemoved(); | 
|  | 80 } | 
|  | 81 | 
|  | 82 void BluetoothRemoteGATTDescriptor::dispose() { | 
|  | 83   notifyDescriptorObjectRemoved(); | 
|  | 84 } | 
|  | 85 | 
|  | 86 void BluetoothRemoteGATTDescriptor::notifyDescriptorObjectRemoved() { | 
|  | 87   if (!m_stopped) { | 
|  | 88     m_stopped = true; | 
|  | 89     WebBluetooth* webbluetooth = BluetoothSupplement::fromExecutionContext( | 
|  | 90         ActiveDOMObject::getExecutionContext()); | 
|  | 91     webbluetooth->descriptorObjectRemoved(m_webDescriptor->descriptorInstanceID, | 
|  | 92                                           this); | 
|  | 93   } | 
|  | 94 } | 
|  | 95 | 
|  | 96 const WTF::AtomicString& BluetoothRemoteGATTDescriptor::interfaceName() const { | 
|  | 97   return EventTargetNames::BluetoothRemoteGATTDescriptor; | 
|  | 98 } | 
|  | 99 | 
|  | 100 ExecutionContext* BluetoothRemoteGATTDescriptor::getExecutionContext() const { | 
|  | 101   return ActiveDOMObject::getExecutionContext(); | 
|  | 102 } | 
|  | 103 | 
|  | 104 void BluetoothRemoteGATTDescriptor::addedEventListener( | 
|  | 105     const AtomicString& eventType, | 
|  | 106     RegisteredEventListener& registeredListener) { | 
|  | 107   EventTargetWithInlineData::addedEventListener(eventType, registeredListener); | 
|  | 108   // We will also need to unregister a descriptor once all the event | 
|  | 109   // listeners have been removed. See http://crbug.com/541390 | 
|  | 110   if (eventType == EventTypeNames::descriptorvaluechanged) { | 
|  | 111     WebBluetooth* webbluetooth = | 
|  | 112         BluetoothSupplement::fromExecutionContext(getExecutionContext()); | 
|  | 113     webbluetooth->registerDescriptorObject( | 
|  | 114         m_webDescriptor->descriptorInstanceID, this); | 
|  | 115   } | 
|  | 116 } | 
|  | 117 | 
|  | 118 // TODO dft -- can we move out into a utility | 
|  | 119 class ReadValueCallback : public WebBluetoothReadValueCallbacks { | 
|  | 120  public: | 
|  | 121   ReadValueCallback(BluetoothRemoteGATTDescriptor* descriptor, | 
|  | 122                     ScriptPromiseResolver* resolver) | 
|  | 123       : m_descriptor(descriptor), m_resolver(resolver) { | 
|  | 124     // We always check that the device is connected before constructing this | 
|  | 125     // object. | 
|  | 126     CHECK(m_descriptor->gatt()->connected()); | 
|  | 127     m_descriptor->gatt()->AddToActiveAlgorithms(m_resolver.get()); | 
|  | 128   } | 
|  | 129 | 
|  | 130   void onSuccess(const WebVector<uint8_t>& value) override { | 
|  | 131     if (!m_resolver->getExecutionContext() || | 
|  | 132         m_resolver->getExecutionContext()->activeDOMObjectsAreStopped()) | 
|  | 133       return; | 
|  | 134 | 
|  | 135     if (!m_descriptor->gatt()->RemoveFromActiveAlgorithms(m_resolver.get())) { | 
|  | 136       m_resolver->reject( | 
|  | 137           DOMException::create(NetworkError, kGATTServerDisconnected)); | 
|  | 138       return; | 
|  | 139     } | 
|  | 140 | 
|  | 141     DOMDataView* domDataView = ConvertWebVectorToDataView(value); | 
|  | 142     if (m_descriptor) | 
|  | 143       m_descriptor->setValue(domDataView); | 
|  | 144 | 
|  | 145     m_resolver->resolve(domDataView); | 
|  | 146   } | 
|  | 147 | 
|  | 148   void onError( | 
|  | 149       int32_t | 
|  | 150           error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */) | 
|  | 151       override { | 
|  | 152     if (!m_resolver->getExecutionContext() || | 
|  | 153         m_resolver->getExecutionContext()->activeDOMObjectsAreStopped()) | 
|  | 154       return; | 
|  | 155 | 
|  | 156     if (!m_descriptor->gatt()->RemoveFromActiveAlgorithms(m_resolver.get())) { | 
|  | 157       m_resolver->reject( | 
|  | 158           DOMException::create(NetworkError, kGATTServerDisconnected)); | 
|  | 159       return; | 
|  | 160     } | 
|  | 161 | 
|  | 162     m_resolver->reject(BluetoothError::take(m_resolver, error)); | 
|  | 163   } | 
|  | 164 | 
|  | 165  private: | 
|  | 166   WeakPersistent<BluetoothRemoteGATTDescriptor> m_descriptor; | 
|  | 167   Persistent<ScriptPromiseResolver> m_resolver; | 
|  | 168 }; | 
|  | 169 | 
|  | 170 ScriptPromise BluetoothRemoteGATTDescriptor::readValue( | 
|  | 171     ScriptState* scriptState) { | 
|  | 172   if (!gatt()->connected()) { | 
|  | 173     return ScriptPromise::rejectWithDOMException( | 
|  | 174         scriptState, | 
|  | 175         DOMException::create(NetworkError, kGATTServerNotConnected)); | 
|  | 176   } | 
|  | 177 | 
|  | 178   WebBluetooth* webbluetooth = | 
|  | 179       BluetoothSupplement::fromScriptState(scriptState); | 
|  | 180 | 
|  | 181   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 
|  | 182   ScriptPromise promise = resolver->promise(); | 
|  | 183 | 
|  | 184   webbluetooth->descriptorReadValue(m_webDescriptor->descriptorInstanceID, | 
|  | 185                                     new ReadValueCallback(this, resolver)); | 
|  | 186   return promise; | 
|  | 187 } | 
|  | 188 | 
|  | 189 class WriteValueCallback : public WebBluetoothWriteValueCallbacks { | 
|  | 190  public: | 
|  | 191   WriteValueCallback(BluetoothRemoteGATTDescriptor* descriptor, | 
|  | 192                      ScriptPromiseResolver* resolver) | 
|  | 193       : m_webDescriptor(descriptor), m_resolver(resolver) {} | 
|  | 194 | 
|  | 195   void onSuccess(const WebVector<uint8_t>& value) override { | 
|  | 196     if (!m_resolver->getExecutionContext() || | 
|  | 197         m_resolver->getExecutionContext()->activeDOMObjectsAreStopped()) | 
|  | 198       return; | 
|  | 199 | 
|  | 200     if (m_webDescriptor) { | 
|  | 201       m_webDescriptor->setValue(ConvertWebVectorToDataView(value)); | 
|  | 202     } | 
|  | 203     m_resolver->resolve(); | 
|  | 204   } | 
|  | 205 | 
|  | 206   void onError( | 
|  | 207       int32_t | 
|  | 208           error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */) | 
|  | 209       override { | 
|  | 210     if (!m_resolver->getExecutionContext() || | 
|  | 211         m_resolver->getExecutionContext()->activeDOMObjectsAreStopped()) | 
|  | 212       return; | 
|  | 213     m_resolver->reject(BluetoothError::take(m_resolver, error)); | 
|  | 214   } | 
|  | 215 | 
|  | 216  private: | 
|  | 217   WeakPersistent<BluetoothRemoteGATTDescriptor> m_webDescriptor; | 
|  | 218   Persistent<ScriptPromiseResolver> m_resolver; | 
|  | 219 }; | 
|  | 220 | 
|  | 221 ScriptPromise BluetoothRemoteGATTDescriptor::writeValue( | 
|  | 222     ScriptState* scriptState, | 
|  | 223     const DOMArrayPiece& value) { | 
|  | 224   WebBluetooth* webbluetooth = | 
|  | 225       BluetoothSupplement::fromScriptState(scriptState); | 
|  | 226 | 
|  | 227   // Partial implementation of writeValue algorithm: | 
|  | 228   // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothgattdescri
     ptor-writevalue | 
|  | 229 | 
|  | 230   // If bytes is more than 512 bytes long (the maximum length of an attribute | 
|  | 231   // value, per Long Attribute Values) return a promise rejected with an | 
|  | 232   // InvalidModificationError and abort. | 
|  | 233   if (value.byteLength() > 512) { | 
|  | 234     return ScriptPromise::rejectWithDOMException( | 
|  | 235         scriptState, DOMException::create(InvalidModificationError, | 
|  | 236                                           "Value can't exceed 512 bytes.")); | 
|  | 237   } | 
|  | 238 | 
|  | 239   // Let valueVector be a copy of the bytes held by value. | 
|  | 240   WebVector<uint8_t> valueVector(value.bytes(), value.byteLength()); | 
|  | 241 | 
|  | 242   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 
|  | 243 | 
|  | 244   ScriptPromise promise = resolver->promise(); | 
|  | 245   webbluetooth->descriptorWriteValue(m_webDescriptor->descriptorInstanceID, | 
|  | 246                                      valueVector, | 
|  | 247                                      new WriteValueCallback(this, resolver)); | 
|  | 248 | 
|  | 249   return promise; | 
|  | 250 } | 
|  | 251 | 
|  | 252 DEFINE_TRACE(BluetoothRemoteGATTDescriptor) { | 
|  | 253   visitor->trace(m_service); | 
|  | 254   visitor->trace(m_characteristic); | 
|  | 255   visitor->trace(m_value); | 
|  | 256   EventTargetWithInlineData::trace(visitor); | 
|  | 257   ActiveDOMObject::trace(visitor); | 
|  | 258 } | 
|  | 259 | 
|  | 260 }  // namespace blink | 
| OLD | NEW | 
|---|