| 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 bluetooth::mojom::blink::UUIDPtr uuid = |
| 228 new GetPrimaryServicesCallback(device(), quantity, resolver)); | 198 BluetoothUUID::createMojoUuid(servicesUUID); |
| 229 | 199 service->RemoteServerGetPrimaryServices( |
| 200 std::move(deviceId), quantity, std::move(uuid), |
| 201 convertToBaseCallback( |
| 202 WTF::bind(&BluetoothRemoteGATTServer::GetPrimaryServicesCallback, |
| 203 wrapPersistent(this), quantity, wrapPersistent(resolver)))); |
| 230 return promise; | 204 return promise; |
| 231 } | 205 } |
| 232 | 206 |
| 233 } // namespace blink | 207 } // namespace blink |
| OLD | NEW |