1use crate::display_controller::{DisplayController, DisplayError, Request};
6use crate::types::{DisplayInfo, LowLightMode, SetDisplayInfo, Theme, ThemeMode, ThemeType};
7use anyhow::{Error, anyhow};
8use async_utils::hanging_get::server;
9use fidl_fuchsia_settings::{
10 DisplayRequest, DisplayRequestStream, DisplaySettings, DisplayWatchResponder,
11 Error as SettingsError, LowLightMode as FidlLowLightMode, Theme as FidlTheme,
12 ThemeMode as FidlThemeMode, ThemeType as FidlThemeType,
13};
14use fuchsia_async as fasync;
15use futures::StreamExt;
16use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
17use futures::channel::oneshot;
18use settings_common::inspect::event::{
19 RequestType, ResponseType, UsagePublisher, UsageResponsePublisher,
20};
21
22impl From<FidlThemeMode> for ThemeMode {
23 fn from(fidl: FidlThemeMode) -> Self {
24 ThemeMode::from_bits(FidlThemeMode::bits(&fidl))
25 .expect("failed to convert FidlThemeMode to ThemeMode")
26 }
27}
28
29impl From<ThemeMode> for FidlThemeMode {
30 fn from(fidl: ThemeMode) -> Self {
31 FidlThemeMode::from_bits(ThemeMode::bits(&fidl))
32 .expect("failed to convert ThemeMode to FidlThemeMode")
33 }
34}
35
36impl From<FidlLowLightMode> for LowLightMode {
37 fn from(fidl_low_light_mode: FidlLowLightMode) -> Self {
38 match fidl_low_light_mode {
39 FidlLowLightMode::Disable => LowLightMode::Disable,
40 FidlLowLightMode::DisableImmediately => LowLightMode::DisableImmediately,
41 FidlLowLightMode::Enable => LowLightMode::Enable,
42 }
43 }
44}
45
46impl From<FidlThemeType> for ThemeType {
47 fn from(fidl_theme_type: FidlThemeType) -> Self {
48 match fidl_theme_type {
49 FidlThemeType::Default => ThemeType::Default,
50 FidlThemeType::Light => ThemeType::Light,
51 FidlThemeType::Dark => ThemeType::Dark,
52 }
53 }
54}
55
56impl From<FidlTheme> for Theme {
57 fn from(fidl_theme: FidlTheme) -> Self {
58 Self {
59 theme_type: fidl_theme.theme_type.map(Into::into),
60 theme_mode: fidl_theme.theme_mode.map(Into::into).unwrap_or_else(ThemeMode::empty),
61 }
62 }
63}
64
65impl From<DisplayInfo> for DisplaySettings {
66 fn from(info: DisplayInfo) -> Self {
67 fidl_fuchsia_settings::DisplaySettings {
68 auto_brightness: Some(info.auto_brightness),
69 adjusted_auto_brightness: Some(info.auto_brightness_value),
70 brightness_value: Some(info.manual_brightness_value),
71 screen_enabled: Some(info.screen_enabled),
72 low_light_mode: Some(match info.low_light_mode {
73 LowLightMode::Enable => FidlLowLightMode::Enable,
74 LowLightMode::Disable => FidlLowLightMode::Disable,
75 LowLightMode::DisableImmediately => FidlLowLightMode::DisableImmediately,
76 }),
77 theme: Some(FidlTheme {
78 theme_type: match info.theme {
79 Some(Theme { theme_type: Some(theme_type), .. }) => match theme_type {
80 ThemeType::Unknown => None,
81 ThemeType::Default => Some(FidlThemeType::Default),
82 ThemeType::Light => Some(FidlThemeType::Light),
83 ThemeType::Dark => Some(FidlThemeType::Dark),
84 },
85 _ => None,
86 },
87 theme_mode: match info.theme {
88 Some(Theme { theme_mode, .. }) if !theme_mode.is_empty() => {
89 Some(FidlThemeMode::from(theme_mode))
90 }
91 _ => None,
92 },
93 ..Default::default()
94 }),
95 ..Default::default()
96 }
97 }
98}
99
100fn to_request(settings: DisplaySettings) -> Result<SetDisplayInfo, Error> {
101 let set_display_info = SetDisplayInfo {
102 manual_brightness_value: settings.brightness_value,
103 auto_brightness_value: settings.adjusted_auto_brightness,
104 auto_brightness: settings.auto_brightness,
105 screen_enabled: settings.screen_enabled,
106 low_light_mode: settings.low_light_mode.map(Into::into),
107 theme: settings.theme.map(Into::into),
108 };
109 match set_display_info {
110 SetDisplayInfo {
112 manual_brightness_value: None,
113 auto_brightness_value: None,
114 auto_brightness: None,
115 screen_enabled: None,
116 low_light_mode: None,
117 theme: None,
118 } => Err(anyhow!("No values set")),
119 _ => Ok(set_display_info),
120 }
121}
122
123pub(crate) type SubscriberObject = (UsageResponsePublisher<DisplayInfo>, DisplayWatchResponder);
124type HangingGetFn = fn(&DisplayInfo, SubscriberObject) -> bool;
125pub(crate) type HangingGet = server::HangingGet<DisplayInfo, SubscriberObject, HangingGetFn>;
126pub(crate) type Publisher = server::Publisher<DisplayInfo, SubscriberObject, HangingGetFn>;
127pub(crate) type Subscriber = server::Subscriber<DisplayInfo, SubscriberObject, HangingGetFn>;
128
129pub struct DisplayFidlHandler {
130 hanging_get: HangingGet,
131 controller_tx: UnboundedSender<Request>,
132 usage_publisher: UsagePublisher<DisplayInfo>,
133}
134
135impl DisplayFidlHandler {
136 pub(crate) fn new<T>(
137 display_controller: &mut DisplayController<T>,
138 usage_publisher: UsagePublisher<DisplayInfo>,
139 initial_value: DisplayInfo,
140 ) -> (Self, UnboundedReceiver<Request>) {
141 let hanging_get = HangingGet::new(initial_value, Self::hanging_get);
142 display_controller.register_publisher(hanging_get.new_publisher());
143 let (controller_tx, controller_rx) = mpsc::unbounded();
144 (Self { hanging_get, controller_tx, usage_publisher }, controller_rx)
145 }
146
147 fn hanging_get(info: &DisplayInfo, (usage_responder, responder): SubscriberObject) -> bool {
148 usage_responder.respond(format!("{info:?}"), ResponseType::OkSome);
149 if let Err(e) = responder.send(&DisplaySettings::from(*info)) {
150 log::warn!("Failed to respond to watch request: {e:?}");
151 return false;
152 }
153 true
154 }
155
156 pub fn handle_stream(&mut self, mut stream: DisplayRequestStream) {
157 let request_handler = RequestHandler {
158 subscriber: self.hanging_get.new_subscriber(),
159 controller_tx: self.controller_tx.clone(),
160 usage_publisher: self.usage_publisher.clone(),
161 };
162 fasync::Task::local(async move {
163 while let Some(Ok(request)) = stream.next().await {
164 request_handler.handle_request(request).await;
165 }
166 })
167 .detach();
168 }
169}
170
171#[derive(Debug)]
172enum HandlerError {
173 AlreadySubscribed,
174 InvalidArgument(
175 #[allow(dead_code)] Error,
177 ),
178 ControllerStopped,
179 Controller(DisplayError),
180}
181
182impl From<&HandlerError> for ResponseType {
183 fn from(error: &HandlerError) -> Self {
184 match error {
185 HandlerError::AlreadySubscribed => ResponseType::AlreadySubscribed,
186 HandlerError::InvalidArgument(_) => ResponseType::InvalidArgument,
187 HandlerError::ControllerStopped => ResponseType::UnexpectedError,
188 HandlerError::Controller(e) => ResponseType::from(e),
189 }
190 }
191}
192
193struct RequestHandler {
194 subscriber: Subscriber,
195 controller_tx: UnboundedSender<Request>,
196 usage_publisher: UsagePublisher<DisplayInfo>,
197}
198
199impl RequestHandler {
200 async fn handle_request(&self, request: DisplayRequest) {
201 match request {
202 DisplayRequest::Watch { responder } => {
203 let usage_res = self.usage_publisher.request("Watch".to_string(), RequestType::Get);
204 if let Err((usage_res, responder)) =
205 self.subscriber.register2((usage_res, responder))
206 {
207 let e = HandlerError::AlreadySubscribed;
208 usage_res.respond(format!("Err({e:?})"), ResponseType::from(&e));
209 drop(responder);
210 }
211 }
212 DisplayRequest::Set { settings, responder } => {
213 let usage_res = self
214 .usage_publisher
215 .request(format!("Set{{settings:{settings:?}}}"), RequestType::Set);
216 if let Err(e) = self.set(settings).await {
217 usage_res.respond(format!("Err({e:?}"), ResponseType::from(&e));
218 let _ = responder.send(Err(SettingsError::Failed));
219 } else {
220 usage_res.respond("Ok(())".to_string(), ResponseType::OkNone);
221 let _ = responder.send(Ok(()));
222 }
223 }
224 }
225 }
226
227 async fn set(&self, settings: DisplaySettings) -> Result<(), HandlerError> {
228 let (set_tx, set_rx) = oneshot::channel();
229 let info = to_request(settings).map_err(HandlerError::InvalidArgument)?;
230 self.controller_tx
231 .unbounded_send(Request::Set(info, set_tx))
232 .map_err(|_| HandlerError::ControllerStopped)?;
233 set_rx
234 .await
235 .map_err(|_| HandlerError::ControllerStopped)
236 .and_then(|res| res.map_err(HandlerError::Controller))
237 }
238}