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 |