Auto merge of #14552 - szeged:advertising_event, r=jdm

Replace AdvertisingData with AdvertisingEvent

<!-- Please describe your changes on the following line: -->
The spec changed AdvertisingData to an event. The low level support is still missing.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors

<!-- Either: -->
- [X] There are tests for these changes

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/14552)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-12-14 13:53:51 -08:00 committed by GitHub
commit eb1bd59682
12 changed files with 237 additions and 99 deletions

View file

@ -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<BluetoothResponseResult>) {
// Step 2.
// TODO: Implement this when supported in lower level
return drop(sender.send(Err(BluetoothError::NotSupported)));
}
}

View file

@ -31,10 +31,6 @@ pub struct BluetoothDeviceMsg {
// Bluetooth Device properties
pub id: String,
pub name: Option<String>,
// Advertising Data properties
pub appearance: Option<u16>,
pub tx_power: Option<i8>,
pub rssi: Option<i8>,
}
#[derive(Deserialize, Serialize)]
@ -93,6 +89,7 @@ pub enum BluetoothRequest {
ReadValue(String, IpcSender<BluetoothResponseResult>),
WriteValue(String, Vec<u8>, IpcSender<BluetoothResponseResult>),
EnableNotification(String, bool, IpcSender<BluetoothResponseResult>),
WatchAdvertisements(String, IpcSender<BluetoothResponseResult>),
Test(String, IpcSender<BluetoothResult<()>>),
Exit,
}
@ -112,6 +109,7 @@ pub enum BluetoothResponse {
ReadValue(Vec<u8>),
WriteValue(Vec<u8>),
EnableNotification(()),
WatchAdvertisements(()),
}
pub trait BluetoothResponseListener {

View file

@ -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

View file

@ -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<u16>,
tx_power: Option<i8>,
rssi: Option<i8>,
}
impl BluetoothAdvertisingData {
pub fn new_inherited(appearance: Option<u16>,
tx_power: Option<i8>,
rssi: Option<i8>)
-> BluetoothAdvertisingData {
BluetoothAdvertisingData {
reflector_: Reflector::new(),
appearance: appearance,
tx_power: tx_power,
rssi: rssi,
}
}
pub fn new(global: &GlobalScope,
appearance: Option<u16>,
txPower: Option<i8>,
rssi: Option<i8>)
-> Root<BluetoothAdvertisingData> {
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<u16> {
self.appearance
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingdata-txpower
fn GetTxPower(&self) -> Option<i8> {
self.tx_power
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingdata-rssi
fn GetRssi(&self) -> Option<i8> {
self.rssi
}
}

View file

@ -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<BluetoothDevice>,
name: Option<DOMString>,
appearance: Option<u16>,
tx_power: Option<i8>,
rssi: Option<i8>,
}
impl BluetoothAdvertisingEvent {
pub fn new_inherited(device: &BluetoothDevice,
name: Option<DOMString>,
appearance: Option<u16>,
tx_power: Option<i8>,
rssi: Option<i8>)
-> 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<DOMString>,
appearance: Option<u16>,
txPower: Option<i8>,
rssi: Option<i8>)
-> Root<BluetoothAdvertisingEvent> {
let ev = reflect_dom_object(box BluetoothAdvertisingEvent::new_inherited(device,
name,
appearance,
txPower,
rssi),
global,
BluetoothAdvertisingEventBinding::Wrap);
{
let event = ev.upcast::<Event>();
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<Root<BluetoothAdvertisingEvent>> {
let global = window.upcast::<GlobalScope>();
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<BluetoothDevice> {
Root::from_ref(&*self.device)
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingevent-name
fn GetName(&self) -> Option<DOMString> {
self.name.clone()
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingevent-appearance
fn GetAppearance(&self) -> Option<u16> {
self.appearance
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingevent-txpower
fn GetTxPower(&self) -> Option<i8> {
self.tx_power
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingevent-rssi
fn GetRssi(&self) -> Option<i8> {
self.rssi
}
// https://dom.spec.whatwg.org/#dom-event-istrusted
fn IsTrusted(&self) -> bool {
self.event.IsTrusted()
}
}

View file

@ -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<DOMString>,
ad_data: MutJS<BluetoothAdvertisingData>,
gatt: MutNullableJS<BluetoothRemoteGATTServer>,
context: MutJS<Bluetooth>,
attribute_instance_map: (DOMRefCell<HashMap<String, MutJS<BluetoothRemoteGATTService>>>,
DOMRefCell<HashMap<String, MutJS<BluetoothRemoteGATTCharacteristic>>>,
DOMRefCell<HashMap<String, MutJS<BluetoothRemoteGATTDescriptor>>>),
watching_advertisements: Cell<bool>,
}
impl BluetoothDevice {
pub fn new_inherited(id: DOMString,
name: Option<DOMString>,
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<DOMString>,
adData: &BluetoothAdvertisingData,
context: &Bluetooth)
-> Root<BluetoothDevice> {
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<BluetoothRequest> {
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<BluetoothAdvertisingData> {
self.ad_data.get()
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-gatt
fn Gatt(&self) -> Root<BluetoothRemoteGATTServer> {
// 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<Promise> {
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<Promise>) {
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())),
}
}
}

View file

@ -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;

View file

@ -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<unsigned short, DataView>;
};
interface BluetoothServiceDataMap {
readonly maplike<UUID, DataView>;
};*/
[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<UUID> 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;
};

View file

@ -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<void> watchAdvertisements();
// void unwatchAdvertisements();
// readonly attribute boolean watchingAdvertisements;
Promise<void> watchAdvertisements();
void unwatchAdvertisements();
readonly attribute boolean watchingAdvertisements;
};
[NoInterfaceObject]

View file

@ -6746,6 +6746,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",

View file

@ -0,0 +1,4 @@
[watchAdvertisements-succeeds.html]
type: testharness
[watchAdvertisements should succeed.]
expected: FAIL

View file

@ -0,0 +1,14 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/_mozilla/mozilla/bluetooth/bluetooth-helpers.js"></script>
<script>
'use strict';
promise_test(() => {
window.testRunner.setBluetoothMockDataSet(adapter_type.heart_rate);
return window.navigator.bluetooth.requestDevice({
filters: [{services: [heart_rate.name]}]
})
.then(device => device.watchAdvertisements());
}, 'watchAdvertisements should succeed.');
</script>