Index: third_party/WebKit/Source/modules/bluetooth/Bluetooth.cpp |
diff --git a/third_party/WebKit/Source/modules/bluetooth/Bluetooth.cpp b/third_party/WebKit/Source/modules/bluetooth/Bluetooth.cpp |
index 35c4e92a0b9ab4b9855d0659acab74c7f657b2e1..b28791ac4230a57bc40261193f3c5eee41baac04 100644 |
--- a/third_party/WebKit/Source/modules/bluetooth/Bluetooth.cpp |
+++ b/third_party/WebKit/Source/modules/bluetooth/Bluetooth.cpp |
@@ -8,15 +8,17 @@ |
#include "bindings/core/v8/ScriptPromise.h" |
#include "bindings/core/v8/ScriptPromiseResolver.h" |
#include "core/dom/DOMException.h" |
+#include "core/dom/Document.h" |
#include "core/dom/ExceptionCode.h" |
+#include "core/dom/ExecutionContext.h" |
+#include "core/frame/LocalFrame.h" |
#include "modules/bluetooth/BluetoothDevice.h" |
#include "modules/bluetooth/BluetoothError.h" |
-#include "modules/bluetooth/BluetoothSupplement.h" |
+#include "modules/bluetooth/BluetoothRemoteGATTCharacteristic.h" |
#include "modules/bluetooth/BluetoothUUID.h" |
#include "modules/bluetooth/RequestDeviceOptions.h" |
#include "platform/UserGestureIndicator.h" |
-#include "public/platform/modules/bluetooth/WebBluetooth.h" |
-#include "public/platform/modules/bluetooth/WebRequestDeviceOptions.h" |
+#include "public/platform/InterfaceProvider.h" |
#include <memory> |
#include <utility> |
@@ -38,9 +40,10 @@ const char kDeviceNameTooLong[] = |
"A device name can't be longer than 248 bytes."; |
} // namespace |
-static void canonicalizeFilter(const BluetoothScanFilterInit& filter, |
- WebBluetoothScanFilter& canonicalizedFilter, |
- ExceptionState& exceptionState) { |
+static void canonicalizeFilter( |
+ const BluetoothScanFilterInit& filter, |
+ mojom::blink::WebBluetoothScanFilterPtr& canonicalizedFilter, |
+ ExceptionState& exceptionState) { |
if (!(filter.hasServices() || filter.hasName() || filter.hasNamePrefix())) { |
exceptionState.throwTypeError( |
"A filter must restrict the devices in some way."); |
@@ -53,18 +56,16 @@ static void canonicalizeFilter(const BluetoothScanFilterInit& filter, |
"'services', if present, must contain at least one service."); |
return; |
} |
- Vector<WebString> services; |
+ canonicalizedFilter->services.emplace(); |
for (const StringOrUnsignedLong& service : filter.services()) { |
const String& validatedService = |
BluetoothUUID::getService(service, exceptionState); |
if (exceptionState.hadException()) |
return; |
- services.append(validatedService); |
+ canonicalizedFilter->services->append(validatedService); |
} |
- canonicalizedFilter.services.assign(services); |
} |
- canonicalizedFilter.hasName = filter.hasName(); |
if (filter.hasName()) { |
size_t nameLength = filter.name().utf8().length(); |
if (nameLength > kMaxDeviceNameLength) { |
@@ -75,7 +76,7 @@ static void canonicalizeFilter(const BluetoothScanFilterInit& filter, |
exceptionState.throwDOMException(NotFoundError, kFilterNameTooLong); |
return; |
} |
- canonicalizedFilter.name = filter.name(); |
+ canonicalizedFilter->name = filter.name(); |
} |
if (filter.hasNamePrefix()) { |
@@ -93,13 +94,14 @@ static void canonicalizeFilter(const BluetoothScanFilterInit& filter, |
"'namePrefix', if present, must me non-empty."); |
return; |
} |
- canonicalizedFilter.namePrefix = filter.namePrefix(); |
+ canonicalizedFilter->name_prefix = filter.namePrefix(); |
} |
} |
-static void convertRequestDeviceOptions(const RequestDeviceOptions& options, |
- WebRequestDeviceOptions& result, |
- ExceptionState& exceptionState) { |
+static void convertRequestDeviceOptions( |
+ const RequestDeviceOptions& options, |
+ mojom::blink::WebBluetoothRequestDeviceOptionsPtr& result, |
+ ExceptionState& exceptionState) { |
if (!(options.hasFilters() ^ options.acceptAllDevices())) { |
exceptionState.throwTypeError( |
"Either 'filters' should be present or 'acceptAllDevices' should be " |
@@ -107,75 +109,64 @@ static void convertRequestDeviceOptions(const RequestDeviceOptions& options, |
return; |
} |
- result.acceptAllDevices = options.acceptAllDevices(); |
+ result->accept_all_devices = options.acceptAllDevices(); |
- result.hasFilters = options.hasFilters(); |
- if (result.hasFilters) { |
+ if (options.hasFilters()) { |
if (options.filters().isEmpty()) { |
exceptionState.throwTypeError( |
"'filters' member must be non-empty to find any devices."); |
return; |
} |
- Vector<WebBluetoothScanFilter> filters; |
+ result->filters.emplace(); |
+ |
for (const BluetoothScanFilterInit& filter : options.filters()) { |
- WebBluetoothScanFilter canonicalizedFilter = WebBluetoothScanFilter(); |
+ auto canonicalizedFilter = mojom::blink::WebBluetoothScanFilter::New(); |
canonicalizeFilter(filter, canonicalizedFilter, exceptionState); |
if (exceptionState.hadException()) |
return; |
- filters.append(canonicalizedFilter); |
+ result->filters.value().append(std::move(canonicalizedFilter)); |
} |
- |
- result.filters.assign(filters); |
} |
if (options.hasOptionalServices()) { |
- Vector<WebString> optionalServices; |
for (const StringOrUnsignedLong& optionalService : |
options.optionalServices()) { |
const String& validatedOptionalService = |
BluetoothUUID::getService(optionalService, exceptionState); |
if (exceptionState.hadException()) |
return; |
- optionalServices.append(validatedOptionalService); |
+ result->optional_services.append(validatedOptionalService); |
} |
- result.optionalServices.assign(optionalServices); |
} |
} |
-class RequestDeviceCallback : public WebBluetoothRequestDeviceCallbacks { |
- public: |
- RequestDeviceCallback(Bluetooth* bluetooth, ScriptPromiseResolver* resolver) |
- : m_bluetooth(bluetooth), m_resolver(resolver) {} |
- |
- void onSuccess(std::unique_ptr<WebBluetoothDeviceInit> deviceInit) override { |
- if (!m_resolver->getExecutionContext() || |
- m_resolver->getExecutionContext()->isContextDestroyed()) |
- return; |
- |
- BluetoothDevice* device = m_bluetooth->getBluetoothDeviceRepresentingDevice( |
- std::move(deviceInit), m_resolver); |
+void Bluetooth::dispose() { |
+ // The pipe to this object must be closed when is marked unreachable to |
+ // prevent messages from being dispatched before lazy sweeping. |
+ if (m_clientBinding.is_bound()) |
+ m_clientBinding.Close(); |
+} |
- m_resolver->resolve(device); |
- } |
+void Bluetooth::RequestDeviceCallback( |
+ ScriptPromiseResolver* resolver, |
+ mojom::blink::WebBluetoothResult result, |
+ mojom::blink::WebBluetoothDevicePtr device) { |
+ if (!resolver->getExecutionContext() || |
+ resolver->getExecutionContext()->isContextDestroyed()) |
+ return; |
- void onError( |
- int32_t |
- error /* Corresponds to WebBluetoothResult in web_bluetooth.mojom */) |
- override { |
- if (!m_resolver->getExecutionContext() || |
- m_resolver->getExecutionContext()->isContextDestroyed()) |
- return; |
- m_resolver->reject(BluetoothError::take(m_resolver, error)); |
+ if (result == mojom::blink::WebBluetoothResult::SUCCESS) { |
+ BluetoothDevice* bluetoothDevice = getBluetoothDeviceRepresentingDevice( |
+ device->id->device_id, device->name, resolver); |
+ resolver->resolve(bluetoothDevice); |
+ } else { |
+ resolver->reject(BluetoothError::take(resolver, result)); |
} |
- |
- private: |
- Persistent<Bluetooth> m_bluetooth; |
- Persistent<ScriptPromiseResolver> m_resolver; |
-}; |
+} |
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice |
ScriptPromise Bluetooth::requestDevice(ScriptState* scriptState, |
@@ -201,40 +192,109 @@ ScriptPromise Bluetooth::requestDevice(ScriptState* scriptState, |
"Must be handling a user gesture to show a permission request.")); |
} |
- WebBluetooth* webbluetooth = |
- BluetoothSupplement::fromScriptState(scriptState); |
- if (!webbluetooth) |
+ if (!m_service) { |
+ InterfaceProvider* interfaceProvider = nullptr; |
+ ExecutionContext* executionContext = scriptState->getExecutionContext(); |
+ if (executionContext->isDocument()) { |
+ Document* document = toDocument(executionContext); |
+ if (document->frame()) |
+ interfaceProvider = document->frame()->interfaceProvider(); |
+ } |
+ |
+ if (interfaceProvider) |
+ interfaceProvider->getInterface(mojo::MakeRequest(&m_service)); |
+ |
+ if (m_service) { |
+ // Create an associated interface ptr and pass it to the |
+ // WebBluetoothService so that it can send us events without us |
+ // prompting. |
+ mojom::blink::WebBluetoothServiceClientAssociatedPtrInfo ptrInfo; |
+ m_clientBinding.Bind(&ptrInfo, m_service.associated_group()); |
+ m_service->SetClient(std::move(ptrInfo)); |
+ } |
+ } |
+ |
+ if (!m_service) { |
return ScriptPromise::rejectWithDOMException( |
scriptState, DOMException::create(NotSupportedError)); |
+ } |
// In order to convert the arguments from service names and aliases to just |
// UUIDs, do the following substeps: |
- WebRequestDeviceOptions webOptions; |
- convertRequestDeviceOptions(options, webOptions, exceptionState); |
+ auto deviceOptions = mojom::blink::WebBluetoothRequestDeviceOptions::New(); |
+ convertRequestDeviceOptions(options, deviceOptions, exceptionState); |
+ |
if (exceptionState.hadException()) |
return exceptionState.reject(scriptState); |
// Subsequent steps are handled in the browser process. |
ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
ScriptPromise promise = resolver->promise(); |
- webbluetooth->requestDevice(webOptions, |
- new RequestDeviceCallback(this, resolver)); |
+ |
+ service()->RequestDevice( |
+ std::move(deviceOptions), |
+ convertToBaseCallback(WTF::bind(&Bluetooth::RequestDeviceCallback, |
+ wrapPersistent(this), |
+ wrapPersistent(resolver)))); |
return promise; |
} |
+void Bluetooth::addDevice(const String& deviceId, BluetoothDevice* device) { |
+ m_connectedDevices.add(deviceId, device); |
+} |
+ |
+void Bluetooth::removeDevice(const String& deviceId) { |
+ m_connectedDevices.remove(deviceId); |
+} |
+ |
+void Bluetooth::registerCharacteristicObject( |
+ const String& characteristicInstanceId, |
+ BluetoothRemoteGATTCharacteristic* characteristic) { |
+ m_activeCharacteristics.add(characteristicInstanceId, characteristic); |
+} |
+ |
+void Bluetooth::characteristicObjectRemoved( |
+ const String& characteristicInstanceId) { |
+ m_activeCharacteristics.remove(characteristicInstanceId); |
+} |
+ |
DEFINE_TRACE(Bluetooth) { |
visitor->trace(m_deviceInstanceMap); |
+ visitor->trace(m_activeCharacteristics); |
+ visitor->trace(m_connectedDevices); |
+} |
+ |
+Bluetooth::Bluetooth() : m_clientBinding(this) {} |
+ |
+void Bluetooth::RemoteCharacteristicValueChanged( |
+ const WTF::String& characteristicInstanceId, |
+ const WTF::Vector<uint8_t>& value) { |
+ BluetoothRemoteGATTCharacteristic* characteristic = |
+ m_activeCharacteristics.get(characteristicInstanceId); |
+ if (characteristic) |
+ characteristic->dispatchCharacteristicValueChanged(value); |
+} |
+ |
+void Bluetooth::GattServerDisconnected( |
+ mojom::blink::WebBluetoothDeviceIdPtr deviceId) { |
+ BluetoothDevice* device = m_connectedDevices.get(deviceId->device_id); |
+ if (device) { |
+ // Remove device from the map before calling dispatchGattServerDisconnected |
+ // to avoid removing a device the gattserverdisconnected event handler might |
+ // have re-connected. |
+ m_connectedDevices.remove(deviceId->device_id); |
+ device->dispatchGattServerDisconnected(); |
+ } |
} |
BluetoothDevice* Bluetooth::getBluetoothDeviceRepresentingDevice( |
- std::unique_ptr<WebBluetoothDeviceInit> deviceInit, |
+ const String& id, |
+ const String& name, |
ScriptPromiseResolver* resolver) { |
- BluetoothDevice* device = m_deviceInstanceMap.get(deviceInit->id); |
+ BluetoothDevice* device = m_deviceInstanceMap.get(id); |
if (!device) { |
- String deviceId = deviceInit->id; |
- device = BluetoothDevice::take(resolver, std::move(deviceInit)); |
- |
- auto result = m_deviceInstanceMap.add(deviceId, device); |
+ device = BluetoothDevice::take(resolver, id, name, this); |
+ auto result = m_deviceInstanceMap.add(id, device); |
DCHECK(result.isNewEntry); |
} |
return device; |