input_testing/
input_device.rs

1// Copyright 2022 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::input_reports_reader::InputReportsReader;
6use anyhow::{Context as _, Error};
7use async_utils::event::Event as AsyncEvent;
8use fidl::endpoints::ServerEnd;
9use fidl::Error as FidlError;
10use fidl_fuchsia_input_report::{
11    DeviceDescriptor, FeatureReport, InputDeviceRequest, InputDeviceRequestStream, InputReport,
12    InputReportsReaderMarker,
13};
14use fuchsia_async as fasync;
15use futures::channel::mpsc;
16use futures::{future, pin_mut, StreamExt, TryFutureExt};
17
18pub type DeviceId = u32;
19
20/// Implements the server side of the
21/// `fuchsia.input.report.InputDevice` FIDL protocol. This struct also enables users to inject
22/// input reports `as fuchsia.ui.input.InputReport`.
23///
24/// # Notes
25/// * Some of the methods of `fuchsia.input.report.InputDevice` are not relevant to
26///   input injection, so this implemnentation does not support them:
27///   * `SendOutputReport` provides a way to change keyboard LED state.
28///   If these FIDL methods are invoked, `InputDevice::flush()` will resolve to Err.
29/// * This implementation does not support multiple calls to `GetInputReportsReader`,
30///   since:
31///   * The ideal semantics for multiple calls are not obvious, and
32///   * Each `InputDevice` has a single FIDL client (an input pipeline implementation),
33///     and the current input pipeline implementation is happy to use a single
34///     `InputReportsReader` for the lifetime of the `InputDevice`.
35pub(crate) struct InputDevice {
36    /// FIFO queue of reports to be consumed by calls to
37    /// `fuchsia.input.report.InputReportsReader.ReadInputReports()`.
38    /// Populated by `input_device::InputDevice`.
39    report_sender: futures::channel::mpsc::UnboundedSender<InputReport>,
40
41    /// `Task` to keep serving the `fuchsia.input.report.InputDevice` protocol.
42    _input_device_task: fasync::Task<()>,
43
44    /// The device_id of the InputDevice.
45    pub device_id: DeviceId,
46}
47
48impl InputDevice {
49    /// Creates a new `InputDevice` that will create a task to:
50    /// a) process requests from `request_stream`, and
51    /// b) respond to `GetDescriptor` calls with the descriptor generated by `descriptor_generator()`
52    pub(super) fn new(
53        request_stream: InputDeviceRequestStream,
54        descriptor: DeviceDescriptor,
55        got_input_reports_reader: AsyncEvent,
56    ) -> Self {
57        let (report_sender, report_receiver) = mpsc::unbounded::<InputReport>();
58
59        // Create a `Task` to keep serving the `fuchsia.input.report.InputDevice` protocol.
60        let input_device_task = fasync::Task::local(Self::serve_reports(
61            request_stream,
62            descriptor,
63            report_receiver,
64            got_input_reports_reader,
65        ));
66
67        Self { report_sender, _input_device_task: input_device_task, device_id: 0 }
68    }
69
70    /// Enqueues an input report, to be read by the input reports reader.
71    pub(super) fn send_input_report(&self, input_report: InputReport) -> Result<(), Error> {
72        self.report_sender
73            .unbounded_send(input_report)
74            .context("failed to send input report to reader")
75    }
76
77    /// Returns a `Future` which resolves when all input reports for this device
78    /// have been sent to the FIDL peer.
79    ///
80    /// # Note
81    /// When the future resolves, input reports may still be sitting unread in the
82    /// channel to the FIDL peer.
83    #[cfg(test)]
84    pub(super) async fn flush(self) {
85        let Self { _input_device_task: input_device_task, report_sender, .. } = self;
86        std::mem::drop(report_sender); // Drop `report_sender` to close channel.
87        input_device_task.await
88    }
89
90    /// Returns a `Future` which resolves when all `InputReport`s for this device
91    /// have been sent to a `fuchsia.input.InputReportsReader` client.
92    ///
93    /// # Notes
94    /// * This function `panic()`s on error, to ensure that the error is reported
95    ///   synchronously. Otherwise, the original error might lead to additional errors, and
96    ///   make the integration tests that use this library harder to debug.
97    /// * When the `Future` resolves, `InputReports` may still be sitting unread in the
98    ///   channel to the `fuchsia.input.InputReportsReader` client. (The client will
99    ///   typically be an input pipeline implementation.)
100    ///
101    /// # Corner cases
102    /// Resolves to `Err` if the `fuchsia.input.InputDevice` client did not call
103    /// `GetInputReportsReader()`, even if no `InputReport`s were queued.
104    async fn serve_reports(
105        request_stream: InputDeviceRequestStream,
106        descriptor: DeviceDescriptor,
107        report_receiver: mpsc::UnboundedReceiver<InputReport>,
108        got_input_reports_reader: AsyncEvent,
109    ) {
110        // Process `fuchsia.input.report.InputDevice` requests, waiting for the `InputDevice`
111        // client to provide a `ServerEnd<InputReportsReader>` by calling `GetInputReportsReader()`.
112        //
113        // `filter_map` creates a new stream `input_reports_reader_server_end_stream` for
114        // `request_stream` baesd on the result of `handle_device_request`, only
115        // `GetInputReportsReader` requests enter `input_reports_reader_server_end_stream`
116        // for following process.
117        let mut input_reports_reader_server_end_stream = request_stream.filter_map(|r| {
118            future::ready(Self::handle_device_request(
119                r,
120                &descriptor,
121                got_input_reports_reader.clone(),
122            ))
123        });
124
125        // Create a `Future` to serve `GetInputReportsReader()` and extract the inpur reader
126        // server_end from the request.
127        let input_reports_reader_fut = {
128            let reader_server_end = input_reports_reader_server_end_stream
129                .next()
130                .await
131                .unwrap_or_else(|| panic!("stream ended without a call to GetInputReportsReader"));
132            InputReportsReader { request_stream: reader_server_end.into_stream(), report_receiver }
133                .into_future()
134        };
135        pin_mut!(input_reports_reader_fut);
136
137        // Create a `Future` to keep serving the `fuchsia.input.report.InputDevice` protocol.
138        // This time, receiving a `ServerEnd<InputReportsReaderMarker>` will be an `Err`.
139        let input_device_server_fut = async {
140            match input_reports_reader_server_end_stream.next().await {
141                Some(_server_end) => {
142                    // There are no obvious "best" semantics for how to handle multiple
143                    // `GetInputReportsReader` calls, and there is no current need to
144                    // do so. Instead of taking a guess at what the client might want
145                    // in such a case, just `panic()`.
146                    panic!("InputDevice does not support multiple GetInputReportsReader calls")
147                }
148                None => Ok(()),
149            }
150        };
151        pin_mut!(input_device_server_fut);
152
153        // Now, process both `fuchsia.input.report.InputDevice` requests, and
154        // `fuchsia.input.report.InputReportsReader` requests. And keep processing
155        // `InputReportsReader` requests even if the `InputDevice` connection
156        // is severed.
157        future::select(
158            input_device_server_fut.and_then(|_: ()| future::pending()),
159            input_reports_reader_fut,
160        )
161        .await
162        .factor_first()
163        .0
164        .unwrap_or_else(|e| panic!("processing FIDL requests: {e}"))
165    }
166
167    /// Processes a single request from an `InputDeviceRequestStream`
168    ///
169    /// # Returns
170    /// * Some(ServerEnd<InputReportsReaderMarker>) if the request yielded an
171    ///   `InputReportsReader`. `InputDevice` should route its `InputReports` to the yielded
172    ///   `InputReportsReader`.
173    /// * None if the request was fully processed by `handle_device_request()`
174    ///
175    /// # Note
176    /// * This function `panic()`s on error. See `serve_reports()` for the reason why.
177    fn handle_device_request(
178        request: Result<InputDeviceRequest, FidlError>,
179        descriptor: &DeviceDescriptor,
180        got_input_reports_reader: AsyncEvent,
181    ) -> Option<ServerEnd<InputReportsReaderMarker>> {
182        match request {
183            Ok(InputDeviceRequest::GetInputReportsReader { reader: reader_server_end, .. }) => {
184                let _ = got_input_reports_reader.signal();
185                Some(reader_server_end)
186            }
187            Ok(InputDeviceRequest::GetDescriptor { responder }) => {
188                match responder.send(&descriptor) {
189                    Ok(()) => None,
190                    Err(e) => panic!("failed to send GetDescriptor response: {e}"),
191                }
192            }
193            Ok(InputDeviceRequest::GetFeatureReport { responder }) => {
194                match responder.send(Ok(&FeatureReport::default())) {
195                    Ok(()) => None,
196                    Err(e) => panic!("failed to send GetFeatureReport response: {e}"),
197                }
198            }
199            Err(e) => {
200                panic!("failed to read `InputReportsReader` request: {:?}", &e);
201            }
202            _ => {
203                panic!(
204                    "InputDevice::handle_device_request does not support this request: {:?}",
205                    &request
206                );
207            }
208        }
209    }
210}
211
212#[cfg(test)]
213mod tests {
214    use super::*;
215    use fidl::endpoints;
216    use fidl_fuchsia_input_report::{DeviceDescriptor, InputDeviceMarker};
217    use fuchsia_async as fasync;
218
219    mod responds_to_get_feature_report_request {
220        use super::*;
221
222        #[fasync::run_until_stalled(test)]
223        async fn single_request_before_call_to_get_feature_report() -> Result<(), Error> {
224            let (proxy, request_stream) = endpoints::create_proxy_and_stream::<InputDeviceMarker>();
225
226            let input_device_server_fut = Box::new(InputDevice::new(
227                request_stream,
228                DeviceDescriptor::default(),
229                AsyncEvent::new(),
230            ))
231            .flush();
232            let get_feature_report_fut = proxy.get_feature_report();
233
234            // Avoid unrelated `panic()`: `InputDevice` requires clients to get an input
235            // reports reader, to help debug integration test failures where no component
236            // read events from the fake device.
237            let (_input_reports_reader_proxy, input_reports_reader_server_end) =
238                endpoints::create_proxy::<InputReportsReaderMarker>();
239            let _ = proxy.get_input_reports_reader(input_reports_reader_server_end);
240
241            std::mem::drop(proxy); // Drop `proxy` to terminate `request_stream`.
242
243            let (_, get_feature_report_result) =
244                future::join(input_device_server_fut, get_feature_report_fut).await;
245            assert_eq!(
246                get_feature_report_result.context("fidl error")?,
247                Ok(FeatureReport::default())
248            );
249            Ok(())
250        }
251    }
252
253    mod responds_to_get_descriptor_request {
254        use super::utils::{make_input_device_proxy_and_struct, make_touchscreen_descriptor};
255        use super::*;
256        use assert_matches::assert_matches;
257        use futures::task::Poll;
258
259        #[fasync::run_until_stalled(test)]
260        async fn single_request_before_call_to_get_input_reports_reader() -> Result<(), Error> {
261            let (proxy, request_stream) = endpoints::create_proxy_and_stream::<InputDeviceMarker>();
262
263            let input_device_server_fut = Box::new(InputDevice::new(
264                request_stream,
265                make_touchscreen_descriptor(),
266                AsyncEvent::new(),
267            ))
268            .flush();
269            let get_descriptor_fut = proxy.get_descriptor();
270
271            // Avoid unrelated `panic()`: `InputDevice` requires clients to get an input
272            // reports reader, to help debug integration test failures where no component
273            // read events from the fake device.
274            let (_input_reports_reader_proxy, input_reports_reader_server_end) =
275                endpoints::create_proxy::<InputReportsReaderMarker>();
276            let _ = proxy.get_input_reports_reader(input_reports_reader_server_end);
277
278            std::mem::drop(proxy); // Drop `proxy` to terminate `request_stream`.
279
280            let (_, get_descriptor_result) =
281                future::join(input_device_server_fut, get_descriptor_fut).await;
282            assert_eq!(get_descriptor_result.context("fidl error")?, make_touchscreen_descriptor());
283            Ok(())
284        }
285
286        #[test]
287        fn multiple_requests_before_call_to_get_input_reports_reader() -> Result<(), Error> {
288            let mut executor = fasync::TestExecutor::new();
289            let (proxy, request_stream) = endpoints::create_proxy_and_stream::<InputDeviceMarker>();
290
291            let input_device_server_fut = Box::new(InputDevice::new(
292                request_stream,
293                make_touchscreen_descriptor(),
294                AsyncEvent::new(),
295            ))
296            .flush();
297            pin_mut!(input_device_server_fut);
298
299            let mut get_descriptor_fut = proxy.get_descriptor();
300            assert_matches!(
301                executor.run_until_stalled(&mut input_device_server_fut),
302                Poll::Pending
303            );
304            std::mem::drop(executor.run_until_stalled(&mut get_descriptor_fut));
305
306            let mut get_descriptor_fut = proxy.get_descriptor();
307            let _ = executor.run_until_stalled(&mut input_device_server_fut);
308            assert_matches!(
309                executor.run_until_stalled(&mut get_descriptor_fut),
310                Poll::Ready(Ok(_))
311            );
312
313            Ok(())
314        }
315
316        #[test]
317        fn after_call_to_get_input_reports_reader_with_report_pending() -> Result<(), Error> {
318            let mut executor = fasync::TestExecutor::new();
319            let (input_device_proxy, input_device, got_input_reports_reader) =
320                make_input_device_proxy_and_struct();
321            input_device
322                .send_input_report(InputReport {
323                    event_time: None,
324                    touch: None,
325                    ..Default::default()
326                })
327                .context("internal error queuing input event")?;
328
329            let input_device_server_fut = input_device.flush();
330            pin_mut!(input_device_server_fut);
331
332            let (_input_reports_reader_proxy, input_reports_reader_server_end) =
333                endpoints::create_proxy::<InputReportsReaderMarker>();
334            input_device_proxy
335                .get_input_reports_reader(input_reports_reader_server_end)
336                .context("sending get_input_reports_reader request")?;
337            assert_matches!(
338                executor.run_until_stalled(&mut input_device_server_fut),
339                Poll::Pending
340            );
341
342            let mut get_descriptor_fut = input_device_proxy.get_descriptor();
343            assert_matches!(
344                executor.run_until_stalled(&mut input_device_server_fut),
345                Poll::Pending
346            );
347            assert_matches!(executor.run_until_stalled(&mut get_descriptor_fut), Poll::Ready(_));
348
349            let mut got_input_reports_reader_fut = got_input_reports_reader.wait();
350            assert_matches!(
351                executor.run_until_stalled(&mut got_input_reports_reader_fut),
352                Poll::Ready(_)
353            );
354
355            Ok(())
356        }
357    }
358
359    mod future_resolution {
360        use super::utils::{make_input_device_proxy_and_struct, make_input_reports_reader_proxy};
361        use super::*;
362        use futures::task::Poll;
363
364        mod resolves_after_all_reports_are_sent_to_input_reports_reader {
365            use super::*;
366            use assert_matches::assert_matches;
367
368            #[test]
369            fn if_device_request_channel_was_closed() {
370                let mut executor = fasync::TestExecutor::new();
371                let (input_device_proxy, input_device, _got_input_reports_reader) =
372                    make_input_device_proxy_and_struct();
373                let input_reports_reader_proxy =
374                    make_input_reports_reader_proxy(&input_device_proxy);
375                input_device
376                    .send_input_report(InputReport {
377                        event_time: None,
378                        touch: None,
379                        ..Default::default()
380                    })
381                    .expect("queuing input report");
382
383                let _input_reports_fut = input_reports_reader_proxy.read_input_reports();
384                let input_device_fut = input_device.flush();
385                pin_mut!(input_device_fut);
386                std::mem::drop(input_device_proxy); // Close device request channel.
387                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Ready(()));
388            }
389
390            #[test]
391            fn even_if_device_request_channel_is_open() {
392                let mut executor = fasync::TestExecutor::new();
393                let (input_device_proxy, input_device, _got_input_reports_reader) =
394                    make_input_device_proxy_and_struct();
395                let input_reports_reader_proxy =
396                    make_input_reports_reader_proxy(&input_device_proxy);
397                input_device
398                    .send_input_report(InputReport {
399                        event_time: None,
400                        touch: None,
401                        ..Default::default()
402                    })
403                    .expect("queuing input report");
404
405                let _input_reports_fut = input_reports_reader_proxy.read_input_reports();
406                let input_device_fut = input_device.flush();
407                pin_mut!(input_device_fut);
408                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Ready(()));
409            }
410
411            #[test]
412            fn even_if_reports_was_empty_and_device_request_channel_is_open() {
413                let mut executor = fasync::TestExecutor::new();
414                let (input_device_proxy, input_device, _got_input_reports_reader) =
415                    make_input_device_proxy_and_struct();
416                let input_reports_reader_proxy =
417                    make_input_reports_reader_proxy(&input_device_proxy);
418                let _input_reports_fut = input_reports_reader_proxy.read_input_reports();
419                let input_device_fut = input_device.flush();
420                pin_mut!(input_device_fut);
421                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Ready(()));
422            }
423        }
424
425        mod panics_if_peer_closed_device_channel_without_calling_get_input_reports_reader {
426            use super::*;
427            use assert_matches::assert_matches;
428
429            #[test]
430            #[should_panic]
431            fn if_reports_were_available() {
432                let mut executor = fasync::TestExecutor::new();
433                let (input_device_proxy, input_device, _got_input_reports_reader) =
434                    make_input_device_proxy_and_struct();
435                input_device
436                    .send_input_report(InputReport {
437                        event_time: None,
438                        touch: None,
439                        ..Default::default()
440                    })
441                    .expect("queuing input report");
442
443                let input_device_fut = input_device.flush();
444                pin_mut!(input_device_fut);
445                std::mem::drop(input_device_proxy);
446
447                // Run the executor until the `InputDevice` causes a panic.
448                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending);
449            }
450
451            #[test]
452            #[should_panic]
453            fn even_if_no_reports_were_available() {
454                let mut executor = fasync::TestExecutor::new();
455                let (input_device_proxy, input_device, _got_input_reports_reader) =
456                    make_input_device_proxy_and_struct();
457                let input_device_fut = input_device.flush();
458                pin_mut!(input_device_fut);
459                std::mem::drop(input_device_proxy);
460
461                // Run the executor until the `InputDevice` causes a panic.
462                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending);
463            }
464        }
465
466        mod is_pending_if_peer_has_device_channel_open_and_has_not_called_get_input_reports_reader {
467            use super::*;
468            use assert_matches::assert_matches;
469
470            #[test]
471            fn if_reports_were_available() {
472                let mut executor = fasync::TestExecutor::new();
473                let (_input_device_proxy, input_device, _got_input_reports_reader) =
474                    make_input_device_proxy_and_struct();
475                input_device
476                    .send_input_report(InputReport {
477                        event_time: None,
478                        touch: None,
479                        ..Default::default()
480                    })
481                    .expect("queuing input report");
482
483                let input_device_fut = input_device.flush();
484                pin_mut!(input_device_fut);
485                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
486            }
487
488            #[test]
489            fn even_if_no_reports_were_available() {
490                let mut executor = fasync::TestExecutor::new();
491                let (_input_device_proxy, input_device, _got_input_reports_reader) =
492                    make_input_device_proxy_and_struct();
493                let input_device_fut = input_device.flush();
494                pin_mut!(input_device_fut);
495                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
496            }
497
498            #[test]
499            fn even_if_get_device_descriptor_has_been_called() {
500                let mut executor = fasync::TestExecutor::new();
501                let (input_device_proxy, input_device, _got_input_reports_reader) =
502                    make_input_device_proxy_and_struct();
503                let input_device_fut = input_device.flush();
504                pin_mut!(input_device_fut);
505                let _get_descriptor_fut = input_device_proxy.get_descriptor();
506                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
507            }
508        }
509
510        mod is_pending_if_peer_has_not_read_any_reports_when_a_report_is_available {
511            use super::*;
512            use assert_matches::assert_matches;
513
514            #[test]
515            fn if_device_request_channel_is_open() {
516                let mut executor = fasync::TestExecutor::new();
517                let (input_device_proxy, input_device, _got_input_reports_reader) =
518                    make_input_device_proxy_and_struct();
519                let _input_reports_reader_proxy =
520                    make_input_reports_reader_proxy(&input_device_proxy);
521                input_device
522                    .send_input_report(InputReport {
523                        event_time: None,
524                        touch: None,
525                        ..Default::default()
526                    })
527                    .expect("queuing input report");
528
529                let input_device_fut = input_device.flush();
530                pin_mut!(input_device_fut);
531                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
532            }
533
534            #[test]
535            fn even_if_device_channel_is_closed() {
536                let mut executor = fasync::TestExecutor::new();
537                let (input_device_proxy, input_device, _got_input_reports_reader) =
538                    make_input_device_proxy_and_struct();
539                let _input_reports_reader_proxy =
540                    make_input_reports_reader_proxy(&input_device_proxy);
541                input_device
542                    .send_input_report(InputReport {
543                        event_time: None,
544                        touch: None,
545                        ..Default::default()
546                    })
547                    .expect("queuing input report");
548
549                let input_device_fut = input_device.flush();
550                std::mem::drop(input_device_proxy); // Terminate `InputDeviceRequestStream`.
551                pin_mut!(input_device_fut);
552                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
553            }
554        }
555
556        mod is_pending_if_peer_did_not_read_all_reports {
557            use super::*;
558            use assert_matches::assert_matches;
559            use fidl_fuchsia_input_report::MAX_DEVICE_REPORT_COUNT;
560
561            #[test]
562            fn if_device_request_channel_is_open() {
563                let mut executor = fasync::TestExecutor::new();
564                let (input_device_proxy, input_device, _got_input_reports_reader) =
565                    make_input_device_proxy_and_struct();
566                let input_reports_reader_proxy =
567                    make_input_reports_reader_proxy(&input_device_proxy);
568                (0..=MAX_DEVICE_REPORT_COUNT).for_each(|_| {
569                    input_device
570                        .send_input_report(InputReport {
571                            event_time: None,
572                            touch: None,
573                            ..Default::default()
574                        })
575                        .expect("queuing input report");
576                });
577
578                // One query isn't enough to consume all of the reports queued above.
579                let _input_reports_fut = input_reports_reader_proxy.read_input_reports();
580                let input_device_fut = input_device.flush();
581                pin_mut!(input_device_fut);
582                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
583            }
584
585            #[test]
586            fn even_if_device_request_channel_is_closed() {
587                let mut executor = fasync::TestExecutor::new();
588                let (input_device_proxy, input_device, _got_input_reports_reader) =
589                    make_input_device_proxy_and_struct();
590                let input_reports_reader_proxy =
591                    make_input_reports_reader_proxy(&input_device_proxy);
592                (0..=MAX_DEVICE_REPORT_COUNT).for_each(|_| {
593                    input_device
594                        .send_input_report(InputReport {
595                            event_time: None,
596                            touch: None,
597                            ..Default::default()
598                        })
599                        .expect("queuing input report");
600                });
601
602                // One query isn't enough to consume all of the reports queued above.
603                let _input_reports_fut = input_reports_reader_proxy.read_input_reports();
604                let input_device_fut = input_device.flush();
605                pin_mut!(input_device_fut);
606                std::mem::drop(input_device_proxy); // Terminate `InputDeviceRequestStream`.
607                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
608            }
609        }
610    }
611
612    mod utils {
613        use {
614            super::*,
615            fidl_fuchsia_input_report::{
616                Axis, ContactInputDescriptor, InputDeviceProxy, InputReportsReaderProxy, Range,
617                TouchDescriptor, TouchInputDescriptor, TouchType, Unit, UnitType,
618            },
619            //zx as zx,
620        };
621
622        /// Creates a `DeviceDescriptor` for a touchscreen that spans [-1000, 1000] on both axes.
623        pub(super) fn make_touchscreen_descriptor() -> DeviceDescriptor {
624            DeviceDescriptor {
625                touch: Some(TouchDescriptor {
626                    input: Some(TouchInputDescriptor {
627                        contacts: Some(
628                            std::iter::repeat(ContactInputDescriptor {
629                                position_x: Some(Axis {
630                                    range: Range { min: -1000, max: 1000 },
631                                    unit: Unit { type_: UnitType::Other, exponent: 0 },
632                                }),
633                                position_y: Some(Axis {
634                                    range: Range { min: -1000, max: 1000 },
635                                    unit: Unit { type_: UnitType::Other, exponent: 0 },
636                                }),
637                                contact_width: Some(Axis {
638                                    range: Range { min: -1000, max: 1000 },
639                                    unit: Unit { type_: UnitType::Other, exponent: 0 },
640                                }),
641                                contact_height: Some(Axis {
642                                    range: Range { min: -1000, max: 1000 },
643                                    unit: Unit { type_: UnitType::Other, exponent: 0 },
644                                }),
645                                ..Default::default()
646                            })
647                            .take(10)
648                            .collect(),
649                        ),
650                        max_contacts: Some(10),
651                        touch_type: Some(TouchType::Touchscreen),
652                        buttons: Some(vec![]),
653                        ..Default::default()
654                    }),
655                    ..Default::default()
656                }),
657                ..Default::default()
658            }
659        }
660
661        /// Creates an `InputDeviceProxy`, for sending `fuchsia.input.report.InputDevice`
662        /// requests, and an `InputDevice` struct that will receive the FIDL requests
663        /// from the `InputDeviceProxy`.S
664        ///
665        /// # Returns
666        /// A tuple of the proxy and struct. The struct is `Box`-ed so that the caller
667        /// can easily invoke `flush()`.
668        pub(super) fn make_input_device_proxy_and_struct(
669        ) -> (InputDeviceProxy, Box<InputDevice>, AsyncEvent) {
670            let (input_device_proxy, input_device_request_stream) =
671                endpoints::create_proxy_and_stream::<InputDeviceMarker>();
672            let got_input_reports_reader = AsyncEvent::new();
673            let input_device = Box::new(InputDevice::new(
674                input_device_request_stream,
675                DeviceDescriptor::default(),
676                got_input_reports_reader.clone(),
677            ));
678            (input_device_proxy, input_device, got_input_reports_reader)
679        }
680
681        /// Creates an `InputReportsReaderProxy`, for sending
682        /// `fuchsia.input.report.InputReportsReader` requests, and registers that
683        /// `InputReportsReader` with the `InputDevice` bound to `InputDeviceProxy`.
684        ///
685        /// # Returns
686        /// The newly created `InputReportsReaderProxy`.
687        pub(super) fn make_input_reports_reader_proxy(
688            input_device_proxy: &InputDeviceProxy,
689        ) -> InputReportsReaderProxy {
690            let (input_reports_reader_proxy, input_reports_reader_server_end) =
691                endpoints::create_proxy::<InputReportsReaderMarker>();
692            input_device_proxy
693                .get_input_reports_reader(input_reports_reader_server_end)
694                .expect("sending get_input_reports_reader request");
695            input_reports_reader_proxy
696        }
697    }
698}