Commit 278801c2 authored by Ovidio Henriquez's avatar Ovidio Henriquez Committed by Commit Bot

bluetooth: getDevices() implementation

This change implements getDevices() which returns a list of
WebBluetoothDevice objects that the current site has permission to
access. If the kWebBluetoothNewPermissionsBackend flag is enabled, the
list of devices will contain all of the permitted devices. If the flag
is not enabled, then the list of devices will contain the permitted
devices that are currently connected to the system.

Design doc:
https://docs.google.com/document/d/1h3uAVXJARHrNWaNACUPiQhLt7XI-fFFQoARSs1WgMDM/edit#heading=h.5ugemo7p04z9

Bug: 577953
Change-Id: I9785f24ee46ac634b6a96d6146f54da37d132a4e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2044660
Commit-Queue: Ovidio de Jesús Ruiz-Henríquez <odejesush@chromium.org>
Reviewed-by: default avatarReilly Grant <reillyg@chromium.org>
Reviewed-by: default avatarVincent Scheib <scheib@chromium.org>
Reviewed-by: default avatarJohn Abd-El-Malek <jam@chromium.org>
Reviewed-by: default avatarMustafa Emre Acer <meacer@chromium.org>
Reviewed-by: default avatarPhilip Jägenstedt <foolip@chromium.org>
Cr-Commit-Position: refs/heads/master@{#748917}
parent c780858b
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "chrome/browser/bluetooth/chrome_bluetooth_delegate.h" #include "chrome/browser/bluetooth/chrome_bluetooth_delegate.h"
#include <memory>
#include "chrome/browser/bluetooth/bluetooth_chooser_context.h" #include "chrome/browser/bluetooth/bluetooth_chooser_context.h"
#include "chrome/browser/bluetooth/bluetooth_chooser_context_factory.h" #include "chrome/browser/bluetooth/bluetooth_chooser_context_factory.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
...@@ -106,3 +108,25 @@ bool ChromeBluetoothDelegate::IsAllowedToAccessAtLeastOneService( ...@@ -106,3 +108,25 @@ bool ChromeBluetoothDelegate::IsAllowedToAccessAtLeastOneService(
frame->GetLastCommittedOrigin(), frame->GetLastCommittedOrigin(),
web_contents->GetMainFrame()->GetLastCommittedOrigin(), device_id); web_contents->GetMainFrame()->GetLastCommittedOrigin(), device_id);
} }
std::vector<blink::mojom::WebBluetoothDevicePtr>
ChromeBluetoothDelegate::GetPermittedDevices(content::RenderFrameHost* frame) {
auto* web_contents = WebContents::FromRenderFrameHost(frame);
std::vector<std::unique_ptr<permissions::ChooserContextBase::Object>>
objects = GetBluetoothChooserContext(web_contents)
->GetGrantedObjects(
frame->GetLastCommittedOrigin(),
web_contents->GetMainFrame()->GetLastCommittedOrigin());
std::vector<blink::mojom::WebBluetoothDevicePtr> permitted_devices;
for (const auto& object : objects) {
auto permitted_device = blink::mojom::WebBluetoothDevice::New();
permitted_device->id =
BluetoothChooserContext::GetObjectDeviceId(object->value);
permitted_device->name =
BluetoothChooserContext::GetObjectName(object->value);
permitted_devices.push_back(std::move(permitted_device));
}
return permitted_devices;
}
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define CHROME_BROWSER_BLUETOOTH_CHROME_BLUETOOTH_DELEGATE_H_ #define CHROME_BROWSER_BLUETOOTH_CHROME_BLUETOOTH_DELEGATE_H_
#include <string> #include <string>
#include <vector>
#include "content/public/browser/bluetooth_delegate.h" #include "content/public/browser/bluetooth_delegate.h"
#include "third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom-forward.h" #include "third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom-forward.h"
...@@ -58,6 +59,8 @@ class ChromeBluetoothDelegate : public content::BluetoothDelegate { ...@@ -58,6 +59,8 @@ class ChromeBluetoothDelegate : public content::BluetoothDelegate {
bool IsAllowedToAccessAtLeastOneService( bool IsAllowedToAccessAtLeastOneService(
content::RenderFrameHost* frame, content::RenderFrameHost* frame,
const blink::WebBluetoothDeviceId& device_id) override; const blink::WebBluetoothDeviceId& device_id) override;
std::vector<blink::mojom::WebBluetoothDevicePtr> GetPermittedDevices(
content::RenderFrameHost* frame) override;
}; };
#endif // CHROME_BROWSER_BLUETOOTH_CHROME_BLUETOOTH_DELEGATE_H_ #endif // CHROME_BROWSER_BLUETOOTH_CHROME_BLUETOOTH_DELEGATE_H_
...@@ -705,6 +705,25 @@ void WebBluetoothServiceImpl::RequestDevice( ...@@ -705,6 +705,25 @@ void WebBluetoothServiceImpl::RequestDevice(
RequestDeviceImpl(std::move(options), std::move(callback), GetAdapter()); RequestDeviceImpl(std::move(options), std::move(callback), GetAdapter());
} }
void WebBluetoothServiceImpl::GetDevices(GetDevicesCallback callback) {
if (GetBluetoothAllowed() != blink::mojom::WebBluetoothResult::SUCCESS ||
!BluetoothAdapterFactoryWrapper::Get().IsLowEnergySupported()) {
std::move(callback).Run({});
return;
}
auto* adapter = GetAdapter();
if (adapter) {
GetDevicesImpl(std::move(callback), adapter);
return;
}
BluetoothAdapterFactoryWrapper::Get().AcquireAdapter(
this,
base::BindOnce(&WebBluetoothServiceImpl::GetDevicesImpl,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void WebBluetoothServiceImpl::RemoteServerConnect( void WebBluetoothServiceImpl::RemoteServerConnect(
const blink::WebBluetoothDeviceId& device_id, const blink::WebBluetoothDeviceId& device_id,
mojo::PendingAssociatedRemote<blink::mojom::WebBluetoothServerClient> mojo::PendingAssociatedRemote<blink::mojom::WebBluetoothServerClient>
...@@ -1421,6 +1440,38 @@ void WebBluetoothServiceImpl::RequestDeviceImpl( ...@@ -1421,6 +1440,38 @@ void WebBluetoothServiceImpl::RequestDeviceImpl(
weak_ptr_factory_.GetWeakPtr(), copyable_callback)); weak_ptr_factory_.GetWeakPtr(), copyable_callback));
} }
void WebBluetoothServiceImpl::GetDevicesImpl(
GetDevicesCallback callback,
scoped_refptr<device::BluetoothAdapter> adapter) {
if (base::FeatureList::IsEnabled(
features::kWebBluetoothNewPermissionsBackend)) {
BluetoothDelegate* delegate =
GetContentClient()->browser()->GetBluetoothDelegate();
if (!delegate) {
std::move(callback).Run({});
return;
}
std::move(callback).Run(delegate->GetPermittedDevices(render_frame_host_));
return;
}
// BluetoothAllowedDevices does not provide a way to get all of the permitted
// devices, so instead return all of the allowed devices that are currently
// known to the system.
std::vector<blink::mojom::WebBluetoothDevicePtr> web_bluetooth_devices;
for (const auto* device : adapter->GetDevices()) {
const blink::WebBluetoothDeviceId* device_id =
allowed_devices().GetDeviceId(device->GetAddress());
if (!device_id || !allowed_devices().IsAllowedToGATTConnect(*device_id))
continue;
web_bluetooth_devices.push_back(
blink::mojom::WebBluetoothDevice::New(*device_id, device->GetName()));
}
std::move(callback).Run(std::move(web_bluetooth_devices));
}
void WebBluetoothServiceImpl::RemoteServerGetPrimaryServicesImpl( void WebBluetoothServiceImpl::RemoteServerGetPrimaryServicesImpl(
const blink::WebBluetoothDeviceId& device_id, const blink::WebBluetoothDeviceId& device_id,
blink::mojom::WebBluetoothGATTQueryQuantity quantity, blink::mojom::WebBluetoothGATTQueryQuantity quantity,
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <unordered_map>
#include <vector> #include <vector>
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
...@@ -196,6 +197,7 @@ class CONTENT_EXPORT WebBluetoothServiceImpl ...@@ -196,6 +197,7 @@ class CONTENT_EXPORT WebBluetoothServiceImpl
void GetAvailability(GetAvailabilityCallback callback) override; void GetAvailability(GetAvailabilityCallback callback) override;
void RequestDevice(blink::mojom::WebBluetoothRequestDeviceOptionsPtr options, void RequestDevice(blink::mojom::WebBluetoothRequestDeviceOptionsPtr options,
RequestDeviceCallback callback) override; RequestDeviceCallback callback) override;
void GetDevices(GetDevicesCallback callback) override;
void RemoteServerConnect( void RemoteServerConnect(
const blink::WebBluetoothDeviceId& device_id, const blink::WebBluetoothDeviceId& device_id,
mojo::PendingAssociatedRemote<blink::mojom::WebBluetoothServerClient> mojo::PendingAssociatedRemote<blink::mojom::WebBluetoothServerClient>
...@@ -251,6 +253,9 @@ class CONTENT_EXPORT WebBluetoothServiceImpl ...@@ -251,6 +253,9 @@ class CONTENT_EXPORT WebBluetoothServiceImpl
RequestDeviceCallback callback, RequestDeviceCallback callback,
scoped_refptr<device::BluetoothAdapter> adapter); scoped_refptr<device::BluetoothAdapter> adapter);
void GetDevicesImpl(GetDevicesCallback callback,
scoped_refptr<device::BluetoothAdapter> adapter);
void RequestScanningStartImpl( void RequestScanningStartImpl(
mojo::AssociatedRemote<blink::mojom::WebBluetoothScanClient> client, mojo::AssociatedRemote<blink::mojom::WebBluetoothScanClient> client,
blink::mojom::WebBluetoothRequestLEScanOptionsPtr options, blink::mojom::WebBluetoothRequestLEScanOptionsPtr options,
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define CONTENT_PUBLIC_BROWSER_BLUETOOTH_DELEGATE_H_ #define CONTENT_PUBLIC_BROWSER_BLUETOOTH_DELEGATE_H_
#include <string> #include <string>
#include <vector>
#include "base/containers/flat_set.h" #include "base/containers/flat_set.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
...@@ -85,6 +86,15 @@ class CONTENT_EXPORT BluetoothDelegate { ...@@ -85,6 +86,15 @@ class CONTENT_EXPORT BluetoothDelegate {
virtual bool IsAllowedToAccessAtLeastOneService( virtual bool IsAllowedToAccessAtLeastOneService(
RenderFrameHost* frame, RenderFrameHost* frame,
const blink::WebBluetoothDeviceId& device_id) = 0; const blink::WebBluetoothDeviceId& device_id) = 0;
// This should return a list of devices that the origin in |frame| has been
// allowed to access. Access permission is granted with
// GrantServiceAccessPermission() and can be revoked by the user in the
// embedder's UI. The list of devices returned should be PermittedDevice
// objects, which contain the necessary fields to create the BluetoothDevice
// JavaScript objects.
virtual std::vector<blink::mojom::WebBluetoothDevicePtr> GetPermittedDevices(
RenderFrameHost* frame) = 0;
}; };
} // namespace content } // namespace content
......
...@@ -86,6 +86,20 @@ bool FakeBluetoothDelegate::IsAllowedToAccessAtLeastOneService( ...@@ -86,6 +86,20 @@ bool FakeBluetoothDelegate::IsAllowedToAccessAtLeastOneService(
return !id_to_services_it->second.empty(); return !id_to_services_it->second.empty();
} }
std::vector<blink::mojom::WebBluetoothDevicePtr>
FakeBluetoothDelegate::GetPermittedDevices(RenderFrameHost* frame) {
std::vector<blink::mojom::WebBluetoothDevicePtr> permitted_devices;
auto& device_address_to_id_map = GetAddressToIdMapForOrigin(frame);
for (const auto& entry : device_address_to_id_map) {
auto permitted_device = blink::mojom::WebBluetoothDevice::New();
WebBluetoothDeviceId device_id = entry.second;
permitted_device->id = device_id;
permitted_device->name = device_id_to_name_map_[device_id];
permitted_devices.push_back(std::move(permitted_device));
}
return permitted_devices;
}
WebBluetoothDeviceId FakeBluetoothDelegate::GetOrCreateDeviceIdForDeviceAddress( WebBluetoothDeviceId FakeBluetoothDelegate::GetOrCreateDeviceIdForDeviceAddress(
RenderFrameHost* frame, RenderFrameHost* frame,
const std::string& device_address) { const std::string& device_address) {
......
...@@ -64,6 +64,8 @@ class FakeBluetoothDelegate : public BluetoothDelegate { ...@@ -64,6 +64,8 @@ class FakeBluetoothDelegate : public BluetoothDelegate {
bool IsAllowedToAccessAtLeastOneService( bool IsAllowedToAccessAtLeastOneService(
RenderFrameHost* frame, RenderFrameHost* frame,
const blink::WebBluetoothDeviceId& device_id) override; const blink::WebBluetoothDeviceId& device_id) override;
std::vector<blink::mojom::WebBluetoothDevicePtr> GetPermittedDevices(
RenderFrameHost* frame) override;
private: private:
using AddressToIdMap = std::map<std::string, blink::WebBluetoothDeviceId>; using AddressToIdMap = std::map<std::string, blink::WebBluetoothDeviceId>;
......
...@@ -181,9 +181,20 @@ interface WebBluetoothService { ...@@ -181,9 +181,20 @@ interface WebBluetoothService {
// Checks if Web Bluetooth is allowed and if a Bluetooth radio is available. // Checks if Web Bluetooth is allowed and if a Bluetooth radio is available.
GetAvailability() => (bool is_available); GetAvailability() => (bool is_available);
// Requests access to a Bluetooth device which matches
// |options->filters->services|. Access is limited to the current origin, and
// to the union of |options->filters->services| and
// |options->optional_services|. Multiple devices may be discoverable that
// match and one must be selected via a chooser user interface.
RequestDevice(WebBluetoothRequestDeviceOptions options) RequestDevice(WebBluetoothRequestDeviceOptions options)
=> (WebBluetoothResult result, WebBluetoothDevice? device); => (WebBluetoothResult result, WebBluetoothDevice? device);
// Returns a list of permitted Bluetooth devices that the current origin can
// access services on. These devices are granted access via RequestDevice(),
// but the permission can be revoked at any time by the user through the
// browser's UI.
GetDevices() => (array<WebBluetoothDevice> devices);
// Creates a GATT Connection to a Bluetooth Device identified by |device_id| // Creates a GATT Connection to a Bluetooth Device identified by |device_id|
// if a connection to the device didn't exist already. If a GATT connection // if a connection to the device didn't exist already. If a GATT connection
// existed already then this function increases the ref count to keep that // existed already then this function increases the ref count to keep that
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <utility> #include <utility>
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h" #include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h" #include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/receiver_set.h"
...@@ -50,6 +51,21 @@ const char kHandleGestureForPermissionRequest[] = ...@@ -50,6 +51,21 @@ const char kHandleGestureForPermissionRequest[] =
"Must be handling a user gesture to show a permission request."; "Must be handling a user gesture to show a permission request.";
} // namespace } // namespace
// Remind developers when they are using Web Bluetooth on unsupported platforms.
// TODO(https://crbug.com/570344): Remove this method when all platforms are
// supported.
void AddUnsupportedPlatformConsoleMessage(ExecutionContext* context) {
#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_MACOSX) && \
!defined(OS_WIN)
context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
mojom::blink::ConsoleMessageSource::kJavaScript,
mojom::blink::ConsoleMessageLevel::kInfo,
"Web Bluetooth is experimental on this platform. See "
"https://github.com/WebBluetoothCG/web-bluetooth/blob/gh-pages/"
"implementation-status.md"));
#endif
}
static void CanonicalizeFilter( static void CanonicalizeFilter(
const BluetoothLEScanFilterInit* filter, const BluetoothLEScanFilterInit* filter,
mojom::blink::WebBluetoothLeScanFilterPtr& canonicalized_filter, mojom::blink::WebBluetoothLeScanFilterPtr& canonicalized_filter,
...@@ -168,6 +184,23 @@ ScriptPromise Bluetooth::getAvailability(ScriptState* script_state, ...@@ -168,6 +184,23 @@ ScriptPromise Bluetooth::getAvailability(ScriptState* script_state,
return promise; return promise;
} }
void Bluetooth::GetDevicesCallback(
ScriptPromiseResolver* resolver,
Vector<mojom::blink::WebBluetoothDevicePtr> devices) {
if (!resolver->GetExecutionContext() ||
resolver->GetExecutionContext()->IsContextDestroyed()) {
return;
}
HeapVector<Member<BluetoothDevice>> bluetooth_devices;
for (auto& device : devices) {
BluetoothDevice* bluetooth_device = GetBluetoothDeviceRepresentingDevice(
std::move(device), resolver->GetExecutionContext());
bluetooth_devices.push_back(*bluetooth_device);
}
resolver->Resolve(bluetooth_devices);
}
void Bluetooth::RequestDeviceCallback( void Bluetooth::RequestDeviceCallback(
ScriptPromiseResolver* resolver, ScriptPromiseResolver* resolver,
mojom::blink::WebBluetoothResult result, mojom::blink::WebBluetoothResult result,
...@@ -186,6 +219,27 @@ void Bluetooth::RequestDeviceCallback( ...@@ -186,6 +219,27 @@ void Bluetooth::RequestDeviceCallback(
} }
} }
ScriptPromise Bluetooth::getDevices(ScriptState* script_state,
ExceptionState& exception_state) {
ExecutionContext* context = GetExecutionContext();
if (!context) {
exception_state.ThrowTypeError(kInactiveDocumentError);
return ScriptPromise();
}
AddUnsupportedPlatformConsoleMessage(context);
CHECK(context->IsSecureContext());
EnsureServiceConnection(context);
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();
service_->GetDevices(WTF::Bind(&Bluetooth::GetDevicesCallback,
WrapPersistent(this),
WrapPersistent(resolver)));
return promise;
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
ScriptPromise Bluetooth::requestDevice(ScriptState* script_state, ScriptPromise Bluetooth::requestDevice(ScriptState* script_state,
const RequestDeviceOptions* options, const RequestDeviceOptions* options,
...@@ -196,17 +250,7 @@ ScriptPromise Bluetooth::requestDevice(ScriptState* script_state, ...@@ -196,17 +250,7 @@ ScriptPromise Bluetooth::requestDevice(ScriptState* script_state,
return ScriptPromise(); return ScriptPromise();
} }
// Remind developers when they are using Web Bluetooth on unsupported platforms. AddUnsupportedPlatformConsoleMessage(context);
#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_MACOSX) && \
!defined(OS_WIN)
context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
mojom::ConsoleMessageSource::kJavaScript,
mojom::ConsoleMessageLevel::kInfo,
"Web Bluetooth is experimental on this platform. See "
"https://github.com/WebBluetoothCG/web-bluetooth/blob/gh-pages/"
"implementation-status.md"));
#endif
CHECK(context->IsSecureContext()); CHECK(context->IsSecureContext());
// If the algorithm is not allowed to show a popup, reject promise with a // If the algorithm is not allowed to show a popup, reject promise with a
......
...@@ -36,6 +36,7 @@ class Bluetooth final : public EventTargetWithInlineData, ...@@ -36,6 +36,7 @@ class Bluetooth final : public EventTargetWithInlineData,
// IDL exposed interface: // IDL exposed interface:
ScriptPromise getAvailability(ScriptState*, ExceptionState&); ScriptPromise getAvailability(ScriptState*, ExceptionState&);
ScriptPromise getDevices(ScriptState*, ExceptionState&);
ScriptPromise requestDevice(ScriptState*, ScriptPromise requestDevice(ScriptState*,
const RequestDeviceOptions*, const RequestDeviceOptions*,
ExceptionState&); ExceptionState&);
...@@ -72,6 +73,9 @@ class Bluetooth final : public EventTargetWithInlineData, ...@@ -72,6 +73,9 @@ class Bluetooth final : public EventTargetWithInlineData,
mojom::blink::WebBluetoothDevicePtr, mojom::blink::WebBluetoothDevicePtr,
ExecutionContext*); ExecutionContext*);
void GetDevicesCallback(ScriptPromiseResolver*,
Vector<mojom::blink::WebBluetoothDevicePtr>);
void RequestDeviceCallback(ScriptPromiseResolver*, void RequestDeviceCallback(ScriptPromiseResolver*,
mojom::blink::WebBluetoothResult, mojom::blink::WebBluetoothResult,
mojom::blink::WebBluetoothDevicePtr); mojom::blink::WebBluetoothDevicePtr);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
SecureContext SecureContext
] interface Bluetooth : EventTarget { ] interface Bluetooth : EventTarget {
[CallWith=ScriptState, RaisesException] Promise<boolean> getAvailability(); [CallWith=ScriptState, RaisesException] Promise<boolean> getAvailability();
[RuntimeEnabled=WebBluetoothGetDevices, CallWith=ScriptState, RaisesException] Promise<sequence<BluetoothDevice>> getDevices();
[CallWith=ScriptState, RaisesException, MeasureAs=WebBluetoothRequestDevice] Promise<BluetoothDevice> requestDevice (optional RequestDeviceOptions options = {}); [CallWith=ScriptState, RaisesException, MeasureAs=WebBluetoothRequestDevice] Promise<BluetoothDevice> requestDevice (optional RequestDeviceOptions options = {});
// https://webbluetoothcg.github.io/web-bluetooth/scanning.html#scanning // https://webbluetoothcg.github.io/web-bluetooth/scanning.html#scanning
......
...@@ -1815,6 +1815,10 @@ ...@@ -1815,6 +1815,10 @@
"default": "experimental", "default": "experimental",
}, },
}, },
{
name: "WebBluetoothGetDevices",
status: "experimental",
},
{ {
name: "WebBluetoothScanning", name: "WebBluetoothScanning",
status: "experimental", status: "experimental",
......
// META: script=/resources/testdriver.js
// META: script=/resources/testdriver-vendor.js
// META: script=/bluetooth/resources/bluetooth-helpers.js
'use strict';
const test_desc = 'getDevices() resolves with permitted devices that can be ' +
'GATT connected to.';
bluetooth_test(async () => {
// Set up two connectable Bluetooth devices with their services discovered.
// One device is a Health Thermometer device with the 'health_thermometer'
// service while the other is a Heart Rate device with the 'heart_rate'
// service. Both devices contain the 'generic_access' service.
let fake_peripherals = await setUpHealthThermometerAndHeartRateDevices();
for (let fake_peripheral of fake_peripherals) {
await fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS});
await fake_peripheral.addFakeService({uuid: 'generic_access'});
if (fake_peripheral.address === '09:09:09:09:09:09')
await fake_peripheral.addFakeService({uuid: 'health_thermometer'});
else
await fake_peripheral.addFakeService({uuid: 'heart_rate'});
await fake_peripheral.setNextGATTDiscoveryResponse({code: HCI_SUCCESS});
}
// Request the Health Thermometer device with access to its 'generic_access'
// service.
await requestDeviceWithTrustedClick(
{filters: [{name: 'Health Thermometer', services: ['generic_access']}]});
let devices = await navigator.bluetooth.getDevices();
assert_equals(
devices.length, 1,
`getDevices() should return the 'Health Thermometer' device.`);
// Only the 'generic_access' service can be accessed.
try {
await devices[0].gatt.connect();
await devices[0].gatt.getPrimaryService('generic_access');
assert_promise_rejects_with_message(
devices[0].gatt.getPrimaryService('health_thermometer'),
{name: 'SecurityError'});
} catch (err) {
assert_unreached(`${err.name}: ${err.message}`);
}
// Request the Heart Rate device with access to both of its services.
await requestDeviceWithTrustedClick({
filters: [{name: 'Heart Rate', services: ['generic_access', 'heart_rate']}]
});
devices = await navigator.bluetooth.getDevices();
assert_equals(
devices.length, 2,
`getDevices() should return the 'Health Thermometer' and 'Health ` +
`Monitor' devices`);
// All of Heart Rate device's services can be accessed, while only the
// 'generic_access' service can be accessed on Health Thermometer.
try {
for (let device of devices) {
await device.gatt.connect();
await device.gatt.getPrimaryService('generic_access');
if (device.name === 'Heart Rate') {
await device.gatt.getPrimaryService('heart_rate');
} else {
assert_promise_rejects_with_message(
devices[0].gatt.getPrimaryService('health_thermometer'),
{name: 'SecurityError'});
}
}
} catch (err) {
assert_unreached(`${err.name}: ${err.message}`);
}
}, test_desc);
\ No newline at end of file
// META: script=/resources/testdriver.js
// META: script=/resources/testdriver-vendor.js
// META: script=/bluetooth/resources/bluetooth-helpers.js
'use strict';
const test_desc = 'getDevices() resolves with empty array if no device ' +
'permissions have been granted.';
bluetooth_test(async () => {
await navigator.bluetooth.test.simulateCentral({state: 'powered-on'});
let devices = await navigator.bluetooth.getDevices();
assert_equals(
0, devices.length, 'getDevices() should resolve with an empty array');
}, test_desc);
\ No newline at end of file
// META: script=/resources/testdriver.js
// META: script=/resources/testdriver-vendor.js
// META: script=/bluetooth/resources/bluetooth-helpers.js
'use strict';
const test_desc = 'multiple calls to getDevices() resolves with the same' +
'BluetoothDevice objects for each granted Bluetooth device.';
bluetooth_test(async () => {
await getConnectedHealthThermometerDevice();
let firstDevices = await navigator.bluetooth.getDevices();
assert_equals(
firstDevices.length, 1, 'getDevices() should return the granted device.');
let secondDevices = await navigator.bluetooth.getDevices();
assert_equals(
secondDevices.length, 1,
'getDevices() should return the granted device.');
assert_equals(
firstDevices[0], secondDevices[0],
'getDevices() should produce the same BluetoothDevice objects for a ' +
'given Bluetooth device.');
}, test_desc);
\ No newline at end of file
...@@ -16,6 +16,7 @@ test(() => { ...@@ -16,6 +16,7 @@ test(() => {
// Bluetooth implements BluetoothDiscovery; // Bluetooth implements BluetoothDiscovery;
assert_true('requestDevice' in navigator.bluetooth); assert_true('requestDevice' in navigator.bluetooth);
assert_true('getDevices' in navigator.bluetooth);
assert_equals(navigator.bluetooth.requestDevice.length, 0); assert_equals(navigator.bluetooth.requestDevice.length, 0);
}, test_desc); }, test_desc);
</script> </script>
This is a testharness.js-based test. This is a testharness.js-based test.
Found 206 tests; 147 PASS, 59 FAIL, 0 TIMEOUT, 0 NOTRUN. Found 206 tests; 149 PASS, 57 FAIL, 0 TIMEOUT, 0 NOTRUN.
PASS idl_test setup PASS idl_test setup
PASS idl_test validation PASS idl_test validation
PASS Partial interface Navigator: original interface defined PASS Partial interface Navigator: original interface defined
...@@ -30,7 +30,7 @@ PASS Bluetooth interface: existence and properties of interface prototype object ...@@ -30,7 +30,7 @@ PASS Bluetooth interface: existence and properties of interface prototype object
PASS Bluetooth interface: operation getAvailability() PASS Bluetooth interface: operation getAvailability()
FAIL Bluetooth interface: attribute onavailabilitychanged assert_true: The prototype object must have a property "onavailabilitychanged" expected true got false FAIL Bluetooth interface: attribute onavailabilitychanged assert_true: The prototype object must have a property "onavailabilitychanged" expected true got false
FAIL Bluetooth interface: attribute referringDevice assert_true: The prototype object must have a property "referringDevice" expected true got false FAIL Bluetooth interface: attribute referringDevice assert_true: The prototype object must have a property "referringDevice" expected true got false
FAIL Bluetooth interface: operation getDevices() assert_own_property: interface prototype object missing non-static operation expected property "getDevices" missing PASS Bluetooth interface: operation getDevices()
PASS Bluetooth interface: operation requestDevice(optional RequestDeviceOptions) PASS Bluetooth interface: operation requestDevice(optional RequestDeviceOptions)
PASS Bluetooth interface: attribute onadvertisementreceived PASS Bluetooth interface: attribute onadvertisementreceived
FAIL Bluetooth interface: attribute ongattserverdisconnected assert_true: The prototype object must have a property "ongattserverdisconnected" expected true got false FAIL Bluetooth interface: attribute ongattserverdisconnected assert_true: The prototype object must have a property "ongattserverdisconnected" expected true got false
...@@ -43,7 +43,7 @@ PASS Stringification of navigator.bluetooth ...@@ -43,7 +43,7 @@ PASS Stringification of navigator.bluetooth
PASS Bluetooth interface: navigator.bluetooth must inherit property "getAvailability()" with the proper type PASS Bluetooth interface: navigator.bluetooth must inherit property "getAvailability()" with the proper type
FAIL Bluetooth interface: navigator.bluetooth must inherit property "onavailabilitychanged" with the proper type assert_inherits: property "onavailabilitychanged" not found in prototype chain FAIL Bluetooth interface: navigator.bluetooth must inherit property "onavailabilitychanged" with the proper type assert_inherits: property "onavailabilitychanged" not found in prototype chain
FAIL Bluetooth interface: navigator.bluetooth must inherit property "referringDevice" with the proper type assert_inherits: property "referringDevice" not found in prototype chain FAIL Bluetooth interface: navigator.bluetooth must inherit property "referringDevice" with the proper type assert_inherits: property "referringDevice" not found in prototype chain
FAIL Bluetooth interface: navigator.bluetooth must inherit property "getDevices()" with the proper type assert_inherits: property "getDevices" not found in prototype chain PASS Bluetooth interface: navigator.bluetooth must inherit property "getDevices()" with the proper type
PASS Bluetooth interface: navigator.bluetooth must inherit property "requestDevice(optional RequestDeviceOptions)" with the proper type PASS Bluetooth interface: navigator.bluetooth must inherit property "requestDevice(optional RequestDeviceOptions)" with the proper type
PASS Bluetooth interface: calling requestDevice(optional RequestDeviceOptions) on navigator.bluetooth with too few arguments must throw TypeError PASS Bluetooth interface: calling requestDevice(optional RequestDeviceOptions) on navigator.bluetooth with too few arguments must throw TypeError
PASS Bluetooth interface: navigator.bluetooth must inherit property "onadvertisementreceived" with the proper type PASS Bluetooth interface: navigator.bluetooth must inherit property "onadvertisementreceived" with the proper type
......
...@@ -8,6 +8,7 @@ interface Bluetooth : EventTarget ...@@ -8,6 +8,7 @@ interface Bluetooth : EventTarget
getter onadvertisementreceived getter onadvertisementreceived
method constructor method constructor
method getAvailability method getAvailability
method getDevices
method requestDevice method requestDevice
method requestLEScan method requestLEScan
setter onadvertisementreceived setter onadvertisementreceived
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment