settings/agent/
media_buttons.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::agent::{
6    AgentError, Context as AgentContext, Invocation, InvocationResult, Lifespan, Payload,
7};
8use crate::base::SettingType;
9use crate::event::{media_buttons, Event, Publisher};
10use crate::handler::base::{Payload as HandlerPayload, Request};
11use crate::input::{monitor_media_buttons, MediaButtons};
12use crate::message::base::Audience;
13use crate::service_context::ServiceContext;
14use crate::{service, trace_guard};
15use fidl_fuchsia_ui_input::MediaButtonsEvent;
16use futures::StreamExt;
17use std::collections::HashSet;
18use std::rc::Rc;
19use {fuchsia_async as fasync, fuchsia_trace as ftrace};
20
21/// Setting types that the media buttons agent will send media button events to, if they're
22/// available on the device.
23fn get_event_setting_types() -> HashSet<SettingType> {
24    vec![SettingType::Audio, SettingType::Light, SettingType::Input].into_iter().collect()
25}
26
27pub(crate) struct MediaButtonsAgent {
28    publisher: Publisher,
29    messenger: service::message::Messenger,
30
31    /// Settings to send media buttons events to.
32    recipient_settings: HashSet<SettingType>,
33}
34
35impl MediaButtonsAgent {
36    pub(crate) async fn create(context: AgentContext) {
37        let mut agent = MediaButtonsAgent {
38            publisher: context.get_publisher(),
39            messenger: context.create_messenger().await.expect("media button messenger created"),
40            recipient_settings: context
41                .available_components
42                .intersection(&get_event_setting_types())
43                .cloned()
44                .collect::<HashSet<SettingType>>(),
45        };
46
47        let mut receptor = context.receptor;
48        fasync::Task::local(async move {
49            while let Ok((Payload::Invocation(invocation), client)) =
50                receptor.next_of::<Payload>().await
51            {
52                let _ = client.reply(Payload::Complete(agent.handle(invocation).await).into());
53            }
54
55            log::info!("Media buttons agent done processing requests");
56        })
57        .detach()
58    }
59
60    async fn handle(&mut self, invocation: Invocation) -> InvocationResult {
61        match invocation.lifespan {
62            Lifespan::Initialization => Err(AgentError::UnhandledLifespan),
63            Lifespan::Service => self.handle_service_lifespan(invocation.service_context).await,
64        }
65    }
66
67    async fn handle_service_lifespan(
68        &mut self,
69        service_context: Rc<ServiceContext>,
70    ) -> InvocationResult {
71        let (input_tx, mut input_rx) = futures::channel::mpsc::unbounded::<MediaButtonsEvent>();
72        if let Err(e) = monitor_media_buttons(service_context, input_tx).await {
73            log::error!("Unable to monitor media buttons: {:?}", e);
74            return Err(AgentError::UnexpectedError);
75        }
76
77        let event_handler = EventHandler {
78            publisher: self.publisher.clone(),
79            messenger: self.messenger.clone(),
80            recipient_settings: self.recipient_settings.clone(),
81        };
82        fasync::Task::local(async move {
83            while let Some(event) = input_rx.next().await {
84                let id = ftrace::Id::new();
85                event_handler.handle_event(event, id);
86            }
87        })
88        .detach();
89
90        Ok(())
91    }
92}
93
94struct EventHandler {
95    publisher: Publisher,
96    messenger: service::message::Messenger,
97    recipient_settings: HashSet<SettingType>,
98}
99
100impl EventHandler {
101    fn handle_event(&self, event: MediaButtonsEvent, id: ftrace::Id) {
102        if event.mic_mute.is_some() || event.camera_disable.is_some() {
103            let media_buttons: MediaButtons = event.into();
104            self.send_event(media_buttons, id);
105        }
106    }
107
108    fn send_event<E>(&self, event: E, id: ftrace::Id)
109    where
110        E: Copy + Into<media_buttons::Event> + Into<Request> + std::fmt::Debug,
111    {
112        self.publisher.send_event(Event::MediaButtons(event.into()));
113        let setting_request: Request = event.into();
114
115        // Send the event to all the interested setting types that are also available.
116        for setting_type in self.recipient_settings.iter() {
117            let guard = trace_guard!(
118                id,
119
120                c"media buttons send event",
121                "setting_type" => format!("{setting_type:?}").as_str()
122            );
123            let mut receptor = self.messenger.message(
124                HandlerPayload::Request(setting_request.clone()).into(),
125                Audience::Address(service::Address::Handler(*setting_type)),
126            );
127            fasync::Task::local(async move {
128                let _ = receptor.next_payload().await;
129                drop(guard);
130            })
131            .detach();
132        }
133    }
134}
135
136#[cfg(test)]
137mod tests {
138    use super::*;
139    use crate::event;
140    use crate::input::common::MediaButtonsEventBuilder;
141    use crate::message::base::MessageEvent;
142    use crate::message::receptor::Receptor;
143    use crate::tests::fakes::service_registry::ServiceRegistry;
144    use crate::tests::helpers::{
145        create_messenger_and_publisher, create_messenger_and_publisher_from_hub,
146        create_receptor_for_setting_type,
147    };
148
149    // Tests that the initialization lifespan is not handled.
150    #[fuchsia::test(allow_stalls = false)]
151    async fn initialization_lifespan_is_unhandled() {
152        // Setup messengers needed to construct the agent.
153        let (messenger, publisher) = create_messenger_and_publisher().await;
154
155        // Construct the agent.
156        let mut agent =
157            MediaButtonsAgent { publisher, messenger, recipient_settings: HashSet::new() };
158
159        // Try to initiatate the initialization lifespan.
160        let result = agent
161            .handle(Invocation {
162                lifespan: Lifespan::Initialization,
163                service_context: Rc::new(ServiceContext::new(None, None)),
164            })
165            .await;
166
167        assert!(matches!(result, Err(AgentError::UnhandledLifespan)));
168    }
169
170    // Tests that the agent cannot start without a media buttons service.
171    #[fuchsia::test(allow_stalls = false)]
172    async fn when_media_buttons_inaccessible_returns_err() {
173        // Setup messengers needed to construct the agent.
174        let (messenger, publisher) = create_messenger_and_publisher().await;
175
176        // Construct the agent.
177        let mut agent =
178            MediaButtonsAgent { publisher, messenger, recipient_settings: HashSet::new() };
179
180        let service_context = Rc::new(ServiceContext::new(
181            // Create a service registry without a media buttons interface.
182            Some(ServiceRegistry::serve(ServiceRegistry::create())),
183            None,
184        ));
185
186        // Try to initiate the Service lifespan without providing the MediaButtons fidl interface.
187        let result =
188            agent.handle(Invocation { lifespan: Lifespan::Service, service_context }).await;
189        assert!(matches!(result, Err(AgentError::UnexpectedError)));
190    }
191
192    // Tests that events can be sent to the intended recipients.
193    #[fuchsia::test(allow_stalls = false)]
194    async fn event_handler_proxies_event() {
195        let service_message_hub = service::MessageHub::create_hub();
196
197        let (messenger, publisher) =
198            create_messenger_and_publisher_from_hub(&service_message_hub).await;
199        let target_setting_type = SettingType::Unknown;
200
201        // Get the messenger's signature and the receptor for agents. We need
202        // a different messenger below because a broadcast would not send a message
203        // to itself. The signature is used to delete the original messenger for this
204        // receptor.
205        let event_receptor = service::build_event_listener(&service_message_hub).await;
206
207        // Create receptor representing handler endpoint.
208        let handler_receptor: Receptor =
209            create_receptor_for_setting_type(&service_message_hub, target_setting_type).await;
210
211        // Make all setting types available.
212        let event_handler = EventHandler {
213            publisher,
214            messenger,
215            recipient_settings: vec![target_setting_type].into_iter().collect(),
216        };
217
218        // Send the events.
219        event_handler.handle_event(
220            MediaButtonsEventBuilder::new().set_mic_mute(true).set_camera_disable(true).build(),
221            0.into(),
222        );
223
224        // Delete the messengers for the receptors we're selecting below. This
225        // will allow the `select!` to eventually hit the `complete` case.
226        service_message_hub.delete(handler_receptor.get_signature());
227        service_message_hub.delete(event_receptor.get_signature());
228
229        let mut agent_received_media_buttons = false;
230
231        let mut received_events: usize = 0;
232
233        let fused_event = event_receptor.fuse();
234        let fused_handler = handler_receptor.fuse();
235        futures::pin_mut!(fused_event, fused_handler);
236
237        // Loop over the select so we can handle the messages as they come in. When all messages
238        // have been handled, due to the messengers being deleted above, the complete branch should
239        // be hit to break out of the loop.
240        loop {
241            futures::select! {
242                message = fused_event.select_next_some() => {
243                    if let MessageEvent::Message(
244                        service::Payload::Event(event::Payload::Event(
245                            event::Event::MediaButtons(event))), _) = message
246                    {
247                        match event {
248                            event::media_buttons::Event::OnButton(
249                                MediaButtons{..}
250                            ) => {
251                                agent_received_media_buttons = true;
252                            }
253                        }
254                    }
255                },
256                message = fused_handler.select_next_some() => {
257                    if let MessageEvent::Message(
258                        service::Payload::Setting(HandlerPayload::Request(
259                            Request::OnButton(_button),
260                        )),
261                        _,
262                    ) = message
263                    {
264                        received_events += 1;
265                    }
266                }
267                complete => break,
268            }
269        }
270
271        assert!(agent_received_media_buttons);
272
273        // setting should have received one event for both mic and camera.
274        assert_eq!(received_events, 1);
275    }
276
277    // Tests that events are not sent to unavailable settings.
278    #[fuchsia::test(allow_stalls = false)]
279    async fn event_handler_sends_no_events_if_no_settings_available() {
280        let service_message_hub = service::MessageHub::create_hub();
281        let (messenger, publisher) =
282            create_messenger_and_publisher_from_hub(&service_message_hub).await;
283
284        // Create messenger to represent unavailable setting handler.
285        let mut handler_receptor: Receptor =
286            create_receptor_for_setting_type(&service_message_hub, SettingType::Unknown).await;
287
288        // Declare all settings as unavailable so that no events are sent.
289        let event_handler =
290            EventHandler { publisher, messenger, recipient_settings: HashSet::new() };
291
292        // Send the events
293        event_handler.handle_event(
294            MediaButtonsEventBuilder::new().set_mic_mute(true).set_camera_disable(true).build(),
295            0.into(),
296        );
297
298        let mut received_events: usize = 0;
299
300        // Delete the messengers for the receptors we're selecting below. This will allow the while
301        // loop below to eventually finish.
302        service_message_hub.delete(handler_receptor.get_signature());
303
304        while let Ok((HandlerPayload::Request(_), _)) =
305            handler_receptor.next_of::<HandlerPayload>().await
306        {
307            received_events += 1;
308        }
309
310        // No events were received via the setting handler.
311        assert_eq!(received_events, 0);
312    }
313}