/* 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 https://mozilla.org/MPL/2.0/. */ use std::rc::Rc; use bluetooth_traits::{BluetoothRequest, BluetoothResponse}; use dom_struct::dom_struct; use ipc_channel::ipc::IpcSender; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::BluetoothPermissionResultBinding::BluetoothPermissionResultMethods; use crate::dom::bindings::codegen::Bindings::NavigatorBinding::Navigator_Binding::NavigatorMethods; use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionStatus_Binding::PermissionStatusMethods; use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::{ PermissionName, PermissionState, }; use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods; use crate::dom::bindings::error::Error; use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object}; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::DOMString; use crate::dom::bluetooth::{AllowedBluetoothDevice, AsyncBluetoothListener, Bluetooth}; use crate::dom::bluetoothdevice::BluetoothDevice; use crate::dom::globalscope::GlobalScope; use crate::dom::permissionstatus::PermissionStatus; use crate::dom::promise::Promise; use crate::script_runtime::CanGc; // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothpermissionresult #[dom_struct] pub(crate) struct BluetoothPermissionResult { status: PermissionStatus, devices: DomRefCell>>, } impl BluetoothPermissionResult { #[cfg_attr(crown, allow(crown::unrooted_must_root))] fn new_inherited(status: &PermissionStatus) -> BluetoothPermissionResult { let result = BluetoothPermissionResult { status: PermissionStatus::new_inherited(status.get_query()), devices: DomRefCell::new(Vec::new()), }; result.status.set_state(status.State()); result } pub(crate) fn new( global: &GlobalScope, status: &PermissionStatus, can_gc: CanGc, ) -> DomRoot { reflect_dom_object( Box::new(BluetoothPermissionResult::new_inherited(status)), global, can_gc, ) } pub(crate) fn get_bluetooth(&self) -> DomRoot { self.global().as_window().Navigator().Bluetooth() } pub(crate) fn get_bluetooth_thread(&self) -> IpcSender { self.global().as_window().bluetooth_thread() } pub(crate) fn get_query(&self) -> PermissionName { self.status.get_query() } pub(crate) fn set_state(&self, state: PermissionState) { self.status.set_state(state) } pub(crate) fn get_state(&self) -> PermissionState { self.status.State() } #[cfg_attr(crown, allow(crown::unrooted_must_root))] pub(crate) fn set_devices(&self, devices: Vec>) { *self.devices.borrow_mut() = devices; } } impl BluetoothPermissionResultMethods for BluetoothPermissionResult { // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothpermissionresult-devices fn Devices(&self) -> Vec> { let device_vec: Vec> = self .devices .borrow() .iter() .map(|d| DomRoot::from_ref(&**d)) .collect(); device_vec } } impl AsyncBluetoothListener for BluetoothPermissionResult { fn handle_response(&self, response: BluetoothResponse, promise: &Rc, can_gc: CanGc) { match response { // https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices // Step 3, 11, 13 - 14. BluetoothResponse::RequestDevice(device) => { self.set_state(PermissionState::Granted); let bluetooth = self.get_bluetooth(); let mut device_instance_map = bluetooth.get_device_map().borrow_mut(); if let Some(existing_device) = device_instance_map.get(&device.id) { // https://webbluetoothcg.github.io/web-bluetooth/#request-the-bluetooth-permission // Step 3. self.set_devices(vec![Dom::from_ref(existing_device)]); // https://w3c.github.io/permissions/#dom-permissions-request // Step 8. return promise.resolve_native(self, can_gc); } let bt_device = BluetoothDevice::new( &self.global(), DOMString::from(device.id.clone()), device.name.map(DOMString::from), &bluetooth, can_gc, ); device_instance_map.insert(device.id.clone(), Dom::from_ref(&bt_device)); self.global() .as_window() .bluetooth_extra_permission_data() .add_new_allowed_device(AllowedBluetoothDevice { deviceId: DOMString::from(device.id), mayUseGATT: true, }); // https://webbluetoothcg.github.io/web-bluetooth/#request-the-bluetooth-permission // Step 3. self.set_devices(vec![Dom::from_ref(&bt_device)]); // https://w3c.github.io/permissions/#dom-permissions-request // Step 8. promise.resolve_native(self, can_gc); }, _ => promise.reject_error(Error::Type("Something went wrong...".to_owned()), can_gc), } } }