1use super::types::SetDisplayInfo;
6use crate::display::display_configuration::{
7 ConfigurationThemeMode, ConfigurationThemeType, DisplayConfiguration,
8};
9use crate::display::display_fidl_handler::Publisher;
10use crate::display::types::{DisplayInfo, LowLightMode, Theme, ThemeBuilder, ThemeMode, ThemeType};
11use anyhow::{Context, Error};
12use async_trait::async_trait;
13use fidl_fuchsia_ui_brightness::{
14 ControlMarker as BrightnessControlMarker, ControlProxy as BrightnessControlProxy,
15};
16use fuchsia_async as fasync;
17use futures::StreamExt;
18use futures::channel::mpsc::UnboundedReceiver;
19use futures::channel::oneshot::Sender;
20use serde::{Deserialize, Serialize};
21use settings_common::call;
22use settings_common::config::default_settings::DefaultSetting;
23use settings_common::inspect::event::{
24 ExternalEventPublisher, ResponseType, SettingValuePublisher,
25};
26use settings_common::service_context::{ExternalServiceProxy, ServiceContext};
27use settings_common::utils::Merge;
28use settings_storage::UpdateState;
29use settings_storage::device_storage::{DeviceStorage, DeviceStorageCompatible};
30use settings_storage::storage_factory::{DefaultLoader, NoneT, StorageAccess, StorageFactory};
31use std::rc::Rc;
32use std::sync::Mutex;
33
34pub(super) const DEFAULT_MANUAL_BRIGHTNESS_VALUE: f32 = 0.5;
35pub(super) const DEFAULT_AUTO_BRIGHTNESS_VALUE: f32 = 0.5;
36
37pub(crate) const DEFAULT_DISPLAY_INFO: DisplayInfo = DisplayInfo::new(
39 false, DEFAULT_MANUAL_BRIGHTNESS_VALUE, DEFAULT_AUTO_BRIGHTNESS_VALUE, true, LowLightMode::Disable, None, );
46
47pub struct DisplayInfoLoader {
51 display_configuration: Mutex<DefaultSetting<DisplayConfiguration, &'static str>>,
52}
53
54impl DisplayInfoLoader {
55 pub(crate) fn new(default_setting: DefaultSetting<DisplayConfiguration, &'static str>) -> Self {
56 Self { display_configuration: Mutex::new(default_setting) }
57 }
58}
59
60impl DefaultLoader for DisplayInfoLoader {
61 type Result = DisplayInfo;
62
63 fn default_value(&self) -> Self::Result {
64 let mut default_display_info = DEFAULT_DISPLAY_INFO;
65
66 if let Ok(Some(display_configuration)) =
67 self.display_configuration.lock().unwrap().get_cached_value()
68 {
69 default_display_info.theme = Some(Theme {
70 theme_type: Some(match display_configuration.theme.theme_type {
71 ConfigurationThemeType::Light => ThemeType::Light,
72 }),
73 theme_mode: if display_configuration
74 .theme
75 .theme_mode
76 .contains(&ConfigurationThemeMode::Auto)
77 {
78 ThemeMode::AUTO
79 } else {
80 ThemeMode::empty()
81 },
82 });
83 }
84
85 default_display_info
86 }
87}
88
89impl DeviceStorageCompatible for DisplayInfo {
90 type Loader = DisplayInfoLoader;
91 const KEY: &'static str = "display_info";
92
93 fn try_deserialize_from(value: &str) -> Result<Self, Error> {
94 Self::extract(value).or_else(|_| DisplayInfoV5::try_deserialize_from(value).map(Self::from))
95 }
96}
97
98impl From<DisplayInfoV5> for DisplayInfo {
99 fn from(v5: DisplayInfoV5) -> Self {
100 DisplayInfo {
101 auto_brightness: v5.auto_brightness,
102 auto_brightness_value: DEFAULT_AUTO_BRIGHTNESS_VALUE,
103 manual_brightness_value: v5.manual_brightness_value,
104 screen_enabled: v5.screen_enabled,
105 low_light_mode: v5.low_light_mode,
106 theme: v5.theme,
107 }
108 }
109}
110
111#[derive(thiserror::Error, Debug)]
112pub enum DisplayError {
113 #[error("Failed to initialize controller: {0:?}")]
114 InitFailure(Error),
115 #[error("Invalid argument: arg: {0:?}, value: {1:?}")]
116 InvalidArgument(&'static str, String),
117 #[error("External failure for Display: dependency: {0:?} request:{1:?} error:{2}")]
118 ExternalFailure(&'static str, &'static str, String),
119 #[error("Write failed for Display: {0:?}")]
120 WriteFailure(Error),
121}
122
123impl From<&DisplayError> for ResponseType {
124 fn from(error: &DisplayError) -> Self {
125 match error {
126 DisplayError::InitFailure(..) => ResponseType::InitFailure,
127 DisplayError::InvalidArgument(..) => ResponseType::InvalidArgument,
128 DisplayError::ExternalFailure(..) => ResponseType::ExternalFailure,
129 DisplayError::WriteFailure(..) => ResponseType::StorageFailure,
130 }
131 }
132}
133
134#[async_trait(?Send)]
135pub trait BrightnessManager: Sized {
136 async fn from_context(
137 service_context: &ServiceContext,
138 external_publisher: ExternalEventPublisher,
139 ) -> Result<Self, DisplayError>;
140 async fn update_brightness(
141 &self,
142 info: DisplayInfo,
143 store: &DeviceStorage,
144 always_send: bool,
147 ) -> Result<Option<DisplayInfo>, DisplayError>;
148}
149
150#[async_trait(?Send)]
151impl BrightnessManager for () {
152 async fn from_context(
153 _: &ServiceContext,
154 _: ExternalEventPublisher,
155 ) -> Result<Self, DisplayError> {
156 Ok(())
157 }
158
159 async fn update_brightness(
162 &self,
163 info: DisplayInfo,
164 store: &DeviceStorage,
165 _: bool,
166 ) -> Result<Option<DisplayInfo>, DisplayError> {
167 if !info.is_finite() {
168 return Err(DisplayError::InvalidArgument("display_info", format!("{info:?}")));
169 }
170 store
171 .write(&info)
172 .await
173 .map(|state| (UpdateState::Updated == state).then_some(info))
174 .context("updating display info")
175 .map_err(DisplayError::WriteFailure)
176 }
177}
178
179pub(crate) struct ExternalBrightnessControl {
180 brightness_service: ExternalServiceProxy<BrightnessControlProxy, ExternalEventPublisher>,
181}
182
183#[async_trait(?Send)]
184impl BrightnessManager for ExternalBrightnessControl {
185 async fn from_context(
186 service_context: &ServiceContext,
187 external_publisher: ExternalEventPublisher,
188 ) -> Result<Self, DisplayError> {
189 service_context
190 .connect_with_publisher::<BrightnessControlMarker, _>(external_publisher)
191 .await
192 .map(|brightness_service| Self { brightness_service })
193 .context("connecting to brightness service")
194 .map_err(DisplayError::InitFailure)
195 }
196
197 async fn update_brightness(
198 &self,
199 info: DisplayInfo,
200 store: &DeviceStorage,
201 always_send: bool,
202 ) -> Result<Option<DisplayInfo>, DisplayError> {
203 if !info.is_finite() {
204 return Err(DisplayError::InvalidArgument("display_info", format!("{info:?}")));
205 }
206 let new_info = store
207 .write(&info)
208 .await
209 .map(|state| (UpdateState::Updated == state).then_some(info))
210 .context("updating brightness")
211 .map_err(DisplayError::WriteFailure)?;
212 if new_info.is_none() && !always_send {
213 return Ok(None);
214 }
215
216 if info.auto_brightness {
217 call!(self.brightness_service => set_auto_brightness())
218 } else {
219 call!(self.brightness_service => set_manual_brightness(info.manual_brightness_value))
220 }
221 .map(|_| new_info)
222 .map_err(|e| {
223 DisplayError::ExternalFailure(
224 "brightness_service".into(),
225 "set_brightness".into(),
226 format!("{e:?}").into(),
227 )
228 })
229 }
230}
231
232pub(crate) enum Request {
233 Set(SetDisplayInfo, Sender<Result<(), DisplayError>>),
234}
235
236pub(crate) struct DisplayController<T = ()> {
237 brightness_manager: T,
238 store: Rc<DeviceStorage>,
239 publisher: Option<Publisher>,
240 setting_value_publisher: SettingValuePublisher<DisplayInfo>,
241}
242
243impl<T> StorageAccess for DisplayController<T> {
244 type Storage = DeviceStorage;
245 type Data = DisplayInfo;
246 const STORAGE_KEY: &'static str = DisplayInfo::KEY;
247}
248
249impl<T> DisplayController<T>
250where
251 T: BrightnessManager + 'static,
252{
253 pub(crate) async fn new<F>(
254 service_context: &ServiceContext,
255 storage_factory: Rc<F>,
256 setting_value_publisher: SettingValuePublisher<DisplayInfo>,
257 external_publisher: ExternalEventPublisher,
258 ) -> Result<DisplayController<T>, DisplayError>
259 where
260 F: StorageFactory<Storage = DeviceStorage>,
261 {
262 let brightness_manager =
263 <T as BrightnessManager>::from_context(service_context, external_publisher).await?;
264 Ok(Self {
265 brightness_manager,
266 store: storage_factory.get_store().await,
267 publisher: None,
268 setting_value_publisher,
269 })
270 }
271
272 pub(crate) async fn restore(&self) -> Result<DisplayInfo, DisplayError> {
273 let display_info = self.store.get::<DisplayInfo>().await;
274 assert!(display_info.is_finite());
275
276 self.brightness_manager
278 .update_brightness(display_info, &self.store, true)
279 .await
280 .map(|info| info.unwrap_or(display_info))
283 }
284
285 pub(crate) async fn handle(
286 self,
287 mut request_rx: UnboundedReceiver<Request>,
288 ) -> fasync::Task<()> {
289 fasync::Task::local(async move {
290 while let Some(request) = request_rx.next().await {
291 let Request::Set(mut set_display_info, tx) = request;
292 let display_info = self.store.get::<DisplayInfo>().await;
293 assert!(display_info.is_finite());
294
295 if let Some(theme) = set_display_info.theme {
296 set_display_info.theme = self.build_theme(theme, &display_info);
297 }
298 let res = self
299 .brightness_manager
300 .update_brightness(display_info.merge(set_display_info), &self.store, false)
301 .await
302 .map(|info| {
303 if let Some(info) = info {
304 self.publish(info);
305 }
306 });
307 let _ = tx.send(res);
308 }
309 })
310 }
311
312 fn build_theme(&self, incoming_theme: Theme, display_info: &DisplayInfo) -> Option<Theme> {
313 let existing_theme_type = display_info.theme.and_then(|theme| theme.theme_type);
314 let new_theme_type = incoming_theme.theme_type.or(existing_theme_type);
315
316 ThemeBuilder::new()
317 .set_theme_type(new_theme_type)
318 .set_theme_mode(incoming_theme.theme_mode)
319 .build()
320 }
321}
322
323impl<T> DisplayController<T> {
324 pub(crate) fn register_publisher(&mut self, publisher: Publisher) {
325 self.publisher = Some(publisher);
326 }
327
328 fn publish(&self, info: DisplayInfo) {
329 let _ = self.setting_value_publisher.publish(&info);
330 if let Some(publisher) = self.publisher.as_ref() {
331 publisher.set(info);
332 }
333 }
334}
335
336#[derive(PartialEq, Debug, Clone, Copy, Serialize, Deserialize)]
339pub struct DisplayInfoV1 {
340 pub manual_brightness_value: f32,
342 pub auto_brightness: bool,
343 pub low_light_mode: LowLightMode,
344}
345
346impl DisplayInfoV1 {
347 const fn new(
348 auto_brightness: bool,
349 manual_brightness_value: f32,
350 low_light_mode: LowLightMode,
351 ) -> DisplayInfoV1 {
352 DisplayInfoV1 { manual_brightness_value, auto_brightness, low_light_mode }
353 }
354}
355
356impl DeviceStorageCompatible for DisplayInfoV1 {
357 type Loader = NoneT;
358 const KEY: &'static str = "display_infoV1";
359}
360
361impl Default for DisplayInfoV1 {
362 fn default() -> Self {
363 DisplayInfoV1::new(
364 false, DEFAULT_MANUAL_BRIGHTNESS_VALUE, LowLightMode::Disable, )
368 }
369}
370
371#[derive(PartialEq, Debug, Clone, Copy, Serialize, Deserialize)]
374pub struct DisplayInfoV2 {
375 pub manual_brightness_value: f32,
376 pub auto_brightness: bool,
377 pub low_light_mode: LowLightMode,
378 pub theme_mode: ThemeModeV1,
379}
380
381impl DisplayInfoV2 {
382 const fn new(
383 auto_brightness: bool,
384 manual_brightness_value: f32,
385 low_light_mode: LowLightMode,
386 theme_mode: ThemeModeV1,
387 ) -> DisplayInfoV2 {
388 DisplayInfoV2 { manual_brightness_value, auto_brightness, low_light_mode, theme_mode }
389 }
390}
391
392impl DeviceStorageCompatible for DisplayInfoV2 {
393 type Loader = NoneT;
394 const KEY: &'static str = "display_infoV2";
395
396 fn try_deserialize_from(value: &str) -> Result<Self, Error> {
397 Self::extract(value).or_else(|_| DisplayInfoV1::try_deserialize_from(value).map(Self::from))
398 }
399}
400
401impl Default for DisplayInfoV2 {
402 fn default() -> Self {
403 DisplayInfoV2::new(
404 false, DEFAULT_MANUAL_BRIGHTNESS_VALUE, LowLightMode::Disable, ThemeModeV1::Unknown, )
409 }
410}
411
412impl From<DisplayInfoV1> for DisplayInfoV2 {
413 fn from(v1: DisplayInfoV1) -> Self {
414 DisplayInfoV2 {
415 auto_brightness: v1.auto_brightness,
416 manual_brightness_value: v1.manual_brightness_value,
417 low_light_mode: v1.low_light_mode,
418 theme_mode: ThemeModeV1::Unknown,
419 }
420 }
421}
422
423#[derive(PartialEq, Debug, Clone, Copy, Serialize, Deserialize)]
424pub enum ThemeModeV1 {
425 Unknown,
426 Default,
427 Light,
428 Dark,
429 Auto,
431}
432
433impl From<ThemeModeV1> for ThemeType {
434 fn from(theme_mode_v1: ThemeModeV1) -> Self {
435 match theme_mode_v1 {
436 ThemeModeV1::Default => ThemeType::Default,
437 ThemeModeV1::Light => ThemeType::Light,
438 ThemeModeV1::Dark => ThemeType::Dark,
439 ThemeModeV1::Unknown | ThemeModeV1::Auto => ThemeType::Unknown,
441 }
442 }
443}
444
445#[derive(PartialEq, Debug, Clone, Copy, Serialize, Deserialize)]
446pub struct DisplayInfoV3 {
447 pub manual_brightness_value: f32,
449 pub auto_brightness: bool,
450 pub screen_enabled: bool,
451 pub low_light_mode: LowLightMode,
452 pub theme_mode: ThemeModeV1,
453}
454
455impl DisplayInfoV3 {
456 const fn new(
457 auto_brightness: bool,
458 manual_brightness_value: f32,
459 screen_enabled: bool,
460 low_light_mode: LowLightMode,
461 theme_mode: ThemeModeV1,
462 ) -> DisplayInfoV3 {
463 DisplayInfoV3 {
464 manual_brightness_value,
465 auto_brightness,
466 screen_enabled,
467 low_light_mode,
468 theme_mode,
469 }
470 }
471}
472
473impl DeviceStorageCompatible for DisplayInfoV3 {
474 type Loader = NoneT;
475 const KEY: &'static str = "display_info";
476
477 fn try_deserialize_from(value: &str) -> Result<Self, Error> {
478 Self::extract(value).or_else(|_| DisplayInfoV2::try_deserialize_from(value).map(Self::from))
479 }
480}
481
482impl Default for DisplayInfoV3 {
483 fn default() -> Self {
484 DisplayInfoV3::new(
485 false, DEFAULT_MANUAL_BRIGHTNESS_VALUE, true, LowLightMode::Disable, ThemeModeV1::Unknown, )
491 }
492}
493
494impl From<DisplayInfoV2> for DisplayInfoV3 {
495 fn from(v2: DisplayInfoV2) -> Self {
496 DisplayInfoV3 {
497 auto_brightness: v2.auto_brightness,
498 manual_brightness_value: v2.manual_brightness_value,
499 screen_enabled: true,
500 low_light_mode: v2.low_light_mode,
501 theme_mode: v2.theme_mode,
502 }
503 }
504}
505
506#[derive(PartialEq, Debug, Clone, Copy, Serialize, Deserialize)]
507pub struct DisplayInfoV4 {
508 pub manual_brightness_value: f32,
510 pub auto_brightness: bool,
511 pub screen_enabled: bool,
512 pub low_light_mode: LowLightMode,
513 pub theme_type: ThemeType,
514}
515
516impl DisplayInfoV4 {
517 const fn new(
518 auto_brightness: bool,
519 manual_brightness_value: f32,
520 screen_enabled: bool,
521 low_light_mode: LowLightMode,
522 theme_type: ThemeType,
523 ) -> DisplayInfoV4 {
524 DisplayInfoV4 {
525 manual_brightness_value,
526 auto_brightness,
527 screen_enabled,
528 low_light_mode,
529 theme_type,
530 }
531 }
532}
533
534impl From<DisplayInfoV3> for DisplayInfoV4 {
535 fn from(v3: DisplayInfoV3) -> Self {
536 DisplayInfoV4 {
537 auto_brightness: v3.auto_brightness,
538 manual_brightness_value: v3.manual_brightness_value,
539 screen_enabled: v3.screen_enabled,
540 low_light_mode: v3.low_light_mode,
541 theme_type: ThemeType::from(v3.theme_mode),
544 }
545 }
546}
547
548impl DeviceStorageCompatible for DisplayInfoV4 {
549 type Loader = NoneT;
550 const KEY: &'static str = "display_info";
551
552 fn try_deserialize_from(value: &str) -> Result<Self, Error> {
553 Self::extract(value).or_else(|_| DisplayInfoV3::try_deserialize_from(value).map(Self::from))
554 }
555}
556
557impl Default for DisplayInfoV4 {
558 fn default() -> Self {
559 DisplayInfoV4::new(
560 false, DEFAULT_MANUAL_BRIGHTNESS_VALUE, true, LowLightMode::Disable, ThemeType::Unknown, )
566 }
567}
568
569#[derive(PartialEq, Debug, Clone, Copy, Serialize, Deserialize)]
570#[serde(deny_unknown_fields)]
571pub struct DisplayInfoV5 {
572 pub manual_brightness_value: f32,
574 pub auto_brightness: bool,
575 pub screen_enabled: bool,
576 pub low_light_mode: LowLightMode,
577 pub theme: Option<Theme>,
578}
579
580impl DisplayInfoV5 {
581 const fn new(
582 auto_brightness: bool,
583 manual_brightness_value: f32,
584 screen_enabled: bool,
585 low_light_mode: LowLightMode,
586 theme: Option<Theme>,
587 ) -> DisplayInfoV5 {
588 DisplayInfoV5 {
589 manual_brightness_value,
590 auto_brightness,
591 screen_enabled,
592 low_light_mode,
593 theme,
594 }
595 }
596}
597
598impl From<DisplayInfoV4> for DisplayInfoV5 {
599 fn from(v4: DisplayInfoV4) -> Self {
600 DisplayInfoV5 {
601 auto_brightness: v4.auto_brightness,
602 manual_brightness_value: v4.manual_brightness_value,
603 screen_enabled: v4.screen_enabled,
604 low_light_mode: v4.low_light_mode,
605 theme: Some(Theme::new(Some(v4.theme_type), ThemeMode::empty())),
607 }
608 }
609}
610
611impl DeviceStorageCompatible for DisplayInfoV5 {
612 type Loader = NoneT;
613 const KEY: &'static str = "display_info";
614
615 fn try_deserialize_from(value: &str) -> Result<Self, Error> {
616 Self::extract(value).or_else(|_| DisplayInfoV4::try_deserialize_from(value).map(Self::from))
617 }
618}
619
620impl Default for DisplayInfoV5 {
621 fn default() -> Self {
622 DisplayInfoV5::new(
623 false, DEFAULT_MANUAL_BRIGHTNESS_VALUE, true, LowLightMode::Disable, Some(Theme::new(Some(ThemeType::Unknown), ThemeMode::empty())), )
629 }
630}
631
632#[cfg(test)]
633mod tests {
634 use super::*;
635
636 #[fuchsia::test]
637 fn test_display_migration_v1_to_v2() {
638 let v1 = DisplayInfoV1 {
639 manual_brightness_value: 0.6,
640 auto_brightness: true,
641 low_light_mode: LowLightMode::Enable,
642 };
643
644 let serialized_v1 = v1.serialize_to();
645 let v2 = DisplayInfoV2::try_deserialize_from(&serialized_v1)
646 .expect("deserialization should succeed");
647
648 assert_eq!(
649 v2,
650 DisplayInfoV2 {
651 manual_brightness_value: v1.manual_brightness_value,
652 auto_brightness: v1.auto_brightness,
653 low_light_mode: v1.low_light_mode,
654 theme_mode: DisplayInfoV2::default().theme_mode,
655 }
656 );
657 }
658
659 #[fuchsia::test]
660 fn test_display_migration_v2_to_v3() {
661 let v2 = DisplayInfoV2 {
662 manual_brightness_value: 0.7,
663 auto_brightness: true,
664 low_light_mode: LowLightMode::Enable,
665 theme_mode: ThemeModeV1::Default,
666 };
667
668 let serialized_v2 = v2.serialize_to();
669 let v3 = DisplayInfoV3::try_deserialize_from(&serialized_v2)
670 .expect("deserialization should succeed");
671
672 assert_eq!(
673 v3,
674 DisplayInfoV3 {
675 manual_brightness_value: v2.manual_brightness_value,
676 auto_brightness: v2.auto_brightness,
677 screen_enabled: DisplayInfoV3::default().screen_enabled,
678 low_light_mode: v2.low_light_mode,
679 theme_mode: v2.theme_mode,
680 }
681 );
682 }
683
684 #[fuchsia::test]
685 fn test_display_migration_v3_to_v4() {
686 let v3 = DisplayInfoV3 {
687 manual_brightness_value: 0.7,
688 auto_brightness: true,
689 low_light_mode: LowLightMode::Enable,
690 theme_mode: ThemeModeV1::Light,
691 screen_enabled: false,
692 };
693
694 let serialized_v3 = v3.serialize_to();
695 let v4 = DisplayInfoV4::try_deserialize_from(&serialized_v3)
696 .expect("deserialization should succeed");
697
698 assert_eq!(
700 v4,
701 DisplayInfoV4 {
702 manual_brightness_value: v3.manual_brightness_value,
703 auto_brightness: v3.auto_brightness,
704 low_light_mode: v3.low_light_mode,
705 theme_type: ThemeType::Light,
706 screen_enabled: v3.screen_enabled,
707 }
708 );
709 }
710
711 #[fuchsia::test]
712 fn test_display_migration_v4_to_v5() {
713 let v4 = DisplayInfoV4 {
714 manual_brightness_value: 0.7,
715 auto_brightness: true,
716 low_light_mode: LowLightMode::Enable,
717 theme_type: ThemeType::Dark,
718 screen_enabled: false,
719 };
720
721 let serialized_v4 = v4.serialize_to();
722 let v5 = DisplayInfoV5::try_deserialize_from(&serialized_v4)
723 .expect("deserialization should succeed");
724
725 assert_eq!(
726 v5,
727 DisplayInfoV5 {
728 manual_brightness_value: v4.manual_brightness_value,
729 auto_brightness: v4.auto_brightness,
730 low_light_mode: v4.low_light_mode,
731 theme: Some(Theme::new(Some(v4.theme_type), ThemeMode::empty())),
732 screen_enabled: v4.screen_enabled,
733 }
734 );
735 }
736
737 #[fuchsia::test]
738 fn test_display_migration_v1_to_current() {
739 let v1 = DisplayInfoV1 {
740 manual_brightness_value: 0.6,
741 auto_brightness: true,
742 low_light_mode: LowLightMode::Enable,
743 };
744
745 let serialized_v1 = v1.serialize_to();
746 let current = DisplayInfo::try_deserialize_from(&serialized_v1)
747 .expect("deserialization should succeed");
748
749 assert_eq!(
750 current,
751 DisplayInfo {
752 manual_brightness_value: v1.manual_brightness_value,
753 auto_brightness: v1.auto_brightness,
754 low_light_mode: v1.low_light_mode,
755 theme: Some(Theme::new(Some(ThemeType::Unknown), ThemeMode::empty())),
756 screen_enabled: DisplayInfoV3::default().screen_enabled,
758 auto_brightness_value: DEFAULT_DISPLAY_INFO.auto_brightness_value,
759 }
760 );
761 }
762
763 #[fuchsia::test]
764 fn test_display_migration_v2_to_current() {
765 let v2 = DisplayInfoV2 {
766 manual_brightness_value: 0.6,
767 auto_brightness: true,
768 low_light_mode: LowLightMode::Enable,
769 theme_mode: ThemeModeV1::Light,
770 };
771
772 let serialized_v2 = v2.serialize_to();
773 let current = DisplayInfo::try_deserialize_from(&serialized_v2)
774 .expect("deserialization should succeed");
775
776 assert_eq!(
777 current,
778 DisplayInfo {
779 manual_brightness_value: v2.manual_brightness_value,
780 auto_brightness: v2.auto_brightness,
781 low_light_mode: v2.low_light_mode,
782 theme: Some(Theme::new(Some(ThemeType::Light), ThemeMode::empty())),
783 screen_enabled: DisplayInfoV3::default().screen_enabled,
785 auto_brightness_value: DEFAULT_DISPLAY_INFO.auto_brightness_value,
786 }
787 );
788 }
789
790 #[fuchsia::test]
791 fn test_display_migration_v3_to_current() {
792 let v3 = DisplayInfoV3 {
793 manual_brightness_value: 0.6,
794 auto_brightness: true,
795 low_light_mode: LowLightMode::Enable,
796 theme_mode: ThemeModeV1::Light,
797 screen_enabled: false,
798 };
799
800 let serialized_v3 = v3.serialize_to();
801 let current = DisplayInfo::try_deserialize_from(&serialized_v3)
802 .expect("deserialization should succeed");
803
804 assert_eq!(
805 current,
806 DisplayInfo {
807 manual_brightness_value: v3.manual_brightness_value,
808 auto_brightness: v3.auto_brightness,
809 low_light_mode: v3.low_light_mode,
810 theme: Some(Theme::new(Some(ThemeType::Light), ThemeMode::empty())),
811 screen_enabled: v3.screen_enabled,
813 auto_brightness_value: DEFAULT_DISPLAY_INFO.auto_brightness_value,
814 }
815 );
816 }
817
818 #[fuchsia::test]
819 fn test_display_migration_v4_to_current() {
820 let v4 = DisplayInfoV4 {
821 manual_brightness_value: 0.6,
822 auto_brightness: true,
823 low_light_mode: LowLightMode::Enable,
824 theme_type: ThemeType::Light,
825 screen_enabled: false,
826 };
827
828 let serialized_v4 = v4.serialize_to();
829 let current = DisplayInfo::try_deserialize_from(&serialized_v4)
830 .expect("deserialization should succeed");
831
832 assert_eq!(
833 current,
834 DisplayInfo {
835 manual_brightness_value: v4.manual_brightness_value,
836 auto_brightness: v4.auto_brightness,
837 low_light_mode: v4.low_light_mode,
838 theme: Some(Theme::new(Some(ThemeType::Light), ThemeMode::empty())),
839 screen_enabled: v4.screen_enabled,
840 auto_brightness_value: DEFAULT_DISPLAY_INFO.auto_brightness_value,
841 }
842 );
843 }
844
845 #[fuchsia::test]
846 fn test_display_migration_v5_to_current() {
847 let v5 = DisplayInfoV5 {
848 manual_brightness_value: 0.6,
849 auto_brightness: true,
850 low_light_mode: LowLightMode::Enable,
851 theme: Some(Theme::new(Some(ThemeType::Light), ThemeMode::AUTO)),
852 screen_enabled: false,
853 };
854
855 let serialized_v5 = v5.serialize_to();
856 let current = DisplayInfo::try_deserialize_from(&serialized_v5)
857 .expect("deserialization should succeed");
858
859 assert_eq!(
860 current,
861 DisplayInfo {
862 manual_brightness_value: v5.manual_brightness_value,
863 auto_brightness: v5.auto_brightness,
864 low_light_mode: v5.low_light_mode,
865 theme: Some(Theme::new(Some(ThemeType::Light), ThemeMode::AUTO)),
866 screen_enabled: v5.screen_enabled,
867 auto_brightness_value: DEFAULT_DISPLAY_INFO.auto_brightness_value,
868 }
869 );
870 }
871}