diff --git a/components/bluetooth/lib.rs b/components/bluetooth/lib.rs index 0207c9e6f744..47f3d89b011a 100644 --- a/components/bluetooth/lib.rs +++ b/components/bluetooth/lib.rs @@ -278,6 +278,9 @@ impl BluetoothManager { BluetoothRequest::EnableNotification(id, enable, sender) => { self.enable_notification(id, enable, sender) }, + BluetoothRequest::WatchAdvertisements(id, sender) => { + self.watch_advertisements(id, sender) + }, BluetoothRequest::Test(data_set_name, sender) => { self.test(data_set_name, sender) } @@ -613,9 +616,6 @@ impl BluetoothManager { let message = BluetoothDeviceMsg { id: device_id, name: device.get_name().ok(), - appearance: device.get_appearance().ok(), - tx_power: device.get_tx_power().ok().map(|p| p as i8), - rssi: device.get_rssi().ok().map(|p| p as i8), }; return drop(sender.send(Ok(BluetoothResponse::RequestDevice(message)))); } @@ -1094,4 +1094,11 @@ impl BluetoothManager { None => return drop(sender.send(Err(BluetoothError::InvalidState))), } } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-watchadvertisements + fn watch_advertisements(&mut self, _device_id: String, sender: IpcSender) { + // Step 2. + // TODO: Implement this when supported in lower level + return drop(sender.send(Err(BluetoothError::NotSupported))); + } } diff --git a/components/bluetooth_traits/lib.rs b/components/bluetooth_traits/lib.rs index 761173eb32f5..5246f4fbe3d8 100644 --- a/components/bluetooth_traits/lib.rs +++ b/components/bluetooth_traits/lib.rs @@ -31,10 +31,6 @@ pub struct BluetoothDeviceMsg { // Bluetooth Device properties pub id: String, pub name: Option, - // Advertising Data properties - pub appearance: Option, - pub tx_power: Option, - pub rssi: Option, } #[derive(Deserialize, Serialize)] @@ -93,6 +89,7 @@ pub enum BluetoothRequest { ReadValue(String, IpcSender), WriteValue(String, Vec, IpcSender), EnableNotification(String, bool, IpcSender), + WatchAdvertisements(String, IpcSender), Test(String, IpcSender>), Exit, } @@ -112,6 +109,7 @@ pub enum BluetoothResponse { ReadValue(Vec), WriteValue(Vec), EnableNotification(()), + WatchAdvertisements(()), } pub trait BluetoothResponseListener { diff --git a/components/script/dom/bluetooth.rs b/components/script/dom/bluetooth.rs index 6d35009f869c..440ee882c66c 100644 --- a/components/script/dom/bluetooth.rs +++ b/components/script/dom/bluetooth.rs @@ -19,7 +19,6 @@ use dom::bindings::js::{MutJS, Root}; use dom::bindings::refcounted::{Trusted, TrustedPromise}; use dom::bindings::reflector::{DomObject, reflect_dom_object}; use dom::bindings::str::DOMString; -use dom::bluetoothadvertisingdata::BluetoothAdvertisingData; use dom::bluetoothdevice::BluetoothDevice; use dom::bluetoothuuid::{BluetoothServiceUUID, BluetoothUUID}; use dom::eventtarget::EventTarget; @@ -400,14 +399,9 @@ impl AsyncBluetoothListener for Bluetooth { if let Some(existing_device) = device_instance_map.get(&device.id.clone()) { return promise.resolve_native(promise_cx, &existing_device.get()); } - let ad_data = BluetoothAdvertisingData::new(&self.global(), - device.appearance, - device.tx_power, - device.rssi); let bt_device = BluetoothDevice::new(&self.global(), DOMString::from(device.id.clone()), device.name.map(DOMString::from), - &ad_data, &self); device_instance_map.insert(device.id, MutJS::new(&bt_device)); // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice diff --git a/components/script/dom/bluetoothadvertisingdata.rs b/components/script/dom/bluetoothadvertisingdata.rs deleted file mode 100644 index 878f4fe82ec5..000000000000 --- a/components/script/dom/bluetoothadvertisingdata.rs +++ /dev/null @@ -1,61 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use dom::bindings::codegen::Bindings::BluetoothAdvertisingDataBinding; -use dom::bindings::codegen::Bindings::BluetoothAdvertisingDataBinding::BluetoothAdvertisingDataMethods; -use dom::bindings::js::Root; -use dom::bindings::reflector::{Reflector, reflect_dom_object}; -use dom::globalscope::GlobalScope; - -// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothadvertisingdata -#[dom_struct] -pub struct BluetoothAdvertisingData { - reflector_: Reflector, - appearance: Option, - tx_power: Option, - rssi: Option, -} - -impl BluetoothAdvertisingData { - pub fn new_inherited(appearance: Option, - tx_power: Option, - rssi: Option) - -> BluetoothAdvertisingData { - BluetoothAdvertisingData { - reflector_: Reflector::new(), - appearance: appearance, - tx_power: tx_power, - rssi: rssi, - } - } - - pub fn new(global: &GlobalScope, - appearance: Option, - txPower: Option, - rssi: Option) - -> Root { - reflect_dom_object(box BluetoothAdvertisingData::new_inherited(appearance, - txPower, - rssi), - global, - BluetoothAdvertisingDataBinding::Wrap) - } -} - -impl BluetoothAdvertisingDataMethods for BluetoothAdvertisingData { - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingdata-appearance - fn GetAppearance(&self) -> Option { - self.appearance - } - - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingdata-txpower - fn GetTxPower(&self) -> Option { - self.tx_power - } - - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingdata-rssi - fn GetRssi(&self) -> Option { - self.rssi - } -} diff --git a/components/script/dom/bluetoothadvertisingevent.rs b/components/script/dom/bluetoothadvertisingevent.rs new file mode 100644 index 000000000000..cc65aa4cd962 --- /dev/null +++ b/components/script/dom/bluetoothadvertisingevent.rs @@ -0,0 +1,126 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use dom::bindings::codegen::Bindings::BluetoothAdvertisingEventBinding::{self, BluetoothAdvertisingEventInit}; +use dom::bindings::codegen::Bindings::BluetoothAdvertisingEventBinding::BluetoothAdvertisingEventMethods; +use dom::bindings::codegen::Bindings::EventBinding::EventBinding::EventMethods; +use dom::bindings::error::Fallible; +use dom::bindings::inheritance::Castable; +use dom::bindings::js::{JS, Root, RootedReference}; +use dom::bindings::reflector::reflect_dom_object; +use dom::bindings::str::DOMString; +use dom::bluetoothdevice::BluetoothDevice; +use dom::event::{Event, EventBubbles, EventCancelable}; +use dom::globalscope::GlobalScope; +use dom::window::Window; +use servo_atoms::Atom; + +// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothadvertisingevent +#[dom_struct] +pub struct BluetoothAdvertisingEvent { + event: Event, + device: JS, + name: Option, + appearance: Option, + tx_power: Option, + rssi: Option, +} + +impl BluetoothAdvertisingEvent { + pub fn new_inherited(device: &BluetoothDevice, + name: Option, + appearance: Option, + tx_power: Option, + rssi: Option) + -> BluetoothAdvertisingEvent { + BluetoothAdvertisingEvent { + event: Event::new_inherited(), + device: JS::from_ref(device), + name: name, + appearance: appearance, + tx_power: tx_power, + rssi: rssi, + } + } + + pub fn new(global: &GlobalScope, + type_: Atom, + bubbles: EventBubbles, + cancelable: EventCancelable, + device: &BluetoothDevice, + name: Option, + appearance: Option, + txPower: Option, + rssi: Option) + -> Root { + let ev = reflect_dom_object(box BluetoothAdvertisingEvent::new_inherited(device, + name, + appearance, + txPower, + rssi), + global, + BluetoothAdvertisingEventBinding::Wrap); + { + let event = ev.upcast::(); + event.init_event(type_, bool::from(bubbles), bool::from(cancelable)); + } + ev + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingevent-bluetoothadvertisingevent + pub fn Constructor(window: &Window, + type_: DOMString, + init: &BluetoothAdvertisingEventInit) + -> Fallible> { + let global = window.upcast::(); + let device = init.device.r(); + let name = init.name.clone(); + let appearance = init.appearance.clone(); + let txPower = init.txPower.clone(); + let rssi = init.rssi.clone(); + let bubbles = EventBubbles::from(init.parent.bubbles); + let cancelable = EventCancelable::from(init.parent.cancelable); + Ok(BluetoothAdvertisingEvent::new(global, + Atom::from(type_), + bubbles, + cancelable, + device, + name, + appearance, + txPower, + rssi)) + } +} + +impl BluetoothAdvertisingEventMethods for BluetoothAdvertisingEvent { + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingevent-device + fn Device(&self) -> Root { + Root::from_ref(&*self.device) + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingevent-name + fn GetName(&self) -> Option { + self.name.clone() + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingevent-appearance + fn GetAppearance(&self) -> Option { + self.appearance + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingevent-txpower + fn GetTxPower(&self) -> Option { + self.tx_power + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingevent-rssi + fn GetRssi(&self) -> Option { + self.rssi + } + + // https://dom.spec.whatwg.org/#dom-event-istrusted + fn IsTrusted(&self) -> bool { + self.event.IsTrusted() + } +} diff --git a/components/script/dom/bluetoothdevice.rs b/components/script/dom/bluetoothdevice.rs index 9b39cfbcd5f8..d3d66b664404 100644 --- a/components/script/dom/bluetoothdevice.rs +++ b/components/script/dom/bluetoothdevice.rs @@ -2,17 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use bluetooth_traits::{BluetoothCharacteristicMsg, BluetoothDescriptorMsg, BluetoothServiceMsg}; +use bluetooth_traits::{BluetoothCharacteristicMsg, BluetoothDescriptorMsg}; +use bluetooth_traits::{BluetoothRequest, BluetoothResponse, BluetoothServiceMsg}; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::BluetoothDeviceBinding; use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods; use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; +use dom::bindings::error::Error; use dom::bindings::js::{MutJS, MutNullableJS, Root}; use dom::bindings::reflector::{DomObject, reflect_dom_object}; use dom::bindings::str::DOMString; -use dom::bluetooth::Bluetooth; -use dom::bluetoothadvertisingdata::BluetoothAdvertisingData; +use dom::bluetooth::{AsyncBluetoothListener, Bluetooth, response_async}; use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties; use dom::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic; use dom::bluetoothremotegattdescriptor::BluetoothRemoteGATTDescriptor; @@ -20,8 +21,12 @@ use dom::bluetoothremotegattserver::BluetoothRemoteGATTServer; use dom::bluetoothremotegattservice::BluetoothRemoteGATTService; use dom::eventtarget::EventTarget; use dom::globalscope::GlobalScope; +use dom::promise::Promise; +use ipc_channel::ipc::IpcSender; +use js::jsapi::JSContext; +use std::cell::Cell; use std::collections::HashMap; - +use std::rc::Rc; // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothdevice #[dom_struct] @@ -29,42 +34,39 @@ pub struct BluetoothDevice { eventtarget: EventTarget, id: DOMString, name: Option, - ad_data: MutJS, gatt: MutNullableJS, context: MutJS, attribute_instance_map: (DOMRefCell>>, DOMRefCell>>, DOMRefCell>>), + watching_advertisements: Cell, } impl BluetoothDevice { pub fn new_inherited(id: DOMString, name: Option, - ad_data: &BluetoothAdvertisingData, context: &Bluetooth) -> BluetoothDevice { BluetoothDevice { eventtarget: EventTarget::new_inherited(), id: id, name: name, - ad_data: MutJS::new(ad_data), gatt: Default::default(), context: MutJS::new(context), attribute_instance_map: (DOMRefCell::new(HashMap::new()), DOMRefCell::new(HashMap::new()), DOMRefCell::new(HashMap::new())), + watching_advertisements: Cell::new(false), } } pub fn new(global: &GlobalScope, id: DOMString, name: Option, - adData: &BluetoothAdvertisingData, context: &Bluetooth) -> Root { reflect_dom_object(box BluetoothDevice::new_inherited(id, name, - adData, context), global, BluetoothDeviceBinding::Wrap) @@ -133,6 +135,10 @@ impl BluetoothDevice { descriptor_map.insert(descriptor.instance_id.clone(), MutJS::new(&bt_descriptor)); return bt_descriptor; } + + fn get_bluetooth_thread(&self) -> IpcSender { + self.global().as_window().bluetooth_thread() + } } impl BluetoothDeviceMethods for BluetoothDevice { @@ -146,11 +152,6 @@ impl BluetoothDeviceMethods for BluetoothDevice { self.name.clone() } - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-addata - fn AdData(&self) -> Root { - self.ad_data.get() - } - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-gatt fn Gatt(&self) -> Root { // TODO: Step 1 - 2: Implement the Permission API. @@ -159,6 +160,46 @@ impl BluetoothDeviceMethods for BluetoothDevice { }) } + #[allow(unrooted_must_root)] + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-watchadvertisements + fn WatchAdvertisements(&self) -> Rc { + let p = Promise::new(&self.global()); + let sender = response_async(&p, self); + // TODO: Step 1. + // Note: Steps 2 - 3 are implemented in components/bluetooth/lib.rs in watch_advertisements function + // and in handle_response function. + self.get_bluetooth_thread().send( + BluetoothRequest::WatchAdvertisements(String::from(self.Id()), sender)).unwrap(); + return p; + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-unwatchadvertisements + fn UnwatchAdvertisements(&self) -> () { + // Step 1. + self.watching_advertisements.set(false) + // TODO: Step 2. + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-watchingadvertisements + fn WatchingAdvertisements(&self) -> bool { + self.watching_advertisements.get() + } + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdeviceeventhandlers-ongattserverdisconnected event_handler!(gattserverdisconnected, GetOngattserverdisconnected, SetOngattserverdisconnected); } + +impl AsyncBluetoothListener for BluetoothDevice { + fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc) { + match response { + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-unwatchadvertisements + BluetoothResponse::WatchAdvertisements(_result) => { + // Step 3.1. + self.watching_advertisements.set(true); + // Step 3.2. + promise.resolve_native(promise_cx, &()); + }, + _ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())), + } + } +} diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 6133b4a78a65..03847518408a 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -223,7 +223,7 @@ mod create; pub mod bindings; pub mod blob; pub mod bluetooth; -pub mod bluetoothadvertisingdata; +pub mod bluetoothadvertisingevent; pub mod bluetoothcharacteristicproperties; pub mod bluetoothdevice; pub mod bluetoothremotegattcharacteristic; diff --git a/components/script/dom/webidls/BluetoothAdvertisingData.webidl b/components/script/dom/webidls/BluetoothAdvertisingEvent.webidl similarity index 50% rename from components/script/dom/webidls/BluetoothAdvertisingData.webidl rename to components/script/dom/webidls/BluetoothAdvertisingEvent.webidl index 27583a95e4ec..2bb88b6f9de7 100644 --- a/components/script/dom/webidls/BluetoothAdvertisingData.webidl +++ b/components/script/dom/webidls/BluetoothAdvertisingEvent.webidl @@ -2,21 +2,32 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -//https://webbluetoothcg.github.io/web-bluetooth/#bluetoothadvertisingdata +// https://webbluetoothcg.github.io/web-bluetooth/#advertising-events /*interface BluetoothManufacturerDataMap { readonly maplike; }; - interface BluetoothServiceDataMap { readonly maplike; };*/ - -[Pref="dom.bluetooth.enabled"] -interface BluetoothAdvertisingData { +[Pref="dom.bluetooth.enabled", Constructor(DOMString type, BluetoothAdvertisingEventInit init)] +interface BluetoothAdvertisingEvent : Event { + readonly attribute BluetoothDevice device; + // readonly attribute FrozenArray uuids; + readonly attribute DOMString? name; readonly attribute unsigned short? appearance; readonly attribute byte? txPower; readonly attribute byte? rssi; // readonly attribute BluetoothManufacturerDataMap manufacturerData; // readonly attribute BluetoothServiceDataMap serviceData; }; +dictionary BluetoothAdvertisingEventInit : EventInit { + required BluetoothDevice device; + // sequence<(DOMString or unsigned long)> uuids; + DOMString name; + unsigned short appearance; + byte txPower; + byte rssi; + // Map manufacturerData; + // Map serviceData; +}; diff --git a/components/script/dom/webidls/BluetoothDevice.webidl b/components/script/dom/webidls/BluetoothDevice.webidl index 0e7843db109d..a68049dd08bd 100644 --- a/components/script/dom/webidls/BluetoothDevice.webidl +++ b/components/script/dom/webidls/BluetoothDevice.webidl @@ -8,13 +8,11 @@ interface BluetoothDevice : EventTarget { readonly attribute DOMString id; readonly attribute DOMString? name; - // TODO: remove this after BluetoothAdvertisingEvent implemented. - readonly attribute BluetoothAdvertisingData adData; readonly attribute BluetoothRemoteGATTServer gatt; - // Promise watchAdvertisements(); - // void unwatchAdvertisements(); - // readonly attribute boolean watchingAdvertisements; + Promise watchAdvertisements(); + void unwatchAdvertisements(); + readonly attribute boolean watchingAdvertisements; }; [NoInterfaceObject] diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 23b77f9ed852..eab79cfa255a 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -6734,6 +6734,12 @@ "url": "/_mozilla/mozilla/binding_keyword.html" } ], + "mozilla/bluetooth/advertisingEvent/watchAdvertisements-succeeds.html": [ + { + "path": "mozilla/bluetooth/advertisingEvent/watchAdvertisements-succeeds.html", + "url": "/_mozilla/mozilla/bluetooth/advertisingEvent/watchAdvertisements-succeeds.html" + } + ], "mozilla/bluetooth/connect/connection-succeeds.html": [ { "path": "mozilla/bluetooth/connect/connection-succeeds.html", diff --git a/tests/wpt/mozilla/meta/mozilla/bluetooth/advertisingEvent/watchAdvertisements-succeeds.html.ini b/tests/wpt/mozilla/meta/mozilla/bluetooth/advertisingEvent/watchAdvertisements-succeeds.html.ini new file mode 100644 index 000000000000..da628804692a --- /dev/null +++ b/tests/wpt/mozilla/meta/mozilla/bluetooth/advertisingEvent/watchAdvertisements-succeeds.html.ini @@ -0,0 +1,4 @@ +[watchAdvertisements-succeeds.html] + type: testharness + [watchAdvertisements should succeed.] + expected: FAIL diff --git a/tests/wpt/mozilla/tests/mozilla/bluetooth/advertisingEvent/watchAdvertisements-succeeds.html b/tests/wpt/mozilla/tests/mozilla/bluetooth/advertisingEvent/watchAdvertisements-succeeds.html new file mode 100644 index 000000000000..45b0164a3032 --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/bluetooth/advertisingEvent/watchAdvertisements-succeeds.html @@ -0,0 +1,14 @@ + + + + +