Chromium Code Reviews| 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 | |
| 120 // object. | |
| 121 CHECK(m_device->gatt()->connected()); | |
| 122 m_device->gatt()->AddToActiveAlgorithms(m_resolver.get()); | |
| 123 } | |
| 124 | 112 |
| 125 void onSuccess( | 113 if (result == mojom::blink::WebBluetoothResult::SUCCESS) { |
| 126 const WebVector<WebBluetoothRemoteGATTService*>& webServices) override { | 114 DCHECK(services); |
| 127 if (!m_resolver->getExecutionContext() || | |
| 128 m_resolver->getExecutionContext()->isContextDestroyed()) | |
| 129 return; | |
| 130 | |
| 131 // If the resolver is not in the set of ActiveAlgorithms then the frame | 115 // If the resolver is not in the set of ActiveAlgorithms then the frame |
| 132 // disconnected so we reject. | 116 // disconnected so we reject. |
| 133 if (!m_device->gatt()->RemoveFromActiveAlgorithms(m_resolver.get())) { | 117 if (!RemoveFromActiveAlgorithms(resolver)) { |
| 134 m_resolver->reject( | 118 resolver->reject( |
| 135 DOMException::create(NetworkError, kGATTServerDisconnected)); | 119 DOMException::create(NetworkError, kGATTServerDisconnected)); |
| 136 return; | 120 return; |
| 137 } | 121 } |
| 138 | 122 |
| 139 if (m_quantity == mojom::blink::WebBluetoothGATTQueryQuantity::SINGLE) { | 123 if (quantity == mojom::blink::WebBluetoothGATTQueryQuantity::SINGLE) { |
| 140 DCHECK_EQ(1u, webServices.size()); | 124 DCHECK_EQ(1u, services->size()); |
| 141 m_resolver->resolve(m_device->getOrCreateBluetoothRemoteGATTService( | 125 resolver->resolve(m_device->getOrCreateBluetoothRemoteGATTService( |
| 142 WTF::wrapUnique(webServices[0]))); | 126 services.value()[0]->instance_id, services.value()[0]->uuid, |
| 127 true /* isPrimary */, device()->id())); | |
| 143 return; | 128 return; |
| 144 } | 129 } |
| 145 | 130 |
| 146 HeapVector<Member<BluetoothRemoteGATTService>> services; | 131 HeapVector<Member<BluetoothRemoteGATTService>> gattServices; |
| 147 services.reserveInitialCapacity(webServices.size()); | 132 gattServices.reserveInitialCapacity(services->size()); |
| 148 for (WebBluetoothRemoteGATTService* webService : webServices) { | 133 |
| 149 services.append(m_device->getOrCreateBluetoothRemoteGATTService( | 134 for (const auto& service : services.value()) { |
| 150 WTF::wrapUnique(webService))); | 135 gattServices.append(m_device->getOrCreateBluetoothRemoteGATTService( |
| 136 service->instance_id, service->uuid, true /* isPrimary */, | |
| 137 device()->id())); | |
| 151 } | 138 } |
| 152 m_resolver->resolve(services); | 139 resolver->resolve(gattServices); |
| 153 } | 140 } else { |
| 154 | 141 if (!RemoveFromActiveAlgorithms(resolver)) { |
|
Reilly Grant (use Gerrit)
2016/12/20 02:08:17
This check can be hoisted out to above if (result
juncai
2016/12/20 22:33:43
Done.
| |
| 155 void onError( | 142 resolver->reject( |
| 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)); | 143 DOMException::create(NetworkError, kGATTServerDisconnected)); |
| 166 return; | 144 return; |
| 167 } | 145 } |
| 168 | 146 |
| 169 m_resolver->reject(BluetoothError::take(m_resolver, error)); | 147 resolver->reject(BluetoothError::take(resolver, result)); |
| 170 } | 148 } |
| 171 | 149 } |
| 172 private: | |
| 173 Persistent<BluetoothDevice> m_device; | |
| 174 mojom::blink::WebBluetoothGATTQueryQuantity m_quantity; | |
| 175 const Persistent<ScriptPromiseResolver> m_resolver; | |
| 176 }; | |
| 177 | 150 |
| 178 ScriptPromise BluetoothRemoteGATTServer::getPrimaryService( | 151 ScriptPromise BluetoothRemoteGATTServer::getPrimaryService( |
| 179 ScriptState* scriptState, | 152 ScriptState* scriptState, |
| 180 const StringOrUnsignedLong& service, | 153 const StringOrUnsignedLong& service, |
| 181 ExceptionState& exceptionState) { | 154 ExceptionState& exceptionState) { |
| 182 String serviceUUID = BluetoothUUID::getService(service, exceptionState); | 155 String serviceUUID = BluetoothUUID::getService(service, exceptionState); |
| 183 if (exceptionState.hadException()) | 156 if (exceptionState.hadException()) |
| 184 return exceptionState.reject(scriptState); | 157 return exceptionState.reject(scriptState); |
| 185 | 158 |
| 186 return getPrimaryServicesImpl( | 159 return getPrimaryServicesImpl( |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 205 ScriptState* scriptState, | 178 ScriptState* scriptState, |
| 206 ExceptionState&) { | 179 ExceptionState&) { |
| 207 return getPrimaryServicesImpl( | 180 return getPrimaryServicesImpl( |
| 208 scriptState, mojom::blink::WebBluetoothGATTQueryQuantity::MULTIPLE); | 181 scriptState, mojom::blink::WebBluetoothGATTQueryQuantity::MULTIPLE); |
| 209 } | 182 } |
| 210 | 183 |
| 211 ScriptPromise BluetoothRemoteGATTServer::getPrimaryServicesImpl( | 184 ScriptPromise BluetoothRemoteGATTServer::getPrimaryServicesImpl( |
| 212 ScriptState* scriptState, | 185 ScriptState* scriptState, |
| 213 mojom::blink::WebBluetoothGATTQueryQuantity quantity, | 186 mojom::blink::WebBluetoothGATTQueryQuantity quantity, |
| 214 String servicesUUID) { | 187 String servicesUUID) { |
| 188 // We always check that the device is connected. | |
| 215 if (!connected()) { | 189 if (!connected()) { |
| 216 return ScriptPromise::rejectWithDOMException( | 190 return ScriptPromise::rejectWithDOMException( |
| 217 scriptState, | 191 scriptState, |
| 218 DOMException::create(NetworkError, kGATTServerNotConnected)); | 192 DOMException::create(NetworkError, kGATTServerNotConnected)); |
| 219 } | 193 } |
| 220 | 194 |
| 221 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 195 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
| 222 ScriptPromise promise = resolver->promise(); | 196 ScriptPromise promise = resolver->promise(); |
| 197 AddToActiveAlgorithms(resolver); | |
| 223 | 198 |
| 224 WebBluetooth* webbluetooth = | 199 mojom::blink::WebBluetoothService* service = m_device->bluetooth()->service(); |
| 225 BluetoothSupplement::fromScriptState(scriptState); | 200 mojom::blink::WebBluetoothDeviceIdPtr deviceId = |
| 226 webbluetooth->getPrimaryServices( | 201 BluetoothDevice::createMojoDeviceId(device()->id()); |
| 227 device()->id(), static_cast<int32_t>(quantity), servicesUUID, | 202 bluetooth::mojom::blink::UUIDPtr uuid = nullptr; |
|
Reilly Grant (use Gerrit)
2016/12/20 02:08:17
No need to initialize to nullptr, that is the defa
juncai
2016/12/20 22:33:43
Done.
| |
| 228 new GetPrimaryServicesCallback(device(), quantity, resolver)); | 203 if (!servicesUUID.isEmpty()) |
| 229 | 204 uuid = BluetoothUUID::createMojoUuid(servicesUUID); |
|
Reilly Grant (use Gerrit)
2016/12/20 02:08:17
I'm wondering whether it would be useful to just h
juncai
2016/12/20 22:33:43
Done.
| |
| 205 service->RemoteServerGetPrimaryServices( | |
| 206 std::move(deviceId), quantity, std::move(uuid), | |
| 207 convertToBaseCallback( | |
| 208 WTF::bind(&BluetoothRemoteGATTServer::GetPrimaryServicesCallback, | |
| 209 wrapPersistent(this), quantity, wrapPersistent(resolver)))); | |
| 230 return promise; | 210 return promise; |
| 231 } | 211 } |
| 232 | 212 |
| 233 } // namespace blink | 213 } // namespace blink |
| OLD | NEW |