| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "modules/bluetooth/BluetoothRemoteGATTCharacteristic.h" | 5 #include "modules/bluetooth/BluetoothRemoteGATTCharacteristic.h" |
| 6 | 6 |
| 7 #include "bindings/core/v8/ScriptPromise.h" | 7 #include "bindings/core/v8/ScriptPromise.h" |
| 8 #include "bindings/core/v8/ScriptPromiseResolver.h" | 8 #include "bindings/core/v8/ScriptPromiseResolver.h" |
| 9 #include "core/dom/DOMDataView.h" | 9 #include "core/dom/DOMDataView.h" |
| 10 #include "core/dom/DOMException.h" | 10 #include "core/dom/DOMException.h" |
| 11 #include "core/dom/ExceptionCode.h" | 11 #include "core/dom/ExceptionCode.h" |
| 12 #include "core/events/Event.h" | 12 #include "core/events/Event.h" |
| 13 #include "core/inspector/ConsoleMessage.h" | 13 #include "core/inspector/ConsoleMessage.h" |
| 14 #include "modules/bluetooth/Bluetooth.h" |
| 14 #include "modules/bluetooth/BluetoothCharacteristicProperties.h" | 15 #include "modules/bluetooth/BluetoothCharacteristicProperties.h" |
| 16 #include "modules/bluetooth/BluetoothDevice.h" |
| 15 #include "modules/bluetooth/BluetoothError.h" | 17 #include "modules/bluetooth/BluetoothError.h" |
| 16 #include "modules/bluetooth/BluetoothRemoteGATTService.h" | 18 #include "modules/bluetooth/BluetoothRemoteGATTService.h" |
| 17 #include "modules/bluetooth/BluetoothSupplement.h" | |
| 18 #include "public/platform/modules/bluetooth/WebBluetooth.h" | |
| 19 #include <memory> | 19 #include <memory> |
| 20 | 20 |
| 21 namespace blink { | 21 namespace blink { |
| 22 | 22 |
| 23 namespace { | 23 namespace { |
| 24 | 24 |
| 25 const char kGATTServerDisconnected[] = | 25 const char kGATTServerDisconnected[] = |
| 26 "GATT Server disconnected while performing a GATT operation."; | 26 "GATT Server disconnected while performing a GATT operation."; |
| 27 const char kGATTServerNotConnected[] = | 27 const char kGATTServerNotConnected[] = |
| 28 "GATT Server is disconnected. Cannot perform GATT operations."; | 28 "GATT Server is disconnected. Cannot perform GATT operations."; |
| 29 const char kInvalidCharacteristic[] = | 29 const char kInvalidCharacteristic[] = |
| 30 "Characteristic is no longer valid. Remember to retrieve the " | 30 "Characteristic is no longer valid. Remember to retrieve the " |
| 31 "characteristic again after reconnecting."; | 31 "characteristic again after reconnecting."; |
| 32 | 32 |
| 33 DOMDataView* ConvertWebVectorToDataView(const WebVector<uint8_t>& webVector) { | 33 DOMDataView* ConvertWTFVectorToDataView(const Vector<uint8_t>& wtfVector) { |
| 34 static_assert(sizeof(*webVector.data()) == 1, | 34 static_assert(sizeof(*wtfVector.data()) == 1, |
| 35 "uint8_t should be a single byte"); | 35 "uint8_t should be a single byte"); |
| 36 DOMArrayBuffer* domBuffer = | 36 DOMArrayBuffer* domBuffer = |
| 37 DOMArrayBuffer::create(webVector.data(), webVector.size()); | 37 DOMArrayBuffer::create(wtfVector.data(), wtfVector.size()); |
| 38 return DOMDataView::create(domBuffer, 0, webVector.size()); | 38 return DOMDataView::create(domBuffer, 0, wtfVector.size()); |
| 39 } | 39 } |
| 40 | 40 |
| 41 } // anonymous namespace | 41 } // anonymous namespace |
| 42 | 42 |
| 43 BluetoothRemoteGATTCharacteristic::BluetoothRemoteGATTCharacteristic( | 43 BluetoothRemoteGATTCharacteristic::BluetoothRemoteGATTCharacteristic( |
| 44 ExecutionContext* context, | 44 ExecutionContext* context, |
| 45 std::unique_ptr<WebBluetoothRemoteGATTCharacteristicInit> webCharacteristic, | 45 const String& characteristicInstanceId, |
| 46 BluetoothRemoteGATTService* service) | 46 const String& serviceInstanceId, |
| 47 const String& uuid, |
| 48 uint32_t characteristicProperties, |
| 49 BluetoothRemoteGATTService* service, |
| 50 BluetoothDevice* device) |
| 47 : ContextLifecycleObserver(context), | 51 : ContextLifecycleObserver(context), |
| 48 m_webCharacteristic(std::move(webCharacteristic)), | 52 m_characteristicInstanceId(characteristicInstanceId), |
| 53 m_serviceInstanceId(serviceInstanceId), |
| 54 m_uuid(uuid), |
| 55 m_characteristicProperties(characteristicProperties), |
| 49 m_service(service), | 56 m_service(service), |
| 50 m_stopped(false) { | 57 m_stopped(false), |
| 51 m_properties = BluetoothCharacteristicProperties::create( | 58 m_device(device) { |
| 52 m_webCharacteristic->characteristicProperties); | 59 m_properties = |
| 60 BluetoothCharacteristicProperties::create(m_characteristicProperties); |
| 53 } | 61 } |
| 54 | 62 |
| 55 BluetoothRemoteGATTCharacteristic* BluetoothRemoteGATTCharacteristic::create( | 63 BluetoothRemoteGATTCharacteristic* BluetoothRemoteGATTCharacteristic::create( |
| 56 ExecutionContext* context, | 64 ExecutionContext* context, |
| 57 std::unique_ptr<WebBluetoothRemoteGATTCharacteristicInit> webCharacteristic, | 65 const String& characteristicInstanceId, |
| 58 BluetoothRemoteGATTService* service) { | 66 const String& serviceInstanceId, |
| 59 DCHECK(webCharacteristic); | 67 const String& uuid, |
| 60 | 68 uint32_t characteristicProperties, |
| 69 BluetoothRemoteGATTService* service, |
| 70 BluetoothDevice* device) { |
| 61 return new BluetoothRemoteGATTCharacteristic( | 71 return new BluetoothRemoteGATTCharacteristic( |
| 62 context, std::move(webCharacteristic), service); | 72 context, characteristicInstanceId, serviceInstanceId, uuid, |
| 73 characteristicProperties, service, device); |
| 63 } | 74 } |
| 64 | 75 |
| 65 void BluetoothRemoteGATTCharacteristic::setValue(DOMDataView* domDataView) { | 76 void BluetoothRemoteGATTCharacteristic::setValue(DOMDataView* domDataView) { |
| 66 m_value = domDataView; | 77 m_value = domDataView; |
| 67 } | 78 } |
| 68 | 79 |
| 69 void BluetoothRemoteGATTCharacteristic::dispatchCharacteristicValueChanged( | 80 void BluetoothRemoteGATTCharacteristic::dispatchCharacteristicValueChanged( |
| 70 const WebVector<uint8_t>& value) { | 81 const Vector<uint8_t>& value) { |
| 71 this->setValue(ConvertWebVectorToDataView(value)); | 82 this->setValue(ConvertWTFVectorToDataView(value)); |
| 72 dispatchEvent(Event::create(EventTypeNames::characteristicvaluechanged)); | 83 dispatchEvent(Event::create(EventTypeNames::characteristicvaluechanged)); |
| 73 } | 84 } |
| 74 | 85 |
| 75 void BluetoothRemoteGATTCharacteristic::contextDestroyed() { | 86 void BluetoothRemoteGATTCharacteristic::contextDestroyed() { |
| 76 notifyCharacteristicObjectRemoved(); | 87 notifyCharacteristicObjectRemoved(); |
| 77 } | 88 } |
| 78 | 89 |
| 79 void BluetoothRemoteGATTCharacteristic::dispose() { | 90 void BluetoothRemoteGATTCharacteristic::dispose() { |
| 80 notifyCharacteristicObjectRemoved(); | 91 notifyCharacteristicObjectRemoved(); |
| 81 } | 92 } |
| 82 | 93 |
| 83 void BluetoothRemoteGATTCharacteristic::notifyCharacteristicObjectRemoved() { | 94 void BluetoothRemoteGATTCharacteristic::notifyCharacteristicObjectRemoved() { |
| 84 if (!m_stopped) { | 95 if (!m_stopped) { |
| 85 m_stopped = true; | 96 m_stopped = true; |
| 86 WebBluetooth* webbluetooth = BluetoothSupplement::fromExecutionContext( | 97 m_device->bluetooth()->characteristicObjectRemoved( |
| 87 ContextLifecycleObserver::getExecutionContext()); | 98 m_characteristicInstanceId); |
| 88 webbluetooth->characteristicObjectRemoved( | |
| 89 m_webCharacteristic->characteristicInstanceID, this); | |
| 90 } | 99 } |
| 91 } | 100 } |
| 92 | 101 |
| 93 const WTF::AtomicString& BluetoothRemoteGATTCharacteristic::interfaceName() | 102 const WTF::AtomicString& BluetoothRemoteGATTCharacteristic::interfaceName() |
| 94 const { | 103 const { |
| 95 return EventTargetNames::BluetoothRemoteGATTCharacteristic; | 104 return EventTargetNames::BluetoothRemoteGATTCharacteristic; |
| 96 } | 105 } |
| 97 | 106 |
| 98 ExecutionContext* BluetoothRemoteGATTCharacteristic::getExecutionContext() | 107 ExecutionContext* BluetoothRemoteGATTCharacteristic::getExecutionContext() |
| 99 const { | 108 const { |
| 100 return ContextLifecycleObserver::getExecutionContext(); | 109 return ContextLifecycleObserver::getExecutionContext(); |
| 101 } | 110 } |
| 102 | 111 |
| 103 void BluetoothRemoteGATTCharacteristic::addedEventListener( | 112 void BluetoothRemoteGATTCharacteristic::addedEventListener( |
| 104 const AtomicString& eventType, | 113 const AtomicString& eventType, |
| 105 RegisteredEventListener& registeredListener) { | 114 RegisteredEventListener& registeredListener) { |
| 106 EventTargetWithInlineData::addedEventListener(eventType, registeredListener); | 115 EventTargetWithInlineData::addedEventListener(eventType, registeredListener); |
| 107 // We will also need to unregister a characteristic once all the event | 116 // We will also need to unregister a characteristic once all the event |
| 108 // listeners have been removed. See http://crbug.com/541390 | 117 // listeners have been removed. See http://crbug.com/541390 |
| 109 if (eventType == EventTypeNames::characteristicvaluechanged) { | 118 if (eventType == EventTypeNames::characteristicvaluechanged) { |
| 110 WebBluetooth* webbluetooth = | 119 m_device->bluetooth()->registerCharacteristicObject( |
| 111 BluetoothSupplement::fromExecutionContext(getExecutionContext()); | 120 m_characteristicInstanceId, this); |
| 112 webbluetooth->registerCharacteristicObject( | |
| 113 m_webCharacteristic->characteristicInstanceID, this); | |
| 114 } | 121 } |
| 115 } | 122 } |
| 116 | 123 |
| 117 class ReadValueCallback : public WebBluetoothReadValueCallbacks { | 124 void BluetoothRemoteGATTCharacteristic::ReadValueCallback( |
| 118 public: | 125 ScriptPromiseResolver* resolver, |
| 119 ReadValueCallback(BluetoothRemoteGATTCharacteristic* characteristic, | 126 mojom::blink::WebBluetoothResult result, |
| 120 ScriptPromiseResolver* resolver) | 127 const Optional<Vector<uint8_t>>& value) { |
| 121 : m_characteristic(characteristic), m_resolver(resolver) { | 128 if (!resolver->getExecutionContext() || |
| 122 // We always check that the device is connected before constructing this | 129 resolver->getExecutionContext()->isContextDestroyed()) |
| 123 // object. | 130 return; |
| 124 CHECK(m_characteristic->gatt()->connected()); | 131 |
| 125 m_characteristic->gatt()->AddToActiveAlgorithms(m_resolver.get()); | 132 // If the resolver is not in the set of ActiveAlgorithms then the frame |
| 133 // disconnected so we reject. |
| 134 if (!gatt()->RemoveFromActiveAlgorithms(resolver)) { |
| 135 resolver->reject( |
| 136 DOMException::create(NetworkError, kGATTServerDisconnected)); |
| 137 return; |
| 126 } | 138 } |
| 127 | 139 |
| 128 void onSuccess(const WebVector<uint8_t>& value) override { | 140 if (result == mojom::blink::WebBluetoothResult::SUCCESS) { |
| 129 if (!m_resolver->getExecutionContext() || | 141 DCHECK(value); |
| 130 m_resolver->getExecutionContext()->isContextDestroyed()) | 142 DOMDataView* domDataView = ConvertWTFVectorToDataView(value.value()); |
| 131 return; | 143 setValue(domDataView); |
| 132 | 144 resolver->resolve(domDataView); |
| 133 if (!m_characteristic->gatt()->RemoveFromActiveAlgorithms( | 145 } else { |
| 134 m_resolver.get())) { | 146 resolver->reject(BluetoothError::take(resolver, result)); |
| 135 m_resolver->reject( | |
| 136 DOMException::create(NetworkError, kGATTServerDisconnected)); | |
| 137 return; | |
| 138 } | |
| 139 | |
| 140 DOMDataView* domDataView = ConvertWebVectorToDataView(value); | |
| 141 if (m_characteristic) | |
| 142 m_characteristic->setValue(domDataView); | |
| 143 | |
| 144 m_resolver->resolve(domDataView); | |
| 145 } | 147 } |
| 146 | 148 } |
| 147 void onError( | |
| 148 int32_t | |
| 149 error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */) | |
| 150 override { | |
| 151 if (!m_resolver->getExecutionContext() || | |
| 152 m_resolver->getExecutionContext()->isContextDestroyed()) | |
| 153 return; | |
| 154 | |
| 155 if (!m_characteristic->gatt()->RemoveFromActiveAlgorithms( | |
| 156 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 Persistent<BluetoothRemoteGATTCharacteristic> m_characteristic; | |
| 167 Persistent<ScriptPromiseResolver> m_resolver; | |
| 168 }; | |
| 169 | 149 |
| 170 ScriptPromise BluetoothRemoteGATTCharacteristic::readValue( | 150 ScriptPromise BluetoothRemoteGATTCharacteristic::readValue( |
| 171 ScriptState* scriptState) { | 151 ScriptState* scriptState) { |
| 152 // We always check that the device is connected. |
| 172 if (!gatt()->connected()) { | 153 if (!gatt()->connected()) { |
| 173 return ScriptPromise::rejectWithDOMException( | 154 return ScriptPromise::rejectWithDOMException( |
| 174 scriptState, | 155 scriptState, |
| 175 DOMException::create(NetworkError, kGATTServerNotConnected)); | 156 DOMException::create(NetworkError, kGATTServerNotConnected)); |
| 176 } | 157 } |
| 177 | 158 |
| 178 if (!gatt()->device()->isValidCharacteristic( | 159 if (!gatt()->device()->isValidCharacteristic(m_characteristicInstanceId)) { |
| 179 m_webCharacteristic->characteristicInstanceID)) { | |
| 180 return ScriptPromise::rejectWithDOMException( | 160 return ScriptPromise::rejectWithDOMException( |
| 181 scriptState, | 161 scriptState, |
| 182 DOMException::create(InvalidStateError, kInvalidCharacteristic)); | 162 DOMException::create(InvalidStateError, kInvalidCharacteristic)); |
| 183 } | 163 } |
| 184 | 164 |
| 185 WebBluetooth* webbluetooth = | |
| 186 BluetoothSupplement::fromScriptState(scriptState); | |
| 187 | |
| 188 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 165 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
| 189 ScriptPromise promise = resolver->promise(); | 166 ScriptPromise promise = resolver->promise(); |
| 190 webbluetooth->readValue(m_webCharacteristic->characteristicInstanceID, | 167 gatt()->AddToActiveAlgorithms(resolver); |
| 191 new ReadValueCallback(this, resolver)); | 168 |
| 169 mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service(); |
| 170 service->RemoteCharacteristicReadValue( |
| 171 m_characteristicInstanceId, |
| 172 convertToBaseCallback( |
| 173 WTF::bind(&BluetoothRemoteGATTCharacteristic::ReadValueCallback, |
| 174 wrapPersistent(this), wrapPersistent(resolver)))); |
| 192 | 175 |
| 193 return promise; | 176 return promise; |
| 194 } | 177 } |
| 195 | 178 |
| 196 class WriteValueCallback : public WebBluetoothWriteValueCallbacks { | 179 void BluetoothRemoteGATTCharacteristic::WriteValueCallback( |
| 197 public: | 180 ScriptPromiseResolver* resolver, |
| 198 WriteValueCallback(BluetoothRemoteGATTCharacteristic* characteristic, | 181 const Vector<uint8_t>& value, |
| 199 ScriptPromiseResolver* resolver) | 182 mojom::blink::WebBluetoothResult result) { |
| 200 : m_characteristic(characteristic), m_resolver(resolver) { | 183 if (!resolver->getExecutionContext() || |
| 201 // We always check that the device is connected before constructing this | 184 resolver->getExecutionContext()->isContextDestroyed()) |
| 202 // object. | 185 return; |
| 203 CHECK(m_characteristic->gatt()->connected()); | 186 |
| 204 m_characteristic->gatt()->AddToActiveAlgorithms(m_resolver.get()); | 187 // If the resolver is not in the set of ActiveAlgorithms then the frame |
| 188 // disconnected so we reject. |
| 189 if (!gatt()->RemoveFromActiveAlgorithms(resolver)) { |
| 190 resolver->reject( |
| 191 DOMException::create(NetworkError, kGATTServerDisconnected)); |
| 192 return; |
| 205 } | 193 } |
| 206 | 194 |
| 207 void onSuccess(const WebVector<uint8_t>& value) override { | 195 if (result == mojom::blink::WebBluetoothResult::SUCCESS) { |
| 208 if (!m_resolver->getExecutionContext() || | 196 setValue(ConvertWTFVectorToDataView(value)); |
| 209 m_resolver->getExecutionContext()->isContextDestroyed()) | 197 resolver->resolve(); |
| 210 return; | 198 } else { |
| 211 | 199 resolver->reject(BluetoothError::take(resolver, result)); |
| 212 if (!m_characteristic->gatt()->RemoveFromActiveAlgorithms( | |
| 213 m_resolver.get())) { | |
| 214 m_resolver->reject( | |
| 215 DOMException::create(NetworkError, kGATTServerDisconnected)); | |
| 216 return; | |
| 217 } | |
| 218 | |
| 219 if (m_characteristic) { | |
| 220 m_characteristic->setValue(ConvertWebVectorToDataView(value)); | |
| 221 } | |
| 222 m_resolver->resolve(); | |
| 223 } | 200 } |
| 224 | 201 } |
| 225 void onError( | |
| 226 int32_t | |
| 227 error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */) | |
| 228 override { | |
| 229 if (!m_resolver->getExecutionContext() || | |
| 230 m_resolver->getExecutionContext()->isContextDestroyed()) | |
| 231 return; | |
| 232 | |
| 233 if (!m_characteristic->gatt()->RemoveFromActiveAlgorithms( | |
| 234 m_resolver.get())) { | |
| 235 m_resolver->reject( | |
| 236 DOMException::create(NetworkError, kGATTServerDisconnected)); | |
| 237 return; | |
| 238 } | |
| 239 | |
| 240 m_resolver->reject(BluetoothError::take(m_resolver, error)); | |
| 241 } | |
| 242 | |
| 243 private: | |
| 244 Persistent<BluetoothRemoteGATTCharacteristic> m_characteristic; | |
| 245 Persistent<ScriptPromiseResolver> m_resolver; | |
| 246 }; | |
| 247 | 202 |
| 248 ScriptPromise BluetoothRemoteGATTCharacteristic::writeValue( | 203 ScriptPromise BluetoothRemoteGATTCharacteristic::writeValue( |
| 249 ScriptState* scriptState, | 204 ScriptState* scriptState, |
| 250 const DOMArrayPiece& value) { | 205 const DOMArrayPiece& value) { |
| 206 // We always check that the device is connected. |
| 251 if (!gatt()->connected()) { | 207 if (!gatt()->connected()) { |
| 252 return ScriptPromise::rejectWithDOMException( | 208 return ScriptPromise::rejectWithDOMException( |
| 253 scriptState, | 209 scriptState, |
| 254 DOMException::create(NetworkError, kGATTServerNotConnected)); | 210 DOMException::create(NetworkError, kGATTServerNotConnected)); |
| 255 } | 211 } |
| 256 | 212 |
| 257 if (!gatt()->device()->isValidCharacteristic( | 213 if (!gatt()->device()->isValidCharacteristic(m_characteristicInstanceId)) { |
| 258 m_webCharacteristic->characteristicInstanceID)) { | |
| 259 return ScriptPromise::rejectWithDOMException( | 214 return ScriptPromise::rejectWithDOMException( |
| 260 scriptState, | 215 scriptState, |
| 261 DOMException::create(InvalidStateError, kInvalidCharacteristic)); | 216 DOMException::create(InvalidStateError, kInvalidCharacteristic)); |
| 262 } | 217 } |
| 263 | 218 |
| 264 WebBluetooth* webbluetooth = | |
| 265 BluetoothSupplement::fromScriptState(scriptState); | |
| 266 // Partial implementation of writeValue algorithm: | 219 // Partial implementation of writeValue algorithm: |
| 267 // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattchar
acteristic-writevalue | 220 // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattchar
acteristic-writevalue |
| 268 | 221 |
| 269 // If bytes is more than 512 bytes long (the maximum length of an attribute | 222 // If bytes is more than 512 bytes long (the maximum length of an attribute |
| 270 // value, per Long Attribute Values) return a promise rejected with an | 223 // value, per Long Attribute Values) return a promise rejected with an |
| 271 // InvalidModificationError and abort. | 224 // InvalidModificationError and abort. |
| 272 if (value.byteLength() > 512) | 225 if (value.byteLength() > 512) |
| 273 return ScriptPromise::rejectWithDOMException( | 226 return ScriptPromise::rejectWithDOMException( |
| 274 scriptState, DOMException::create(InvalidModificationError, | 227 scriptState, DOMException::create(InvalidModificationError, |
| 275 "Value can't exceed 512 bytes.")); | 228 "Value can't exceed 512 bytes.")); |
| 276 | 229 |
| 277 // Let valueVector be a copy of the bytes held by value. | 230 // Let valueVector be a copy of the bytes held by value. |
| 278 WebVector<uint8_t> valueVector(value.bytes(), value.byteLength()); | 231 Vector<uint8_t> valueVector; |
| 232 valueVector.append(value.bytes(), value.byteLength()); |
| 279 | 233 |
| 280 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 234 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
| 235 ScriptPromise promise = resolver->promise(); |
| 236 gatt()->AddToActiveAlgorithms(resolver); |
| 281 | 237 |
| 282 ScriptPromise promise = resolver->promise(); | 238 mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service(); |
| 283 webbluetooth->writeValue(m_webCharacteristic->characteristicInstanceID, | 239 service->RemoteCharacteristicWriteValue( |
| 284 valueVector, new WriteValueCallback(this, resolver)); | 240 m_characteristicInstanceId, valueVector, |
| 241 convertToBaseCallback(WTF::bind( |
| 242 &BluetoothRemoteGATTCharacteristic::WriteValueCallback, |
| 243 wrapPersistent(this), wrapPersistent(resolver), valueVector))); |
| 285 | 244 |
| 286 return promise; | 245 return promise; |
| 287 } | 246 } |
| 288 | 247 |
| 289 class NotificationsCallback : public WebBluetoothNotificationsCallbacks { | 248 void BluetoothRemoteGATTCharacteristic::NotificationsCallback( |
| 290 public: | 249 ScriptPromiseResolver* resolver, |
| 291 NotificationsCallback(BluetoothRemoteGATTCharacteristic* characteristic, | 250 mojom::blink::WebBluetoothResult result) { |
| 292 ScriptPromiseResolver* resolver) | 251 if (!resolver->getExecutionContext() || |
| 293 : m_characteristic(characteristic), m_resolver(resolver) { | 252 resolver->getExecutionContext()->isContextDestroyed()) |
| 294 // We always check that the device is connected before constructing this | 253 return; |
| 295 // object. | 254 |
| 296 CHECK(m_characteristic->gatt()->connected()); | 255 // If the resolver is not in the set of ActiveAlgorithms then the frame |
| 297 m_characteristic->gatt()->AddToActiveAlgorithms(m_resolver.get()); | 256 // disconnected so we reject. |
| 257 if (!gatt()->RemoveFromActiveAlgorithms(resolver)) { |
| 258 resolver->reject( |
| 259 DOMException::create(NetworkError, kGATTServerDisconnected)); |
| 260 return; |
| 298 } | 261 } |
| 299 | 262 |
| 300 void onSuccess() override { | 263 if (result == mojom::blink::WebBluetoothResult::SUCCESS) { |
| 301 if (!m_resolver->getExecutionContext() || | 264 resolver->resolve(this); |
| 302 m_resolver->getExecutionContext()->isContextDestroyed()) | 265 } else { |
| 303 return; | 266 resolver->reject(BluetoothError::take(resolver, result)); |
| 304 | |
| 305 if (!m_characteristic->gatt()->RemoveFromActiveAlgorithms( | |
| 306 m_resolver.get())) { | |
| 307 m_resolver->reject( | |
| 308 DOMException::create(NetworkError, kGATTServerDisconnected)); | |
| 309 return; | |
| 310 } | |
| 311 | |
| 312 m_resolver->resolve(m_characteristic); | |
| 313 } | 267 } |
| 314 | 268 } |
| 315 void onError( | |
| 316 int32_t | |
| 317 error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */) | |
| 318 override { | |
| 319 if (!m_resolver->getExecutionContext() || | |
| 320 m_resolver->getExecutionContext()->isContextDestroyed()) | |
| 321 return; | |
| 322 | |
| 323 if (!m_characteristic->gatt()->RemoveFromActiveAlgorithms( | |
| 324 m_resolver.get())) { | |
| 325 m_resolver->reject( | |
| 326 DOMException::create(NetworkError, kGATTServerDisconnected)); | |
| 327 return; | |
| 328 } | |
| 329 | |
| 330 m_resolver->reject(BluetoothError::take(m_resolver, error)); | |
| 331 } | |
| 332 | |
| 333 private: | |
| 334 Persistent<BluetoothRemoteGATTCharacteristic> m_characteristic; | |
| 335 Persistent<ScriptPromiseResolver> m_resolver; | |
| 336 }; | |
| 337 | 269 |
| 338 ScriptPromise BluetoothRemoteGATTCharacteristic::startNotifications( | 270 ScriptPromise BluetoothRemoteGATTCharacteristic::startNotifications( |
| 339 ScriptState* scriptState) { | 271 ScriptState* scriptState) { |
| 272 // We always check that the device is connected. |
| 340 if (!gatt()->connected()) { | 273 if (!gatt()->connected()) { |
| 341 return ScriptPromise::rejectWithDOMException( | 274 return ScriptPromise::rejectWithDOMException( |
| 342 scriptState, | 275 scriptState, |
| 343 DOMException::create(NetworkError, kGATTServerNotConnected)); | 276 DOMException::create(NetworkError, kGATTServerNotConnected)); |
| 344 } | 277 } |
| 345 | 278 |
| 346 if (!gatt()->device()->isValidCharacteristic( | 279 if (!gatt()->device()->isValidCharacteristic(m_characteristicInstanceId)) { |
| 347 m_webCharacteristic->characteristicInstanceID)) { | |
| 348 return ScriptPromise::rejectWithDOMException( | 280 return ScriptPromise::rejectWithDOMException( |
| 349 scriptState, | 281 scriptState, |
| 350 DOMException::create(InvalidStateError, kInvalidCharacteristic)); | 282 DOMException::create(InvalidStateError, kInvalidCharacteristic)); |
| 351 } | 283 } |
| 352 | 284 |
| 353 WebBluetooth* webbluetooth = | |
| 354 BluetoothSupplement::fromScriptState(scriptState); | |
| 355 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 285 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
| 356 ScriptPromise promise = resolver->promise(); | 286 ScriptPromise promise = resolver->promise(); |
| 357 webbluetooth->startNotifications( | 287 gatt()->AddToActiveAlgorithms(resolver); |
| 358 m_webCharacteristic->characteristicInstanceID, | 288 |
| 359 new NotificationsCallback(this, resolver)); | 289 mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service(); |
| 290 service->RemoteCharacteristicStartNotifications( |
| 291 m_characteristicInstanceId, |
| 292 convertToBaseCallback( |
| 293 WTF::bind(&BluetoothRemoteGATTCharacteristic::NotificationsCallback, |
| 294 wrapPersistent(this), wrapPersistent(resolver)))); |
| 295 |
| 360 return promise; | 296 return promise; |
| 361 } | 297 } |
| 362 | 298 |
| 363 ScriptPromise BluetoothRemoteGATTCharacteristic::stopNotifications( | 299 ScriptPromise BluetoothRemoteGATTCharacteristic::stopNotifications( |
| 364 ScriptState* scriptState) { | 300 ScriptState* scriptState) { |
| 301 // We always check that the device is connected. |
| 365 if (!gatt()->connected()) { | 302 if (!gatt()->connected()) { |
| 366 return ScriptPromise::rejectWithDOMException( | 303 return ScriptPromise::rejectWithDOMException( |
| 367 scriptState, | 304 scriptState, |
| 368 DOMException::create(NetworkError, kGATTServerNotConnected)); | 305 DOMException::create(NetworkError, kGATTServerNotConnected)); |
| 369 } | 306 } |
| 370 | 307 |
| 371 if (!gatt()->device()->isValidCharacteristic( | 308 if (!gatt()->device()->isValidCharacteristic(m_characteristicInstanceId)) { |
| 372 m_webCharacteristic->characteristicInstanceID)) { | |
| 373 return ScriptPromise::rejectWithDOMException( | 309 return ScriptPromise::rejectWithDOMException( |
| 374 scriptState, | 310 scriptState, |
| 375 DOMException::create(InvalidStateError, kInvalidCharacteristic)); | 311 DOMException::create(InvalidStateError, kInvalidCharacteristic)); |
| 376 } | 312 } |
| 377 | 313 |
| 378 WebBluetooth* webbluetooth = | |
| 379 BluetoothSupplement::fromScriptState(scriptState); | |
| 380 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 314 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
| 381 ScriptPromise promise = resolver->promise(); | 315 ScriptPromise promise = resolver->promise(); |
| 382 webbluetooth->stopNotifications(m_webCharacteristic->characteristicInstanceID, | 316 gatt()->AddToActiveAlgorithms(resolver); |
| 383 new NotificationsCallback(this, resolver)); | 317 |
| 318 mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service(); |
| 319 service->RemoteCharacteristicStopNotifications( |
| 320 m_characteristicInstanceId, |
| 321 convertToBaseCallback( |
| 322 WTF::bind(&BluetoothRemoteGATTCharacteristic::NotificationsCallback, |
| 323 wrapPersistent(this), wrapPersistent(resolver), |
| 324 mojom::blink::WebBluetoothResult::SUCCESS))); |
| 384 return promise; | 325 return promise; |
| 385 } | 326 } |
| 386 | 327 |
| 387 DEFINE_TRACE(BluetoothRemoteGATTCharacteristic) { | 328 DEFINE_TRACE(BluetoothRemoteGATTCharacteristic) { |
| 388 visitor->trace(m_service); | 329 visitor->trace(m_service); |
| 389 visitor->trace(m_properties); | 330 visitor->trace(m_properties); |
| 390 visitor->trace(m_value); | 331 visitor->trace(m_value); |
| 332 visitor->trace(m_device); |
| 391 EventTargetWithInlineData::trace(visitor); | 333 EventTargetWithInlineData::trace(visitor); |
| 392 ContextLifecycleObserver::trace(visitor); | 334 ContextLifecycleObserver::trace(visitor); |
| 393 } | 335 } |
| 394 | 336 |
| 395 } // namespace blink | 337 } // namespace blink |
| OLD | NEW |