From 359548f60762b13716ca1d7a45077af77b8aa38f Mon Sep 17 00:00:00 2001 From: zakorgyula Date: Wed, 7 Sep 2016 09:10:30 +0200 Subject: [PATCH] requestDevice update --- components/net/bluetooth_thread.rs | 15 ++-- components/net_traits/bluetooth_scanfilter.rs | 34 ++++++++- components/script/dom/bluetooth.rs | 76 ++++++++++++++----- .../script/dom/webidls/Bluetooth.webidl | 17 +++-- .../bluetooth_request_all_devices.html | 28 +++++++ 5 files changed, 136 insertions(+), 34 deletions(-) create mode 100644 tests/html/bluetooth/bluetooth_request_all_devices.html diff --git a/components/net/bluetooth_thread.rs b/components/net/bluetooth_thread.rs index 51226e21d902..e81ed2be8b60 100644 --- a/components/net/bluetooth_thread.rs +++ b/components/net/bluetooth_thread.rs @@ -114,7 +114,8 @@ fn matches_filter(device: &BluetoothDevice, filter: &BluetoothScanfilter) -> boo } } } - return true; + + true } fn matches_filters(device: &BluetoothDevice, filters: &BluetoothScanfilterSequence) -> bool { @@ -437,10 +438,14 @@ impl BluetoothManager { } let _ = session.stop_discovery(); } - let devices = self.get_and_cache_devices(&mut adapter); - let matched_devices: Vec = devices.into_iter() - .filter(|d| matches_filters(d, options.get_filters())) - .collect(); + + let mut matched_devices = self.get_and_cache_devices(&mut adapter); + if !options.is_accepting_all_devices() { + matched_devices = matched_devices.into_iter() + .filter(|d| matches_filters(d, options.get_filters())) + .collect(); + } + if let Some(address) = self.select_device(matched_devices) { let device_id = match self.address_to_id.get(&address) { Some(id) => id.clone(), diff --git a/components/net_traits/bluetooth_scanfilter.rs b/components/net_traits/bluetooth_scanfilter.rs index 2dd7f14d725b..b5017de72ad4 100644 --- a/components/net_traits/bluetooth_scanfilter.rs +++ b/components/net_traits/bluetooth_scanfilter.rs @@ -28,14 +28,23 @@ pub struct BluetoothScanfilter { name: String, name_prefix: String, services: ServiceUUIDSequence, + manufacturer_id: Option, + service_data_uuid: String, } impl BluetoothScanfilter { - pub fn new(name: String, name_prefix: String, services: Vec) -> BluetoothScanfilter { + pub fn new(name: String, + name_prefix: String, + services: Vec, + manufacturer_id: Option, + service_data_uuid: String) + -> BluetoothScanfilter { BluetoothScanfilter { name: name, name_prefix: name_prefix, services: ServiceUUIDSequence::new(services), + manufacturer_id: manufacturer_id, + service_data_uuid: service_data_uuid, } } @@ -51,8 +60,20 @@ impl BluetoothScanfilter { &self.services.0 } + pub fn get_manufacturer_id(&self) -> Option { + self.manufacturer_id + } + + pub fn get_service_data_uuid(&self) -> &str { + &self.service_data_uuid + } + pub fn is_empty_or_invalid(&self) -> bool { - (self.name.is_empty() && self.name_prefix.is_empty() && self.get_services().is_empty()) || + (self.name.is_empty() && + self.name_prefix.is_empty() && + self.get_services().is_empty() && + self.manufacturer_id.is_none() && + self.service_data_uuid.is_empty()) || self.name.len() > MAX_NAME_LENGTH || self.name_prefix.len() > MAX_NAME_LENGTH } @@ -67,7 +88,6 @@ impl BluetoothScanfilterSequence { } pub fn has_empty_or_invalid_filter(&self) -> bool { - self.0.is_empty() || self.0.iter().any(BluetoothScanfilter::is_empty_or_invalid) } @@ -78,6 +98,10 @@ impl BluetoothScanfilterSequence { fn get_services_set(&self) -> HashSet { self.iter().flat_map(|filter| filter.services.get_services_set()).collect() } + + fn is_empty(&self) -> bool { + self.0.is_empty() + } } #[derive(Deserialize, Serialize)] @@ -103,4 +127,8 @@ impl RequestDeviceoptions { pub fn get_services_set(&self) -> HashSet { &self.filters.get_services_set() | &self.optional_services.get_services_set() } + + pub fn is_accepting_all_devices(&self) -> bool { + self.filters.is_empty() + } } diff --git a/components/script/dom/bluetooth.rs b/components/script/dom/bluetooth.rs index b6c04a1e867d..cac1cb7c7ee7 100644 --- a/components/script/dom/bluetooth.rs +++ b/components/script/dom/bluetooth.rs @@ -4,8 +4,7 @@ use bluetooth_blacklist::{Blacklist, uuid_is_blacklisted}; use core::clone::Clone; -use dom::bindings::codegen::Bindings::BluetoothBinding; -use dom::bindings::codegen::Bindings::BluetoothBinding::{BluetoothMethods, BluetoothScanFilter}; +use dom::bindings::codegen::Bindings::BluetoothBinding::{self, BluetoothMethods, BluetoothRequestDeviceFilter}; use dom::bindings::codegen::Bindings::BluetoothBinding::RequestDeviceOptions; use dom::bindings::error::Error::{self, Security, Type}; use dom::bindings::error::Fallible; @@ -21,7 +20,7 @@ use net_traits::bluetooth_scanfilter::{BluetoothScanfilter, BluetoothScanfilterS use net_traits::bluetooth_scanfilter::{RequestDeviceoptions, ServiceUUIDSequence}; use net_traits::bluetooth_thread::{BluetoothError, BluetoothMethodMsg}; -const FILTER_EMPTY_ERROR: &'static str = "'filters' member must be nonempty to find any devices."; +const FILTER_EMPTY_ERROR: &'static str = "'filters' member, if present, must be nonempty to find any devices."; const FILTER_ERROR: &'static str = "A filter must restrict the devices in some way."; const FILTER_NAME_TOO_LONG_ERROR: &'static str = "A 'name' or 'namePrefix' can't be longer then 29 bytes."; // 248 is the maximum number of UTF-8 code units in a Bluetooth Device Name. @@ -34,6 +33,8 @@ const MAX_FILTER_NAME_LENGTH: usize = 29; const NAME_PREFIX_ERROR: &'static str = "'namePrefix', if present, must be nonempty."; const NAME_TOO_LONG_ERROR: &'static str = "A device name can't be longer than 248 bytes."; const SERVICE_ERROR: &'static str = "'services', if present, must contain at least one service."; +const OPTIONS_ERROR: &'static str = "Fields of 'options' conflict with each other. + Either 'acceptAllDevices' member must be true, or 'filters' member must be set to a value."; // https://webbluetoothcg.github.io/web-bluetooth/#bluetooth #[dom_struct] @@ -62,7 +63,7 @@ impl Bluetooth { // https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices fn request_bluetooth_devices(&self, - filters: &[BluetoothScanFilter], + filters: &Option>, optional_services: &Option>) -> Fallible> { let option = try!(convert_request_device_options(self.global().r(), filters, optional_services)); @@ -84,39 +85,46 @@ impl Bluetooth { Err(Error::from(error)) }, } + } } fn convert_request_device_options(global: GlobalRef, - filters: &[BluetoothScanFilter], + filters: &Option>, optional_services: &Option>) -> Fallible { - if filters.is_empty() { - return Err(Type(FILTER_EMPTY_ERROR.to_owned())); - } - - let mut filters_vec = vec!(); - for filter in filters { - filters_vec.push(try!(canonicalize_filter(&filter, global))); + let mut uuid_filters = vec!(); + if let &Some(ref filters) = filters { + if filters.is_empty() { + return Err(Type(FILTER_EMPTY_ERROR.to_owned())); + } + for filter in filters { + uuid_filters.push(try!(canonicalize_filter(&filter, global))); + } } - let mut optional_services_vec = vec!(); + let mut optional_services_uuids = vec!(); if let &Some(ref opt_services) = optional_services { for opt_service in opt_services { let uuid = try!(BluetoothUUID::GetService(global, opt_service.clone())).to_string(); + if !uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) { - optional_services_vec.push(uuid); + optional_services_uuids.push(uuid); } } } - Ok(RequestDeviceoptions::new(BluetoothScanfilterSequence::new(filters_vec), - ServiceUUIDSequence::new(optional_services_vec))) + Ok(RequestDeviceoptions::new(BluetoothScanfilterSequence::new(uuid_filters), + ServiceUUIDSequence::new(optional_services_uuids))) } -fn canonicalize_filter(filter: &BluetoothScanFilter, global: GlobalRef) -> Fallible { - if filter.services.is_none() && filter.name.is_none() && filter.namePrefix.is_none() { - return Err(Type(FILTER_ERROR.to_owned())); +fn canonicalize_filter(filter: &BluetoothRequestDeviceFilter, global: GlobalRef) -> Fallible { + if filter.services.is_none() && + filter.name.is_none() && + filter.namePrefix.is_none() && + filter.manufacturerId.is_none() && + filter.serviceDataUUID.is_none() { + return Err(Type(FILTER_ERROR.to_owned())); } let services_vec = match filter.services { @@ -167,7 +175,24 @@ fn canonicalize_filter(filter: &BluetoothScanFilter, global: GlobalRef) -> Falli None => String::new(), }; - Ok(BluetoothScanfilter::new(name, name_prefix, services_vec)) + let manufacturer_id = filter.manufacturerId; + + let service_data_uuid = match filter.serviceDataUUID { + Some(ref service_data_uuid) => { + let uuid = try!(BluetoothUUID::GetService(global, service_data_uuid.clone())).to_string(); + if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) { + return Err(Security) + } + uuid + }, + None => String::new(), + }; + + Ok(BluetoothScanfilter::new(name, + name_prefix, + services_vec, + manufacturer_id, + service_data_uuid)) } impl From for Error { @@ -185,6 +210,15 @@ impl From for Error { impl BluetoothMethods for Bluetooth { // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice fn RequestDevice(&self, option: &RequestDeviceOptions) -> Fallible> { - self.request_bluetooth_devices(&option.filters, &option.optionalServices) + if (option.filters.is_some() && option.acceptAllDevices) || + (option.filters.is_none() && !option.acceptAllDevices) { + return Err(Type(OPTIONS_ERROR.to_owned())); + } + + if !option.acceptAllDevices { + return self.request_bluetooth_devices(&option.filters, &option.optionalServices); + } + + self.request_bluetooth_devices(&None, &option.optionalServices) } } diff --git a/components/script/dom/webidls/Bluetooth.webidl b/components/script/dom/webidls/Bluetooth.webidl index 63cea97ca19e..6c575db150ce 100644 --- a/components/script/dom/webidls/Bluetooth.webidl +++ b/components/script/dom/webidls/Bluetooth.webidl @@ -4,24 +4,31 @@ // https://webbluetoothcg.github.io/web-bluetooth/#bluetooth -dictionary BluetoothScanFilter { +dictionary BluetoothRequestDeviceFilter { sequence services; DOMString name; DOMString namePrefix; + unsigned short manufacturerId; + BluetoothServiceUUID serviceDataUUID; }; dictionary RequestDeviceOptions { - required sequence filters; + sequence filters; sequence optionalServices /*= []*/; + boolean acceptAllDevices = false; }; [Pref="dom.bluetooth.enabled", Exposed=(Window,Worker)] interface Bluetooth { - // Promise requestDevice(RequestDeviceOptions options); - [Throws] - BluetoothDevice requestDevice(RequestDeviceOptions options); +// [SecureContext] +// readonly attribute BluetoothDevice? referringDevice; +// [SecureContext] +// Promise requestDevice(RequestDeviceOptions options); + [Throws] + BluetoothDevice requestDevice(optional RequestDeviceOptions options); }; // Bluetooth implements EventTarget; +// Bluetooth implements BluetoothDeviceEventHandlers; // Bluetooth implements CharacteristicEventHandlers; // Bluetooth implements ServiceEventHandlers; diff --git a/tests/html/bluetooth/bluetooth_request_all_devices.html b/tests/html/bluetooth/bluetooth_request_all_devices.html new file mode 100644 index 000000000000..8bf80ab3d28e --- /dev/null +++ b/tests/html/bluetooth/bluetooth_request_all_devices.html @@ -0,0 +1,28 @@ + + +Request All Devices + + +

+    
+    
+
+