From c895131a64d5ba90c06bd75c7548f1f2ec8e0200 Mon Sep 17 00:00:00 2001 From: Attila Dusnoki Date: Wed, 23 Nov 2016 03:22:43 -0800 Subject: [PATCH] servo: Merge #14276 - Add Start/Stop notifications (from szeged:notify); r=jdm Add support for Start and Stop Notifications for WebBluetooth --- - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] There are tests for these changes Source-Repo: https://github.com/servo/servo Source-Revision: c4b7cc863eb9c0387577be33db4e2c0a6fd92a60 --- servo/components/bluetooth/lib.rs | 24 ++++++++++ servo/components/bluetooth/test.rs | 7 ++- servo/components/bluetooth_traits/lib.rs | 2 + .../dom/bluetoothremotegattcharacteristic.rs | 44 +++++++++++++++++++ .../BluetoothRemoteGATTCharacteristic.webidl | 4 +- 5 files changed, 77 insertions(+), 4 deletions(-) diff --git a/servo/components/bluetooth/lib.rs b/servo/components/bluetooth/lib.rs index 19ddf857037e..9bc00e0c43fd 100644 --- a/servo/components/bluetooth/lib.rs +++ b/servo/components/bluetooth/lib.rs @@ -275,6 +275,9 @@ impl BluetoothManager { BluetoothRequest::WriteValue(id, value, sender) => { self.write_value(id, value, sender) }, + BluetoothRequest::EnableNotification(id, enable, sender) => { + self.enable_notification(id, enable, sender) + }, BluetoothRequest::Test(data_set_name, sender) => { self.test(data_set_name, sender) } @@ -977,4 +980,25 @@ impl BluetoothManager { None => return drop(sender.send(Err(BluetoothError::InvalidState))), } } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-startnotifications + fn enable_notification(&mut self, id: String, enable: bool, sender: IpcSender) { + let mut adapter = get_adapter_or_return_error!(self, sender); + match self.get_gatt_characteristic(&mut adapter, &id) { + Some(c) => { + let result = match enable { + true => c.start_notify(), + false => c.stop_notify(), + }; + match result { + // Step 11. + Ok(_) => return drop(sender.send(Ok(BluetoothResponse::EnableNotification(())))), + // Step 4. + Err(_) => return drop(sender.send(Err(BluetoothError::NotSupported))), + } + }, + // Step 3. + None => return drop(sender.send(Err(BluetoothError::InvalidState))), + } + } } diff --git a/servo/components/bluetooth/test.rs b/servo/components/bluetooth/test.rs index b4aa7ef286ba..8578db79aa5e 100644 --- a/servo/components/bluetooth/test.rs +++ b/servo/components/bluetooth/test.rs @@ -18,6 +18,7 @@ const ADAPTER_ERROR: &'static str = "No adapter found"; const WRONG_DATA_SET_ERROR: &'static str = "Wrong data set name was provided"; const READ_FLAG: &'static str = "read"; const WRITE_FLAG: &'static str = "write"; +const NOTIFY_FLAG: &'static str = "notify"; // Adapter names // https://cs.chromium.org/chromium/src/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h?l=65 @@ -217,10 +218,11 @@ fn create_heart_rate_service(device: &BluetoothDevice, } // Heart Rate Measurement Characteristic - let _heart_rate_measurement_characteristic = + let heart_rate_measurement_characteristic = try!(create_characteristic_with_value(&heart_rate_service, HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID.to_owned(), vec![0])); + try!(heart_rate_measurement_characteristic.set_flags(vec![NOTIFY_FLAG.to_string()])); // Body Sensor Location Characteristic 1 let body_sensor_location_characteristic_1 = @@ -357,10 +359,11 @@ fn create_two_heart_rate_services_device(adapter: &BluetoothAdapter) -> Result<( let heart_rate_service_empty_2 = try!(create_heart_rate_service(&heart_rate_device_empty, true)); - let _heart_rate_measurement_characteristic = + let heart_rate_measurement_characteristic = try!(create_characteristic_with_value(&heart_rate_service_empty_1, HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID.to_owned(), vec![0])); + try!(heart_rate_measurement_characteristic.set_flags(vec![NOTIFY_FLAG.to_string()])); let _body_sensor_location_characteristic_1 = try!(create_characteristic_with_value(&heart_rate_service_empty_1, diff --git a/servo/components/bluetooth_traits/lib.rs b/servo/components/bluetooth_traits/lib.rs index de07a9f4fd7d..5c06e900141f 100644 --- a/servo/components/bluetooth_traits/lib.rs +++ b/servo/components/bluetooth_traits/lib.rs @@ -92,6 +92,7 @@ pub enum BluetoothRequest { GetDescriptors(String, Option, IpcSender), ReadValue(String, IpcSender), WriteValue(String, Vec, IpcSender), + EnableNotification(String, bool, IpcSender), Test(String, IpcSender>), Exit, } @@ -110,6 +111,7 @@ pub enum BluetoothResponse { GetDescriptors(BluetoothDescriptorsMsg), ReadValue(Vec), WriteValue(Vec), + EnableNotification(()), } pub trait BluetoothResponseListener { diff --git a/servo/components/script/dom/bluetoothremotegattcharacteristic.rs b/servo/components/script/dom/bluetoothremotegattcharacteristic.rs index dae5fd3e5584..390878342dbc 100644 --- a/servo/components/script/dom/bluetoothremotegattcharacteristic.rs +++ b/servo/components/script/dom/bluetoothremotegattcharacteristic.rs @@ -214,6 +214,47 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris BluetoothRequest::WriteValue(self.get_instance_id(), value, sender)).unwrap(); return p; } + + #[allow(unrooted_must_root)] + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-startnotifications + fn StartNotifications(&self) -> Rc { + let p = Promise::new(&self.global()); + let p_cx = p.global().get_cx(); + // Step 1. + if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Reads) { + p.reject_error(p_cx, Security); + return p; + } + // Step 3. + if !(self.Properties().Notify() || + self.Properties().Indicate()) { + p.reject_error(p_cx, NotSupported); + return p; + } + // Step 6. + if !self.Service().Device().Gatt().Connected() { + p.reject_error(p_cx, Network); + return p; + } + let sender = response_async(&p, self); + self.get_bluetooth_thread().send( + BluetoothRequest::EnableNotification(self.get_instance_id(), + true, + sender)).unwrap(); + return p; + } + + #[allow(unrooted_must_root)] + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-stopnotifications + fn StopNotifications(&self) -> Rc { + let p = Promise::new(&self.global()); + let sender = response_async(&p, self); + self.get_bluetooth_thread().send( + BluetoothRequest::EnableNotification(self.get_instance_id(), + false, + sender)).unwrap(); + return p; + } } impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic { @@ -263,6 +304,9 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic { *self.value.borrow_mut() = Some(value.clone()); promise.resolve_native(promise_cx, &value); }, + BluetoothResponse::EnableNotification(_result) => { + promise.resolve_native(promise_cx, self); + }, _ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())), } } diff --git a/servo/components/script/dom/webidls/BluetoothRemoteGATTCharacteristic.webidl b/servo/components/script/dom/webidls/BluetoothRemoteGATTCharacteristic.webidl index 596a10954572..d1d937475b48 100644 --- a/servo/components/script/dom/webidls/BluetoothRemoteGATTCharacteristic.webidl +++ b/servo/components/script/dom/webidls/BluetoothRemoteGATTCharacteristic.webidl @@ -17,8 +17,8 @@ interface BluetoothRemoteGATTCharacteristic { //Promise readValue(); Promise writeValue(sequence value); //Promise writeValue(BufferSource value); - //Promise startNotifications(); - //Promise stopNotifications(); + Promise startNotifications(); + Promise stopNotifications(); }; //BluetootRemoteGATTCharacteristic implements EventTarget;