| // Copyright 2021 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::prelude::*, |
| fidl_fuchsia_accessibility::{MagnificationHandlerMarker, MagnifierMarker}, |
| fidl_fuchsia_accessibility_scene as a11y_view, |
| fidl_fuchsia_input_injection::InputDeviceRegistryRequestStream, |
| fidl_fuchsia_session_scene::{ |
| ManagerRequest as SceneManagerRequest, ManagerRequestStream as SceneManagerRequestStream, |
| }, |
| fidl_fuchsia_ui_accessibility_view::{ |
| RegistryRequest as A11yViewRegistryRequest, |
| RegistryRequestStream as A11yViewRegistryRequestStream, |
| }, |
| fidl_fuchsia_ui_app as ui_app, fidl_fuchsia_ui_composition as fland, |
| fidl_fuchsia_ui_scenic::ScenicMarker, |
| fidl_fuchsia_ui_views as ui_views, fuchsia_async as fasync, |
| fuchsia_component::{client::connect_to_protocol, server::ServiceFs}, |
| fuchsia_inspect as inspect, |
| fuchsia_syslog::{fx_log_err, fx_log_info, fx_log_warn}, |
| fuchsia_zircon as zx, |
| futures::lock::Mutex, |
| futures::{StreamExt, TryStreamExt}, |
| scene_management::{self, SceneManager}, |
| std::rc::Rc, |
| std::sync::Arc, |
| }; |
| |
| mod input_device_registry_server; |
| mod input_pipeline; |
| |
| enum ExposedServices { |
| AccessibilityViewRegistry(A11yViewRegistryRequestStream), |
| SceneManager(SceneManagerRequestStream), |
| InputDeviceRegistry(InputDeviceRegistryRequestStream), |
| } |
| |
| #[fuchsia::main(logging_tags = [ "scene_manager" ])] |
| async fn main() -> Result<(), Error> { |
| let mut fs = ServiceFs::new_local(); |
| |
| inspect_runtime::serve(inspect::component::inspector(), &mut fs)?; |
| |
| 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.take_and_serve_directory_handle()?; |
| |
| let (input_device_registry_server, input_device_registry_request_stream_receiver) = |
| input_device_registry_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(); |
| |
| let scenic = connect_to_protocol::<ScenicMarker>()?; |
| |
| let use_flatland = scenic.uses_flatland().await.expect("Failed to get flatland info."); |
| let display_ownership = |
| scenic.get_display_ownership_event().await.expect("Failed to get display ownership."); |
| fx_log_info!("Instantiating SceneManager, use_flatland: {:?}", use_flatland); |
| |
| let scene_manager: Arc<Mutex<Box<dyn SceneManager>>> = if use_flatland { |
| // TODO(fxbug.dev/86379): Support for insertion of accessibility view. Pass ViewRefInstalled |
| // to the SceneManager, the same way we do for the Gfx branch. |
| let display = connect_to_protocol::<fland::FlatlandDisplayMarker>()?; |
| let root_flatland = connect_to_protocol::<fland::FlatlandMarker>()?; |
| let pointerinjector_flatland = connect_to_protocol::<fland::FlatlandMarker>()?; |
| let a11y_flatland = connect_to_protocol::<fland::FlatlandMarker>()?; |
| let cursor_view_provider = connect_to_protocol::<ui_app::ViewProviderMarker>()?; |
| let a11y_view_provider = connect_to_protocol::<a11y_view::ProviderMarker>()?; |
| Arc::new(Mutex::new(Box::new( |
| scene_management::FlatlandSceneManager::new( |
| scenic, |
| display, |
| pointerinjector_flatland, |
| root_flatland, |
| a11y_flatland, |
| cursor_view_provider, |
| a11y_view_provider, |
| ) |
| .await?, |
| ))) |
| } else { |
| let view_ref_installed = connect_to_protocol::<ui_views::ViewRefInstalledMarker>()?; |
| let gfx_scene_manager: Arc<Mutex<Box<dyn SceneManager>>> = Arc::new(Mutex::new(Box::new( |
| scene_management::GfxSceneManager::new(scenic, view_ref_installed, None, None).await?, |
| ))); |
| if let Err(e) = register_gfx_as_magnifier(Arc::clone(&gfx_scene_manager)) { |
| fx_log_warn!("failed to register as the magnification handler: {:?}", e); |
| } |
| gfx_scene_manager |
| }; |
| |
| // Create a node under root to hang all input pipeline inspect data off of. |
| let inspect_node = |
| Rc::new(inspect::component::inspector().root().create_child("input_pipeline")); |
| |
| // Start input pipeline. |
| if let Ok(input_pipeline) = input_pipeline::handle_input( |
| use_flatland, |
| scene_manager.clone(), |
| input_device_registry_request_stream_receiver, |
| icu_data_loader, |
| &inspect_node.clone(), |
| display_ownership, |
| ) |
| .await |
| { |
| fasync::Task::local(input_pipeline.handle_input_events()).detach(); |
| } |
| |
| while let Some(service_request) = fs.next().await { |
| match service_request { |
| ExposedServices::AccessibilityViewRegistry(request_stream) => { |
| fasync::Task::local(handle_accessibility_view_registry_request_stream( |
| request_stream, |
| Arc::clone(&scene_manager), |
| )) |
| .detach() |
| } |
| ExposedServices::SceneManager(request_stream) => { |
| fasync::Task::local(handle_scene_manager_request_stream( |
| request_stream, |
| Arc::clone(&scene_manager), |
| )) |
| .detach(); |
| } |
| ExposedServices::InputDeviceRegistry(request_stream) => { |
| match &input_device_registry_server.handle_request(request_stream).await { |
| Ok(()) => (), |
| Err(e) => { |
| // If `handle_request()` returns `Err`, then the `unbounded_send()` call |
| // from `handle_request()` failed with either: |
| // * `TrySendError::SendErrorKind::Full`, or |
| // * `TrySendError::SendErrorKind::Disconnected`. |
| // |
| // These are unexpected, because: |
| // * `Full` can't happen, because `InputDeviceRegistryServer` |
| // uses an `UnboundedSender`. |
| // * `Disconnected` is highly unlikely, because the corresponding |
| // `UnboundedReceiver` lives in `main::input_fut`, and `input_fut`'s |
| // lifetime is nearly as long as `input_device_registry_server`'s. |
| // |
| // Nonetheless, InputDeviceRegistry isn't critical to production use. |
| // So we just log the error and move on. |
| fx_log_warn!( |
| "failed to forward InputDeviceRegistryRequestStream: {:?}; \ |
| must restart to enable input injection", |
| e |
| ) |
| } |
| } |
| } |
| } |
| } |
| |
| fx_log_info!("Finished service handler loop; exiting main."); |
| Ok(()) |
| } |
| |
| pub async fn handle_scene_manager_request_stream( |
| mut request_stream: SceneManagerRequestStream, |
| scene_manager: Arc<Mutex<Box<dyn scene_management::SceneManager>>>, |
| ) { |
| while let Ok(Some(request)) = request_stream.try_next().await { |
| match request { |
| SceneManagerRequest::SetRootView { view_provider, responder } => { |
| if let Ok(proxy) = view_provider.into_proxy() { |
| let mut scene_manager = scene_manager.lock().await; |
| match scene_manager.set_root_view(proxy).await { |
| Ok(mut view_ref) => match responder.send(&mut view_ref) { |
| Ok(_) => {} |
| Err(e) => { |
| fx_log_err!("Error responding to SetRootView(): {}", e); |
| } |
| }, |
| Err(e) => { |
| // Log an error and close the connection. This can be a consequence of |
| // the child View not connecting to the scene graph (hence we don't |
| // receive the ViewRef to return), or perhaps an internal bug which |
| // requires further investigation. |
| fx_log_err!("Failed to obtain ViewRef from set_root_view(): {}", e); |
| } |
| } |
| } |
| } |
| }; |
| } |
| } |
| |
| pub async fn handle_accessibility_view_registry_request_stream( |
| mut request_stream: A11yViewRegistryRequestStream, |
| scene_manager: Arc<Mutex<Box<dyn scene_management::SceneManager>>>, |
| ) { |
| while let Ok(Some(request)) = request_stream.try_next().await { |
| match request { |
| A11yViewRegistryRequest::CreateAccessibilityViewHolder { |
| a11y_view_ref: _, |
| a11y_view_token, |
| responder, |
| .. |
| } => { |
| let mut scene_manager = scene_manager.lock().await; |
| let r = scene_manager.insert_a11y_view(a11y_view_token); |
| |
| let _ = match r { |
| Ok(mut result) => { |
| let _ = responder.send(&mut result); |
| } |
| Err(e) => { |
| fx_log_warn!("Closing A11yViewRegistry connection due to error {:?}", e); |
| responder.control_handle().shutdown_with_epitaph(zx::Status::PEER_CLOSED); |
| } |
| }; |
| } |
| A11yViewRegistryRequest::CreateAccessibilityViewport { |
| viewport_creation_token: _, |
| responder, |
| .. |
| } => { |
| fx_log_err!("A11yViewRegistry.CreateAccessibilityViewport not implemented!"); |
| responder.control_handle().shutdown_with_epitaph(zx::Status::PEER_CLOSED); |
| } |
| }; |
| } |
| } |
| |
| fn register_gfx_as_magnifier( |
| scene_manager: Arc<Mutex<Box<dyn SceneManager>>>, |
| ) -> Result<(), anyhow::Error> { |
| let (magnification_handler_client, magnification_handler_server) = |
| fidl::endpoints::create_request_stream::<MagnificationHandlerMarker>()?; |
| scene_management::GfxSceneManager::handle_magnification_handler_request_stream( |
| magnification_handler_server, |
| scene_manager, |
| ); |
| let magnifier_proxy = connect_to_protocol::<MagnifierMarker>()?; |
| magnifier_proxy.register_handler(magnification_handler_client)?; |
| Ok(()) |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use anyhow::format_err; |
| use fidl::endpoints::create_endpoints; |
| use fidl_fuchsia_session_scene::{ |
| ManagerMarker as SceneManagerMarker, ManagerProxy as SceneManagerProxy, |
| }; |
| use fidl_fuchsia_ui_accessibility_view::{RegistryMarker, RegistryProxy}; |
| use fidl_fuchsia_ui_app::{ViewProviderMarker, ViewProviderRequest}; |
| use fidl_fuchsia_ui_scenic as ui_scenic; |
| use fidl_fuchsia_ui_views as ui_views; |
| use fidl_fuchsia_ui_views::ViewToken; |
| use fuchsia_async as fasync; |
| use fuchsia_component_test::{ |
| Capability, ChildOptions, RealmBuilder, RealmInstance, Ref, Route, |
| }; |
| use fuchsia_scenic as scenic; |
| use futures::TryStreamExt; |
| |
| const SCENIC_URL: &str = "#meta/scenic.cm"; |
| |
| const MOCK_COBALT_URL: &str = "#meta/mock_cobalt.cm"; |
| |
| const SCENE_MANAGER_URL: &str = "#meta/scene_manager.cm"; |
| |
| const FAKE_HDCP_URL: &str = "#meta/hdcp.cm"; |
| |
| async fn setup_realm() -> Result<RealmInstance, anyhow::Error> { |
| let builder = RealmBuilder::new().await?; |
| |
| let mock_cobalt = |
| builder.add_child("mock_cobalt", MOCK_COBALT_URL, ChildOptions::new().eager()).await?; |
| |
| let hdcp = builder.add_child("hdcp", FAKE_HDCP_URL, ChildOptions::new().eager()).await?; |
| builder |
| .add_route( |
| Route::new() |
| .capability(Capability::protocol_by_name("fuchsia.sysmem.Allocator")) |
| .capability(Capability::protocol_by_name("fuchsia.tracing.provider.Registry")) |
| .from(Ref::parent()) |
| .to(&hdcp), |
| ) |
| .await?; |
| |
| let scenic = builder |
| .add_child("scenic", SCENIC_URL, ChildOptions::new().eager()) |
| .await |
| .expect("Failed to start scenic"); |
| builder |
| .add_route( |
| Route::new() |
| .capability(Capability::protocol_by_name("fuchsia.hardware.display.Provider")) |
| .from(&hdcp) |
| .to(&scenic), |
| ) |
| .await?; |
| builder |
| .add_route( |
| Route::new() |
| .capability(Capability::protocol_by_name("fuchsia.scheduler.ProfileProvider")) |
| .capability(Capability::protocol_by_name("fuchsia.sysmem.Allocator")) |
| .capability(Capability::protocol_by_name("fuchsia.tracing.provider.Registry")) |
| .capability(Capability::protocol_by_name("fuchsia.ui.input.ImeService")) |
| .capability(Capability::protocol_by_name("fuchsia.vulkan.loader.Loader")) |
| .from(Ref::parent()) |
| .to(&scenic), |
| ) |
| .await?; |
| builder |
| .add_route( |
| Route::new() |
| .capability(Capability::protocol_by_name("fuchsia.cobalt.LoggerFactory")) |
| .from(&mock_cobalt) |
| .to(&scenic), |
| ) |
| .await?; |
| builder |
| .add_route( |
| Route::new() |
| .capability(Capability::protocol_by_name("fuchsia.ui.views.ViewRefFocused")) |
| .from(&scenic) |
| .to(Ref::parent()), |
| ) |
| .await?; |
| |
| let scene_manager = builder |
| .add_child("scene_manager", SCENE_MANAGER_URL, ChildOptions::new().eager()) |
| .await?; |
| builder |
| .add_route( |
| Route::new() |
| .capability(Capability::protocol_by_name( |
| "fuchsia.ui.accessibility.view.Registry", |
| )) |
| .capability(Capability::protocol_by_name("fuchsia.session.scene.Manager")) |
| .from(&scene_manager) |
| .to(Ref::parent()), |
| ) |
| .await?; |
| builder |
| .add_route( |
| Route::new() |
| .capability(Capability::protocol_by_name("fuchsia.ui.app.ViewProvider")) |
| .from(Ref::parent()) |
| .to(&scene_manager), |
| ) |
| .await?; |
| |
| builder |
| .add_route( |
| Route::new() |
| .capability(Capability::protocol_by_name("fuchsia.ui.views.ViewRefInstalled")) |
| .capability(Capability::protocol_by_name("fuchsia.ui.scenic.Scenic")) |
| .capability(Capability::protocol_by_name("fuchsia.ui.scenic.Session")) |
| .capability(Capability::protocol_by_name("fuchsia.ui.composition.Flatland")) |
| .capability(Capability::protocol_by_name( |
| "fuchsia.ui.composition.FlatlandDisplay", |
| )) |
| .from(&scenic) |
| .to(Ref::parent()) |
| .to(&scene_manager), |
| ) |
| .await?; |
| |
| builder |
| .add_route( |
| Route::new() |
| .capability(Capability::protocol_by_name("fuchsia.logger.LogSink")) |
| .from(Ref::parent()) |
| .to(&hdcp) |
| .to(&mock_cobalt) |
| .to(&scene_manager) |
| .to(&scenic), |
| ) |
| .await?; |
| |
| let instance = builder.build().await.expect("Failed to build instance"); |
| Ok(instance) |
| } |
| |
| async fn present_session_changes(session: &scenic::SessionPtr) { |
| let _ = session |
| .lock() |
| // Passing 0 for requested_presentation_time tells scenic that that it should process |
| // enqueued operation as soon as possible. |
| // Passing 0 for requested_prediction_span guarantees that scenic will provide at least |
| // one future time. |
| .present2(0, 0) |
| .await |
| .expect("Failed to present"); |
| } |
| |
| async fn view_is_focused( |
| view_ref_focused_proxy: &ui_views::ViewRefFocusedProxy, |
| ) -> Result<bool, anyhow::Error> { |
| view_ref_focused_proxy |
| .watch() |
| .await |
| .map_err(|err| format_err!("ViewRefFocused fidl error for client view: {:?}", err)) |
| .map(|focused_state| focused_state.focused.unwrap_or(false)) |
| } |
| |
| async fn insert_a11y_view( |
| session: scenic::SessionPtr, |
| accessibility_view_registry_proxy: &RegistryProxy, |
| ) -> Result<(scenic::View, scenic::ViewHolder, ui_views::ViewRef), anyhow::Error> { |
| // Create a11y ViewRef and ViewToken pairs. |
| let mut a11y_view_token_pair = scenic::ViewTokenPair::new()?; |
| let a11y_viewref_pair = scenic::ViewRefPair::new()?; |
| let mut viewref_dup_for_registry = |
| fuchsia_scenic::duplicate_view_ref(&a11y_viewref_pair.view_ref)?; |
| let viewref_dup_to_return = |
| fuchsia_scenic::duplicate_view_ref(&a11y_viewref_pair.view_ref)?; |
| // Create a11y view and try inserting into scene. |
| let a11y_view = scenic::View::new3( |
| session.clone(), |
| a11y_view_token_pair.view_token, |
| a11y_viewref_pair.control_ref, |
| a11y_viewref_pair.view_ref, |
| Some(String::from("a11y view")), |
| ); |
| |
| present_session_changes(&session).await; |
| |
| let proxy_view_holder_token = accessibility_view_registry_proxy |
| .create_accessibility_view_holder( |
| &mut viewref_dup_for_registry, |
| &mut a11y_view_token_pair.view_holder_token, |
| ) |
| .await |
| .unwrap(); |
| |
| // Attach proxy view holder to the scene. This step is necessary to ensure that the client |
| // view is attached to the scene. |
| let proxy_view_holder = scenic::ViewHolder::new( |
| session.clone(), |
| proxy_view_holder_token, |
| Some(String::from("proxy view holder")), |
| ); |
| a11y_view.add_child(&proxy_view_holder); |
| present_session_changes(&session).await; |
| |
| Ok((a11y_view, proxy_view_holder, viewref_dup_to_return)) |
| } |
| |
| async fn set_root_view( |
| client_session: scenic::SessionPtr, |
| scene_manager: SceneManagerProxy, |
| ) -> Result<(scenic::View, ui_views::ViewRef), anyhow::Error> { |
| // Create ViewProvider endpoints. The scene manager uses this service to create the root |
| // view. |
| let (view_provider_client, view_provider_server) = create_endpoints::<ViewProviderMarker>() |
| .expect("Failed to create local ViewProvider proxy and stream"); |
| |
| let client_view_ref = scene_manager.set_root_view(view_provider_client).await.unwrap(); |
| |
| // Create a mock ViewProvider. |
| let mut view_provider_stream = view_provider_server.into_stream()?; |
| let client_view = match view_provider_stream.try_next().await.unwrap() { |
| Some(ViewProviderRequest::CreateViewWithViewRef { |
| token, |
| view_ref_control, |
| view_ref, |
| .. |
| }) => { |
| let view_token = ViewToken { value: token }; |
| Ok(scenic::View::new3( |
| client_session.clone(), |
| view_token, |
| view_ref_control, |
| view_ref, |
| Some(String::from("root view")), |
| )) |
| } |
| |
| _ => Err("Unexpected method call"), |
| } |
| .expect("CreateViewWithViewRef was not called"); |
| |
| present_session_changes(&client_session).await; |
| |
| Ok((client_view, client_view_ref)) |
| } |
| |
| #[allow(unused_variables)] |
| #[fasync::run_singlethreaded(test)] |
| async fn test_attach_a11y_view() -> Result<(), anyhow::Error> { |
| // Setup realm instance. |
| let realm_instance = setup_realm().await.expect("Failed to setup realm"); |
| |
| // Connect to services. |
| let accessibility_view_registry_proxy = |
| realm_instance.root.connect_to_protocol_at_exposed_dir::<RegistryMarker>()?; |
| |
| let view_ref_installed_proxy = realm_instance |
| .root |
| .connect_to_protocol_at_exposed_dir::<ui_views::ViewRefInstalledMarker>()?; |
| |
| let scenic_proxy = |
| realm_instance.root.connect_to_protocol_at_exposed_dir::<ui_scenic::ScenicMarker>()?; |
| |
| // Instantiate scenic session in which to create a11y view. |
| let (session_proxy, session_request_stream) = fidl::endpoints::create_proxy()?; |
| scenic_proxy.create_session2(session_request_stream, None, None)?; |
| let session = scenic::Session::new(session_proxy); |
| |
| // Create a11y view. Proxy view holder is not required for this test case, and can be dropped. |
| let (a11y_view, _, mut a11y_view_ref) = |
| insert_a11y_view(session, &accessibility_view_registry_proxy).await.unwrap(); |
| |
| // Listen for a11y view ref installed event. |
| let watch_result = view_ref_installed_proxy |
| .watch(&mut a11y_view_ref) |
| .await |
| .expect("ViewRefInstalled fidl error for a11y view") |
| .expect("ViewRefInstalledError for a11y view"); |
| |
| Ok(()) |
| } |
| |
| #[allow(unused_variables)] |
| #[fasync::run_singlethreaded(test)] |
| async fn test_set_root_view_before_a11y_view() -> Result<(), anyhow::Error> { |
| // Setup realm instance. |
| let realm_instance = setup_realm().await.expect("Failed to setup realm"); |
| |
| // Connect to services. |
| let accessibility_view_registry_proxy = |
| realm_instance.root.connect_to_protocol_at_exposed_dir::<RegistryMarker>()?; |
| |
| let view_ref_installed_proxy = realm_instance |
| .root |
| .connect_to_protocol_at_exposed_dir::<ui_views::ViewRefInstalledMarker>()?; |
| |
| let scenic_proxy = |
| realm_instance.root.connect_to_protocol_at_exposed_dir::<ui_scenic::ScenicMarker>()?; |
| |
| let scene_manager = |
| realm_instance.root.connect_to_protocol_at_exposed_dir::<SceneManagerMarker>().unwrap(); |
| |
| // Instantiate scenic session in which to create a11y view. |
| let (session_proxy, session_request_stream) = fidl::endpoints::create_proxy()?; |
| scenic_proxy.create_session2(session_request_stream, None, None)?; |
| let session = scenic::Session::new(session_proxy); |
| |
| // Insert a11y view. The a11y view ref is not required for this test case, and can be |
| // dropped. |
| let (a11y_view, proxy_view_holder, _) = |
| insert_a11y_view(session, &accessibility_view_registry_proxy).await.unwrap(); |
| |
| // Create session in which to create root view. |
| let (client_session_proxy, client_session_request_stream) = |
| fidl::endpoints::create_proxy()?; |
| scenic_proxy.create_session2(client_session_request_stream, None, None)?; |
| let client_session = scenic::Session::new(client_session_proxy); |
| |
| // Set root view. |
| let (client_view, mut client_view_ref) = |
| set_root_view(client_session, scene_manager).await.unwrap(); |
| |
| // Verify that the client view was attached to the scene. |
| let watch_result = view_ref_installed_proxy |
| .watch(&mut client_view_ref) |
| .await |
| .expect("ViewRefInstalled fidl error for client view") |
| .expect("ViewRefInstalledError for client view"); |
| |
| Ok(()) |
| } |
| |
| #[allow(unused_variables)] |
| #[fasync::run_singlethreaded(test)] |
| async fn test_set_root_view_after_a11y_view() -> Result<(), anyhow::Error> { |
| // Setup realm instance. |
| let realm_instance = setup_realm().await.expect("Failed to setup realm"); |
| |
| // Connect to services. |
| let accessibility_view_registry_proxy = |
| realm_instance.root.connect_to_protocol_at_exposed_dir::<RegistryMarker>()?; |
| |
| let view_ref_installed_proxy = realm_instance |
| .root |
| .connect_to_protocol_at_exposed_dir::<ui_views::ViewRefInstalledMarker>()?; |
| |
| let scenic_proxy = |
| realm_instance.root.connect_to_protocol_at_exposed_dir::<ui_scenic::ScenicMarker>()?; |
| |
| let scene_manager = |
| realm_instance.root.connect_to_protocol_at_exposed_dir::<SceneManagerMarker>().unwrap(); |
| |
| // Create session in which to create root view. |
| // The |view_ref_focused| endpoint is required to verify that the client view is refocused |
| // after the a11y view is inserted. |
| let (client_session_proxy, client_session_request_stream) = |
| fidl::endpoints::create_proxy()?; |
| let (view_ref_focused_proxy, view_ref_focused_request_stream) = |
| fidl::endpoints::create_proxy()?; |
| let mut session_endpoints = ui_scenic::SessionEndpoints::EMPTY; |
| session_endpoints.session = Some(client_session_request_stream); |
| session_endpoints.view_ref_focused = Some(view_ref_focused_request_stream); |
| scenic_proxy.create_session_t(session_endpoints).await?; |
| let client_session = scenic::Session::new(client_session_proxy); |
| |
| // Create ViewProvider endpoints. The scene manager uses this service to create the root |
| // view. |
| let (view_provider_client, view_provider_server) = create_endpoints::<ViewProviderMarker>() |
| .expect("Failed to create local ViewProvider proxy and stream"); |
| |
| // Set root view. Client view ref is not required for this test case, and can be dropped. |
| let (client_view, _) = set_root_view(client_session, scene_manager).await.unwrap(); |
| |
| // Instantiate scenic session in which to create a11y view. |
| let (session_proxy, session_request_stream) = fidl::endpoints::create_proxy()?; |
| scenic_proxy.create_session2(session_request_stream, None, None)?; |
| let session = scenic::Session::new(session_proxy); |
| |
| // Insert a11y view. The a11y view ref is not required for this test case, and can be |
| // dropped. |
| let (a11y_view, proxy_view_holder, _) = |
| insert_a11y_view(session, &accessibility_view_registry_proxy).await.unwrap(); |
| |
| // Verify that the client view was focused. |
| let client_view_focused = view_is_focused(&view_ref_focused_proxy).await.unwrap(); |
| if !client_view_focused { |
| panic!("Client view ref not focused after a11y view inserted"); |
| } |
| |
| Ok(()) |
| } |
| } |