[settings] Add fake fuchsia.hardware.light service for testing

Pre-requisite for properly testing restore functionality.

Test: no functionality changes in this CL
Bug: 53625
Change-Id: I6e459163515ccb31eada6c59d725c1c20384d963
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/404697
Commit-Queue: William Xiao <wxyz@google.com>
Reviewed-by: Chip Fukuhara <cfukuhara@google.com>
Reviewed-by: Paul Faria <paulfaria@google.com>
Testability-Review: Chip Fukuhara <cfukuhara@google.com>
diff --git a/garnet/bin/setui/src/tests/fakes.rs b/garnet/bin/setui/src/tests/fakes.rs
index 7bae09dd..33f6fda 100644
--- a/garnet/bin/setui/src/tests/fakes.rs
+++ b/garnet/bin/setui/src/tests/fakes.rs
@@ -7,6 +7,7 @@
 pub mod bluetooth_service;
 pub mod fake_hanging_get_handler;
 pub mod fake_hanging_get_types;
+pub mod hardware_light_service;
 pub mod hardware_power_statecontrol_service;
 pub mod input_device_registry_service;
 pub mod service_registry;
diff --git a/garnet/bin/setui/src/tests/fakes/hardware_light_service.rs b/garnet/bin/setui/src/tests/fakes/hardware_light_service.rs
new file mode 100644
index 0000000..631fd64
--- /dev/null
+++ b/garnet/bin/setui/src/tests/fakes/hardware_light_service.rs
@@ -0,0 +1,115 @@
+// Copyright 2020 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::tests::fakes::base::Service;
+use anyhow::{format_err, Error};
+use fidl::endpoints::ServerEnd;
+use fidl::endpoints::ServiceMarker;
+use fidl_fuchsia_hardware_light::{Info, LightMarker, LightRequest, Rgb};
+use fuchsia_async as fasync;
+use fuchsia_zircon::Channel;
+use futures::lock::Mutex;
+use futures::TryStreamExt;
+use std::collections::HashMap;
+use std::sync::Arc;
+
+/// An implementation of fuchsia.hardware.light for testing use.
+pub struct HardwareLightService {
+    light_info: Arc<Mutex<HashMap<u32, Info>>>,
+    simple_values: Arc<Mutex<HashMap<u32, bool>>>,
+    brightness_values: Arc<Mutex<HashMap<u32, u8>>>,
+    rgb_values: Arc<Mutex<HashMap<u32, Rgb>>>,
+}
+
+/// Allow dead code since this is just a fake for testing.
+#[allow(dead_code)]
+impl HardwareLightService {
+    pub fn new() -> Self {
+        Self {
+            light_info: Arc::new(Mutex::new(HashMap::new())),
+            simple_values: Arc::new(Mutex::new(HashMap::new())),
+            brightness_values: Arc::new(Mutex::new(HashMap::new())),
+            rgb_values: Arc::new(Mutex::new(HashMap::new())),
+        }
+    }
+
+    pub async fn insert_light_info(&self, index: u32, value: Info) {
+        self.light_info.lock().await.insert(index, value);
+    }
+
+    pub async fn insert_simple_value(&self, index: u32, value: bool) {
+        self.simple_values.lock().await.insert(index, value);
+    }
+
+    pub async fn insert_brightness_value(&self, index: u32, value: u8) {
+        self.brightness_values.lock().await.insert(index, value);
+    }
+
+    pub async fn insert_rgb_value(&self, index: u32, value: Rgb) {
+        self.rgb_values.lock().await.insert(index, value);
+    }
+}
+
+impl Service for HardwareLightService {
+    fn can_handle_service(&self, service_name: &str) -> bool {
+        return service_name == LightMarker::NAME;
+    }
+
+    fn process_stream(&self, service_name: &str, channel: Channel) -> Result<(), Error> {
+        if !self.can_handle_service(service_name) {
+            return Err(format_err!("unsupported"));
+        }
+
+        let mut request_stream = ServerEnd::<LightMarker>::new(channel).into_stream()?;
+
+        let light_info = self.light_info.clone();
+        let simple_values = self.simple_values.clone();
+        let brightness_values = self.brightness_values.clone();
+        let rgb_values = self.rgb_values.clone();
+        fasync::spawn(async move {
+            while let Some(req) = request_stream.try_next().await.unwrap() {
+                match req {
+                    LightRequest::GetNumLights { responder } => responder
+                        .send(light_info.lock().await.len() as u32)
+                        .expect("get num lights"),
+                    LightRequest::GetInfo { index, responder } => responder
+                        .send(&mut Ok(light_info
+                            .lock()
+                            .await
+                            .get(&index)
+                            .expect("unknown light")
+                            .clone()))
+                        .expect("get num lights"),
+                    LightRequest::GetCurrentBrightnessValue { index, responder } => responder
+                        .send(&mut Ok(brightness_values
+                            .lock()
+                            .await
+                            .get(&index)
+                            .expect("unknown light")
+                            .clone()))
+                        .expect("get brightness value"),
+                    LightRequest::GetCurrentSimpleValue { index, responder } => responder
+                        .send(&mut Ok(simple_values
+                            .lock()
+                            .await
+                            .get(&index)
+                            .expect("unknown light")
+                            .clone()))
+                        .expect("get simple value"),
+                    LightRequest::GetCurrentRgbValue { index, responder } => responder
+                        .send(&mut Ok(rgb_values
+                            .lock()
+                            .await
+                            .get(&index)
+                            .expect("unknown light")
+                            .clone()))
+                        .expect("get rgb value"),
+                    _ => {}
+                }
+            }
+        });
+
+        Ok(())
+    }
+}