1use crate::base::{Dependency, Entity, SettingType};
6use crate::handler::base::Error;
7use crate::ingress::registration::{Registrant, Registrar};
8use crate::job::source::Seeder;
9use fidl_fuchsia_settings::{
10 AccessibilityRequestStream, AudioRequestStream, DisplayRequestStream,
11 DoNotDisturbRequestStream, FactoryResetRequestStream, InputRequestStream, IntlRequestStream,
12 KeyboardRequestStream, LightRequestStream, NightModeRequestStream, PrivacyRequestStream,
13 SetupRequestStream,
14};
15use fuchsia_component::server::{ServiceFsDir, ServiceObjLocal};
16use serde::Deserialize;
17
18impl From<Error> for zx::Status {
19 fn from(error: Error) -> zx::Status {
20 match error {
21 Error::UnhandledType(_) => zx::Status::UNAVAILABLE,
22 _ => zx::Status::INTERNAL,
23 }
24 }
25}
26#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
28pub enum Interface {
29 Accessibility,
30 Audio,
31 Display(display::InterfaceFlags),
32 DoNotDisturb,
33 FactoryReset,
34 Input,
35 Intl,
36 Keyboard,
37 Light,
38 NightMode,
39 Privacy,
40 Setup,
41}
42
43#[derive(Clone, Deserialize, PartialEq, Eq, Hash, Debug)]
47pub enum InterfaceSpec {
48 Accessibility,
49 Audio,
50 Display(Vec<display::InterfaceSpec>),
52 DoNotDisturb,
53 FactoryReset,
54 Input,
55 Intl,
56 Keyboard,
57 Light,
58 NightMode,
59 Privacy,
60 Setup,
61}
62
63impl From<InterfaceSpec> for Interface {
64 fn from(spec: InterfaceSpec) -> Self {
65 match spec {
66 InterfaceSpec::Audio => Interface::Audio,
67 InterfaceSpec::Accessibility => Interface::Accessibility,
68 InterfaceSpec::Display(variants) => Interface::Display(variants.into()),
69 InterfaceSpec::DoNotDisturb => Interface::DoNotDisturb,
70 InterfaceSpec::FactoryReset => Interface::FactoryReset,
71 InterfaceSpec::Input => Interface::Input,
72 InterfaceSpec::Intl => Interface::Intl,
73 InterfaceSpec::Keyboard => Interface::Keyboard,
74 InterfaceSpec::Light => Interface::Light,
75 InterfaceSpec::NightMode => Interface::NightMode,
76 InterfaceSpec::Privacy => Interface::Privacy,
77 InterfaceSpec::Setup => Interface::Setup,
78 }
79 }
80}
81
82pub mod display {
83 use bitflags::bitflags;
84 use serde::Deserialize;
85
86 bitflags! {
87 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
91 pub struct InterfaceFlags: u64 {
92 const BASE = 1 << 0;
93 }
94 }
95
96 #[derive(Copy, Clone, Deserialize, PartialEq, Eq, Hash, Debug)]
97 pub enum InterfaceSpec {
98 Base,
99 }
100
101 impl From<Vec<InterfaceSpec>> for InterfaceFlags {
102 fn from(variants: Vec<InterfaceSpec>) -> Self {
103 variants.into_iter().fold(InterfaceFlags::empty(), |flags, variant| {
104 flags
105 | match variant {
106 InterfaceSpec::Base => InterfaceFlags::BASE,
107 }
108 })
109 }
110 }
111}
112
113pub(crate) type Register =
117 Box<dyn for<'a> FnOnce(&Seeder, &mut ServiceFsDir<'_, ServiceObjLocal<'a, ()>>)>;
118
119impl Interface {
120 fn dependencies(self) -> Vec<Dependency> {
122 match self {
123 Interface::Accessibility => {
124 vec![Dependency::Entity(Entity::Handler(SettingType::Accessibility))]
125 }
126 Interface::Audio => {
127 vec![Dependency::Entity(Entity::Handler(SettingType::Audio))]
128 }
129 Interface::Display(interfaces) => {
130 let mut dependencies = Vec::new();
131
132 if interfaces.contains(display::InterfaceFlags::BASE) {
133 dependencies.push(Dependency::Entity(Entity::Handler(SettingType::Display)));
134 }
135
136 if dependencies.is_empty() {
137 panic!("A valid interface flag must be specified with Interface::Display");
138 }
139
140 dependencies
141 }
142 Interface::DoNotDisturb => {
143 vec![Dependency::Entity(Entity::Handler(SettingType::DoNotDisturb))]
144 }
145 Interface::FactoryReset => {
146 vec![Dependency::Entity(Entity::Handler(SettingType::FactoryReset))]
147 }
148 Interface::Input => {
149 vec![Dependency::Entity(Entity::Handler(SettingType::Input))]
150 }
151 Interface::Intl => {
152 vec![Dependency::Entity(Entity::Handler(SettingType::Intl))]
153 }
154 Interface::Keyboard => {
155 vec![Dependency::Entity(Entity::Handler(SettingType::Keyboard))]
156 }
157 Interface::Light => {
158 vec![Dependency::Entity(Entity::Handler(SettingType::Light))]
159 }
160 Interface::NightMode => {
161 vec![Dependency::Entity(Entity::Handler(SettingType::NightMode))]
162 }
163 Interface::Privacy => {
164 vec![Dependency::Entity(Entity::Handler(SettingType::Privacy))]
165 }
166 Interface::Setup => {
167 vec![Dependency::Entity(Entity::Handler(SettingType::Setup))]
168 }
169 }
170 }
171
172 fn registration_fn(self) -> Register {
175 Box::new(
176 move |seeder: &Seeder, service_dir: &mut ServiceFsDir<'_, ServiceObjLocal<'_, ()>>| {
177 match self {
178 Interface::Audio => {
179 let seeder = seeder.clone();
180 let _ = service_dir.add_fidl_service(move |stream: AudioRequestStream| {
181 seeder.seed(stream);
182 });
183 }
184 Interface::Accessibility => {
185 let seeder = seeder.clone();
186 let _ = service_dir.add_fidl_service(
187 move |stream: AccessibilityRequestStream| {
188 seeder.seed(stream);
189 },
190 );
191 }
192 Interface::Display(_) => {
193 let seeder = seeder.clone();
194 let _ =
195 service_dir.add_fidl_service(move |stream: DisplayRequestStream| {
196 seeder.seed(stream);
197 });
198 }
199 Interface::DoNotDisturb => {
200 let seeder = seeder.clone();
201 let _ = service_dir.add_fidl_service(
202 move |stream: DoNotDisturbRequestStream| {
203 seeder.seed(stream);
204 },
205 );
206 }
207 Interface::FactoryReset => {
208 let seeder = seeder.clone();
209 let _ = service_dir.add_fidl_service(
210 move |stream: FactoryResetRequestStream| {
211 seeder.seed(stream);
212 },
213 );
214 }
215 Interface::Input => {
216 let seeder = seeder.clone();
217 let _ = service_dir.add_fidl_service(move |stream: InputRequestStream| {
218 seeder.seed(stream);
219 });
220 }
221 Interface::Intl => {
222 let seeder = seeder.clone();
223 let _ = service_dir.add_fidl_service(move |stream: IntlRequestStream| {
224 seeder.seed(stream);
225 });
226 }
227 Interface::Keyboard => {
228 let seeder = seeder.clone();
229 let _ =
230 service_dir.add_fidl_service(move |stream: KeyboardRequestStream| {
231 seeder.seed(stream);
232 });
233 }
234 Interface::Light => {
235 let seeder = seeder.clone();
236 let _ = service_dir.add_fidl_service(move |stream: LightRequestStream| {
237 seeder.seed(stream);
238 });
239 }
240 Interface::NightMode => {
241 let seeder = seeder.clone();
242 let _ =
243 service_dir.add_fidl_service(move |stream: NightModeRequestStream| {
244 seeder.seed(stream);
245 });
246 }
247 Interface::Privacy => {
248 let seeder = seeder.clone();
249 let _ =
250 service_dir.add_fidl_service(move |stream: PrivacyRequestStream| {
251 seeder.seed(stream);
252 });
253 }
254 Interface::Setup => {
255 let seeder = seeder.clone();
256 let _ = service_dir.add_fidl_service(move |stream: SetupRequestStream| {
257 seeder.seed(stream);
258 });
259 }
260 }
261 },
262 )
263 }
264
265 pub(crate) fn registrant(self) -> Registrant {
269 Registrant::new(
270 format!("{self:?}"),
271 Registrar::Fidl(self.registration_fn()),
272 self.dependencies().into_iter().collect(),
273 )
274 }
275}
276
277#[cfg(test)]
278mod tests {
279 use fidl_fuchsia_settings::PrivacyMarker;
280 use fuchsia_async as fasync;
281 use fuchsia_component::server::ServiceFs;
282 use futures::StreamExt;
283
284 use assert_matches::assert_matches;
285
286 use crate::base::{Dependency, Entity, SettingType};
287 use crate::handler::base::{Payload, Request};
288 use crate::ingress::registration::Registrant;
289 use crate::job::manager::Manager;
290 use crate::job::source::Seeder;
291 use crate::message::base::MessengerType;
292 use crate::service;
293
294 use super::Interface;
295
296 #[fuchsia::test(allow_stalls = false)]
297 async fn test_fidl_seeder_bringup() {
298 let mut fs = ServiceFs::new_local();
299 let delegate = service::MessageHub::create_hub();
300 let job_manager_signature = Manager::spawn(&delegate).await;
301 let job_seeder = Seeder::new(&delegate, job_manager_signature).await;
302
303 let setting_type = SettingType::Privacy;
305
306 let registrant: Registrant = Interface::Privacy.registrant();
307
308 assert!(registrant
310 .get_dependencies()
311 .contains(&Dependency::Entity(Entity::Handler(setting_type))));
312
313 let mut rx = delegate
315 .create(MessengerType::Addressable(service::Address::Handler(setting_type)))
316 .await
317 .expect("messenger should be created")
318 .1;
319
320 registrant.register(&job_seeder, &mut fs.root_dir());
322
323 let connector = fs.create_protocol_connector().expect("should create connector");
325 fasync::Task::local(fs.collect()).detach();
326
327 let privacy_proxy =
329 connector.connect_to_protocol::<PrivacyMarker>().expect("should connect to protocol");
330 fasync::Task::local(async move {
331 let _ = privacy_proxy.watch().await;
332 })
333 .detach();
334
335 assert_matches!(rx.next_of::<Payload>().await, Ok((Payload::Request(Request::Listen), _)));
337 }
338}