1use anyhow::{Context as _, Error};
6use async_trait::async_trait;
7use derivative::Derivative;
8use fidl::endpoints::ProtocolMarker;
9use fidl_fuchsia_hardware_backlight as backlight;
10
11use fidl_fuchsia_hardware_backlight::{DeviceProxy as BacklightProxy, State as BacklightCommand};
12use fidl_fuchsia_ui_display_singleton::{DisplayPowerMarker, DisplayPowerProxy, PowerMode};
13use fuchsia_async as fasync;
14use fuchsia_component::client::{Service, connect_to_protocol};
15use futures::channel::oneshot;
16use futures::lock::Mutex;
17use std::sync::Arc;
18
19const MIN_REGULATED_BRIGHTNESS: f64 = 0.0004;
21const MAX_REGULATED_BRIGHTNESS: f64 = 1.0;
23
24async fn open_backlight() -> Result<BacklightProxy, Error> {
25 log::trace!("Opening backlight device");
26 let device = Service::open(backlight::ServiceMarker)
27 .context("Failed to open service")?
28 .watch_for_any()
29 .await
30 .context("Failed to find instance")?
31 .connect_to_backlight()
32 .context("Failed to connect to backlight service")?;
33 log::info!("Opening backlight");
34 Ok(device)
35}
36
37fn open_display_power_service() -> Result<DisplayPowerProxy, Error> {
38 log::info!("Opening display controller");
39 connect_to_protocol::<DisplayPowerMarker>()
40 .context("Failed to connect to display power service")
41}
42
43#[derive(Derivative)]
51#[derivative(Debug)]
52enum PowerState {
53 Indeterminate,
56 BothOn,
57 BacklightOffDisplayPoweringDown(#[derivative(Debug = "ignore")] fasync::Task<()>),
59 BothOff,
60 DisplayOnBacklightPoweringUp(
63 #[derivative(Debug = "ignore")] fasync::Task<()>,
64 Vec<PendingBacklightCommand>,
65 ),
66}
67
68impl Default for PowerState {
69 fn default() -> Self {
70 Self::Indeterminate
71 }
72}
73
74#[derive(Debug)]
76struct PendingBacklightCommand {
77 command: BacklightCommand,
78 future_handle: oneshot::Sender<Result<(), Error>>,
81}
82
83#[derive(Debug, Clone)]
84pub struct Backlight {
85 backlight_proxy: BacklightProxy,
86 display_power: Option<DisplayPower>,
87}
88
89impl Backlight {
90 pub async fn without_display_power() -> Result<Self, Error> {
93 let backlight_proxy = open_backlight().await?;
94 Self::without_display_power_internal(backlight_proxy)
95 }
96
97 fn without_display_power_internal(backlight_proxy: BacklightProxy) -> Result<Self, Error> {
98 Ok(Backlight { backlight_proxy, display_power: None })
99 }
100
101 #[allow(unused)]
104 pub async fn with_display_power(
105 power_off_delay_millis: u16,
106 power_on_delay_millis: u16,
107 ) -> Result<Self, Error> {
108 let backlight_proxy = open_backlight().await?;
109 let display_power_proxy = open_display_power_service()?;
110 Self::with_display_power_internal(
111 backlight_proxy,
112 display_power_proxy,
113 zx::MonotonicDuration::from_millis(power_off_delay_millis as i64),
114 zx::MonotonicDuration::from_millis(power_on_delay_millis as i64),
115 )
116 .await
117 }
118
119 async fn with_display_power_internal(
120 backlight_proxy: BacklightProxy,
121 display_power_proxy: DisplayPowerProxy,
122 power_off_delay: impl Into<zx::MonotonicDuration>,
123 power_on_delay: impl Into<zx::MonotonicDuration>,
124 ) -> Result<Self, Error> {
125 let display_power = DisplayPower::new(
126 &backlight_proxy,
127 display_power_proxy,
128 power_off_delay,
129 power_on_delay,
130 )
131 .await?;
132 Ok(Backlight { backlight_proxy, display_power: Some(display_power) })
133 }
134
135 pub async fn get_max_absolute_brightness(&self) -> Result<f64, Error> {
136 let connection = self
137 .backlight_proxy
138 .get_max_absolute_brightness()
139 .await
140 .context("Didn't connect correctly")?;
141 let max_brightness: f64 = connection
142 .map_err(zx::Status::from_raw)
143 .context("Failed to get_max_absolute_brightness")?;
144 Ok(max_brightness)
145 }
146
147 async fn get(&self) -> Result<f64, Error> {
148 let backlight_info = get_state_normalized(&self.backlight_proxy).await?;
149 assert!(backlight_info.brightness >= 0.0);
150 assert!(backlight_info.brightness <= MAX_REGULATED_BRIGHTNESS);
151 Ok(if backlight_info.backlight_on { backlight_info.brightness } else { 0.0 })
152 }
153
154 async fn set(&self, value: f64) -> Result<(), Error> {
155 let regulated_value =
157 num_traits::clamp(value, MIN_REGULATED_BRIGHTNESS, MAX_REGULATED_BRIGHTNESS);
158 let backlight_on = value > 0.0;
159
160 match self.display_power.as_ref() {
161 None => self.set_backlight_state_normalized(regulated_value, backlight_on).await,
162 Some(display_power) => {
163 self.clone().set_dual_state(display_power, regulated_value, backlight_on).await
164 }
165 }
166 }
167
168 async fn set_dual_state(
169 &self,
170 display_power: &DisplayPower,
171 regulated_value: f64,
172 backlight_on: bool,
173 ) -> Result<(), Error> {
174 let power_state_arc = display_power.power_state.clone();
175 let mut power_state = power_state_arc.lock().await;
179 match &mut *power_state {
180 PowerState::BothOn => {
181 if backlight_on {
182 } else {
184 self.set_backlight_state_normalized(regulated_value, backlight_on).await?;
185 log::info!("Turned backlight off");
186 log::info!("DDIC power off scheduled");
187 let task =
188 self.clone().make_scheduled_updates_task(display_power.power_off_delay);
189 *power_state = PowerState::BacklightOffDisplayPoweringDown(task);
190 }
191 drop(power_state);
192 self.set_backlight_state_normalized(regulated_value, backlight_on).await
193 }
194 PowerState::BacklightOffDisplayPoweringDown(_task) => {
195 if backlight_on {
196 log::info!("DDIC power on cancelled");
197 *power_state = PowerState::BothOn;
199 drop(power_state);
200 self.set_backlight_state_normalized(regulated_value, backlight_on).await
201 } else {
202 drop(power_state);
204 Ok(())
205 }
206 }
207 PowerState::BothOff => {
208 if backlight_on {
209 display_power.set_display_power_and_log_errors(true).await?;
210 let (pending_change, receiver) =
211 Self::make_pending_change(regulated_value, backlight_on);
212 let task =
213 self.clone().make_scheduled_updates_task(display_power.power_on_delay);
214 *power_state =
215 PowerState::DisplayOnBacklightPoweringUp(task, vec![pending_change]);
216 drop(power_state);
217 log::info!("Backlight power on scheduled");
218 receiver.await?
219 } else {
220 display_power.set_display_power_and_log_errors(false).await?;
221 drop(power_state);
222 Ok(())
223 }
224 }
225 PowerState::DisplayOnBacklightPoweringUp(_task, ref mut pending_changes) => {
226 if backlight_on {
227 let (pending_change, receiver) =
228 Self::make_pending_change(regulated_value, backlight_on);
229 pending_changes.push(pending_change);
230 drop(power_state);
231 receiver.await?
232 } else {
233 log::info!("Backlight power on cancelled");
234 *power_state = PowerState::BothOff;
236 drop(power_state);
237 Ok(())
238 }
239 }
240 PowerState::Indeterminate => {
241 unreachable!()
242 }
243 }
244 }
245
246 fn make_scheduled_updates_task(&self, delay: zx::MonotonicDuration) -> fasync::Task<()> {
247 let time = fasync::MonotonicInstant::after(delay);
248 log::trace!("Setting timer for {:?}", &time);
249 let timer = fasync::Timer::new(time);
250 let self_ = self.clone();
251 let fut = async move {
252 log::trace!("Awaiting timer");
253 timer.await;
254 log::trace!("Timer {:?} elapsed", time);
255 self_.process_scheduled_updates().await;
256 };
257 fasync::Task::local(fut)
258 }
259
260 fn make_pending_change(
263 regulated_value: f64,
264 backlight_on: bool,
265 ) -> (PendingBacklightCommand, oneshot::Receiver<Result<(), Error>>) {
266 let (sender, receiver) = oneshot::channel::<Result<(), Error>>();
267 let pending_change = PendingBacklightCommand {
268 command: BacklightCommand { backlight_on, brightness: regulated_value },
269 future_handle: sender,
270 };
271 (pending_change, receiver)
272 }
273
274 async fn process_scheduled_updates(&self) {
276 let self_ = self.clone();
277 match &self.display_power {
278 Some(display_power) => {
279 let power_state_arc = display_power.power_state.clone();
280 let mut power_state_guard = power_state_arc.lock().await;
281 let power_state = std::mem::take(&mut *power_state_guard);
282
283 log::debug!(
284 "Processing scheduled updates after timer. Most recent state: {:?}",
285 &power_state
286 );
287
288 match power_state {
289 PowerState::BacklightOffDisplayPoweringDown(_) => {
290 if let Ok(_) = display_power.set_display_power_and_log_errors(false).await {
291 *power_state_guard = PowerState::BothOff;
292 } else {
293 *power_state_guard = PowerState::BothOn;
296 }
297 }
298 PowerState::DisplayOnBacklightPoweringUp(_, pending_changes) => {
299 assert!(!pending_changes.is_empty());
300 let mut turned_on = false;
301 for pending_change in pending_changes.into_iter() {
302 assert!(pending_change.command.backlight_on);
303 let result = self_
304 .set_backlight_state_normalized(
305 pending_change.command.brightness,
306 pending_change.command.backlight_on,
307 )
308 .await;
309 *power_state_guard = PowerState::BothOn;
312 log::debug!("Sending result for pending change {:?}", &pending_change);
313 if let Err(e) = pending_change.future_handle.send(result) {
314 log::warn!("Failed to send result for pending change: {:#?}", e);
315 } else if !turned_on {
316 turned_on = true;
317 log::info!("Turned backlight on");
318 }
319 }
320 }
321 PowerState::Indeterminate => {
322 unreachable!()
323 }
324 _ => {}
325 }
326 }
327 None => {
328 unreachable!()
329 }
330 }
331 }
332
333 async fn set_backlight_state_normalized(
334 &self,
335 regulated_value: f64,
336 backlight_on: bool,
337 ) -> Result<(), Error> {
338 log::debug!(
339 "set_state_normalized(brightness: {:.3}, backlight_on: {}",
340 regulated_value,
341 backlight_on
342 );
343 self.backlight_proxy
344 .set_state_normalized(&BacklightCommand { backlight_on, brightness: regulated_value })
345 .await?
346 .map_err(|e| zx::Status::from_raw(e))
347 .context("Failed to set backlight state")
348 }
349}
350
351#[derive(Debug, Clone)]
353struct DisplayPower {
354 proxy: DisplayPowerProxy,
355 power_state: Arc<Mutex<PowerState>>,
356 power_off_delay: zx::MonotonicDuration,
357 power_on_delay: zx::MonotonicDuration,
358}
359
360impl DisplayPower {
361 async fn new(
362 backlight_proxy: &BacklightProxy,
363 display_power_proxy: DisplayPowerProxy,
364 power_off_delay: impl Into<zx::MonotonicDuration>,
365 power_on_delay: impl Into<zx::MonotonicDuration>,
366 ) -> Result<Self, Error> {
367 let initial_state = if get_state_normalized(&backlight_proxy).await?.backlight_on {
370 PowerState::BothOn
371 } else {
372 PowerState::BothOff
373 };
374 log::info!("Initial power state: {:?}", &initial_state);
375
376 Ok(DisplayPower {
377 proxy: display_power_proxy,
378 power_state: Arc::new(Mutex::new(initial_state)),
379 power_off_delay: power_off_delay.into(),
380 power_on_delay: power_on_delay.into(),
381 })
382 }
383
384 async fn set_display_power_and_log_errors(&self, display_on: bool) -> Result<(), Error> {
385 let on_off = if display_on { "on" } else { "off" };
386 log::info!("Turning DDIC power {}", on_off);
387 self.proxy
388 .set_power_mode(if display_on { PowerMode::On } else { PowerMode::Off })
389 .await
390 .map_err(|fidl_error| Into::<Error>::into(fidl_error))
391 .with_context(|| format!("Failed to connect to {}", DisplayPowerMarker::DEBUG_NAME))
392 .and_then(|inner| {
393 inner.map_err(|e| {
394 let status = zx::Status::from_raw(e);
395 Error::from(status)
396 })
397 })
398 .with_context(|| format!("Failed to turn {on_off} display"))
399 .map_err(|e| {
400 log::error!("{:#?}", &e);
401 e
402 })?;
403 log::info!("Turned DDIC power {}", on_off);
404 Ok(())
405 }
406}
407
408async fn get_state_normalized(backlight_proxy: &BacklightProxy) -> Result<BacklightCommand, Error> {
409 backlight_proxy
410 .get_state_normalized()
411 .await?
412 .map_err(|e| zx::Status::from_raw(e))
413 .context("Failed to get_state_normalized")
414}
415
416#[async_trait]
417pub trait BacklightControl: std::fmt::Debug + Send + Sync {
418 async fn get_brightness(&self) -> Result<f64, Error>;
419 async fn set_brightness(&self, value: f64) -> Result<(), Error>;
420 async fn get_max_absolute_brightness(&self) -> Result<f64, Error>;
421}
422
423#[async_trait]
424impl BacklightControl for Backlight {
425 async fn get_brightness(&self) -> Result<f64, Error> {
426 self.get().await
427 }
428 async fn set_brightness(&self, value: f64) -> Result<(), Error> {
429 self.clone().set(value).await
430 }
431 async fn get_max_absolute_brightness(&self) -> Result<f64, Error> {
432 self.get_max_absolute_brightness().await
433 }
434}
435
436#[cfg(test)]
437mod tests {
438 use super::*;
439 use fidl::endpoints::create_proxy_and_stream;
440 use fidl_fuchsia_hardware_backlight::{
441 DeviceMarker as BacklightMarker, DeviceRequestStream as BacklightRequestStream,
442 };
443 use fuchsia_async::{self as fasync};
444 use futures::join;
445 use futures::prelude::future;
446 use futures_util::stream::StreamExt;
447
448 fn mock_backlight() -> (Arc<Backlight>, BacklightRequestStream) {
449 let (backlight_proxy, backlight_stream) = create_proxy_and_stream::<BacklightMarker>();
450
451 (
452 Arc::new(Backlight::without_display_power_internal(backlight_proxy).unwrap()),
453 backlight_stream,
454 )
455 }
456
457 async fn mock_device_set(mut reqs: BacklightRequestStream) -> BacklightCommand {
458 match reqs.next().await.unwrap() {
459 Ok(fidl_fuchsia_hardware_backlight::DeviceRequest::SetStateNormalized {
460 state: command,
461 ..
462 }) => {
463 return command;
464 }
465 request => panic!("Unexpected request: {:?}", request),
466 }
467 }
468
469 async fn mock_device_get(
470 mut reqs: BacklightRequestStream,
471 backlight_command: BacklightCommand,
472 ) {
473 match reqs.next().await.unwrap() {
474 Ok(fidl_fuchsia_hardware_backlight::DeviceRequest::GetStateNormalized {
475 responder,
476 }) => {
477 let response = backlight_command;
478 let _ = responder.send(Ok(&response));
479 }
480 Ok(fidl_fuchsia_hardware_backlight::DeviceRequest::GetMaxAbsoluteBrightness {
481 responder,
482 }) => {
483 if let Err(e) = responder.send(Ok(250.0)) {
484 panic!("Failed to reply to GetMaxAbsoluteBrightness: {}", e);
485 }
486 }
487 request => panic!("Unexpected request: {:?}", request),
488 }
489 }
490
491 #[fasync::run_singlethreaded(test)]
492 async fn test_brightness_returns_zero_if_backlight_off() {
493 let (mock, backlight_stream) = mock_backlight();
495 let backlight_fut = mock_device_get(
496 backlight_stream,
497 BacklightCommand { backlight_on: false, brightness: 0.04 },
498 );
499
500 let get_fut = mock.get();
502 let (brightness, _) = future::join(get_fut, backlight_fut).await;
503
504 assert_eq!(brightness.unwrap(), 0.0);
506 }
507
508 #[fasync::run_singlethreaded(test)]
509 async fn test_brightness_returns_non_zero_if_backlight_on() {
510 let (mock, backlight_stream) = mock_backlight();
512 let backlight_fut = mock_device_get(
513 backlight_stream,
514 BacklightCommand { backlight_on: true, brightness: 0.04 },
515 );
516
517 let get_fut = mock.get();
519 let (brightness, _) = future::join(get_fut, backlight_fut).await;
520
521 assert_eq!(brightness.unwrap(), 0.04);
523 }
524
525 #[fasync::run_singlethreaded(test)]
526 async fn test_zero_brightness_turns_backlight_off() {
527 let (mock, backlight_stream) = mock_backlight();
529 let backlight_fut = mock_device_set(backlight_stream);
530
531 let set_fut = mock.set(0.0);
533 let (_, backlight_command) = futures::join!(set_fut, backlight_fut);
534
535 assert_eq!(backlight_command.backlight_on, false);
537 }
538
539 #[fasync::run_singlethreaded(test)]
540 async fn test_negative_brightness_turns_backlight_off() {
541 let (mock, backlight_stream) = mock_backlight();
543 let backlight_fut = mock_device_set(backlight_stream);
544
545 let set_fut = mock.set(-0.01);
547 let (_, backlight_command) = join!(set_fut, backlight_fut);
548
549 assert_eq!(backlight_command.backlight_on, false);
551 }
552
553 #[fasync::run_singlethreaded(test)]
554 async fn test_brightness_turns_backlight_on() {
555 let (mock, backlight_stream) = mock_backlight();
557 let backlight_fut = mock_device_set(backlight_stream);
558
559 let set_fut = mock.set(0.55);
561 let (_, backlight_command) = join!(set_fut, backlight_fut);
562
563 assert_eq!(backlight_command.backlight_on, true);
565 assert_eq!(backlight_command.brightness, 0.55);
566 }
567
568 #[fasync::run_singlethreaded(test)]
569 async fn test_get_max_absolute_brightness() {
570 let (mock, backlight_stream) = mock_backlight();
572 let backlight_fut = mock_device_get(
573 backlight_stream,
574 BacklightCommand { backlight_on: false, brightness: 0.04 },
575 );
576
577 let mock_fut = mock.get_max_absolute_brightness();
579 let (max_brightness, _) = future::join(mock_fut, backlight_fut).await;
580
581 assert_eq!(max_brightness.unwrap(), 250.0);
583 }
584}
585
586#[cfg(test)]
587mod dual_state_tests {
588 use super::*;
589 use assert_matches::assert_matches;
590 use fidl::endpoints::create_proxy_and_stream;
591 use fidl_fuchsia_hardware_backlight::{
592 DeviceMarker as BacklightMarker, DeviceRequestStream as BacklightRequestStream,
593 };
594 use fidl_fuchsia_ui_display_singleton::{
595 DisplayPowerRequest, DisplayPowerRequestStream, PowerMode,
596 };
597 use fuchsia_async::{self as fasync, Task};
598 use futures::prelude::future;
599 use futures::{Future, TryStreamExt};
600 use std::task::Poll;
601 use test_helpers::ResettableFuture;
602
603 #[derive(Debug, Clone)]
604 struct FakeBacklightService {
605 get_state_normalized_response: ResettableFuture<Result<BacklightCommand, i32>>,
606 set_state_normalized_response: Arc<Mutex<Result<(), i32>>>,
607 }
608
609 #[allow(dead_code)]
610 impl FakeBacklightService {
611 pub fn new() -> Self {
612 Self {
613 get_state_normalized_response: ResettableFuture::new(),
614 set_state_normalized_response: Arc::new(Mutex::new(Ok(()))),
615 }
616 }
617
618 pub fn start(&self) -> Result<(BacklightProxy, Task<()>), Error> {
619 let (proxy, stream) = create_proxy_and_stream::<BacklightMarker>();
620 let task = Task::local(self.clone().process_requests(stream));
621 Ok((proxy, task))
622 }
623
624 async fn process_requests(self, mut stream: BacklightRequestStream) {
625 use fidl_fuchsia_hardware_backlight::DeviceRequest::*;
626
627 log::debug!("FakeBacklightService::process_requests");
628 while let Ok(Some(req)) = stream.try_next().await {
629 log::debug!("FakeBacklightService: {}", req.method_name());
630 match req {
631 GetStateNormalized { responder } => {
632 let result = self.get_state_normalized_response.get().await;
633 responder
634 .send(result.as_ref().map_err(|e| *e))
635 .expect("send GetStateNormalized");
636 }
637 SetStateNormalized { state, responder } => {
638 let result = self.set_state_normalized_response.lock().await.clone();
639 if result.is_ok() {
640 self.set_get_state_normalized_response(Ok(state)).await;
641 }
642 responder.send(result).expect("send SetStateNormalized");
643 }
644 _ => {
645 unimplemented!();
646 }
647 };
648 }
649 }
650
651 pub async fn set_get_state_normalized_response(
652 &self,
653 response: Result<BacklightCommand, i32>,
654 ) {
655 self.get_state_normalized_response.set(response).await;
656 }
657
658 pub async fn clear_get_state_normalized_response(&self) {
659 self.get_state_normalized_response.clear().await;
660 }
661
662 pub async fn set_set_state_normalized_response(&self, result: Result<(), i32>) {
663 let mut guard = self.set_state_normalized_response.lock().await;
664 *guard = result;
665 }
666 }
667
668 #[derive(Debug, Clone)]
669 struct FakeDisplayPowerService {
670 set_power_mode_response: Arc<Mutex<Result<(), i32>>>,
671 last_set_power_mode_value: Arc<Mutex<Option<PowerMode>>>,
672 }
673
674 #[allow(dead_code)]
675 impl FakeDisplayPowerService {
676 pub fn new() -> Self {
677 Self {
678 set_power_mode_response: Arc::new(Mutex::new(Ok(()))),
679 last_set_power_mode_value: Arc::new(Mutex::new(None)),
680 }
681 }
682
683 pub fn start(&self) -> Result<(DisplayPowerProxy, Task<()>), Error> {
684 let (proxy, stream) = create_proxy_and_stream::<DisplayPowerMarker>();
685 let task = Task::local(self.clone().process_requests(stream));
686 Ok((proxy, task))
687 }
688
689 async fn process_requests(self, mut stream: DisplayPowerRequestStream) {
690 log::debug!("FakeDisplayPowerService::process_requests");
691 while let Ok(Some(req)) = stream.try_next().await {
692 log::debug!("FakeDisplayPowerService: {}", req.method_name());
693 match req {
694 DisplayPowerRequest::SetPowerMode { power_mode, responder } => {
695 let result = self.set_power_mode_response.lock().await.clone();
696 if result.is_ok() {
697 self.last_set_power_mode_value.lock().await.replace(power_mode);
698 }
699 responder.send(result).expect("send SetPowerMode");
700 }
701 DisplayPowerRequest::_UnknownMethod { ordinal, .. } => {
702 panic!("Unexpected method: {}", ordinal);
703 }
704 };
705 }
706 log::warn!("FakeDisplayPowerService stopped");
707 }
708
709 pub async fn set_set_power_mode_response(&self, response: Result<(), i32>) {
710 (*self.set_power_mode_response.lock().await) = response;
711 }
712
713 pub async fn last_set_power_mode_value(&self) -> Option<PowerMode> {
714 self.last_set_power_mode_value.lock().await.clone()
715 }
716 }
717
718 trait PollExt<T> {
719 fn into_option(self) -> Option<T>;
720 #[allow(dead_code)]
721 fn unwrap(self) -> T;
722 }
723
724 impl<T> PollExt<T> for Poll<T> {
725 fn into_option(self) -> Option<T> {
726 match self {
727 Poll::Ready(x) => Some(x),
728 Poll::Pending => None,
729 }
730 }
731
732 fn unwrap(self) -> T {
733 self.into_option().unwrap()
734 }
735 }
736
737 trait TestExecutorExt {
738 fn pin_and_run_until_stalled<F: Future>(&mut self, main_future: F) -> Option<F::Output>;
739 fn wake_timers_and_run_until_stalled(&mut self) -> bool;
742 }
743
744 impl TestExecutorExt for fasync::TestExecutor {
745 fn pin_and_run_until_stalled<F: Future>(&mut self, main_future: F) -> Option<F::Output> {
746 self.run_until_stalled(&mut Box::pin(main_future)).into_option()
747 }
748
749 fn wake_timers_and_run_until_stalled(&mut self) -> bool {
750 let did_wake_timers = self.wake_expired_timers();
751 let _ = self.run_until_stalled(&mut future::pending::<()>());
752 did_wake_timers
753 }
754 }
755
756 #[allow(dead_code)]
757 struct Handles {
758 fake_backlight_service: FakeBacklightService,
759 backlight_proxy: BacklightProxy,
760 backlight_task: Task<()>,
761
762 fake_display_power_service: FakeDisplayPowerService,
763 display_power_proxy: DisplayPowerProxy,
764 display_power_task: Task<()>,
765
766 backlight: Backlight,
767 }
768
769 impl Handles {
770 fn new(
773 power_off_delay_ms: i64,
774 power_on_delay_ms: i64,
775 initial_backlight_state: BacklightCommand,
776 ) -> (fasync::TestExecutor, Handles) {
777 let mut exec = fasync::TestExecutor::new_with_fake_time();
778 exec.set_fake_time(zx::MonotonicInstant::ZERO.into());
779
780 let fake_backlight_service = FakeBacklightService::new();
781 let (backlight_proxy, backlight_task) = fake_backlight_service.start().unwrap();
782
783 let fake_display_power_service = FakeDisplayPowerService::new();
784 let (display_power_proxy, display_power_task) =
785 fake_display_power_service.start().unwrap();
786
787 let fake_backlight_service_ = fake_backlight_service.clone();
788
789 let backlight = exec
790 .pin_and_run_until_stalled(async {
791 fake_backlight_service_
792 .set_get_state_normalized_response(Ok(initial_backlight_state))
793 .await;
794
795 Backlight::with_display_power_internal(
796 backlight_proxy.clone(),
797 display_power_proxy.clone(),
798 zx::MonotonicDuration::from_millis(power_off_delay_ms),
799 zx::MonotonicDuration::from_millis(power_on_delay_ms),
800 )
801 .await
802 .unwrap()
803 })
804 .unwrap();
805
806 (
807 exec,
808 Handles {
809 fake_backlight_service,
810 backlight_proxy,
811 backlight_task,
812 fake_display_power_service,
813 display_power_proxy,
814 display_power_task,
815 backlight,
816 },
817 )
818 }
819 }
820
821 #[test]
822 fn positive_brightness_changes_without_affecting_ddic() {
823 let power_off_delay_ms = 100;
824 let power_on_delay_ms = 50;
825
826 let (mut exec, h) = Handles::new(
827 power_off_delay_ms,
828 power_on_delay_ms,
829 BacklightCommand { backlight_on: true, brightness: 1.0 },
830 );
831
832 exec.pin_and_run_until_stalled(async {
833 assert_eq!(h.backlight.get().await.unwrap(), 1.0);
834
835 h.backlight.set(0.9).await.unwrap();
836 assert_eq!(h.backlight.get().await.unwrap(), 0.9);
837
838 h.backlight.set(0.5).await.unwrap();
839 assert_eq!(h.backlight.get().await.unwrap(), 0.5);
840
841 assert_eq!(h.fake_display_power_service.last_set_power_mode_value().await, None)
842 })
843 .unwrap();
844 }
845
846 #[test]
847 fn zero_brightness_turns_ddic_off() {
848 let power_off_delay_ms = 100;
849 let power_on_delay_ms = 50;
850
851 let (mut exec, h) = Handles::new(
852 power_off_delay_ms,
853 power_on_delay_ms,
854 BacklightCommand { backlight_on: true, brightness: 1.0 },
855 );
856
857 exec.pin_and_run_until_stalled(async {
858 assert_eq!(h.backlight.get().await.unwrap(), 1.0);
859 assert_eq!(h.fake_display_power_service.last_set_power_mode_value().await, None);
860
861 h.backlight.set(0.0).await.unwrap();
862 assert_eq!(h.backlight.get().await.unwrap(), 0.0);
863 assert_eq!(h.fake_display_power_service.last_set_power_mode_value().await, None);
864 })
865 .unwrap();
866
867 exec.set_fake_time(
869 (zx::MonotonicInstant::ZERO
870 + zx::MonotonicDuration::from_millis(power_off_delay_ms - 1))
871 .into(),
872 );
873 assert_eq!(exec.wake_timers_and_run_until_stalled(), false);
874
875 exec.pin_and_run_until_stalled(async {
876 assert_eq!(h.fake_display_power_service.last_set_power_mode_value().await, None);
877 })
878 .unwrap();
879
880 exec.set_fake_time(
882 (zx::MonotonicInstant::ZERO
883 + zx::MonotonicDuration::from_millis(power_off_delay_ms + 1))
884 .into(),
885 );
886 assert_eq!(exec.wake_timers_and_run_until_stalled(), true);
887
888 exec.pin_and_run_until_stalled(async {
889 assert_eq!(
890 h.fake_display_power_service.last_set_power_mode_value().await,
891 Some(PowerMode::Off)
892 );
893 })
894 .unwrap();
895 }
896
897 #[test]
898 fn backlight_turns_on_after_ddic() {
899 let power_off_delay_ms = 100;
900 let power_on_delay_ms = 50;
901
902 let (mut exec, h) = Handles::new(
903 power_off_delay_ms,
904 power_on_delay_ms,
905 BacklightCommand { backlight_on: false, brightness: MIN_REGULATED_BRIGHTNESS },
906 );
907
908 exec.pin_and_run_until_stalled(async {
909 assert_eq!(h.backlight.get().await.unwrap(), 0.0);
910 assert_eq!(h.fake_display_power_service.last_set_power_mode_value().await, None);
911 })
912 .unwrap();
913
914 let backlight_ = h.backlight.clone();
915
916 let mut turn_on_backlight_fut = Box::pin(async {
917 backlight_.set(0.1).await.unwrap();
918 });
919 assert_matches!(exec.run_until_stalled(&mut turn_on_backlight_fut), Poll::Pending);
920
921 exec.pin_and_run_until_stalled(async {
922 assert_eq!(h.backlight.get().await.unwrap(), 0.0);
923 assert_eq!(
924 h.fake_display_power_service.last_set_power_mode_value().await,
925 Some(PowerMode::On)
926 );
927 })
928 .unwrap();
929
930 exec.set_fake_time(
931 (zx::MonotonicInstant::ZERO
932 + zx::MonotonicDuration::from_millis(power_on_delay_ms - 1))
933 .into(),
934 );
935 assert_eq!(exec.wake_timers_and_run_until_stalled(), false);
936 assert_matches!(exec.run_until_stalled(&mut turn_on_backlight_fut), Poll::Pending);
937 exec.pin_and_run_until_stalled(async {
938 assert_eq!(h.backlight.get().await.unwrap(), 0.0);
939 })
940 .unwrap();
941
942 exec.set_fake_time(
943 (zx::MonotonicInstant::ZERO
944 + zx::MonotonicDuration::from_millis(power_on_delay_ms + 1))
945 .into(),
946 );
947 assert_eq!(exec.wake_timers_and_run_until_stalled(), true);
948 assert_matches!(exec.run_until_stalled(&mut turn_on_backlight_fut), Poll::Ready(()));
949 exec.pin_and_run_until_stalled(async {
950 assert_eq!(h.backlight.get().await.unwrap(), 0.1);
951 })
952 .unwrap();
953 }
954
955 #[test]
956 fn repeated_backlight_off_commands_do_not_affect_ddic() {
957 let power_off_delay_ms = 100;
958 let power_on_delay_ms = 50;
959
960 let (mut exec, h) = Handles::new(
961 power_off_delay_ms,
962 power_on_delay_ms,
963 BacklightCommand { backlight_on: false, brightness: MIN_REGULATED_BRIGHTNESS },
964 );
965
966 exec.pin_and_run_until_stalled(async {
967 assert_eq!(h.backlight.get().await.unwrap(), 0.0);
968 assert_eq!(h.fake_display_power_service.last_set_power_mode_value().await, None);
969
970 h.backlight.set(0.0).await.unwrap();
971 assert_eq!(h.backlight.get().await.unwrap(), 0.0);
972 assert_eq!(
973 h.fake_display_power_service.last_set_power_mode_value().await,
974 Some(PowerMode::Off)
975 );
976 })
977 .unwrap();
978 }
979
980 #[test]
981 fn ddic_power_off_is_preempted_by_backlight_on_commands() {
982 let power_off_delay_ms = 100;
983 let power_on_delay_ms = 50;
984
985 let (mut exec, h) = Handles::new(
986 power_off_delay_ms,
987 power_on_delay_ms,
988 BacklightCommand { backlight_on: true, brightness: 1.0 },
989 );
990
991 exec.pin_and_run_until_stalled(async {
992 h.backlight.set(0.0).await.unwrap();
993 assert_eq!(h.backlight.get().await.unwrap(), 0.0);
994 assert_eq!(h.fake_display_power_service.last_set_power_mode_value().await, None);
995 })
996 .unwrap();
997
998 exec.set_fake_time(
1000 (zx::MonotonicInstant::ZERO
1001 + zx::MonotonicDuration::from_millis(power_off_delay_ms - 10))
1002 .into(),
1003 );
1004 assert_eq!(exec.wake_timers_and_run_until_stalled(), false);
1005
1006 exec.pin_and_run_until_stalled(async {
1007 assert_eq!(h.fake_display_power_service.last_set_power_mode_value().await, None);
1008 })
1009 .unwrap();
1010
1011 exec.pin_and_run_until_stalled(async {
1012 h.backlight.set(0.5).await.unwrap();
1013 assert_eq!(h.backlight.get().await.unwrap(), 0.5);
1014 assert_eq!(h.fake_display_power_service.last_set_power_mode_value().await, None);
1015 })
1016 .unwrap();
1017
1018 exec.set_fake_time(
1020 (zx::MonotonicInstant::ZERO
1021 + zx::MonotonicDuration::from_millis(power_off_delay_ms + 10))
1022 .into(),
1023 );
1024 assert_eq!(exec.wake_timers_and_run_until_stalled(), false);
1026
1027 exec.pin_and_run_until_stalled(async {
1028 assert_eq!(h.fake_display_power_service.last_set_power_mode_value().await, None);
1029 })
1030 .unwrap();
1031 }
1032
1033 #[test]
1034 fn backlight_power_on_is_preempted_by_ddic_off_commands() {
1035 let power_off_delay_ms = 100;
1036 let power_on_delay_ms = 50;
1037
1038 let (mut exec, h) = Handles::new(
1039 power_off_delay_ms,
1040 power_on_delay_ms,
1041 BacklightCommand { backlight_on: false, brightness: MIN_REGULATED_BRIGHTNESS },
1042 );
1043
1044 let mut turn_on_backlight_1_fut = Box::pin(h.backlight.set(0.1));
1045 let mut turn_on_backlight_2_fut = Box::pin(h.backlight.set(0.2));
1046 assert_matches!(exec.run_until_stalled(&mut turn_on_backlight_1_fut), Poll::Pending);
1047 assert_matches!(exec.run_until_stalled(&mut turn_on_backlight_2_fut), Poll::Pending);
1048
1049 exec.set_fake_time(
1050 (zx::MonotonicInstant::ZERO
1051 + zx::MonotonicDuration::from_millis(power_on_delay_ms - 1))
1052 .into(),
1053 );
1054 assert_eq!(exec.wake_timers_and_run_until_stalled(), false);
1055 assert_matches!(exec.run_until_stalled(&mut turn_on_backlight_1_fut), Poll::Pending);
1056 assert_matches!(exec.run_until_stalled(&mut turn_on_backlight_2_fut), Poll::Pending);
1057
1058 let turn_off_backlight_fut = Box::pin(h.backlight.set(0.0));
1059 exec.pin_and_run_until_stalled(async {
1060 assert_matches!(turn_off_backlight_fut.await, Ok(()));
1061 assert_matches!(
1063 turn_on_backlight_1_fut.await.unwrap_err().downcast::<oneshot::Canceled>(),
1064 Ok(_)
1065 );
1066 assert_matches!(
1067 turn_on_backlight_2_fut.await.unwrap_err().downcast::<oneshot::Canceled>(),
1068 Ok(_)
1069 );
1070
1071 assert_eq!(h.backlight.get().await.unwrap(), 0.0);
1072 })
1073 .unwrap();
1074
1075 exec.set_fake_time(
1076 (zx::MonotonicInstant::ZERO
1077 + zx::MonotonicDuration::from_millis(power_on_delay_ms + 1))
1078 .into(),
1079 );
1080 assert_eq!(exec.wake_timers_and_run_until_stalled(), false);
1081
1082 exec.pin_and_run_until_stalled(async {
1083 assert_eq!(h.backlight.get().await.unwrap(), 0.0);
1084 })
1085 .unwrap();
1086 }
1087
1088 #[test]
1089 fn error_in_ddic_power_off_does_not_affect_later_backlight_commands() {
1090 let power_off_delay_ms = 100;
1091 let power_on_delay_ms = 50;
1092
1093 let (mut exec, h) = Handles::new(
1094 power_off_delay_ms,
1095 power_on_delay_ms,
1096 BacklightCommand { backlight_on: true, brightness: 1.0 },
1097 );
1098
1099 exec.pin_and_run_until_stalled(async {
1100 h.fake_display_power_service
1101 .set_set_power_mode_response(Err(zx::Status::BAD_STATE.into_raw()))
1102 .await;
1103
1104 assert_eq!(h.backlight.get().await.unwrap(), 1.0);
1105 assert_eq!(h.fake_display_power_service.last_set_power_mode_value().await, None);
1106
1107 h.backlight.set(0.0).await.unwrap();
1108 assert_eq!(h.backlight.get().await.unwrap(), 0.0);
1109 assert_eq!(h.fake_display_power_service.last_set_power_mode_value().await, None);
1110 })
1111 .unwrap();
1112
1113 exec.set_fake_time(
1114 (zx::MonotonicInstant::ZERO
1115 + zx::MonotonicDuration::from_millis(power_off_delay_ms + 1))
1116 .into(),
1117 );
1118 assert_eq!(exec.wake_timers_and_run_until_stalled(), true);
1119
1120 exec.pin_and_run_until_stalled(async {
1121 assert_eq!(h.fake_display_power_service.last_set_power_mode_value().await, None);
1122
1123 h.backlight.set(0.5).await.unwrap();
1124 assert_eq!(h.backlight.get().await.unwrap(), 0.5);
1125 assert_eq!(h.fake_display_power_service.last_set_power_mode_value().await, None);
1126 })
1127 .unwrap();
1128 }
1129
1130 #[test]
1131 fn error_in_ddic_power_on_is_recoverable() {
1132 let power_off_delay_ms = 100;
1133 let power_on_delay_ms = 50;
1134
1135 let (mut exec, h) = Handles::new(
1136 power_off_delay_ms,
1137 power_on_delay_ms,
1138 BacklightCommand { backlight_on: false, brightness: MIN_REGULATED_BRIGHTNESS },
1139 );
1140
1141 exec.pin_and_run_until_stalled(async {
1142 h.fake_display_power_service
1143 .set_set_power_mode_response(Err(zx::Status::UNAVAILABLE.into_raw()))
1144 .await;
1145
1146 assert_matches!(h.backlight.set(0.5).await, Err(_));
1147 assert_eq!(h.fake_display_power_service.last_set_power_mode_value().await, None);
1148
1149 h.fake_display_power_service.set_set_power_mode_response(Ok(())).await;
1150 })
1151 .unwrap();
1152
1153 let mut retry_fut = Box::pin(h.backlight.set(0.7));
1154 assert_matches!(exec.run_until_stalled(&mut retry_fut), Poll::Pending);
1155
1156 exec.set_fake_time(
1157 (zx::MonotonicInstant::ZERO
1158 + zx::MonotonicDuration::from_millis(power_on_delay_ms + 1))
1159 .into(),
1160 );
1161 assert_eq!(exec.wake_timers_and_run_until_stalled(), true);
1162
1163 assert_matches!(exec.run_until_stalled(&mut retry_fut), Poll::Ready(Ok(())));
1164 }
1165
1166 #[test]
1167 fn ddic_does_not_power_off_if_backlight_fails_to_power_off() {
1168 let power_off_delay_ms = 100;
1169 let power_on_delay_ms = 50;
1170
1171 let (mut exec, h) = Handles::new(
1172 power_off_delay_ms,
1173 power_on_delay_ms,
1174 BacklightCommand { backlight_on: true, brightness: 0.5 },
1175 );
1176
1177 exec.pin_and_run_until_stalled(async {
1178 h.fake_backlight_service
1179 .set_set_state_normalized_response(Err(zx::Status::NO_RESOURCES.into_raw()))
1180 .await;
1181 assert_matches!(h.backlight.set(0.0).await, Err(_));
1182 })
1183 .unwrap();
1184
1185 exec.set_fake_time(
1186 (zx::MonotonicInstant::ZERO
1187 + zx::MonotonicDuration::from_millis(power_off_delay_ms + 1))
1188 .into(),
1189 );
1190 assert_eq!(exec.wake_timers_and_run_until_stalled(), false);
1191
1192 exec.pin_and_run_until_stalled(async {
1193 assert_eq!(h.fake_display_power_service.last_set_power_mode_value().await, None);
1194 })
1195 .unwrap();
1196 }
1197}