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/BluetoothRemoteGATTServer.h" | 5 #include "modules/bluetooth/BluetoothRemoteGATTServer.h" |
6 | 6 |
7 #include "bindings/core/v8/CallbackPromiseAdapter.h" | 7 #include "bindings/core/v8/CallbackPromiseAdapter.h" |
8 #include "bindings/core/v8/ScriptPromise.h" | 8 #include "bindings/core/v8/ScriptPromise.h" |
9 #include "bindings/core/v8/ScriptPromiseResolver.h" | 9 #include "bindings/core/v8/ScriptPromiseResolver.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 "modules/bluetooth/Bluetooth.h" | 13 #include "modules/bluetooth/Bluetooth.h" |
| 14 #include "modules/bluetooth/BluetoothDevice.h" |
14 #include "modules/bluetooth/BluetoothError.h" | 15 #include "modules/bluetooth/BluetoothError.h" |
15 #include "modules/bluetooth/BluetoothRemoteGATTService.h" | 16 #include "modules/bluetooth/BluetoothRemoteGATTService.h" |
16 #include "modules/bluetooth/BluetoothSupplement.h" | |
17 #include "modules/bluetooth/BluetoothUUID.h" | 17 #include "modules/bluetooth/BluetoothUUID.h" |
18 #include "public/platform/modules/bluetooth/WebBluetooth.h" | |
19 | 18 |
20 namespace blink { | 19 namespace blink { |
21 | 20 |
22 namespace { | 21 namespace { |
23 | 22 |
24 const char kGATTServerDisconnected[] = | 23 const char kGATTServerDisconnected[] = |
25 "GATT Server disconnected while retrieving services."; | 24 "GATT Server disconnected while retrieving services."; |
26 const char kGATTServerNotConnected[] = | 25 const char kGATTServerNotConnected[] = |
27 "GATT Server is disconnected. Cannot retrieve services."; | 26 "GATT Server is disconnected. Cannot retrieve services."; |
28 } | 27 |
| 28 } // namespace |
29 | 29 |
30 BluetoothRemoteGATTServer::BluetoothRemoteGATTServer(BluetoothDevice* device) | 30 BluetoothRemoteGATTServer::BluetoothRemoteGATTServer(BluetoothDevice* device) |
31 : m_device(device), m_connected(false) {} | 31 : m_device(device), m_connected(false) {} |
32 | 32 |
33 BluetoothRemoteGATTServer* BluetoothRemoteGATTServer::create( | 33 BluetoothRemoteGATTServer* BluetoothRemoteGATTServer::create( |
34 BluetoothDevice* device) { | 34 BluetoothDevice* device) { |
35 return new BluetoothRemoteGATTServer(device); | 35 return new BluetoothRemoteGATTServer(device); |
36 } | 36 } |
37 | 37 |
38 void BluetoothRemoteGATTServer::AddToActiveAlgorithms( | 38 void BluetoothRemoteGATTServer::AddToActiveAlgorithms( |
39 ScriptPromiseResolver* resolver) { | 39 ScriptPromiseResolver* resolver) { |
40 auto result = m_activeAlgorithms.add(resolver); | 40 auto result = m_activeAlgorithms.add(resolver); |
41 CHECK(result.isNewEntry); | 41 CHECK(result.isNewEntry); |
42 } | 42 } |
43 | 43 |
44 bool BluetoothRemoteGATTServer::RemoveFromActiveAlgorithms( | 44 bool BluetoothRemoteGATTServer::RemoveFromActiveAlgorithms( |
45 ScriptPromiseResolver* resolver) { | 45 ScriptPromiseResolver* resolver) { |
46 if (!m_activeAlgorithms.contains(resolver)) { | 46 if (!m_activeAlgorithms.contains(resolver)) { |
47 return false; | 47 return false; |
48 } | 48 } |
49 m_activeAlgorithms.remove(resolver); | 49 m_activeAlgorithms.remove(resolver); |
50 return true; | 50 return true; |
51 } | 51 } |
52 | 52 |
53 DEFINE_TRACE(BluetoothRemoteGATTServer) { | 53 DEFINE_TRACE(BluetoothRemoteGATTServer) { |
54 visitor->trace(m_activeAlgorithms); | 54 visitor->trace(m_activeAlgorithms); |
55 visitor->trace(m_device); | 55 visitor->trace(m_device); |
56 } | 56 } |
57 | 57 |
58 class ConnectCallback : public WebBluetoothRemoteGATTServerConnectCallbacks { | 58 void BluetoothRemoteGATTServer::ConnectCallback( |
59 public: | 59 ScriptPromiseResolver* resolver, |
60 ConnectCallback(BluetoothDevice* device, ScriptPromiseResolver* resolver) | 60 mojom::blink::WebBluetoothResult result) { |
61 : m_device(device), m_resolver(resolver) {} | 61 if (!resolver->getExecutionContext() || |
| 62 resolver->getExecutionContext()->isContextDestroyed()) |
| 63 return; |
62 | 64 |
63 void onSuccess() override { | 65 if (result == mojom::blink::WebBluetoothResult::SUCCESS) { |
64 if (!m_resolver->getExecutionContext() || | 66 setConnected(true); |
65 m_resolver->getExecutionContext()->isContextDestroyed()) | 67 resolver->resolve(this); |
66 return; | 68 } else { |
67 m_device->gatt()->setConnected(true); | 69 resolver->reject(BluetoothError::take(resolver, result)); |
68 m_resolver->resolve(m_device->gatt()); | |
69 } | 70 } |
70 | 71 } |
71 void onError( | |
72 int32_t | |
73 error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */) | |
74 override { | |
75 if (!m_resolver->getExecutionContext() || | |
76 m_resolver->getExecutionContext()->isContextDestroyed()) | |
77 return; | |
78 m_resolver->reject(BluetoothError::take(m_resolver, error)); | |
79 } | |
80 | |
81 private: | |
82 Persistent<BluetoothDevice> m_device; | |
83 Persistent<ScriptPromiseResolver> m_resolver; | |
84 }; | |
85 | 72 |
86 ScriptPromise BluetoothRemoteGATTServer::connect(ScriptState* scriptState) { | 73 ScriptPromise BluetoothRemoteGATTServer::connect(ScriptState* scriptState) { |
87 WebBluetooth* webbluetooth = | 74 m_device->bluetooth()->addDevice(device()->id(), device()); |
88 BluetoothSupplement::fromScriptState(scriptState); | |
89 if (!webbluetooth) | |
90 return ScriptPromise::rejectWithDOMException( | |
91 scriptState, DOMException::create(NotSupportedError)); | |
92 | 75 |
93 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 76 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
94 ScriptPromise promise = resolver->promise(); | 77 ScriptPromise promise = resolver->promise(); |
95 webbluetooth->connect(device()->id(), device(), | 78 |
96 new ConnectCallback(device(), resolver)); | 79 mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service(); |
| 80 mojom::blink::WebBluetoothDeviceIdPtr deviceId = |
| 81 BluetoothDevice::createMojoDeviceId(device()->id()); |
| 82 service->RemoteServerConnect( |
| 83 std::move(deviceId), |
| 84 convertToBaseCallback( |
| 85 WTF::bind(&BluetoothRemoteGATTServer::ConnectCallback, |
| 86 wrapPersistent(this), wrapPersistent(resolver)))); |
| 87 |
97 return promise; | 88 return promise; |
98 } | 89 } |
99 | 90 |
100 void BluetoothRemoteGATTServer::disconnect(ScriptState* scriptState) { | 91 void BluetoothRemoteGATTServer::disconnect(ScriptState* scriptState) { |
101 if (!m_connected) | 92 if (!m_connected) |
102 return; | 93 return; |
103 device()->cleanupDisconnectedDeviceAndFireEvent(); | 94 device()->cleanupDisconnectedDeviceAndFireEvent(); |
104 WebBluetooth* webbluetooth = | 95 m_device->bluetooth()->removeDevice(device()->id()); |
105 BluetoothSupplement::fromScriptState(scriptState); | 96 mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service(); |
106 webbluetooth->disconnect(device()->id()); | 97 mojom::blink::WebBluetoothDeviceIdPtr deviceId = |
| 98 BluetoothDevice::createMojoDeviceId(device()->id()); |
| 99 service->RemoteServerDisconnect(std::move(deviceId)); |
107 } | 100 } |
108 | 101 |
109 // Class that allows us to resolve the promise with a single service or | 102 // Callback that allows us to resolve the promise with a single service or |
110 // with a vector owning the services. | 103 // with a vector owning the services. |
111 class GetPrimaryServicesCallback | 104 void BluetoothRemoteGATTServer::GetPrimaryServicesCallback( |
112 : public WebBluetoothGetPrimaryServicesCallbacks { | 105 mojom::blink::WebBluetoothGATTQueryQuantity quantity, |
113 public: | 106 ScriptPromiseResolver* resolver, |
114 GetPrimaryServicesCallback( | 107 mojom::blink::WebBluetoothResult result, |
115 BluetoothDevice* device, | 108 Optional<Vector<mojom::blink::WebBluetoothRemoteGATTServicePtr>> services) { |
116 mojom::blink::WebBluetoothGATTQueryQuantity quantity, | 109 if (!resolver->getExecutionContext() || |
117 ScriptPromiseResolver* resolver) | 110 resolver->getExecutionContext()->isContextDestroyed()) |
118 : m_device(device), m_quantity(quantity), m_resolver(resolver) { | 111 return; |
119 // We always check that the device is connected before constructing this | 112 |
120 // object. | 113 // If the resolver is not in the set of ActiveAlgorithms then the frame |
121 CHECK(m_device->gatt()->connected()); | 114 // disconnected so we reject. |
122 m_device->gatt()->AddToActiveAlgorithms(m_resolver.get()); | 115 if (!RemoveFromActiveAlgorithms(resolver)) { |
| 116 resolver->reject( |
| 117 DOMException::create(NetworkError, kGATTServerDisconnected)); |
| 118 return; |
123 } | 119 } |
124 | 120 |
125 void onSuccess( | 121 if (result == mojom::blink::WebBluetoothResult::SUCCESS) { |
126 const WebVector<WebBluetoothRemoteGATTService*>& webServices) override { | 122 DCHECK(services); |
127 if (!m_resolver->getExecutionContext() || | |
128 m_resolver->getExecutionContext()->isContextDestroyed()) | |
129 return; | |
130 | 123 |
131 // If the resolver is not in the set of ActiveAlgorithms then the frame | 124 if (quantity == mojom::blink::WebBluetoothGATTQueryQuantity::SINGLE) { |
132 // disconnected so we reject. | 125 DCHECK_EQ(1u, services->size()); |
133 if (!m_device->gatt()->RemoveFromActiveAlgorithms(m_resolver.get())) { | 126 resolver->resolve(m_device->getOrCreateBluetoothRemoteGATTService( |
134 m_resolver->reject( | 127 services.value()[0]->instance_id, services.value()[0]->uuid, |
135 DOMException::create(NetworkError, kGATTServerDisconnected)); | 128 true /* isPrimary */, device()->id())); |
136 return; | 129 return; |
137 } | 130 } |
138 | 131 |
139 if (m_quantity == mojom::blink::WebBluetoothGATTQueryQuantity::SINGLE) { | 132 HeapVector<Member<BluetoothRemoteGATTService>> gattServices; |
140 DCHECK_EQ(1u, webServices.size()); | 133 gattServices.reserveInitialCapacity(services->size()); |
141 m_resolver->resolve(m_device->getOrCreateBluetoothRemoteGATTService( | 134 |
142 WTF::wrapUnique(webServices[0]))); | 135 for (const auto& service : services.value()) { |
143 return; | 136 gattServices.append(m_device->getOrCreateBluetoothRemoteGATTService( |
| 137 service->instance_id, service->uuid, true /* isPrimary */, |
| 138 device()->id())); |
144 } | 139 } |
145 | 140 resolver->resolve(gattServices); |
146 HeapVector<Member<BluetoothRemoteGATTService>> services; | 141 } else { |
147 services.reserveInitialCapacity(webServices.size()); | 142 resolver->reject(BluetoothError::take(resolver, result)); |
148 for (WebBluetoothRemoteGATTService* webService : webServices) { | |
149 services.append(m_device->getOrCreateBluetoothRemoteGATTService( | |
150 WTF::wrapUnique(webService))); | |
151 } | |
152 m_resolver->resolve(services); | |
153 } | 143 } |
154 | 144 } |
155 void onError( | |
156 int32_t | |
157 error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */) | |
158 override { | |
159 if (!m_resolver->getExecutionContext() || | |
160 m_resolver->getExecutionContext()->isContextDestroyed()) | |
161 return; | |
162 | |
163 if (!m_device->gatt()->RemoveFromActiveAlgorithms(m_resolver.get())) { | |
164 m_resolver->reject( | |
165 DOMException::create(NetworkError, kGATTServerDisconnected)); | |
166 return; | |
167 } | |
168 | |
169 m_resolver->reject(BluetoothError::take(m_resolver, error)); | |
170 } | |
171 | |
172 private: | |
173 Persistent<BluetoothDevice> m_device; | |
174 mojom::blink::WebBluetoothGATTQueryQuantity m_quantity; | |
175 const Persistent<ScriptPromiseResolver> m_resolver; | |
176 }; | |
177 | 145 |
178 ScriptPromise BluetoothRemoteGATTServer::getPrimaryService( | 146 ScriptPromise BluetoothRemoteGATTServer::getPrimaryService( |
179 ScriptState* scriptState, | 147 ScriptState* scriptState, |
180 const StringOrUnsignedLong& service, | 148 const StringOrUnsignedLong& service, |
181 ExceptionState& exceptionState) { | 149 ExceptionState& exceptionState) { |
182 String serviceUUID = BluetoothUUID::getService(service, exceptionState); | 150 String serviceUUID = BluetoothUUID::getService(service, exceptionState); |
183 if (exceptionState.hadException()) | 151 if (exceptionState.hadException()) |
184 return exceptionState.reject(scriptState); | 152 return exceptionState.reject(scriptState); |
185 | 153 |
186 return getPrimaryServicesImpl( | 154 return getPrimaryServicesImpl( |
(...skipping 18 matching lines...) Expand all Loading... |
205 ScriptState* scriptState, | 173 ScriptState* scriptState, |
206 ExceptionState&) { | 174 ExceptionState&) { |
207 return getPrimaryServicesImpl( | 175 return getPrimaryServicesImpl( |
208 scriptState, mojom::blink::WebBluetoothGATTQueryQuantity::MULTIPLE); | 176 scriptState, mojom::blink::WebBluetoothGATTQueryQuantity::MULTIPLE); |
209 } | 177 } |
210 | 178 |
211 ScriptPromise BluetoothRemoteGATTServer::getPrimaryServicesImpl( | 179 ScriptPromise BluetoothRemoteGATTServer::getPrimaryServicesImpl( |
212 ScriptState* scriptState, | 180 ScriptState* scriptState, |
213 mojom::blink::WebBluetoothGATTQueryQuantity quantity, | 181 mojom::blink::WebBluetoothGATTQueryQuantity quantity, |
214 String servicesUUID) { | 182 String servicesUUID) { |
| 183 // We always check that the device is connected. |
215 if (!connected()) { | 184 if (!connected()) { |
216 return ScriptPromise::rejectWithDOMException( | 185 return ScriptPromise::rejectWithDOMException( |
217 scriptState, | 186 scriptState, |
218 DOMException::create(NetworkError, kGATTServerNotConnected)); | 187 DOMException::create(NetworkError, kGATTServerNotConnected)); |
219 } | 188 } |
220 | 189 |
221 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 190 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
222 ScriptPromise promise = resolver->promise(); | 191 ScriptPromise promise = resolver->promise(); |
| 192 AddToActiveAlgorithms(resolver); |
223 | 193 |
224 WebBluetooth* webbluetooth = | 194 mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service(); |
225 BluetoothSupplement::fromScriptState(scriptState); | 195 mojom::blink::WebBluetoothDeviceIdPtr deviceId = |
226 webbluetooth->getPrimaryServices( | 196 BluetoothDevice::createMojoDeviceId(device()->id()); |
227 device()->id(), static_cast<int32_t>(quantity), servicesUUID, | 197 WTF::Optional<String> uuid = WTF::nullopt; |
228 new GetPrimaryServicesCallback(device(), quantity, resolver)); | 198 if (!servicesUUID.isEmpty()) |
| 199 uuid = servicesUUID; |
229 | 200 |
| 201 service->RemoteServerGetPrimaryServices( |
| 202 std::move(deviceId), quantity, uuid, |
| 203 convertToBaseCallback( |
| 204 WTF::bind(&BluetoothRemoteGATTServer::GetPrimaryServicesCallback, |
| 205 wrapPersistent(this), quantity, wrapPersistent(resolver)))); |
230 return promise; | 206 return promise; |
231 } | 207 } |
232 | 208 |
233 } // namespace blink | 209 } // namespace blink |
OLD | NEW |