Skip to content

Commit

Permalink
[Web Bluetooth] Add manufacturerData filter when requesting device
Browse files Browse the repository at this point in the history
This CL adds support for new manufacturerData filter so that developers
can request Bluetooth LE devices based on manufacturer specific data
(company identifier and data).

Spec: WebBluetoothCG/web-bluetooth#545
Test: https://manufacturer-data.glitch.me/
Bug: 707635
Change-Id: I63b80812f35c8f0f557ceaf53632d0d6d2d52b9b
  • Loading branch information
beaufortfrancois authored and chromium-wpt-export-bot committed Apr 29, 2021
1 parent 9ff0db2 commit d08a267
Show file tree
Hide file tree
Showing 10 changed files with 388 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// META: script=/resources/testharness.js
// META: script=/resources/testharnessreport.js
// META: script=/resources/testdriver.js
// META: script=/resources/testdriver-vendor.js
// META: script=/bluetooth/resources/bluetooth-test.js
// META: script=/bluetooth/resources/bluetooth-fake-devices.js
'use strict';
const test_desc =
'Manufacturer data mask size must be equal to dataPrefix size.';

let filters = [{
manufacturerData: [{
companyIdentifier: 0x0001,
dataPrefix: new Uint8Array([0x01, 0x02, 0x03, 0x04]),
mask: new Uint8Array([0xff]),
}],
}];

bluetooth_test(
(t) => promise_rejects_js(
t, TypeError, requestDeviceWithTrustedClick({filters})),
test_desc);
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// META: script=/resources/testdriver.js
// META: script=/resources/testdriver-vendor.js
// META: script=/bluetooth/resources/bluetooth-test.js
// META: script=/bluetooth/resources/bluetooth-fake-devices.js
'use strict';
const test_desc = 'dataPrefix value buffer must not be detached';

function detachBuffer(buffer) {
window.postMessage('', '*', [buffer]);
}

bluetooth_test(async (t) => {
const typed_array = Uint8Array.of(1, 2);
detachBuffer(typed_array.buffer);

await promise_rejects_dom(
t, 'InvalidStateError', requestDeviceWithTrustedClick({
filters: [{
manufacturerData:
[{companyIdentifier: 0x0001, dataPrefix: typed_array}]
}]
}));

const array_buffer = Uint8Array.of(3, 4).buffer;
detachBuffer(array_buffer);

await promise_rejects_dom(
t, 'InvalidStateError', requestDeviceWithTrustedClick({
filters: [{
manufacturerData:
[{companyIdentifier: 0x0001, dataPrefix: array_buffer}]
}]
}));
}, test_desc);
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// META: script=/resources/testharness.js
// META: script=/resources/testharnessreport.js
// META: script=/resources/testdriver.js
// META: script=/resources/testdriver-vendor.js
// META: script=/bluetooth/resources/bluetooth-test.js
// META: script=/bluetooth/resources/bluetooth-fake-devices.js
'use strict';
const test_desc = 'requestDevice with empty manufacturerData. ' +
'Should reject with TypeError.';
const test_specs = [
{filters: [{manufacturerData: []}]},
{filters: [{manufacturerData: [], name: 'Name'}]},
{filters: [{manufacturerData: [], services: ['heart_rate']}]},
{filters: [{manufacturerData: [], name: 'Name', services: ['heart_rate']}]},
{filters: [{manufacturerData: []}], optionalServices: ['heart_rate']}, {
filters: [{manufacturerData: [], name: 'Name'}],
optionalServices: ['heart_rate']
},
{
filters: [{manufacturerData: [], services: ['heart_rate']}],
optionalServices: ['heart_rate']
},
{
filters: [{manufacturerData: [], name: 'Name', services: ['heart_rate']}],
optionalServices: ['heart_rate']
}
];

bluetooth_test((t) => {
let test_promises = Promise.resolve();
test_specs.forEach(args => {
test_promises = test_promises.then(
() => promise_rejects_js(
t, TypeError, requestDeviceWithTrustedClick(args)));
});
return test_promises;
}, test_desc);
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// META: script=/resources/testdriver.js
// META: script=/resources/testdriver-vendor.js
// META: script=/bluetooth/resources/bluetooth-test.js
// META: script=/bluetooth/resources/bluetooth-fake-devices.js
'use strict';
const test_desc = 'companyIdentifier must be in the [0, 65535] range';

bluetooth_test(async (t) => {
await promise_rejects_js(
t, TypeError,
requestDeviceWithTrustedClick(
{filters: [{manufacturerData: [{companyIdentifier: -1}]}]}));
await promise_rejects_js(
t, TypeError,
requestDeviceWithTrustedClick(
{filters: [{manufacturerData: [{companyIdentifier: 65536}]}]}));
}, test_desc);
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// META: script=/resources/testdriver.js
// META: script=/resources/testdriver-vendor.js
// META: script=/bluetooth/resources/bluetooth-test.js
// META: script=/bluetooth/resources/bluetooth-fake-devices.js
'use strict';
const test_desc = 'mask value buffer must not be detached';

function detachBuffer(buffer) {
window.postMessage('', '*', [buffer]);
}

bluetooth_test(async (t) => {
const typed_array = Uint8Array.of(1, 2);
detachBuffer(typed_array.buffer);

await promise_rejects_dom(
t, 'InvalidStateError', requestDeviceWithTrustedClick({
filters: [
{manufacturerData: [{companyIdentifier: 0x0001, mask: typed_array}]}
]
}));

const array_buffer = Uint8Array.of(3, 4).buffer;
detachBuffer(array_buffer);

await promise_rejects_dom(
t, 'InvalidStateError', requestDeviceWithTrustedClick({
filters: [
{manufacturerData: [{companyIdentifier: 0x0001, mask: array_buffer}]}
]
}));
}, test_desc);
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// META: script=/resources/testharness.js
// META: script=/resources/testharnessreport.js
// META: script=/resources/testdriver.js
// META: script=/resources/testdriver-vendor.js
// META: script=/bluetooth/resources/bluetooth-test.js
// META: script=/bluetooth/resources/bluetooth-fake-devices.js
'use strict';
const test_desc = 'Manufacturer data company identifier must be unique.';
const expected = new TypeError();

let filters = [{
manufacturerData: [
{
companyIdentifier: 0x0001,
},
{
companyIdentifier: 0x0001,
}
]
}];

bluetooth_test(
(t) => promise_rejects_js(
t, TypeError, requestDeviceWithTrustedClick({filters})),
test_desc);
34 changes: 30 additions & 4 deletions bluetooth/requestDevice/filter-matches.https.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
let matching_services = [health_thermometer.uuid];
let matching_name = 'Health Thermometer';
let matching_namePrefix = 'Health';
let matching_manufacturerData = [{ companyIdentifier: 0x0001 }];

let test_specs = [
{
Expand All @@ -24,25 +25,50 @@
name: matching_name,
}]
},
{filters: [{services: matching_services, namePrefix: matching_namePrefix}]}, {
{
filters: [{
services: matching_services,
namePrefix: matching_namePrefix
}]
},
{
filters: [{
services: matching_services,
manufacturerData: matching_manufacturerData
}]
},
{
filters: [{
name: matching_name,
}],
optionalServices: matching_services
},
{
filters: [{name: matching_name, namePrefix: matching_namePrefix}],
filters: [{
namePrefix: matching_namePrefix
}],
optionalServices: matching_services
},
{
filters: [{
manufacturerData: matching_manufacturerData
}],
optionalServices: matching_services
},
{
filters: [{namePrefix: matching_namePrefix}],
filters: [{
name: matching_name,
namePrefix: matching_namePrefix,
manufacturerData: matching_manufacturerData
}],
optionalServices: matching_services
},
{
filters: [{
services: matching_services,
name: matching_name,
namePrefix: matching_namePrefix
namePrefix: matching_namePrefix,
manufacturerData: matching_manufacturerData
}]
}
];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// META: script=/resources/testharness.js
// META: script=/resources/testharnessreport.js
// META: script=/resources/testdriver.js
// META: script=/resources/testdriver-vendor.js
// META: script=/bluetooth/resources/bluetooth-test.js
// META: script=/bluetooth/resources/bluetooth-fake-devices.js
'use strict';
const test_desc = 'Matches a filter when manufacturer data match.';

let test_specs = [
{
filters: [{
manufacturerData: [{
companyIdentifier: 0x0001,
}],
}],
},
{
filters: [{
manufacturerData: [{
companyIdentifier: 0x0001,
dataPrefix: new Uint8Array([0x01]),
}],
}],
},
{
filters: [{
manufacturerData: [{
companyIdentifier: 0x0001,
dataPrefix: new Uint8Array([0x01]),
mask: new Uint8Array([0xff]),
}],
}],
},
{
filters: [{
manufacturerData: [{
companyIdentifier: 0x0001,
dataPrefix: new Uint8Array([0x01, 0x02]),
}],
}],
},
{
filters: [{
manufacturerData: [{
companyIdentifier: 0x0001,
dataPrefix: new Uint8Array([0x01, 0x02]),
mask: new Uint8Array([0xff, 0xff]),
}],
}],
},
{
filters: [{
manufacturerData: [
{
companyIdentifier: 0x0001,
dataPrefix: new Uint8Array([0x01, 0x02]),
mask: new Uint8Array([0xff, 0xff]),
},
{
companyIdentifier: 0x0002,
}
],
}],
},
{
filters: [{
manufacturerData: [
{
companyIdentifier: 0x0001,
dataPrefix: new Uint8Array([0x01, 0x02]),
mask: new Uint8Array([0xff, 0xff]),
},
{
companyIdentifier: 0x0002,
dataPrefix: new Uint8Array([0x03]),
}
],
}],
},
{
filters: [{
manufacturerData: [
{
companyIdentifier: 0x0001,
dataPrefix: new Uint8Array([0x01, 0x02]),
mask: new Uint8Array([0xff, 0xff]),
},
{
companyIdentifier: 0x0002,
dataPrefix: new Uint8Array([0x03]),
mask: new Uint8Array([0xff]),
}
],
}],
},
{
filters: [{
manufacturerData: [
{
companyIdentifier: 0x0001,
dataPrefix: new Uint8Array([0x01, 0x02]),
mask: new Uint8Array([0xff, 0xff]),
},
{
companyIdentifier: 0x0002,
dataPrefix: new Uint8Array([0x03, 0x04]),
}
],
}],
},
{
filters: [{
manufacturerData: [
{
companyIdentifier: 0x0001,
dataPrefix: new Uint8Array([0x01, 0x02]),
mask: new Uint8Array([0xff, 0xff]),
},
{
companyIdentifier: 0x0002,
dataPrefix: new Uint8Array([0x03, 0x04]),
mask: new Uint8Array([0xff, 0xff])
}
],
}],
},
];

bluetooth_test(
() => setUpHealthThermometerDevice().then(() => {
let test_promises = Promise.resolve();
test_specs.forEach(args => {
test_promises = test_promises.then(async () => {
const device = await requestDeviceWithTrustedClick(args);
assert_equals(device.name, 'Health Thermometer');
});
});
return test_promises;
}),
test_desc);
Loading

0 comments on commit d08a267

Please sign in to comment.