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