[input] impl the fidl server to read the touchpad_mode switch
Bug: 99687
Change-Id: I63ddb2e8107bf9bca617bbb63215eefbb306f231
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/678925
Commit-Queue: Jianpeng Chao <chaopeng@google.com>
Reviewed-by: Alice Neels <neelsa@google.com>
Reviewed-by: Mukesh Agrawal <quiche@google.com>
diff --git a/src/ui/bin/scene_manager/BUILD.gn b/src/ui/bin/scene_manager/BUILD.gn
index 7b2db6b..a8a5864 100644
--- a/src/ui/bin/scene_manager/BUILD.gn
+++ b/src/ui/bin/scene_manager/BUILD.gn
@@ -28,6 +28,7 @@
"//sdk/fidl/fuchsia.ui.app:fuchsia.ui.app-rustc",
"//sdk/fidl/fuchsia.ui.composition:fuchsia.ui.composition-rustc",
"//sdk/fidl/fuchsia.ui.input:fuchsia.ui.input-rustc",
+ "//sdk/fidl/fuchsia.ui.input.config:fuchsia.ui.input.config-rustc",
"//sdk/fidl/fuchsia.ui.pointerinjector.configuration:fuchsia.ui.pointerinjector.configuration-rustc",
"//sdk/fidl/fuchsia.ui.scenic:fuchsia.ui.scenic-rustc",
"//sdk/fidl/fuchsia.ui.shortcut:fuchsia.ui.shortcut-rustc",
@@ -61,6 +62,7 @@
]
sources = [
+ "src/input_config_server.rs",
"src/input_device_registry_server.rs",
"src/input_pipeline.rs",
"src/main.rs",
diff --git a/src/ui/bin/scene_manager/meta/scene_manager.cml b/src/ui/bin/scene_manager/meta/scene_manager.cml
index 75f7f81..cd2d226 100644
--- a/src/ui/bin/scene_manager/meta/scene_manager.cml
+++ b/src/ui/bin/scene_manager/meta/scene_manager.cml
@@ -22,6 +22,7 @@
"fuchsia.input.injection.InputDeviceRegistry",
"fuchsia.session.scene.Manager",
"fuchsia.ui.accessibility.view.Registry",
+ "fuchsia.ui.input.config.Features",
],
},
],
@@ -86,6 +87,7 @@
"fuchsia.input.injection.InputDeviceRegistry",
"fuchsia.session.scene.Manager",
"fuchsia.ui.accessibility.view.Registry",
+ "fuchsia.ui.input.config.Features",
],
from: "self",
},
diff --git a/src/ui/bin/scene_manager/src/input_config_server.rs b/src/ui/bin/scene_manager/src/input_config_server.rs
new file mode 100644
index 0000000..87bbbc3
--- /dev/null
+++ b/src/ui/bin/scene_manager/src/input_config_server.rs
@@ -0,0 +1,65 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use {
+ anyhow::Error, fidl_fuchsia_ui_input_config::FeaturesRequestStream,
+ futures::channel::mpsc::UnboundedSender,
+};
+
+/// A struct which forwards `FeaturesRequestStream`s over an
+/// `mpsc::UnboundedSender`.
+pub(crate) struct InputConfigFeaturesServer {
+ sender: UnboundedSender<FeaturesRequestStream>,
+}
+
+/// Creates an `InputConfigFeaturesServer`.
+///
+/// Returns both the server, and the `mpsc::UnboundedReceiver` which can be
+/// used to receive `FeaturesRequest`'s forwarded by the server.
+pub(crate) fn make_server_and_receiver(
+) -> (InputConfigFeaturesServer, futures::channel::mpsc::UnboundedReceiver<FeaturesRequestStream>) {
+ let (sender, receiver) = futures::channel::mpsc::unbounded::<FeaturesRequestStream>();
+ (InputConfigFeaturesServer { sender }, receiver)
+}
+
+impl InputConfigFeaturesServer {
+ /// Handles the incoming `FeaturesRequest`.
+ ///
+ /// Simply forwards the request over the `mpsc::UnboundedSender`.
+ pub async fn handle_request(&self, stream: FeaturesRequestStream) -> Result<(), Error> {
+ self.sender.unbounded_send(stream).map_err(anyhow::Error::from)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use {
+ super::*, assert_matches::assert_matches, fidl::endpoints::create_proxy_and_stream,
+ fidl_fuchsia_ui_input_config::FeaturesMarker, fuchsia_async as fasync,
+ };
+
+ #[fasync::run_singlethreaded(test)]
+ async fn test_handle_request_forwards_stream_and_returns_ok() {
+ let (server, mut receiver) = make_server_and_receiver();
+ let (_proxy, stream) =
+ create_proxy_and_stream::<FeaturesMarker>().expect("should make proxy/stream");
+ assert_matches!(server.handle_request(stream).await, Ok(()));
+
+ // Note: can't use `assert_matches!()` here, because `FeaturesRequest`
+ // does not implement `Debug`.
+ match receiver.try_next() {
+ Ok(opt) => assert!(opt.is_some()),
+ Err(e) => panic!("reading failed with {:#?}", e),
+ }
+ }
+
+ #[fasync::run_singlethreaded(test)]
+ async fn test_handle_request_returns_error_on_disconnected_receiver() {
+ let (server, receiver) = make_server_and_receiver();
+ let (_proxy, stream) =
+ create_proxy_and_stream::<FeaturesMarker>().expect("should make proxy/stream");
+ std::mem::drop(receiver);
+ assert_matches!(server.handle_request(stream).await, Err(_));
+ }
+}
diff --git a/src/ui/bin/scene_manager/src/input_pipeline.rs b/src/ui/bin/scene_manager/src/input_pipeline.rs
index f4d64ef..64dd932 100644
--- a/src/ui/bin/scene_manager/src/input_pipeline.rs
+++ b/src/ui/bin/scene_manager/src/input_pipeline.rs
@@ -7,6 +7,7 @@
anyhow::{Context, Error},
fidl_fuchsia_input_injection::InputDeviceRegistryRequestStream,
fidl_fuchsia_settings as fsettings,
+ fidl_fuchsia_ui_input_config::FeaturesRequestStream as InputConfigFeaturesRequestStream,
fidl_fuchsia_ui_pointerinjector_configuration::SetupProxy,
fidl_fuchsia_ui_shortcut as ui_shortcut, fuchsia_async as fasync,
fuchsia_component::client::connect_to_protocol,
@@ -35,6 +36,8 @@
///
/// # Parameters
/// - `scene_manager`: The scene manager used by the session.
+/// - `input_config_request_stream_receiver`: A receiving end of a MPSC channel for
+/// `InputConfig` messages.
/// - `input_device_registry_request_stream_receiver`: A receiving end of a MPSC channel for
/// `InputDeviceRegistry` messages.
/// - `node`: The inspect node to insert individual inspect handler nodes into.
@@ -43,6 +46,9 @@
// new Flatland API.
use_flatland: bool,
scene_manager: Arc<Mutex<Box<dyn SceneManager>>>,
+ input_config_request_stream_receiver: futures::channel::mpsc::UnboundedReceiver<
+ InputConfigFeaturesRequestStream,
+ >,
input_device_registry_request_stream_receiver: futures::channel::mpsc::UnboundedReceiver<
InputDeviceRegistryRequestStream,
>,
@@ -76,6 +82,13 @@
fasync::Task::local(input_device_registry_fut).detach();
+ let input_config_fut = handle_input_config_request_streams(
+ input_config_request_stream_receiver,
+ input_pipeline.input_device_bindings().clone(),
+ );
+
+ fasync::Task::local(input_config_fut).detach();
+
Ok(input_pipeline)
}
@@ -323,6 +336,28 @@
assembly.add_handler(ImmersiveModeShortcutHandler::new())
}
+pub async fn handle_input_config_request_streams(
+ mut stream_receiver: futures::channel::mpsc::UnboundedReceiver<
+ InputConfigFeaturesRequestStream,
+ >,
+ input_device_bindings: InputDeviceBindingHashMap,
+) {
+ while let Some(stream) = stream_receiver.next().await {
+ match InputPipeline::handle_input_config_request_stream(stream, &input_device_bindings)
+ .await
+ {
+ Ok(()) => (),
+ Err(e) => {
+ fx_log_warn!(
+ "failure while serving InputConfig.Features: {}; \
+ will continue serving other clients",
+ e
+ );
+ }
+ }
+ }
+}
+
pub async fn handle_input_device_registry_request_streams(
mut stream_receiver: futures::channel::mpsc::UnboundedReceiver<
InputDeviceRegistryRequestStream,
diff --git a/src/ui/bin/scene_manager/src/main.rs b/src/ui/bin/scene_manager/src/main.rs
index 0a3cf66..99875aa 100644
--- a/src/ui/bin/scene_manager/src/main.rs
+++ b/src/ui/bin/scene_manager/src/main.rs
@@ -16,6 +16,7 @@
RegistryRequestStream as A11yViewRegistryRequestStream,
},
fidl_fuchsia_ui_app as ui_app, fidl_fuchsia_ui_composition as fland,
+ fidl_fuchsia_ui_input_config::FeaturesRequestStream as InputConfigFeaturesRequestStream,
fidl_fuchsia_ui_scenic::ScenicMarker,
fidl_fuchsia_ui_views as ui_views, fuchsia_async as fasync,
fuchsia_component::{client::connect_to_protocol, server::ServiceFs},
@@ -29,6 +30,7 @@
std::sync::Arc,
};
+mod input_config_server;
mod input_device_registry_server;
mod input_pipeline;
@@ -36,6 +38,7 @@
AccessibilityViewRegistry(A11yViewRegistryRequestStream),
SceneManager(SceneManagerRequestStream),
InputDeviceRegistry(InputDeviceRegistryRequestStream),
+ InputConfigFeatures(InputConfigFeaturesRequestStream),
}
#[fuchsia::main(logging_tags = [ "scene_manager" ])]
@@ -47,11 +50,15 @@
fs.dir("svc").add_fidl_service(ExposedServices::AccessibilityViewRegistry);
fs.dir("svc").add_fidl_service(ExposedServices::SceneManager);
fs.dir("svc").add_fidl_service(ExposedServices::InputDeviceRegistry);
+ fs.dir("svc").add_fidl_service(ExposedServices::InputConfigFeatures);
fs.take_and_serve_directory_handle()?;
let (input_device_registry_server, input_device_registry_request_stream_receiver) =
input_device_registry_server::make_server_and_receiver();
+ let (input_config_server, input_config_receiver) =
+ input_config_server::make_server_and_receiver();
+
// This call should normally never fail. The ICU data loader must be kept alive to ensure
// Unicode data is kept in memory.
let icu_data_loader = icu_data::Loader::new().unwrap();
@@ -103,6 +110,7 @@
if let Ok(input_pipeline) = input_pipeline::handle_input(
use_flatland,
scene_manager.clone(),
+ input_config_receiver,
input_device_registry_request_stream_receiver,
icu_data_loader,
&inspect_node.clone(),
@@ -155,6 +163,14 @@
}
}
}
+ ExposedServices::InputConfigFeatures(request_stream) => {
+ match &input_config_server.handle_request(request_stream).await {
+ Ok(()) => (),
+ Err(e) => {
+ fx_log_warn!("failed to forward InputConfigFeaturesRequestStream: {:?}", e)
+ }
+ }
+ }
}
}
diff --git a/src/ui/lib/input_pipeline/src/consumer_controls_binding.rs b/src/ui/lib/input_pipeline/src/consumer_controls_binding.rs
index 8b90510..94f9bd2 100644
--- a/src/ui/lib/input_pipeline/src/consumer_controls_binding.rs
+++ b/src/ui/lib/input_pipeline/src/consumer_controls_binding.rs
@@ -8,6 +8,7 @@
async_trait::async_trait,
fidl_fuchsia_input_report as fidl_input_report,
fidl_fuchsia_input_report::{InputDeviceProxy, InputReport},
+ fidl_fuchsia_ui_input_config::FeaturesRequest as InputConfigFeaturesRequest,
fuchsia_syslog::fx_log_err,
fuchsia_zircon as zx,
futures::channel::mpsc::Sender,
@@ -68,6 +69,13 @@
fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
input_device::InputDeviceDescriptor::ConsumerControls(self.device_descriptor.clone())
}
+
+ async fn handle_input_config_request(
+ &self,
+ _request: &InputConfigFeaturesRequest,
+ ) -> Result<(), Error> {
+ Ok(())
+ }
}
impl ConsumerControlsBinding {
diff --git a/src/ui/lib/input_pipeline/src/fake_input_device_binding.rs b/src/ui/lib/input_pipeline/src/fake_input_device_binding.rs
index c7a5d87..65ccb09 100644
--- a/src/ui/lib/input_pipeline/src/fake_input_device_binding.rs
+++ b/src/ui/lib/input_pipeline/src/fake_input_device_binding.rs
@@ -3,7 +3,8 @@
// found in the LICENSE file.
use {
- crate::input_device, crate::keyboard_binding, async_trait::async_trait,
+ crate::input_device, crate::keyboard_binding, anyhow::Error, async_trait::async_trait,
+ fidl_fuchsia_ui_input_config::FeaturesRequest as InputConfigFeaturesRequest,
futures::channel::mpsc::Sender,
};
@@ -11,12 +12,18 @@
pub struct FakeInputDeviceBinding {
/// The channel to stream InputEvents to.
event_sender: Sender<input_device::InputEvent>,
+
+ /// The channel to stream received input config requests.
+ input_config_requests_sender: Sender<InputConfigFeaturesRequest>,
}
#[allow(dead_code)]
impl FakeInputDeviceBinding {
- pub fn new(input_event_sender: Sender<input_device::InputEvent>) -> Self {
- FakeInputDeviceBinding { event_sender: input_event_sender }
+ pub fn new(
+ input_event_sender: Sender<input_device::InputEvent>,
+ input_config_requests_sender: Sender<InputConfigFeaturesRequest>,
+ ) -> Self {
+ FakeInputDeviceBinding { event_sender: input_event_sender, input_config_requests_sender }
}
}
@@ -31,4 +38,24 @@
fn input_event_sender(&self) -> Sender<input_device::InputEvent> {
self.event_sender.clone()
}
+
+ async fn handle_input_config_request(
+ &self,
+ request: &InputConfigFeaturesRequest,
+ ) -> Result<(), Error> {
+ let copied = match request {
+ InputConfigFeaturesRequest::SetTouchpadMode { enable, control_handle } => {
+ InputConfigFeaturesRequest::SetTouchpadMode {
+ enable: *enable,
+ control_handle: control_handle.to_owned(),
+ }
+ }
+ };
+
+ self.input_config_requests_sender
+ .clone()
+ .try_send(copied)
+ .expect("send input_config_request");
+ Ok(())
+ }
}
diff --git a/src/ui/lib/input_pipeline/src/input_device.rs b/src/ui/lib/input_pipeline/src/input_device.rs
index 9929286..3a76a99 100644
--- a/src/ui/lib/input_pipeline/src/input_device.rs
+++ b/src/ui/lib/input_pipeline/src/input_device.rs
@@ -13,7 +13,9 @@
fidl::endpoints::Proxy,
fidl_fuchsia_input_report as fidl_input_report,
fidl_fuchsia_input_report::{InputDeviceMarker, InputReport},
- fidl_fuchsia_io as fio, fuchsia_async as fasync, fuchsia_zircon as zx,
+ fidl_fuchsia_io as fio,
+ fidl_fuchsia_ui_input_config::FeaturesRequest as InputConfigFeaturesRequest,
+ fuchsia_async as fasync, fuchsia_zircon as zx,
futures::{channel::mpsc::Sender, stream::StreamExt},
std::path::PathBuf,
};
@@ -134,6 +136,12 @@
/// Returns the input event stream's sender.
fn input_event_sender(&self) -> Sender<InputEvent>;
+
+ /// Handles input config changes.
+ async fn handle_input_config_request(
+ &self,
+ request: &InputConfigFeaturesRequest,
+ ) -> Result<(), Error>;
}
/// Initializes the input report stream for the device bound to `device_proxy`.
diff --git a/src/ui/lib/input_pipeline/src/input_pipeline.rs b/src/ui/lib/input_pipeline/src/input_pipeline.rs
index dec82d6..fcf4419 100644
--- a/src/ui/lib/input_pipeline/src/input_pipeline.rs
+++ b/src/ui/lib/input_pipeline/src/input_pipeline.rs
@@ -8,7 +8,9 @@
focus_listener::FocusListener, input_device, input_handler,
},
anyhow::{format_err, Context, Error},
- fidl_fuchsia_input_injection, fidl_fuchsia_io as fio, fuchsia_async as fasync,
+ fidl_fuchsia_input_injection, fidl_fuchsia_io as fio,
+ fidl_fuchsia_ui_input_config::FeaturesRequestStream as InputConfigFeaturesRequestStream,
+ fuchsia_async as fasync,
fuchsia_fs::open_directory_in_namespace,
fuchsia_syslog::{fx_log_err, fx_log_warn},
fuchsia_vfs_watcher::{WatchEvent, Watcher},
@@ -454,6 +456,35 @@
Ok(())
}
+ /// Handles the incoming InputConfigFeaturesRequestStream.
+ ///
+ /// This method will end when the request stream is closed. If the stream closes with an
+ /// error the error will be returned in the Result.
+ ///
+ /// # Parameters
+ /// - `stream`: The stream of InputConfigFeaturesRequests.
+ /// - `bindings`: Holds all the InputDeviceBindings associated with the InputPipeline.
+ pub async fn handle_input_config_request_stream(
+ mut stream: InputConfigFeaturesRequestStream,
+ bindings: &InputDeviceBindingHashMap,
+ ) -> Result<(), Error> {
+ while let Some(request) =
+ stream.try_next().await.context("Error handling input config request stream")?
+ {
+ let bindings = bindings.lock().await;
+ for v in bindings.values() {
+ for binding in v.iter() {
+ match binding.handle_input_config_request(&request).await {
+ Ok(()) => (),
+ Err(e) => fx_log_err!("Error handling input config request {:?}", e),
+ }
+ }
+ }
+ }
+
+ Ok(())
+ }
+
/// Starts all tasks in an asynchronous executor.
fn run(tasks: Vec<fuchsia_async::Task<()>>) {
fasync::Task::local(async move {
@@ -556,7 +587,12 @@
crate::input_device::{self, InputDeviceBinding},
crate::mouse_binding,
crate::utils::Position,
+ assert_matches::assert_matches,
fidl::endpoints::{create_proxy, create_proxy_and_stream, create_request_stream},
+ fidl_fuchsia_ui_input_config::{
+ FeaturesMarker as InputConfigFeaturesMarker,
+ FeaturesRequest as InputConfigFeaturesRequest,
+ },
fuchsia_async as fasync, fuchsia_zircon as zx,
futures::channel::mpsc::Sender,
futures::FutureExt,
@@ -652,10 +688,16 @@
// Create two fake device bindings.
let (device_event_sender, device_event_receiver) =
futures::channel::mpsc::channel(input_device::INPUT_EVENT_BUFFER_SIZE);
- let first_device_binding =
- fake_input_device_binding::FakeInputDeviceBinding::new(device_event_sender.clone());
- let second_device_binding =
- fake_input_device_binding::FakeInputDeviceBinding::new(device_event_sender.clone());
+ let (input_config_features_sender, _input_config_features_receiver) =
+ futures::channel::mpsc::channel(1);
+ let first_device_binding = fake_input_device_binding::FakeInputDeviceBinding::new(
+ device_event_sender.clone(),
+ input_config_features_sender.clone(),
+ );
+ let second_device_binding = fake_input_device_binding::FakeInputDeviceBinding::new(
+ device_event_sender.clone(),
+ input_config_features_sender.clone(),
+ );
// Create a fake input handler.
let (handler_event_sender, mut handler_event_receiver) =
@@ -699,8 +741,12 @@
// Create two fake device bindings.
let (device_event_sender, device_event_receiver) =
futures::channel::mpsc::channel(input_device::INPUT_EVENT_BUFFER_SIZE);
- let input_device_binding =
- fake_input_device_binding::FakeInputDeviceBinding::new(device_event_sender.clone());
+ let (input_config_features_sender, _input_config_features_receiver) =
+ futures::channel::mpsc::channel(1);
+ let input_device_binding = fake_input_device_binding::FakeInputDeviceBinding::new(
+ device_event_sender.clone(),
+ input_config_features_sender.clone(),
+ );
// Create two fake input handlers.
let (first_handler_event_sender, mut first_handler_event_receiver) =
@@ -953,4 +999,38 @@
let bindings = bindings.lock().await;
assert_eq!(bindings.len(), 1);
}
+
+ /// Tests that config changes are forwarded to device bindings.
+ #[fasync::run_singlethreaded(test)]
+ async fn handle_input_config_request_stream() {
+ let (device_event_sender, _device_event_receiver) =
+ futures::channel::mpsc::channel(input_device::INPUT_EVENT_BUFFER_SIZE);
+ let (input_config_features_sender, mut input_config_features_receiver) =
+ futures::channel::mpsc::channel(1);
+ let fake_device_binding = fake_input_device_binding::FakeInputDeviceBinding::new(
+ device_event_sender,
+ input_config_features_sender,
+ );
+ let bindings: InputDeviceBindingHashMap = Arc::new(Mutex::new(HashMap::new()));
+ bindings.lock().await.insert(1, vec![Box::new(fake_device_binding)]);
+
+ let bindings_clone = bindings.clone();
+
+ let (input_config_features_proxy, input_config_features_request_stream) =
+ create_proxy_and_stream::<InputConfigFeaturesMarker>().unwrap();
+ input_config_features_proxy.set_touchpad_mode(true).expect("set_touchpad_mode");
+ // Drop proxy to terminate request stream.
+ std::mem::drop(input_config_features_proxy);
+ InputPipeline::handle_input_config_request_stream(
+ input_config_features_request_stream,
+ &bindings_clone,
+ )
+ .await
+ .expect("handle_input_config_request_stream");
+
+ assert_matches!(
+ input_config_features_receiver.next().await.unwrap(),
+ InputConfigFeaturesRequest::SetTouchpadMode { enable: true, .. }
+ );
+ }
}
diff --git a/src/ui/lib/input_pipeline/src/keyboard_binding.rs b/src/ui/lib/input_pipeline/src/keyboard_binding.rs
index 90b13c2..96aa735 100644
--- a/src/ui/lib/input_pipeline/src/keyboard_binding.rs
+++ b/src/ui/lib/input_pipeline/src/keyboard_binding.rs
@@ -11,6 +11,7 @@
fidl_fuchsia_input_report::{InputDeviceProxy, InputReport},
fidl_fuchsia_ui_input3 as fidl_ui_input3,
fidl_fuchsia_ui_input3::KeyEventType,
+ fidl_fuchsia_ui_input_config::FeaturesRequest as InputConfigFeaturesRequest,
fuchsia_async as fasync,
fuchsia_syslog::fx_log_err,
fuchsia_zircon as zx,
@@ -230,6 +231,13 @@
fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
input_device::InputDeviceDescriptor::Keyboard(self.device_descriptor.clone())
}
+
+ async fn handle_input_config_request(
+ &self,
+ _request: &InputConfigFeaturesRequest,
+ ) -> Result<(), Error> {
+ Ok(())
+ }
}
impl KeyboardBinding {
diff --git a/src/ui/lib/input_pipeline/src/mouse_binding.rs b/src/ui/lib/input_pipeline/src/mouse_binding.rs
index 03d317a..2a7be61 100644
--- a/src/ui/lib/input_pipeline/src/mouse_binding.rs
+++ b/src/ui/lib/input_pipeline/src/mouse_binding.rs
@@ -9,6 +9,7 @@
async_trait::async_trait,
fidl_fuchsia_input_report as fidl_input_report,
fidl_fuchsia_input_report::{InputDeviceProxy, InputReport},
+ fidl_fuchsia_ui_input_config::FeaturesRequest as InputConfigFeaturesRequest,
fuchsia_syslog::fx_log_err,
fuchsia_zircon as zx,
futures::channel::mpsc::Sender,
@@ -161,6 +162,13 @@
fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
input_device::InputDeviceDescriptor::Mouse(self.device_descriptor.clone())
}
+
+ async fn handle_input_config_request(
+ &self,
+ _request: &InputConfigFeaturesRequest,
+ ) -> Result<(), Error> {
+ Ok(())
+ }
}
impl MouseBinding {
diff --git a/src/ui/lib/input_pipeline/src/touch_binding.rs b/src/ui/lib/input_pipeline/src/touch_binding.rs
index 7922a17..014e873 100644
--- a/src/ui/lib/input_pipeline/src/touch_binding.rs
+++ b/src/ui/lib/input_pipeline/src/touch_binding.rs
@@ -9,7 +9,9 @@
async_trait::async_trait,
fidl_fuchsia_input_report as fidl_input_report,
fidl_fuchsia_input_report::{InputDeviceProxy, InputReport},
- fidl_fuchsia_ui_input as fidl_ui_input, fidl_fuchsia_ui_pointerinjector as pointerinjector,
+ fidl_fuchsia_ui_input as fidl_ui_input,
+ fidl_fuchsia_ui_input_config::FeaturesRequest as InputConfigFeaturesRequest,
+ fidl_fuchsia_ui_pointerinjector as pointerinjector,
fuchsia_syslog::fx_log_err,
fuchsia_zircon as zx,
futures::channel::mpsc::Sender,
@@ -157,8 +159,10 @@
device_descriptor: TouchDeviceDescriptor,
/// Touch device type of the touch device.
- /// TODO(fxb/99687): following CL will begin use this field and remove the underscore.
- _touch_device_type: TouchDeviceType,
+ touch_device_type: TouchDeviceType,
+
+ /// Proxy to the device.
+ device_proxy: InputDeviceProxy,
}
#[async_trait]
@@ -170,6 +174,38 @@
fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
input_device::InputDeviceDescriptor::Touch(self.device_descriptor.clone())
}
+
+ async fn handle_input_config_request(
+ &self,
+ request: &InputConfigFeaturesRequest,
+ ) -> Result<(), Error> {
+ match request {
+ InputConfigFeaturesRequest::SetTouchpadMode { enable, .. } => {
+ match self.touch_device_type {
+ TouchDeviceType::TouchScreen => Ok(()),
+ TouchDeviceType::WindowsPrecisionTouchpad => {
+ // `get_feature_report` to only modify the input_mode and
+ // keep other feature as is.
+ let mut report = match self.device_proxy.get_feature_report().await? {
+ Ok(report) => report,
+ Err(e) => return Err(format_err!("get_feature_report failed: {}", e)),
+ };
+ let mut touch =
+ report.touch.unwrap_or(fidl_input_report::TouchFeatureReport::EMPTY);
+ touch.input_mode = match enable {
+ true => Some(fidl_input_report::TouchConfigurationInputMode::WindowsPrecisionTouchpadCollection),
+ false => Some(fidl_input_report::TouchConfigurationInputMode::MouseCollection),
+ };
+ report.touch = Some(touch);
+ self.device_proxy
+ .set_feature_report(report)
+ .await?
+ .map_err(|e| format_err!("set_feature_report failed: {}", e))
+ }
+ }
+ }
+ }
+ }
}
impl TouchBinding {
@@ -191,7 +227,7 @@
input_event_sender: Sender<input_device::InputEvent>,
) -> Result<Self, Error> {
let device_binding =
- Self::bind_device(&device_proxy, device_id, input_event_sender).await?;
+ Self::bind_device(device_proxy.clone(), device_id, input_event_sender).await?;
input_device::initialize_report_stream(
device_proxy,
device_binding.get_device_descriptor(),
@@ -213,12 +249,12 @@
/// If the device descriptor could not be retrieved, or the descriptor could not be parsed
/// correctly.
async fn bind_device(
- device: &InputDeviceProxy,
+ device_proxy: InputDeviceProxy,
device_id: u32,
input_event_sender: Sender<input_device::InputEvent>,
) -> Result<Self, Error> {
let device_descriptor: fidl_fuchsia_input_report::DeviceDescriptor =
- device.get_descriptor().await?;
+ device_proxy.get_descriptor().await?;
match device_descriptor.touch {
Some(fidl_fuchsia_input_report::TouchDescriptor {
@@ -241,7 +277,8 @@
.filter_map(Result::ok)
.collect(),
},
- _touch_device_type: get_device_type(device).await,
+ touch_device_type: get_device_type(&device_proxy).await,
+ device_proxy,
}),
descriptor => Err(format_err!("Touch Descriptor failed to parse: \n {:?}", descriptor)),
}
@@ -448,15 +485,21 @@
mod tests {
use {
super::*,
+ crate::input_pipeline::InputDeviceBindingHashMap,
+ crate::input_pipeline::InputPipeline,
crate::testing_utilities::{
self, create_touch_contact, create_touch_event, create_touch_input_report,
},
crate::utils::Position,
assert_matches::assert_matches,
+ fidl::endpoints::create_proxy_and_stream,
fidl::endpoints::spawn_stream_handler,
+ fidl_fuchsia_ui_input_config::FeaturesMarker as InputConfigFeaturesMarker,
fuchsia_async as fasync,
+ futures::lock::Mutex,
futures::StreamExt,
pretty_assertions::assert_eq,
+ std::sync::Arc,
test_case::test_case,
};
@@ -690,70 +733,7 @@
let input_device_proxy = spawn_stream_handler(move |input_device_request| async move {
match input_device_request {
fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
- let _ = responder.send(fidl_input_report::DeviceDescriptor {
- mouse: match has_mouse_descriptor {
- true => Some(fidl_input_report::MouseDescriptor {
- input: Some(fidl_input_report::MouseInputDescriptor {
- movement_x: None,
- movement_y: None,
- position_x: None,
- position_y: None,
- scroll_v: None,
- scroll_h: None,
- buttons: None,
- ..fidl_input_report::MouseInputDescriptor::EMPTY
- }),
- ..fidl_input_report::MouseDescriptor::EMPTY
- }),
- false => None,
- },
- touch: Some(fidl_input_report::TouchDescriptor {
- input: Some(fidl_input_report::TouchInputDescriptor {
- contacts: Some(vec![fidl_input_report::ContactInputDescriptor {
- position_x: Some(fidl_input_report::Axis {
- range: fidl_input_report::Range { min: 1, max: 2 },
- unit: fidl_input_report::Unit {
- type_: fidl_input_report::UnitType::None,
- exponent: 0,
- },
- }),
- position_y: Some(fidl_input_report::Axis {
- range: fidl_input_report::Range { min: 2, max: 3 },
- unit: fidl_input_report::Unit {
- type_: fidl_input_report::UnitType::Other,
- exponent: 100000,
- },
- }),
- pressure: Some(fidl_input_report::Axis {
- range: fidl_input_report::Range { min: 3, max: 4 },
- unit: fidl_input_report::Unit {
- type_: fidl_input_report::UnitType::Grams,
- exponent: -991,
- },
- }),
- contact_width: Some(fidl_input_report::Axis {
- range: fidl_input_report::Range { min: 5, max: 6 },
- unit: fidl_input_report::Unit {
- type_:
- fidl_input_report::UnitType::EnglishAngularVelocity,
- exponent: 123,
- },
- }),
- contact_height: Some(fidl_input_report::Axis {
- range: fidl_input_report::Range { min: 7, max: 8 },
- unit: fidl_input_report::Unit {
- type_: fidl_input_report::UnitType::Pascals,
- exponent: 100,
- },
- }),
- ..fidl_input_report::ContactInputDescriptor::EMPTY
- }]),
- ..fidl_input_report::TouchInputDescriptor::EMPTY
- }),
- ..fidl_input_report::TouchDescriptor::EMPTY
- }),
- ..fidl_input_report::DeviceDescriptor::EMPTY
- });
+ let _ = responder.send(get_touchpad_device_descriptor(has_mouse_descriptor));
}
fidl_input_report::InputDeviceRequest::GetFeatureReport { responder } => {
let _ = responder.send(&mut Ok(fidl_input_report::FeatureReport {
@@ -773,6 +753,152 @@
futures::channel::mpsc::channel(input_device::INPUT_EVENT_BUFFER_SIZE);
let binding = TouchBinding::new(input_device_proxy, 0, device_event_sender).await.unwrap();
- pretty_assertions::assert_eq!(binding._touch_device_type, expect_touch_device_type);
+ pretty_assertions::assert_eq!(binding.touch_device_type, expect_touch_device_type);
+ }
+
+ #[test_case(false, fidl_input_report::TouchConfigurationInputMode::MouseCollection; "mouse mode")]
+ #[test_case(true, fidl_input_report::TouchConfigurationInputMode::WindowsPrecisionTouchpadCollection; "touchpad mode")]
+ #[fasync::run_singlethreaded(test)]
+ async fn handle_input_config_request(
+ enable_touchpad_mode: bool,
+ want_touch_configuration_input_mode: fidl_input_report::TouchConfigurationInputMode,
+ ) {
+ let (set_feature_report_sender, mut set_feature_report_receiver) =
+ futures::channel::mpsc::channel::<fidl_input_report::FeatureReport>(1);
+ let input_device_proxy = spawn_stream_handler(move |input_device_request| {
+ let mut set_feature_report_sender = set_feature_report_sender.clone();
+ async move {
+ match input_device_request {
+ fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
+ let _ = responder.send(get_touchpad_device_descriptor(true));
+ }
+ fidl_input_report::InputDeviceRequest::GetFeatureReport { responder } => {
+ let _ = responder.send(&mut Ok(fidl_input_report::FeatureReport {
+ touch: Some(fidl_input_report::TouchFeatureReport {
+ input_mode: Some(
+ fidl_input_report::TouchConfigurationInputMode::MouseCollection,
+ ),
+ ..fidl_input_report::TouchFeatureReport::EMPTY
+ }),
+ ..fidl_input_report::FeatureReport::EMPTY
+ }));
+ }
+ fidl_input_report::InputDeviceRequest::SetFeatureReport {
+ report,
+ responder,
+ } => {
+ match set_feature_report_sender.try_send(report) {
+ Ok(_) => {
+ let _ = responder.send(&mut Ok(()));
+ }
+ Err(e) => {
+ panic!(
+ "try_send set_feature_report_request failed: {}",
+ e.to_string()
+ );
+ }
+ };
+ }
+ fidl_input_report::InputDeviceRequest::GetInputReportsReader { .. } => {
+ // Do not panic as `initialize_report_stream()` will call this protocol.
+ }
+ _ => panic!("InputDevice handler received an unexpected request"),
+ }
+ }
+ })
+ .unwrap();
+
+ let (device_event_sender, _device_event_receiver) =
+ futures::channel::mpsc::channel(input_device::INPUT_EVENT_BUFFER_SIZE);
+
+ let binding = TouchBinding::new(input_device_proxy, 0, device_event_sender).await.unwrap();
+ let bindings: InputDeviceBindingHashMap = Arc::new(Mutex::new(HashMap::new()));
+ bindings.lock().await.insert(1, vec![Box::new(binding)]);
+
+ let bindings_clone = bindings.clone();
+
+ let (input_config_features_proxy, input_config_features_request_stream) =
+ create_proxy_and_stream::<InputConfigFeaturesMarker>().unwrap();
+ input_config_features_proxy
+ .set_touchpad_mode(enable_touchpad_mode)
+ .expect("set_touchpad_mode");
+
+ // Drop proxy to terminate request stream.
+ std::mem::drop(input_config_features_proxy);
+
+ InputPipeline::handle_input_config_request_stream(
+ input_config_features_request_stream,
+ &bindings_clone,
+ )
+ .await
+ .expect("handle_input_config_request_stream");
+
+ let got_feature_report = set_feature_report_receiver.next().await;
+ let want_feature_report = Some(fidl_input_report::FeatureReport {
+ touch: Some(fidl_input_report::TouchFeatureReport {
+ input_mode: Some(want_touch_configuration_input_mode),
+ ..fidl_input_report::TouchFeatureReport::EMPTY
+ }),
+ ..fidl_input_report::FeatureReport::EMPTY
+ });
+ pretty_assertions::assert_eq!(want_feature_report, got_feature_report);
+ }
+
+ /// Returns an |fidl_fuchsia_input_report::DeviceDescriptor| for
+ /// touchpad related tests.
+ fn get_touchpad_device_descriptor(
+ has_mouse_descriptor: bool,
+ ) -> fidl_fuchsia_input_report::DeviceDescriptor {
+ fidl_input_report::DeviceDescriptor {
+ mouse: match has_mouse_descriptor {
+ true => Some(fidl_input_report::MouseDescriptor::EMPTY),
+ false => None,
+ },
+ touch: Some(fidl_input_report::TouchDescriptor {
+ input: Some(fidl_input_report::TouchInputDescriptor {
+ contacts: Some(vec![fidl_input_report::ContactInputDescriptor {
+ position_x: Some(fidl_input_report::Axis {
+ range: fidl_input_report::Range { min: 1, max: 2 },
+ unit: fidl_input_report::Unit {
+ type_: fidl_input_report::UnitType::None,
+ exponent: 0,
+ },
+ }),
+ position_y: Some(fidl_input_report::Axis {
+ range: fidl_input_report::Range { min: 2, max: 3 },
+ unit: fidl_input_report::Unit {
+ type_: fidl_input_report::UnitType::Other,
+ exponent: 100000,
+ },
+ }),
+ pressure: Some(fidl_input_report::Axis {
+ range: fidl_input_report::Range { min: 3, max: 4 },
+ unit: fidl_input_report::Unit {
+ type_: fidl_input_report::UnitType::Grams,
+ exponent: -991,
+ },
+ }),
+ contact_width: Some(fidl_input_report::Axis {
+ range: fidl_input_report::Range { min: 5, max: 6 },
+ unit: fidl_input_report::Unit {
+ type_: fidl_input_report::UnitType::EnglishAngularVelocity,
+ exponent: 123,
+ },
+ }),
+ contact_height: Some(fidl_input_report::Axis {
+ range: fidl_input_report::Range { min: 7, max: 8 },
+ unit: fidl_input_report::Unit {
+ type_: fidl_input_report::UnitType::Pascals,
+ exponent: 100,
+ },
+ }),
+ ..fidl_input_report::ContactInputDescriptor::EMPTY
+ }]),
+ ..fidl_input_report::TouchInputDescriptor::EMPTY
+ }),
+ ..fidl_input_report::TouchDescriptor::EMPTY
+ }),
+ ..fidl_input_report::DeviceDescriptor::EMPTY
+ }
}
}