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