pub mod action;
pub mod common;
pub mod config;
pub mod device;
pub mod error;
pub mod models;
pub mod vision;
use crate::common::point::Point;
use crate::common::rect::Rect;
use crate::common::relative_rect::RelativeRect;
use crate::models::KeyCode;
pub use config::DroidConfig;
use device::DeviceController;
use error::{DroidError, Result};
use image::{DynamicImage, GenericImageView};
pub use models::Target;
use std::path::Path;
use std::time::Duration;
pub struct Droid {
controller: DeviceController,
pub(crate) config: DroidConfig,
}
impl Droid {
pub fn new(config: DroidConfig) -> Result<Self> {
let controller =
DeviceController::new(config.device_serial.as_deref(), config.adb_server_addr)?;
Ok(Self { controller, config })
}
pub(crate) fn resolve_target(
&mut self,
target: &Target,
threshold: f32,
search_rect: Option<RelativeRect>,
) -> Result<Point> {
match target {
Target::Point(p) => {
if search_rect.is_some() {
log::warn!("Search region is ignored when the target is a Point.");
}
log::debug!("Target resolved to a direct point: {:?}", p);
Ok(*p)
}
Target::Image(path) => {
log::debug!("Attempting to resolve image target: {:?}", path);
let needle = image::open(path)?;
let haystack = self.controller.screenshot()?;
let absolute_search_rect: Option<Rect> = search_rect.map(|relative_rect| {
let (w, h) = haystack.dimensions();
relative_rect.to_absolute(w, h)
});
let match_result = vision::find_template(
&haystack,
&needle,
threshold,
path,
absolute_search_rect,
)?;
let center_point = match_result.rect.center();
log::info!(
"Image target found at {:?}, center: {:?}, confidence: {:.4}",
match_result.rect,
center_point,
match_result.confidence
);
Ok(center_point)
}
}
}
pub fn touch(&mut self, target: Target) -> action::touch::TouchBuilder<'_> {
action::touch::TouchBuilder::new(self, target)
}
pub fn swipe(&mut self, start: Target, end: Target) -> action::swipe::SwipeBuilder<'_> {
action::swipe::SwipeBuilder::new(self, start, end)
}
pub fn wait_for(&mut self, target: Target) -> action::wait::WaitBuilder<'_> {
action::wait::WaitBuilder::new(self, target)
}
pub fn text(&mut self, text: &str) -> action::text::TextBuilder<'_> {
action::text::TextBuilder::new(self, text)
}
pub fn sleep(&self, duration: Duration) {
log::info!("Sleeping for {:?}", duration);
std::thread::sleep(duration);
}
pub fn screenshot(&mut self) -> Result<DynamicImage> {
self.controller.screenshot()
}
pub fn snapshot<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
let path_ref = path.as_ref();
log::info!("Saving snapshot to {:?}", path_ref);
let image = self.screenshot()?;
image.save(path_ref)?;
Ok(())
}
pub fn keyevent(&mut self, key_code: KeyCode) -> action::keyevent::KeyeventBuilder<'_> {
action::keyevent::KeyeventBuilder::new(self, key_code)
}
}