Commit e39d59d4 authored by Reilly Grant's avatar Reilly Grant Committed by Commit Bot

[serial] Support filtering ports by USB vendor and product IDs

This change implements support for filtering serial ports based on a USB
vendor and product ID. The naming of the filter properties comes from
the Serial API polyfill library where I felt it was important to be
specific that this filter will only apply to USB devices and so also
implies that the device being requested by the page will be a USB
device.

This is useful for applications which are targeting a particular model
of serial device that is known to be connected over USB and advertises
a recognizable vendor ID/product ID pair.

Bug: 884928
Change-Id: Ie6a2674911c449ed48d58ea82175fe03bc14c572
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1994262Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarOvidio de Jesús Ruiz-Henríquez <odejesush@chromium.org>
Commit-Queue: Reilly Grant <reillyg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#730218}
parent 712bce08
......@@ -912,6 +912,7 @@ if (!is_android) {
"serial/serial_input_signals.idl",
"serial/serial_options.idl",
"serial/serial_output_signals.idl",
"serial/serial_port_filter.idl",
"serial/serial_port_request_options.idl",
],
"abspath")
......
......@@ -18,6 +18,8 @@
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/modules/event_target_modules_names.h"
#include "third_party/blink/renderer/modules/serial/serial_port.h"
#include "third_party/blink/renderer/modules/serial/serial_port_filter.h"
#include "third_party/blink/renderer/modules/serial/serial_port_request_options.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
namespace blink {
......@@ -102,11 +104,40 @@ ScriptPromise Serial::requestPort(ScriptState* script_state,
return ScriptPromise();
}
Vector<mojom::blink::SerialPortFilterPtr> filters;
if (options && options->hasFilters()) {
for (const auto& filter : options->filters()) {
auto mojo_filter = mojom::blink::SerialPortFilter::New();
mojo_filter->has_vendor_id = filter->hasUsbVendorId();
if (mojo_filter->has_vendor_id) {
mojo_filter->vendor_id = filter->usbVendorId();
} else {
exception_state.ThrowTypeError(
"A filter must provide a property to filter by.");
return ScriptPromise();
}
mojo_filter->has_product_id = filter->hasUsbProductId();
if (mojo_filter->has_product_id) {
if (!mojo_filter->has_vendor_id) {
exception_state.ThrowTypeError(
"A filter containing a usbProductId must also specify a "
"usbVendorId.");
return ScriptPromise();
}
mojo_filter->product_id = filter->usbProductId();
}
filters.push_back(std::move(mojo_filter));
}
}
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
request_port_promises_.insert(resolver);
EnsureServiceConnection();
service_->RequestPort(Vector<mojom::blink::SerialPortFilterPtr>(),
service_->RequestPort(std::move(filters),
WTF::Bind(&Serial::OnRequestPort, WrapPersistent(this),
WrapPersistent(resolver)));
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// https://wicg.github.io/serial
dictionary SerialPortFilter {
unsigned short usbVendorId;
unsigned short usbProductId;
};
......@@ -5,4 +5,5 @@
// https://wicg.github.io/serial
dictionary SerialPortRequestOptions {
sequence<SerialPortFilter> filters;
};
......@@ -55,5 +55,34 @@ serial_test(async (t, fake) => {
assert_true(firstPort === secondPort);
}, 'requestPort() returns the same port object every time');
serial_test(async (t, fake) => {
let guid = fake.addPort();
fake.setSelectedPort(guid);
await trustedClick();
let port = await navigator.serial.requestPort({ filters: [] });
assert_true(port instanceof SerialPort);
}, 'An empty list of filters is valid');
serial_test(async (t, fake) => {
let guid = fake.addPort();
fake.setSelectedPort(guid);
await trustedClick();
return promise_rejects(t, new TypeError(), navigator.serial.requestPort({
filters: [{}],
}));
}, 'An empty filter is not valid');
serial_test(async (t, fake) => {
let guid = fake.addPort();
fake.setSelectedPort(guid);
await trustedClick();
return promise_rejects(t, new TypeError(), navigator.serial.requestPort({
filters: [{ usbProductId: 0x0001 }],
}));
}, 'requestPort() requires a USB vendor ID if a product ID specified');
</script>
</body>
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