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 HangingGetObserver, RequestType, ResponseType, UsagePublisher,
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 HangingGetObserver<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(info: &AccessibilityInfo, observer: SubscriberObject) -> bool {
77 let (usage_responder, responder) = observer.into_parts();
78 usage_responder.respond(format!("{info:?}"), ResponseType::OkSome);
79 if let Err(e) = responder.send(&AccessibilitySettings::from(*info)) {
80 log::warn!("Failed to respond to watch request: {e:?}");
81 return false;
82 }
83 true
84 }
85
86 pub fn handle_stream(&mut self, mut stream: AccessibilityRequestStream) {
87 let request_handler = RequestHandler {
88 subscriber: self.hanging_get.new_subscriber(),
89 controller_tx: self.controller_tx.clone(),
90 usage_publisher: self.usage_publisher.clone(),
91 };
92 fasync::Task::local(async move {
93 while let Some(Ok(request)) = stream.next().await {
94 request_handler.handle_request(request).await;
95 }
96 })
97 .detach();
98 }
99}
100
101#[derive(Debug)]
102enum HandlerError {
103 AlreadySubscribed,
104 ControllerStopped,
105 Controller(AccessibilityError),
106}
107
108impl From<&HandlerError> for ResponseType {
109 fn from(error: &HandlerError) -> Self {
110 match error {
111 HandlerError::AlreadySubscribed => ResponseType::AlreadySubscribed,
112 HandlerError::ControllerStopped => ResponseType::UnexpectedError,
113 HandlerError::Controller(e) => ResponseType::from(e),
114 }
115 }
116}
117
118struct RequestHandler {
119 subscriber: Subscriber,
120 controller_tx: UnboundedSender<Request>,
121 usage_publisher: UsagePublisher<AccessibilityInfo>,
122}
123
124impl RequestHandler {
125 async fn handle_request(&self, request: AccessibilityRequest) {
126 match request {
127 AccessibilityRequest::Watch { responder } => {
128 let usage_res = self.usage_publisher.request("Watch".to_string(), RequestType::Get);
129 let observer = HangingGetObserver::new(usage_res, responder);
130 if let Err(observer) = self.subscriber.register2(observer) {
131 let e = HandlerError::AlreadySubscribed;
132 let (usage_res, responder) = observer.into_parts();
133 usage_res.respond(format!("Err({e:?})"), ResponseType::from(&e));
134 drop(responder);
135 }
136 }
137 AccessibilityRequest::Set { settings, responder } => {
138 let usage_res = self
139 .usage_publisher
140 .request(format!("Set{{settings:{settings:?}}}"), RequestType::Set);
141 if let Err(e) = self.set(settings).await {
142 usage_res.respond(format!("Err({e:?}"), ResponseType::from(&e));
143 let _ = responder.send(Err(SettingsError::Failed));
144 } else {
145 usage_res.respond("Ok(())".to_string(), ResponseType::OkNone);
146 let _ = responder.send(Ok(()));
147 }
148 }
149 }
150 }
151
152 async fn set(&self, settings: AccessibilitySettings) -> Result<(), HandlerError> {
153 let (set_tx, set_rx) = oneshot::channel();
154 self.controller_tx
155 .unbounded_send(Request::Set(AccessibilityInfo::from(settings), set_tx))
156 .map_err(|_| HandlerError::ControllerStopped)?;
157 set_rx
158 .await
159 .map_err(|_| HandlerError::ControllerStopped)
160 .and_then(|res| res.map_err(HandlerError::Controller))
161 }
162}