settings/accessibility/
accessibility_controller.rs1use super::accessibility_fidl_handler::Publisher;
6use crate::accessibility::types::AccessibilityInfo;
7use anyhow::{Context, Error};
8use fuchsia_async as fasync;
9use futures::StreamExt;
10use futures::channel::mpsc::UnboundedReceiver;
11use futures::channel::oneshot::Sender;
12use settings_common::inspect::event::{ResponseType, SettingValuePublisher};
13use settings_common::utils::Merge;
14use settings_storage::UpdateState;
15use settings_storage::device_storage::{DeviceStorage, DeviceStorageCompatible};
16use settings_storage::storage_factory::{NoneT, StorageAccess, StorageFactory};
17use std::rc::Rc;
18
19impl DeviceStorageCompatible for AccessibilityInfo {
20 type Loader = NoneT;
21 const KEY: &'static str = "accessibility_info";
22}
23
24#[derive(thiserror::Error, Debug)]
25pub enum AccessibilityError {
26 #[error("Invalid argument: arg: {0:?}, value: {1:?}")]
27 InvalidArgument(&'static str, String),
28 #[error("Write failed for Display: {0:?}")]
29 WriteFailure(Error),
30}
31
32impl From<&AccessibilityError> for ResponseType {
33 fn from(error: &AccessibilityError) -> Self {
34 match error {
35 AccessibilityError::InvalidArgument(..) => ResponseType::InvalidArgument,
36 AccessibilityError::WriteFailure(..) => ResponseType::StorageFailure,
37 }
38 }
39}
40
41pub(crate) enum Request {
42 Set(AccessibilityInfo, Sender<Result<(), AccessibilityError>>),
43}
44
45impl StorageAccess for AccessibilityController {
46 type Storage = DeviceStorage;
47 type Data = AccessibilityInfo;
48 const STORAGE_KEY: &'static str = AccessibilityInfo::KEY;
49}
50
51pub(crate) struct AccessibilityController {
52 store: Rc<DeviceStorage>,
53 publisher: Option<Publisher>,
54 setting_value_publisher: SettingValuePublisher<AccessibilityInfo>,
55}
56
57impl AccessibilityController {
58 pub(super) async fn new<F>(
59 storage_factory: Rc<F>,
60 setting_value_publisher: SettingValuePublisher<AccessibilityInfo>,
61 ) -> Self
62 where
63 F: StorageFactory<Storage = DeviceStorage>,
64 {
65 AccessibilityController {
66 store: storage_factory.get_store().await,
67 publisher: None,
68 setting_value_publisher,
69 }
70 }
71
72 pub(super) fn register_publisher(&mut self, publisher: Publisher) {
73 self.publisher = Some(publisher);
74 }
75
76 fn publish(&self, info: AccessibilityInfo) {
77 let _ = self.setting_value_publisher.publish(&info);
78 if let Some(publisher) = self.publisher.as_ref() {
79 publisher.set(info);
80 }
81 }
82
83 pub(super) async fn handle(
84 self,
85 mut request_rx: UnboundedReceiver<Request>,
86 ) -> fasync::Task<()> {
87 fasync::Task::local(async move {
88 while let Some(request) = request_rx.next().await {
89 let Request::Set(info, tx) = request;
90 let res = self.set(info).await.map(|info| {
91 if let Some(info) = info {
92 self.publish(info);
93 }
94 });
95 let _ = tx.send(res);
96 }
97 })
98 }
99
100 async fn set(
101 &self,
102 info: AccessibilityInfo,
103 ) -> Result<Option<AccessibilityInfo>, AccessibilityError> {
104 let original_info = self.store.get::<AccessibilityInfo>().await;
105 assert!(original_info.is_finite());
106 if !info.is_finite() {
108 return Err(AccessibilityError::InvalidArgument("accessibility", format!("{info:?}")));
109 }
110
111 let info = original_info.merge(info);
112 self.store
113 .write(&info)
114 .await
115 .map(|state| (UpdateState::Updated == state).then_some(info))
116 .context("updating accessibility info")
117 .map_err(AccessibilityError::WriteFailure)
118 }
119
120 pub(super) async fn restore(&self) -> AccessibilityInfo {
121 self.store.get::<AccessibilityInfo>().await
122 }
123}