blob: feede3317d42a71209bf53656d31185b42bb7318 [file] [log] [blame]
// 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 anyhow::Error;
use crate::tiles::types::{
AddTileInput, AddTileOutput, ListTileOutput, RemoveTileInput, TileOutput,
};
use fidl_fuchsia_developer_tiles::ControllerMarker;
use fuchsia_component::client::{launch, launcher, App};
use fuchsia_syslog::macros::fx_log_info;
use serde_json::{from_value, to_value, Value};
use std::cell::RefCell;
/// Facade providing access to fuchsia.developer.tiles interfaces.
pub struct TilesFacade {
tiles: RefCell<Option<App>>,
}
impl std::fmt::Debug for TilesFacade {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TilesFacade").finish()
}
}
impl TilesFacade {
pub fn new() -> TilesFacade {
TilesFacade { tiles: RefCell::new(None) }
}
/// Starts tiles.cmx component.
pub fn start_tile(&self) -> Result<Value, Error> {
if self.tiles.borrow().is_none() {
match launch(
&launcher()?,
String::from("fuchsia-pkg://fuchsia.com/tiles#meta/tiles.cmx"),
None,
) {
Ok(a) => {
self.tiles.replace(Some(a));
fx_log_info!("start_tile");
return Ok(to_value(TileOutput::Success)?);
}
Err(err) => {
return Err(format_err!("Starting Tiles component failed with err {:?}", err))
}
}
}
return Ok(to_value(TileOutput::Success)?);
}
/// Starts tiles.cmx component flatland version.
pub fn start_flatland_tile(&self) -> Result<Value, Error> {
if self.tiles.borrow().is_none() {
match launch(
&launcher()?,
String::from("fuchsia-pkg://fuchsia.com/tiles#meta/tiles-flatland.cmx"),
None,
) {
Ok(a) => {
self.tiles.replace(Some(a));
fx_log_info!("start_flatland_tile");
return Ok(to_value(TileOutput::Success)?);
}
Err(err) => {
return Err(format_err!("Starting Tiles component failed with err {:?}", err))
}
}
}
return Ok(to_value(TileOutput::Success)?);
}
/// Asks the tiles component to quit.
pub fn stop_tile(&self) -> Result<Value, Error> {
if self.tiles.borrow().is_some() {
let controller_proxy =
self.tiles.borrow().as_ref().unwrap().connect_to_protocol::<ControllerMarker>()?;
controller_proxy.quit()?;
self.tiles.replace(None);
}
return Ok(to_value(TileOutput::Success)?);
}
/// Adds a tile by url, optionally user can also specify args and focus.
///
/// params format:
/// {
/// "url": "full package url",
/// "allowed_focus": true/false,
/// "args": ["arg1", "arg2"]
/// }
/// Example:
/// {
/// "url": "fuchsia-pkg://fuchsia.com/flatland_examples#meta/flatland-view-provider.cmx"
/// }
pub async fn add_from_url(&self, args: Value) -> Result<Value, Error> {
let add_request: AddTileInput = from_value(args)?;
fx_log_info!("Add tile request received {:?}", add_request);
self.start_tile()?;
let controller_proxy =
self.tiles.borrow().as_ref().unwrap().connect_to_protocol::<ControllerMarker>()?;
match add_request {
AddTileInput { url, allow_focus, args } => {
let focus = match allow_focus {
Some(f) => f,
None => false,
};
let argv = match args {
Some(x) => x,
None => vec![],
};
let arg_strs: Vec<&str> = argv.iter().map(|a| a.as_str()).collect();
let key = controller_proxy
.add_tile_from_url(&url, focus, Some(&mut arg_strs.into_iter()))
.await?;
let return_value = to_value(AddTileOutput::new(key))?;
return Ok(return_value);
}
}
}
/// Remove a tile by its key id from the current tiles.cmx realm.
///
/// params format:
/// {
/// "key": "key number",
/// }
///
/// Example:
/// {
/// "key": "1",
/// }
pub async fn remove(&self, args: Value) -> Result<Value, Error> {
let remove_request: RemoveTileInput = from_value(args)?;
fx_log_info!("Remove tile request received {:?}", remove_request);
self.start_tile()?;
let controller_proxy =
self.tiles.borrow().as_ref().unwrap().connect_to_protocol::<ControllerMarker>()?;
let key =
remove_request.key.parse::<u32>().map_err(|_| anyhow!("key must be an integer"))?;
match controller_proxy.remove_tile(key) {
Ok(_) => Ok(to_value(TileOutput::Success)?),
Err(err) => Err(format_err!("Remove tiles failed with err {:?}", err)),
}
}
/// List tiles from the current tiles.cmx realm.
///
/// Returns the tiles key, url, and focuse values in arrays.
pub async fn list(&self) -> Result<Value, Error> {
self.start_tile()?;
let controller_proxy =
self.tiles.borrow().as_ref().unwrap().connect_to_protocol::<ControllerMarker>()?;
let (keys, urls, _sizes, focuses) = controller_proxy.list_tiles().await?;
let return_value = to_value(ListTileOutput::new(&keys, &urls, &focuses))?;
return Ok(return_value);
}
}