test_call_manager/
lib.rs

1// Copyright 2021 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 anyhow::{bail, format_err, Error};
6use async_utils::hanging_get::client::HangingGetStream;
7use derivative::Derivative;
8use fidl_fuchsia_bluetooth::PeerId;
9use fidl_fuchsia_bluetooth_hfp::{
10    CallAction, CallDirection, CallManagerMarker, CallManagerRequest, CallManagerRequestStream,
11    CallMarker, CallRequest, CallRequestStream, CallState as FidlCallState,
12    CallWatchStateResponder, DtmfCode, HeadsetGainProxy, HfpMarker, HfpProxy, NetworkInformation,
13    NextCall, PeerHandlerRequest, PeerHandlerRequestStream,
14    PeerHandlerWatchNetworkInformationResponder, PeerHandlerWatchNextCallResponder, SignalStrength,
15};
16use fidl_fuchsia_bluetooth_hfp_test::{ConnectionBehavior, HfpTestMarker, HfpTestProxy};
17use fuchsia_async as fasync;
18use fuchsia_component::client;
19use futures::lock::Mutex;
20use futures::stream::StreamExt;
21use futures::{FutureExt, TryStreamExt};
22use log::*;
23use serde::Serialize;
24use std::collections::{HashMap, VecDeque};
25use std::sync::Arc;
26
27type CallId = u64;
28type Number = String;
29type Memory = String;
30
31/// Handles call actions initiated by the Hands Free.
32#[derive(Debug, Default, Clone)]
33struct Dialer {
34    /// The last dialed Number if one exists.
35    last_dialed: Option<Number>,
36    /// A map of Memory locations to Numbers.
37    address_book: HashMap<Memory, Number>,
38    /// The result that should be returned from a request to dial a Number.
39    dial_result: HashMap<Number, zx::Status>,
40}
41
42impl Dialer {
43    /// Performs an outgoing call initiation action, simulating a request to the network.
44    /// If the request was a success, the number of the outgoing call is returned.
45    /// If the request failed, the failure status is returned.
46    /// Defaults to failure with `zx::Status::NOT_FOUND` if the number associated with the call
47    /// action has not been explicitly set to return a result.
48    ///
49    /// Panics if `action` is a `CallAction::TransferActive`.
50    pub fn dial(&mut self, action: CallAction) -> Result<Number, zx::Status> {
51        let number = match &action {
52            CallAction::TransferActive(_) => panic!("TransferActive action passed to dial"),
53            CallAction::DialFromNumber(number) => Ok(number),
54            CallAction::DialFromLocation(location) => {
55                self.address_book.get(location).ok_or(zx::Status::NOT_FOUND)
56            }
57            CallAction::RedialLast(_) => self.last_dialed.as_ref().ok_or(zx::Status::NOT_FOUND),
58        }?
59        .to_owned();
60
61        let result = self.dial_result.get(&number).cloned().unwrap_or(zx::Status::NOT_FOUND);
62        info!("Dial action result: {:?} - {:?}", action, result);
63        if result == zx::Status::OK {
64            self.last_dialed = Some(number.clone());
65            Ok(number)
66        } else {
67            Err(result)
68        }
69    }
70}
71
72#[derive(Derivative)]
73#[derivative(Debug)]
74/// State associated with the call manager (client) end of the HFP fidl service.
75struct ManagerState {
76    #[derivative(Debug = "ignore")]
77    peer_watcher: Option<fasync::Task<()>>,
78    network: NetworkInformation,
79    operator: String,
80    subscriber_numbers: Vec<String>,
81    nrec_support: bool,
82    battery_level: Option<u8>,
83    dialer: Dialer,
84}
85
86impl Default for ManagerState {
87    fn default() -> Self {
88        Self {
89            peer_watcher: None,
90            network: NetworkInformation::default(),
91            operator: String::new(),
92            subscriber_numbers: vec![],
93            nrec_support: true,
94            battery_level: None,
95            dialer: Dialer::default(),
96        }
97    }
98}
99
100/// State associated with a single Peer HF device.
101#[derive(Derivative)]
102#[derivative(Debug, Default)]
103struct PeerState {
104    reported_network: Option<NetworkInformation>,
105    network_responder: Option<PeerHandlerWatchNetworkInformationResponder>,
106    // nrec is enabled by default when a peer connects
107    #[derivative(Default(value = "true"))]
108    nrec_enabled: bool,
109    battery_level: u8,
110    speaker_gain: u8,
111    requested_speaker_gain: Option<u8>,
112    microphone_gain: u8,
113    requested_microphone_gain: Option<u8>,
114    #[derivative(Debug = "ignore")]
115    gain_control_watcher: Option<fasync::Task<()>>,
116    gain_control: Option<HeadsetGainProxy>,
117    call_responder: Option<PeerHandlerWatchNextCallResponder>,
118    // The tasks for managing a peer's call actions is owned by the peer.
119    // This task is separate from the manager's view of the call's state.
120    #[derivative(Debug = "ignore")]
121    call_tasks: HashMap<CallId, fasync::Task<()>>,
122}
123
124/// State associated with a single Call.
125#[derive(Derivative)]
126#[derivative(Debug)]
127struct CallState {
128    remote: String,
129    peer_id: Option<PeerId>,
130    responder: Option<CallWatchStateResponder>,
131    state: FidlCallState,
132    direction: CallDirection,
133    reported_state: Option<FidlCallState>,
134    dtmf_codes: Vec<DtmfCode>,
135}
136
137impl CallState {
138    /// Update the `state` and report the state if it is a new state and there is a
139    /// responder to report with.
140    pub fn update_state(&mut self, state: FidlCallState) -> Result<(), Error> {
141        self.state = state;
142        if self.reported_state != Some(state) && self.responder.is_some() {
143            let responder =
144                self.responder.take().expect("responder must be some after checking for presence");
145            responder.send(state)?;
146            self.reported_state = Some(state);
147        }
148        Ok(())
149    }
150}
151
152#[derive(Serialize)]
153pub struct StateSer {
154    manager: ManagerStateSer,
155    peers: HashMap<u64, PeerStateSer>,
156    calls: HashMap<CallId, CallStateSer>,
157}
158
159#[derive(Serialize)]
160pub struct ManagerStateSer {
161    network: NetworkInformationSer,
162    operator: String,
163    subscriber_numbers: Vec<String>,
164    nrec_support: bool,
165    battery_level: Option<u8>,
166    dialer: DialerSer,
167}
168
169#[derive(Serialize)]
170pub struct NetworkInformationSer {
171    service_available: Option<bool>,
172    signal_strength: Option<u8>,
173    roaming: Option<bool>,
174}
175
176impl From<NetworkInformation> for NetworkInformationSer {
177    fn from(info: NetworkInformation) -> Self {
178        let signal_strength = info.signal_strength.map(|strength| match strength {
179            SignalStrength::None => 0,
180            SignalStrength::VeryLow => 1,
181            SignalStrength::Low => 2,
182            SignalStrength::Medium => 3,
183            SignalStrength::High => 4,
184            SignalStrength::VeryHigh => 5,
185        });
186        Self { service_available: info.service_available, signal_strength, roaming: info.roaming }
187    }
188}
189
190impl From<&ManagerState> for ManagerStateSer {
191    fn from(state: &ManagerState) -> Self {
192        Self {
193            network: state.network.clone().into(),
194            operator: state.operator.clone(),
195            subscriber_numbers: state.subscriber_numbers.clone(),
196            nrec_support: state.nrec_support.clone(),
197            battery_level: state.battery_level.clone(),
198            dialer: state.dialer.clone().into(),
199        }
200    }
201}
202
203#[derive(Serialize)]
204struct PeerStateSer {
205    reported_network: Option<NetworkInformationSer>,
206    nrec_enabled: bool,
207    battery_level: u8,
208    speaker_gain: u8,
209    requested_speaker_gain: Option<u8>,
210    microphone_gain: u8,
211    requested_microphone_gain: Option<u8>,
212}
213
214impl From<&PeerState> for PeerStateSer {
215    fn from(state: &PeerState) -> Self {
216        Self {
217            reported_network: state.reported_network.clone().map(Into::into),
218            nrec_enabled: state.nrec_enabled,
219            battery_level: state.battery_level,
220            speaker_gain: state.speaker_gain,
221            requested_speaker_gain: state.requested_speaker_gain,
222            microphone_gain: state.microphone_gain,
223            requested_microphone_gain: state.requested_microphone_gain,
224        }
225    }
226}
227
228#[derive(Serialize)]
229struct CallStateSer {
230    remote: String,
231    direction: String,
232    state: String,
233    reported_state: Option<String>,
234    dtmf_codes: Vec<String>,
235}
236
237impl From<&CallState> for CallStateSer {
238    fn from(state: &CallState) -> Self {
239        Self {
240            remote: state.remote.clone(),
241            direction: format!("{:?}", state.direction),
242            state: format!("{:?}", state.state),
243            reported_state: state.reported_state.clone().map(|s| format!("{:?}", s)),
244            dtmf_codes: state.dtmf_codes.iter().map(|code| format!("{:?}", code)).collect(),
245        }
246    }
247}
248
249#[derive(Serialize)]
250struct DialerSer {
251    /// The last dialed Number if one exists.
252    last_dialed: Option<Number>,
253    /// A map of Memory locations to Numbers.
254    address_book: HashMap<Memory, Number>,
255    /// The result that should be returned from a request to dial a Number.
256    dial_result: HashMap<Number, String>,
257}
258
259impl From<Dialer> for DialerSer {
260    fn from(dialer: Dialer) -> Self {
261        Self {
262            last_dialed: dialer.last_dialed,
263            address_book: dialer.address_book,
264            dial_result: dialer
265                .dial_result
266                .into_iter()
267                .map(|(k, v)| (k, format!("{:?}", v)))
268                .collect(),
269        }
270    }
271}
272
273#[derive(Derivative, Default)]
274#[derivative(Debug)]
275struct TestCallManagerInner {
276    /// Connection to HFP Test interface
277    #[derivative(Debug = "ignore")]
278    test_proxy: Option<HfpTestProxy>,
279    /// Call manager state that is not associated with a particular peer or call.
280    manager: ManagerState,
281    /// Most commands are directed at a single peer. These commands are sent to the `active_peer`.
282    active_peer: Option<PeerId>,
283    /// State for all connected peer devices.
284    peers: HashMap<PeerId, PeerState>,
285    /// The next CallId to be assigned to a new call
286    next_call_id: CallId,
287    /// State for all ongoing calls
288    #[derivative(Debug = "ignore")]
289    calls: HashMap<CallId, CallState>,
290    /// Unreported calls
291    unreported_calls: VecDeque<CallId>,
292}
293
294impl TestCallManagerInner {
295    /// Remove a peer by `id` and all references to that peer.
296    pub fn remove_peer(&mut self, id: PeerId) {
297        let _ = self.peers.remove(&id);
298
299        for call in self.calls.values_mut() {
300            if call.peer_id == Some(id) {
301                call.peer_id = None;
302            }
303        }
304
305        if self.active_peer == Some(id) {
306            self.active_peer = None;
307        }
308    }
309
310    pub fn active_peer_mut(&mut self) -> Option<&mut PeerState> {
311        if let Some(id) = &self.active_peer {
312            Some(self.peers.get_mut(id).expect("Active peer must exist in peers map"))
313        } else {
314            None
315        }
316    }
317}
318
319#[derive(Debug, Clone)]
320pub struct TestCallManager {
321    inner: Arc<Mutex<TestCallManagerInner>>,
322}
323
324/// Perform Bluetooth HFP functions by acting as the call manager (client) side of the
325/// fuchsia.bluetooth.hfp.Hfp protocol.
326impl TestCallManager {
327    pub fn new() -> TestCallManager {
328        TestCallManager { inner: Arc::new(Mutex::new(TestCallManagerInner::default())) }
329    }
330
331    pub async fn set_request_stream(&self, stream: CallManagerRequestStream) {
332        let task =
333            fasync::Task::spawn(self.clone().watch_for_peers(stream).map(|f| f.unwrap_or({})));
334        self.inner.lock().await.manager.peer_watcher = Some(task);
335    }
336
337    pub async fn register_manager(&self, proxy: HfpProxy) -> Result<(), Error> {
338        let (client_end, stream) = fidl::endpoints::create_request_stream::<CallManagerMarker>();
339        proxy.register(client_end)?;
340        self.set_request_stream(stream).await;
341        Ok(())
342    }
343
344    /// Initialize the HFP service.
345    pub async fn init_hfp_service(&self) -> Result<(), Error> {
346        let mut inner = self.inner.lock().await;
347
348        if inner.manager.peer_watcher.is_none() {
349            info!("Connecting to HFP and setting new service proxy");
350
351            let hfp_service_proxy = client::connect_to_protocol::<HfpMarker>()
352                .map_err(|err| format_err!("Failed to create HFP service proxy: {}", err))?;
353
354            inner.test_proxy =
355                Some(client::connect_to_protocol::<HfpTestMarker>().map_err(|err| {
356                    format_err!("Failed to create HFP Test service proxy: {}", err)
357                })?);
358
359            let (client_end, stream) =
360                fidl::endpoints::create_request_stream::<CallManagerMarker>();
361            hfp_service_proxy.register(client_end)?;
362
363            let task =
364                fasync::Task::spawn(self.clone().watch_for_peers(stream).map(|f| f.unwrap_or({})));
365
366            inner.manager.peer_watcher = Some(task);
367        }
368        Ok(())
369    }
370
371    /// Return a list of Calls by call id and remote number.
372    pub async fn list_calls(&self) -> Result<Vec<(u64, String)>, Error> {
373        let inner = self.inner.lock().await;
374        Ok(inner.calls.iter().map(|(&id, state)| (id, state.remote.clone())).collect())
375    }
376
377    /// Notify HFP of an ongoing call. Simulates a new call from the network in the
378    /// "incoming ringing" state.
379    ///
380    /// Arguments:
381    ///     `remote`: The number associated with the remote party. This can be any string formatted
382    ///     number (e.g. +1-555-555-5555).
383    ///     `fidl_state`: The state to assign to the newly created call.
384    pub async fn new_call(
385        &self,
386        remote: &str,
387        fidl_state: FidlCallState,
388        direction: CallDirection,
389    ) -> Result<CallId, Error> {
390        let remote = remote.to_string();
391        let mut inner = self.inner.lock().await;
392        let call_id = inner.next_call_id;
393        inner.next_call_id += 1;
394        let mut state = CallState {
395            remote: remote.clone(),
396            peer_id: None,
397            responder: None,
398            state: fidl_state,
399            direction,
400            reported_state: None,
401            dtmf_codes: vec![],
402        };
403
404        if let Some(peer_id) = inner.active_peer.clone() {
405            let peer = inner.peers.get_mut(&peer_id).expect("Active peer must exist in peers map");
406
407            let (client_end, stream) = fidl::endpoints::create_request_stream::<CallMarker>();
408            // This does not handle the case where there is no peer responder
409            let responder = peer
410                .call_responder
411                .take()
412                .ok_or_else(|| format_err!("No peer call responder for {:?}", peer_id))?;
413            let next_call = NextCall {
414                call: Some(client_end),
415                remote: Some(remote),
416                state: Some(fidl_state),
417                direction: Some(direction),
418                ..Default::default()
419            };
420            if let Ok(()) = responder.send(next_call) {
421                let task = fasync::Task::local(self.clone().manage_call(peer_id, call_id, stream));
422                let _ = peer.call_tasks.insert(call_id, task);
423                state.peer_id = Some(peer_id);
424            }
425        } else {
426            inner.unreported_calls.push_back(call_id);
427        }
428
429        let _ = inner.calls.insert(call_id, state);
430        Ok(call_id)
431    }
432
433    /// Notify HFP of an incoming call. Simulates a new call from the network in the
434    /// "incoming ringing" state.
435    ///
436    /// Arguments:
437    ///     `remote`: The number associated with the remote party. This can be any string formatted
438    ///     number (e.g. +1-555-555-5555).
439    pub async fn incoming_ringing_call(&self, remote: &str) -> Result<CallId, Error> {
440        self.new_call(remote, FidlCallState::IncomingRinging, CallDirection::MobileTerminated).await
441    }
442
443    /// Notify HFP of an incoming waiting call. Simulates a new call from the network in the
444    /// "incoming waiting" state.
445    ///
446    /// Arguments:
447    ///     `remote`: The number associated with the remote party. This can be any string formatted
448    ///     number (e.g. +1-555-555-5555).
449    pub async fn incoming_waiting_call(&self, remote: &str) -> Result<CallId, Error> {
450        self.new_call(remote, FidlCallState::IncomingWaiting, CallDirection::MobileTerminated).await
451    }
452
453    /// Notify HFP of an outgoing call. Simulates a new call to the network in the
454    /// "outgoing notifying" state.
455    ///
456    /// Arguments:
457    ///     `remote`: The number associated with the remote party. This can be any string formatted
458    ///     number (e.g. +1-555-555-5555).
459    pub async fn outgoing_call(&self, remote: &str) -> Result<CallId, Error> {
460        self.new_call(remote, FidlCallState::OutgoingDialing, CallDirection::MobileOriginated).await
461    }
462
463    /// Notify HFP of an update to the state of an ongoing call.
464    ///
465    /// Arguments:
466    ///     `call_id`: The unique id of the call as assigned by the call manager.
467    ///     `fidl_state`: The state to assign to the call.
468    async fn update_call(&self, call_id: CallId, fidl_state: FidlCallState) -> Result<(), Error> {
469        // TODO: do not allow invalid state transitions (e.g. Terminated to Active)
470        self.inner
471            .lock()
472            .await
473            .calls
474            .get_mut(&call_id)
475            .ok_or_else(|| format_err!("Unknown Call Id {}", call_id))
476            .and_then(|call| call.update_state(fidl_state))
477    }
478
479    /// Notify HFP that a call is now active.
480    ///
481    /// Arguments:
482    ///     `call_id`: The unique id of the call as assigned by the call manager.
483    pub async fn set_call_active(&self, call_id: CallId) -> Result<(), Error> {
484        match self.update_call(call_id, FidlCallState::OngoingActive).await {
485            Ok(()) => Ok(()),
486            Err(e) => Err(format_err!("Failed to set call active: {}", e)),
487        }
488    }
489
490    /// Notify HFP that a call is now held.
491    ///
492    /// Arguments:
493    ///     `call_id`: The unique id of the call as assigned by the call manager.
494    pub async fn set_call_held(&self, call_id: CallId) -> Result<(), Error> {
495        match self.update_call(call_id, FidlCallState::OngoingHeld).await {
496            Ok(()) => Ok(()),
497            Err(e) => Err(format_err!("Failed to set call active: {}", e)),
498        }
499    }
500
501    /// Notify HFP that a call is now terminated.
502    ///
503    /// Arguments:
504    ///     `call_id`: The unique id of the call as assigned by the call manager.
505    pub async fn set_call_terminated(&self, call_id: CallId) -> Result<(), Error> {
506        match self.update_call(call_id, FidlCallState::Terminated).await {
507            Ok(()) => Ok(()),
508            Err(e) => Err(format_err!("Failed to terminate call: {}", e)),
509        }
510    }
511
512    /// Notify HFP that a call's audio is now transferred to the Audio Gateway.
513    ///
514    /// Arguments:
515    ///     `call_id`: The unique id of the call as assigned by the call manager.
516    pub async fn set_call_transferred_to_ag(&self, call_id: CallId) -> Result<(), Error> {
517        match self.update_call(call_id, FidlCallState::TransferredToAg).await {
518            Ok(()) => Ok(()),
519            Err(e) => Err(format_err!("Failed to transfer call to ag: {}", e)),
520        }
521    }
522
523    /// Return a list of HFP peers along with a boolean specifying whether each peer is the
524    /// "active" peer.
525    pub async fn list_peers(&self) -> Result<Vec<(u64, bool)>, Error> {
526        let inner = self.inner.lock().await;
527        Ok(inner
528            .peers
529            .keys()
530            .map(|&id| (id.value, inner.active_peer.map(|active| active == id).unwrap_or(false)))
531            .collect())
532    }
533
534    /// Set the active peer with the provided id. All future commands will be directed towards that
535    /// peer.
536    ///
537    /// Arguments:
538    ///     `id`: The unique id for the peer that initiated the request.
539    pub async fn set_active_peer(&self, id: u64) -> Result<(), Error> {
540        let id = PeerId { value: id };
541        let mut inner = self.inner.lock().await;
542        if inner.peers.contains_key(&id) {
543            inner.active_peer = Some(id);
544            Ok(())
545        } else {
546            Err(format_err!("Peer {:?} not connected", id))
547        }
548    }
549
550    // Report all calls to the given peer. Panics if `id` does not point to a valid peer in the
551    // peers map.
552    fn report_calls(
553        self,
554        id: PeerId,
555        mut inner: futures::lock::MutexGuard<'_, TestCallManagerInner>,
556    ) -> Result<(), Error> {
557        // keep popping from unreported until we get one
558        // that is also found in the calls map.
559        while let Some(cid) = inner.unreported_calls.pop_front() {
560            if let Some(call) = inner.calls.get(&cid) {
561                let remote = call.remote.clone();
562                let state = call.state;
563                let direction = call.direction;
564                let (client_end, stream) = fidl::endpoints::create_request_stream::<CallMarker>();
565                let peer = inner.peers.get_mut(&id).expect("peer just added");
566                let next_call = NextCall {
567                    call: Some(client_end),
568                    remote: Some(remote),
569                    state: Some(state),
570                    direction: Some(direction),
571                    ..Default::default()
572                };
573                let res = peer.call_responder.take().expect("just put here").send(next_call);
574                if let Ok(()) = res {
575                    let task = fasync::Task::local(self.manage_call(id, cid, stream));
576                    let _ = peer.call_tasks.insert(cid, task);
577                    inner.calls.get_mut(&cid).expect("still here").peer_id = Some(id);
578                }
579                break;
580            }
581        }
582        Ok(())
583    }
584
585    /// Handle a peer `request`. Most requests are handled by immediately responding with the
586    /// relevant data which is stored in the facade's state.
587    ///
588    /// Arguments:
589    ///     `id`: The unique id for the peer that initiated the request.
590    ///     `request`: A request made by a client of the fuchsia.bluetooth.hfp.PeerHandler protocol.
591    async fn handle_peer_request(
592        &mut self,
593        id: PeerId,
594        request: PeerHandlerRequest,
595    ) -> Result<(), Error> {
596        info!("Received Peer Handler request for {:?}: {:?}", id, request);
597        match request {
598            PeerHandlerRequest::WatchNetworkInformation { responder, .. } => {
599                let mut inner = self.inner.lock().await;
600                let current_network = inner.manager.network.clone();
601                let peer = inner
602                    .peers
603                    .get_mut(&id)
604                    .ok_or_else(|| format_err!("peer removed: {:?}", id))?;
605
606                if Some(&current_network) == peer.reported_network.as_ref() {
607                    peer.network_responder = Some(responder);
608                } else {
609                    responder.send(&current_network)?;
610                    peer.reported_network = Some(current_network);
611                }
612            }
613            PeerHandlerRequest::WatchNextCall { responder, .. } => {
614                let this = self.clone();
615                let mut inner = self.inner.lock().await;
616                let peer = inner
617                    .peers
618                    .get_mut(&id)
619                    .ok_or_else(|| format_err!("peer removed: {:?}", id))?;
620                if peer.call_responder.is_none() {
621                    peer.call_responder = Some(responder);
622                    this.report_calls(id, inner)?;
623                } else {
624                    let err = format_err!("double hanging get call on PeerHandler::WatchNextCall");
625                    error!(err:%; "");
626                    *inner = TestCallManagerInner::default();
627                    return Err(err);
628                }
629            }
630            PeerHandlerRequest::RequestOutgoingCall { action, responder } => {
631                if let CallAction::TransferActive(_) = action {
632                    let inner = self.inner.lock().await;
633                    match inner
634                        .calls
635                        .iter()
636                        .find(|(_, call)| call.state == FidlCallState::OngoingActive)
637                    {
638                        Some((&id, _)) => {
639                            drop(inner);
640                            // result can be ignored because id was just found in the call map.
641                            let _ = self.update_call(id, FidlCallState::TransferredToAg).await;
642                        }
643                        None => drop(responder.send(Err(zx::Status::NOT_FOUND.into_raw()))),
644                    };
645                } else {
646                    // Simulate dialing action and then respond to any outstanding WatchForCall
647                    // requests.
648                    let result = match {
649                        // Only hold onto the lock while using it to "dial" the number.
650                        // Holding the lock past this point would cause a deadlock when
651                        // calling `outgoing_call`.
652                        let mut inner = self.inner.lock().await;
653                        inner.manager.dialer.dial(action)
654                    } {
655                        Ok(number) => match self.outgoing_call(&number).await {
656                            Ok(id) => {
657                                info!(CallId = id; "Initiated outgoing call to {}", number);
658                                Ok(())
659                            }
660                            Err(e) => {
661                                error!("Could not initiate outgoing call action: {}", e);
662                                Err(zx::Status::INTERNAL.into_raw())
663                            }
664                        },
665                        Err(status) => Err(status.into_raw()),
666                    };
667                    info!("sending result to peer: {:?}", result);
668
669                    // Once dialing and hanging gets have been handled, send response.
670                    let _ = responder.send(result);
671                }
672            }
673            PeerHandlerRequest::QueryOperator { responder, .. } => {
674                responder.send(Some(&self.inner.lock().await.manager.operator))?;
675            }
676            PeerHandlerRequest::SubscriberNumberInformation { responder, .. } => {
677                responder.send(&self.inner.lock().await.manager.subscriber_numbers)?;
678            }
679            PeerHandlerRequest::SetNrecMode { enabled, responder, .. } => {
680                let mut inner = self.inner.lock().await;
681                if inner.manager.nrec_support {
682                    let peer = inner
683                        .peers
684                        .get_mut(&id)
685                        .ok_or_else(|| format_err!("peer removed: {:?}", id))?;
686                    peer.nrec_enabled = enabled;
687                    responder.send(Ok(()))?;
688                } else {
689                    responder.send(Err(zx::Status::NOT_SUPPORTED.into_raw()))?;
690                }
691            }
692            PeerHandlerRequest::ReportHeadsetBatteryLevel { level, .. } => {
693                self.inner
694                    .lock()
695                    .await
696                    .peers
697                    .get_mut(&id)
698                    .ok_or_else(|| format_err!("peer removed: {:?}", id))?
699                    .battery_level = level;
700            }
701            PeerHandlerRequest::GainControl { control, .. } => {
702                let this = self.clone();
703                let proxy = control.into_proxy();
704                let proxy_ = proxy.clone();
705                let task = fasync::Task::spawn(async move {
706                    let mut speaker_gain_stream =
707                        HangingGetStream::new(proxy.clone(), HeadsetGainProxy::watch_speaker_gain);
708                    let mut microphone_gain_stream = HangingGetStream::new(
709                        proxy.clone(),
710                        HeadsetGainProxy::watch_microphone_gain,
711                    );
712
713                    loop {
714                        futures::select! {
715                            gain = speaker_gain_stream.next() => {
716                                let mut inner = this.inner.lock().await;
717                                let peer = inner.peers.get_mut(&id);
718                                match (peer, gain) {
719                                    (Some(peer), Some(Ok(gain))) => peer.speaker_gain = gain,
720                                    _ => break,
721                                }
722                            }
723                            gain = microphone_gain_stream.next() => {
724                                let mut inner = this.inner.lock().await;
725                                let peer = inner.peers.get_mut(&id);
726                                match (peer, gain) {
727                                    (Some(peer), Some(Ok(gain))) => peer.microphone_gain = gain,
728                                    _ => break,
729                                }
730                            }
731                        }
732                    }
733                    info!("Headset gain control channel for peer {:?} closed", id);
734                });
735                let mut inner = self.inner.lock().await;
736                let peer = inner
737                    .peers
738                    .get_mut(&id)
739                    .ok_or_else(|| format_err!("peer removed: {:?}", id))?;
740                if let Some(requested) = peer.requested_speaker_gain.take() {
741                    proxy_.set_speaker_gain(requested)?;
742                }
743                if let Some(requested) = peer.requested_microphone_gain.take() {
744                    proxy_.set_microphone_gain(requested)?;
745                }
746                peer.gain_control_watcher = Some(task);
747                peer.gain_control = Some(proxy_);
748            }
749        }
750        Ok(())
751    }
752
753    /// Handle all PeerHandlerRequests for a peer, removing the peer after the request stream
754    /// is closed.
755    ///
756    /// Arguments:
757    ///     `id`: The unique id for the peer that initiated the stream.
758    ///     `stream`: A stream of requests associated with a single peer.
759    async fn manage_peer(mut self, id: PeerId, mut stream: PeerHandlerRequestStream) {
760        while let Some(Ok(request)) = stream.next().await {
761            if let Err(err) = self.handle_peer_request(id, request).await {
762                error!(err:%; "");
763                break;
764            };
765        }
766        self.inner.lock().await.remove_peer(id);
767    }
768
769    /// Watch for new Hands Free peer devices that connect to the DUT.
770    ///
771    /// Spawns a new task to manage each peer that connects.
772    ///
773    /// Arguments:
774    ///     `proxy`: The client end of the CallManager protocol which is used to watch for new
775    ///     Bluetooth peers.
776    async fn watch_for_peers(
777        self,
778        mut stream: CallManagerRequestStream,
779    ) -> Result<(), fidl::Error> {
780        // Entries are only removed from the map when they are replaced, so the size of `peers`
781        // will grow as the total number of unique peers grows. This is acceptable as the number of
782        // unique peers that connect to a DUT is expected to be relatively small.
783        let mut peers = HashMap::new();
784        while let Some(CallManagerRequest::PeerConnected { id, handle, responder }) =
785            stream.try_next().await?
786        {
787            let stream = handle.into_stream();
788            info!("Handling Peer: {:?}", id);
789            {
790                let mut inner = self.inner.lock().await;
791                let _ = inner.peers.insert(id, PeerState::default());
792                inner.active_peer = Some(id);
793            }
794
795            let task = fasync::Task::spawn(self.clone().manage_peer(id, stream));
796            let _ = peers.insert(id, task);
797            let _ = responder.send();
798        }
799        Ok(())
800    }
801
802    /// Manage an ongoing call that is being routed to the Hands Free peer. Handle any requests
803    /// made by the peer that are associated with the individual call.
804    ///
805    /// Arguments:
806    ///     `peer_id`: The unique id of the peer as assigned by the Bluetooth stack.
807    ///     `call_id`: The unique id of the call as assigned by the call manager.
808    ///     `stream`: A stream of requests associated with a single call.
809    async fn manage_call(self, peer_id: PeerId, call_id: CallId, mut stream: CallRequestStream) {
810        while let Some(request) = stream.next().await {
811            info!("Got call request: {:?} {:?} -> {:?}", peer_id, call_id, request);
812            let mut inner = self.inner.lock().await;
813            let state = if let Some(state) = inner.calls.get_mut(&call_id) {
814                state
815            } else {
816                info!("Call management by {:?} ended: {:?}", peer_id, call_id);
817                break;
818            };
819            match request {
820                Ok(CallRequest::WatchState { responder, .. }) => {
821                    if state.responder.is_some() {
822                        warn!("Call client sent multiple WatchState requests. Closing channel");
823                        break;
824                    }
825                    state.responder = Some(responder);
826                    // Trigger an update with the existing state to send it on the responder if
827                    // necessary.
828                    if let Err(e) = state.update_state(state.state) {
829                        info!("Call ended: {}", e);
830                        break;
831                    }
832                }
833                Ok(CallRequest::RequestHold { .. }) => {
834                    if let Err(e) = state.update_state(FidlCallState::OngoingHeld) {
835                        info!("Call ended: {}", e);
836                        break;
837                    }
838                }
839                Ok(CallRequest::RequestActive { .. }) => {
840                    if let Err(e) = state.update_state(FidlCallState::OngoingActive) {
841                        info!("Call ended: {}", e);
842                        break;
843                    }
844                }
845                Ok(CallRequest::RequestTerminate { .. }) => {
846                    if let Err(e) = state.update_state(FidlCallState::Terminated) {
847                        info!("Call ended: {}", e);
848                        break;
849                    }
850                }
851                Ok(CallRequest::RequestTransferAudio { .. }) => {
852                    if let Err(e) = state.update_state(FidlCallState::TransferredToAg) {
853                        info!("Call ended: {}", e);
854                        break;
855                    }
856                }
857                Ok(CallRequest::SendDtmfCode { code, responder, .. }) => {
858                    state.dtmf_codes.push(code);
859                    if let Err(e) = responder.send(Ok(())) {
860                        info!("Call ended: {}", e);
861                        break;
862                    }
863                }
864                Err(e) => {
865                    warn!("Call fidl channel error: {}", e);
866                }
867            }
868        }
869
870        // Cleanup before exiting call task
871        let mut inner = self.inner.lock().await;
872        if let Some(call) = inner.calls.get_mut(&call_id) {
873            call.peer_id = None
874        }
875        if let Some(peer) = inner.peers.get_mut(&peer_id) {
876            let _ = peer.call_tasks.remove(&call_id);
877        }
878    }
879
880    /// Request that the active peer's speaker gain be set to `value`.
881    ///
882    /// Arguments:
883    ///     `value`: must be between 0-15 inclusive.
884    pub async fn set_speaker_gain(&self, value: u64) -> Result<(), Error> {
885        let value = value as u8;
886        let mut inner = self.inner.lock().await;
887        let peer = inner.active_peer_mut().ok_or_else(|| format_err!("No active peer"))?;
888        if peer.speaker_gain != value {
889            if let Some(gain_control) = &peer.gain_control {
890                gain_control.set_speaker_gain(value)?;
891            } else {
892                peer.requested_speaker_gain = Some(value);
893            }
894        }
895        Ok(())
896    }
897
898    /// Request that the active peer's microphone gain be set to `value`.
899    ///
900    /// Arguments:
901    ///     `value`: must be between 0-15 inclusive.
902    pub async fn set_microphone_gain(&self, value: u64) -> Result<(), Error> {
903        let value = value as u8;
904        let mut inner = self.inner.lock().await;
905        let peer = inner.active_peer_mut().ok_or_else(|| format_err!("No active peer"))?;
906        if peer.microphone_gain != value {
907            if let Some(gain_control) = &peer.gain_control {
908                gain_control.set_microphone_gain(value)?;
909            } else {
910                peer.requested_microphone_gain = Some(value);
911            }
912        }
913        Ok(())
914    }
915
916    /// Update the facade's network information with the provided `network`.
917    /// Any fields in `network` that are `None` will not be updated.
918    ///
919    /// Arguments:
920    ///     `network`: The updated network information fields.
921    pub async fn update_network_information(
922        &self,
923        network: NetworkInformation,
924    ) -> Result<(), Error> {
925        let mut inner = self.inner.lock().await;
926
927        // Update network state
928        let last_net = std::mem::replace(&mut inner.manager.network, NetworkInformation::default());
929        inner.manager.network = NetworkInformation {
930            service_available: network.service_available.or(last_net.service_available),
931            signal_strength: network.signal_strength.or(last_net.signal_strength),
932            roaming: network.roaming.or(last_net.roaming),
933            ..last_net
934        };
935        let current_network = inner.manager.network.clone();
936
937        for peer in inner.peers.values_mut() {
938            // Update the client if a responder is present
939            if Some(&current_network) != peer.reported_network.as_ref() {
940                if let Some(responder) = peer.network_responder.take() {
941                    responder.send(&current_network)?;
942                    peer.reported_network = Some(current_network.clone());
943                }
944            }
945        }
946
947        Ok(())
948    }
949
950    pub async fn set_subscriber_number(&self, number: &str) {
951        self.inner.lock().await.manager.subscriber_numbers = vec![number.to_owned()];
952    }
953
954    pub async fn set_operator(&self, value: &str) {
955        self.inner.lock().await.manager.operator = value.to_owned();
956    }
957
958    pub async fn set_nrec_support(&self, value: bool) {
959        self.inner.lock().await.manager.nrec_support = value;
960    }
961
962    pub async fn set_battery_level(&self, value: u64) -> Result<(), Error> {
963        if value > 5 {
964            bail!("Value out of range: {}. Battery level must be 0-5.", value);
965        }
966        let mut inner = self.inner.lock().await;
967        let proxy = inner
968            .test_proxy
969            .as_ref()
970            .ok_or_else(|| format_err!("Cannot set battery without HfpTest proxy"))?;
971        proxy.battery_indicator(value as u8)?;
972        inner.manager.battery_level = Some(value as u8);
973        Ok(())
974    }
975
976    pub async fn get_state(&self) -> StateSer {
977        let inner = self.inner.lock().await;
978        StateSer {
979            manager: (&inner.manager).into(),
980            peers: inner
981                .peers
982                .iter()
983                .map(|(&PeerId { value: id }, peer)| (id, peer.into()))
984                .collect(),
985            calls: inner.calls.iter().map(|(&id, call)| (id, call.into())).collect(),
986        }
987    }
988
989    /// Set the simulated "last dialed" number.
990    ///
991    /// Arguments:
992    ///     `number`: Number to be set. To clear the last dialed number, set `number` to `None`.
993    pub async fn set_last_dialed(&self, number: Option<Number>) {
994        self.inner.lock().await.manager.dialer.last_dialed = number;
995    }
996
997    /// Store a number at a specific location in address book memory.
998    ///
999    /// Arguments:
1000    ///     `location`: The key used to look up a specific number in address book memory.
1001    ///     `number`: Number to be set. To remove the address book entry, set `number` to `None`.
1002    pub async fn set_memory_location(&self, location: Memory, number: Option<Number>) {
1003        let _ = match number {
1004            Some(number) => {
1005                self.inner.lock().await.manager.dialer.address_book.insert(location, number)
1006            }
1007            None => self.inner.lock().await.manager.dialer.address_book.remove(&location),
1008        };
1009    }
1010
1011    /// Set the simulated result that will be returned after HFP requests an outgoing call.
1012    /// This result is used regardless of whether a number was specified directly through
1013    /// CallAction::dial_from_number or indirectly through either CallAction::dial_from_location or
1014    /// CallAction::redial_last.
1015    ///
1016    /// Arguments:
1017    ///     `number`: Number that maps to a simulated result.
1018    ///     `status`: The simulated result value for `number`.
1019    pub async fn set_dial_result(&self, number: Number, status: zx::Status) {
1020        let _ = self.inner.lock().await.manager.dialer.dial_result.insert(number, status);
1021    }
1022
1023    /// Configure the connection behavior when the component receives new search results from
1024    /// the bredr.Profile protocol.
1025    ///
1026    /// Arguments:
1027    ///     `autoconnect`: determine whether the component should automatically attempt to
1028    ///                    make a new RFCOMM connection.
1029    pub async fn set_connection_behavior(&self, autoconnect: bool) -> Result<(), Error> {
1030        let inner = self.inner.lock().await;
1031        let proxy = inner.test_proxy.as_ref().ok_or_else(|| {
1032            format_err!("Cannot set slc connection behavior on command without HfpTest proxy")
1033        })?;
1034        let () = proxy.set_connection_behavior(&ConnectionBehavior {
1035            autoconnect: Some(autoconnect),
1036            ..Default::default()
1037        })?;
1038        Ok(())
1039    }
1040
1041    /// Cleanup any HFP related objects.
1042    pub async fn cleanup(&self) {
1043        *self.inner.lock().await = TestCallManagerInner::default();
1044    }
1045}
1046
1047#[cfg(test)]
1048mod tests {
1049    use super::*;
1050    use fidl_fuchsia_bluetooth_hfp::PeerHandlerMarker;
1051
1052    #[fuchsia::test]
1053    async fn outgoing_call_does_not_deadlock() {
1054        let manager = TestCallManager::new();
1055
1056        // set up the dial result so that an outgoing call request will be a success.
1057        manager.set_dial_result("123".to_string(), zx::Status::OK).await;
1058
1059        let (proxy, stream) = fidl::endpoints::create_proxy_and_stream::<PeerHandlerMarker>();
1060
1061        // Create a background task to manage a peer channel.
1062        fasync::Task::local({
1063            let manager = manager.clone();
1064            async move {
1065                manager.manage_peer(PeerId { value: 1 }, stream).await;
1066            }
1067        })
1068        .detach();
1069
1070        // requesting an outgoing call should complete successfully
1071        let result =
1072            proxy.request_outgoing_call(&CallAction::DialFromNumber("123".to_string())).await;
1073        assert!(result.is_ok());
1074    }
1075}