xref: /aosp_15_r20/frameworks/native/libs/input/rust/data_store.rs (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 /*
2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //! Contains the DataStore, used to store input related data in a persistent way.
18 
19 use crate::input::KeyboardType;
20 use log::{debug, error, info};
21 use serde::{Deserialize, Serialize};
22 use std::fs::File;
23 use std::io::{Read, Write};
24 use std::path::Path;
25 use std::sync::{Arc, RwLock};
26 
27 /// Data store to be used to store information that persistent across device reboots.
28 pub struct DataStore {
29     file_reader_writer: Box<dyn FileReaderWriter>,
30     inner: Arc<RwLock<DataStoreInner>>,
31 }
32 
33 #[derive(Default)]
34 struct DataStoreInner {
35     is_loaded: bool,
36     data: Data,
37 }
38 
39 #[derive(Default, Serialize, Deserialize)]
40 struct Data {
41     // Map storing data for keyboard classification for specific devices.
42     #[serde(default)]
43     keyboard_classifications: Vec<KeyboardClassification>,
44     // NOTE: Important things to consider:
45     // - Add any data that needs to be persisted here in this struct.
46     // - Mark all new fields with "#[serde(default)]" for backward compatibility.
47     // - Also, you can't modify the already added fields.
48     // - Can add new nested fields to existing structs. e.g. Add another field to the struct
49     //   KeyboardClassification and mark it "#[serde(default)]".
50 }
51 
52 #[derive(Default, Serialize, Deserialize)]
53 struct KeyboardClassification {
54     descriptor: String,
55     keyboard_type: KeyboardType,
56     is_finalized: bool,
57 }
58 
59 impl DataStore {
60     /// Creates a new instance of Data store
new(file_reader_writer: Box<dyn FileReaderWriter>) -> Self61     pub fn new(file_reader_writer: Box<dyn FileReaderWriter>) -> Self {
62         Self { file_reader_writer, inner: Default::default() }
63     }
64 
load(&mut self)65     fn load(&mut self) {
66         if self.inner.read().unwrap().is_loaded {
67             return;
68         }
69         self.load_internal();
70     }
71 
load_internal(&mut self)72     fn load_internal(&mut self) {
73         let s = self.file_reader_writer.read();
74         let data: Data = if !s.is_empty() {
75             let deserialize: Data = match serde_json::from_str(&s) {
76                 Ok(deserialize) => deserialize,
77                 Err(msg) => {
78                     error!("Unable to deserialize JSON data into struct: {:?} -> {:?}", msg, s);
79                     Default::default()
80                 }
81             };
82             deserialize
83         } else {
84             Default::default()
85         };
86 
87         let mut inner = self.inner.write().unwrap();
88         inner.data = data;
89         inner.is_loaded = true;
90     }
91 
save(&mut self)92     fn save(&mut self) {
93         let string_to_save;
94         {
95             let inner = self.inner.read().unwrap();
96             string_to_save = serde_json::to_string(&inner.data).unwrap();
97         }
98         self.file_reader_writer.write(string_to_save);
99     }
100 
101     /// Get keyboard type of the device (as stored in the data store)
get_keyboard_type(&mut self, descriptor: &String) -> Option<(KeyboardType, bool)>102     pub fn get_keyboard_type(&mut self, descriptor: &String) -> Option<(KeyboardType, bool)> {
103         self.load();
104         let data = &self.inner.read().unwrap().data;
105         for keyboard_classification in data.keyboard_classifications.iter() {
106             if keyboard_classification.descriptor == *descriptor {
107                 return Some((
108                     keyboard_classification.keyboard_type,
109                     keyboard_classification.is_finalized,
110                 ));
111             }
112         }
113         None
114     }
115 
116     /// Save keyboard type of the device in the data store
set_keyboard_type( &mut self, descriptor: &String, keyboard_type: KeyboardType, is_finalized: bool, )117     pub fn set_keyboard_type(
118         &mut self,
119         descriptor: &String,
120         keyboard_type: KeyboardType,
121         is_finalized: bool,
122     ) {
123         {
124             let data = &mut self.inner.write().unwrap().data;
125             data.keyboard_classifications
126                 .retain(|classification| classification.descriptor != *descriptor);
127             data.keyboard_classifications.push(KeyboardClassification {
128                 descriptor: descriptor.to_string(),
129                 keyboard_type,
130                 is_finalized,
131             })
132         }
133         self.save();
134     }
135 }
136 
137 pub trait FileReaderWriter {
read(&self) -> String138     fn read(&self) -> String;
write(&self, to_write: String)139     fn write(&self, to_write: String);
140 }
141 
142 /// Default file reader writer implementation
143 pub struct DefaultFileReaderWriter {
144     filepath: String,
145 }
146 
147 impl DefaultFileReaderWriter {
148     /// Creates a new instance of Default file reader writer that can read and write string to a
149     /// particular file in the filesystem
new(filepath: String) -> Self150     pub fn new(filepath: String) -> Self {
151         Self { filepath }
152     }
153 }
154 
155 impl FileReaderWriter for DefaultFileReaderWriter {
read(&self) -> String156     fn read(&self) -> String {
157         let path = Path::new(&self.filepath);
158         let mut fs_string = String::new();
159         match File::open(path) {
160             Err(e) => info!("couldn't open {:?}: {}", path, e),
161             Ok(mut file) => match file.read_to_string(&mut fs_string) {
162                 Err(e) => error!("Couldn't read from {:?}: {}", path, e),
163                 Ok(_) => debug!("Successfully read from file {:?}", path),
164             },
165         };
166         fs_string
167     }
168 
write(&self, to_write: String)169     fn write(&self, to_write: String) {
170         let path = Path::new(&self.filepath);
171         match File::create(path) {
172             Err(e) => error!("couldn't create {:?}: {}", path, e),
173             Ok(mut file) => match file.write_all(to_write.as_bytes()) {
174                 Err(e) => error!("Couldn't write to {:?}: {}", path, e),
175                 Ok(_) => debug!("Successfully saved to file {:?}", path),
176             },
177         };
178     }
179 }
180 
181 #[cfg(test)]
182 mod tests {
183     use crate::data_store::{
184         test_file_reader_writer::TestFileReaderWriter, DataStore, FileReaderWriter,
185     };
186     use crate::input::KeyboardType;
187 
188     #[test]
test_backward_compatibility_version_1()189     fn test_backward_compatibility_version_1() {
190         // This test tests JSON string that will be created by the first version of data store
191         // This test SHOULD NOT be modified
192         let test_reader_writer = TestFileReaderWriter::new();
193         test_reader_writer.write(r#"{"keyboard_classifications":[{"descriptor":"descriptor","keyboard_type":{"type":"Alphabetic"},"is_finalized":true}]}"#.to_string());
194 
195         let mut data_store = DataStore::new(Box::new(test_reader_writer));
196         let (keyboard_type, is_finalized) =
197             data_store.get_keyboard_type(&"descriptor".to_string()).unwrap();
198         assert_eq!(keyboard_type, KeyboardType::Alphabetic);
199         assert!(is_finalized);
200     }
201 }
202 
203 #[cfg(test)]
204 pub mod test_file_reader_writer {
205 
206     use crate::data_store::FileReaderWriter;
207     use std::sync::{Arc, RwLock};
208 
209     #[derive(Default)]
210     struct TestFileReaderWriterInner {
211         fs_string: String,
212     }
213 
214     #[derive(Default, Clone)]
215     pub struct TestFileReaderWriter(Arc<RwLock<TestFileReaderWriterInner>>);
216 
217     impl TestFileReaderWriter {
new() -> Self218         pub fn new() -> Self {
219             Default::default()
220         }
221     }
222 
223     impl FileReaderWriter for TestFileReaderWriter {
read(&self) -> String224         fn read(&self) -> String {
225             self.0.read().unwrap().fs_string.clone()
226         }
227 
write(&self, fs_string: String)228         fn write(&self, fs_string: String) {
229             self.0.write().unwrap().fs_string = fs_string;
230         }
231     }
232 }
233