settings/accessibility/
accessibility_fidl_handler.rs1use super::AccessibilityController;
6use super::accessibility_controller::{AccessibilityError, Request};
7use crate::accessibility::types::{AccessibilityInfo, CaptionsSettings, ColorBlindnessType};
8use async_utils::hanging_get::server;
9use fidl_fuchsia_settings::{
10 AccessibilityRequest, AccessibilityRequestStream, AccessibilitySettings,
11 AccessibilityWatchResponder, Error as SettingsError,
12};
13use fuchsia_async as fasync;
14use futures::StreamExt;
15use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
16use futures::channel::oneshot;
17use settings_common::inspect::event::{
18 RequestType, ResponseType, UsagePublisher, UsageResponsePublisher,
19};
20
21impl From<AccessibilityInfo> for AccessibilitySettings {
22 fn from(info: AccessibilityInfo) -> Self {
23 return AccessibilitySettings {
24 audio_description: info.audio_description,
25 screen_reader: info.screen_reader,
26 color_inversion: info.color_inversion,
27 enable_magnification: info.enable_magnification,
28 color_correction: info.color_correction.map(ColorBlindnessType::into),
29 captions_settings: info.captions_settings.map(CaptionsSettings::into),
30 ..Default::default()
31 };
32 }
33}
34
35impl From<AccessibilitySettings> for AccessibilityInfo {
36 fn from(settings: AccessibilitySettings) -> Self {
37 AccessibilityInfo {
38 audio_description: settings.audio_description,
39 screen_reader: settings.screen_reader,
40 color_inversion: settings.color_inversion,
41 enable_magnification: settings.enable_magnification,
42 color_correction: settings
43 .color_correction
44 .map(fidl_fuchsia_settings::ColorBlindnessType::into),
45 captions_settings: settings
46 .captions_settings
47 .map(fidl_fuchsia_settings::CaptionsSettings::into),
48 }
49 }
50}
51
52pub(crate) type SubscriberObject =
53 (UsageResponsePublisher<AccessibilityInfo>, AccessibilityWatchResponder);
54type HangingGetFn = fn(&AccessibilityInfo, SubscriberObject) -> bool;
55pub(crate) type HangingGet = server::HangingGet<AccessibilityInfo, SubscriberObject, HangingGetFn>;
56pub(crate) type Publisher = server::Publisher<AccessibilityInfo, SubscriberObject, HangingGetFn>;
57pub(crate) type Subscriber = server::Subscriber<AccessibilityInfo, SubscriberObject, HangingGetFn>;
58
59pub struct AccessibilityFidlHandler {
60 hanging_get: HangingGet,
61 controller_tx: UnboundedSender<Request>,
62 usage_publisher: UsagePublisher<AccessibilityInfo>,
63}
64
65impl AccessibilityFidlHandler {
66 pub(crate) fn new(
67 accessibility_controller: &mut AccessibilityController,
68 usage_publisher: UsagePublisher<AccessibilityInfo>,
69 initial_value: AccessibilityInfo,
70 ) -> (Self, UnboundedReceiver<Request>) {
71 let hanging_get = HangingGet::new(initial_value, Self::hanging_get);
72 accessibility_controller.register_publisher(hanging_get.new_publisher());
73 let (controller_tx, controller_rx) = mpsc::unbounded();
74 (Self { hanging_get, controller_tx, usage_publisher }, controller_rx)
75 }
76
77 fn hanging_get(
78 info: &AccessibilityInfo,
79 (usage_responder, responder): SubscriberObject,
80 ) -> bool {
81 usage_responder.respond(format!("{info:?}"), ResponseType::OkSome);
82 if let Err(e) = responder.send(&AccessibilitySettings::from(*info)) {
83 log::warn!("Failed to respond to watch request: {e:?}");
84 return false;
85 }
86 true
87 }
88
89 pub fn handle_stream(&mut self, mut stream: AccessibilityRequestStream) {
90 let request_handler = RequestHandler {
91 subscriber: self.hanging_get.new_subscriber(),
92 controller_tx: self.controller_tx.clone(),
93 usage_publisher: self.usage_publisher.clone(),
94 };
95 fasync::Task::local(async move {
96 while let Some(Ok(request)) = stream.next().await {
97 request_handler.handle_request(request).await;
98 }
99 })
100 .detach();
101 }
102}
103
104#[derive(Debug)]
105enum HandlerError {
106 AlreadySubscribed,
107 ControllerStopped,
108 Controller(AccessibilityError),
109}
110
111impl From<&HandlerError> for ResponseType {
112 fn from(error: &HandlerError) -> Self {
113 match error {
114 HandlerError::AlreadySubscribed => ResponseType::AlreadySubscribed,
115 HandlerError::ControllerStopped => ResponseType::UnexpectedError,
116 HandlerError::Controller(e) => ResponseType::from(e),
117 }
118 }
119}
120
121struct RequestHandler {
122 subscriber: Subscriber,
123 controller_tx: UnboundedSender<Request>,
124 usage_publisher: UsagePublisher<AccessibilityInfo>,
125}
126
127impl RequestHandler {
128 async fn handle_request(&self, request: AccessibilityRequest) {
129 match request {
130 AccessibilityRequest::Watch { responder } => {
131 let usage_res = self.usage_publisher.request("Watch".to_string(), RequestType::Get);
132 if let Err((usage_res, responder)) =
133 self.subscriber.register2((usage_res, responder))
134 {
135 let e = HandlerError::AlreadySubscribed;
136 usage_res.respond(format!("Err({e:?})"), ResponseType::from(&e));
137 drop(responder);
138 }
139 }
140 AccessibilityRequest::Set { settings, responder } => {
141 let usage_res = self
142 .usage_publisher
143 .request(format!("Set{{settings:{settings:?}}}"), RequestType::Set);
144 if let Err(e) = self.set(settings).await {
145 usage_res.respond(format!("Err({e:?}"), ResponseType::from(&e));
146 let _ = responder.send(Err(SettingsError::Failed));
147 } else {
148 usage_res.respond("Ok(())".to_string(), ResponseType::OkNone);
149 let _ = responder.send(Ok(()));
150 }
151 }
152 }
153 }
154
155 async fn set(&self, settings: AccessibilitySettings) -> Result<(), HandlerError> {
156 let (set_tx, set_rx) = oneshot::channel();
157 self.controller_tx
158 .unbounded_send(Request::Set(AccessibilityInfo::from(settings), set_tx))
159 .map_err(|_| HandlerError::ControllerStopped)?;
160 set_rx
161 .await
162 .map_err(|_| HandlerError::ControllerStopped)
163 .and_then(|res| res.map_err(HandlerError::Controller))
164 }
165}