use std::sync::LazyLock;
use image::RgbImage;
use regex::Regex;
use crate::device::AdbDevice;
use crate::errors::{AdbError, Result};
impl AdbDevice {
pub async fn screenshot(&self, display_id: Option<i32>, error_ok: bool) -> Result<RgbImage> {
match self.screencap(display_id).await {
Ok(img) => Ok(img),
Err(e) => {
if error_ok {
let ws = self.window_size(None).await?;
Ok(RgbImage::new(ws.width, ws.height))
} else {
Err(e)
}
}
}
}
async fn screencap(&self, display_id: Option<i32>) -> Result<RgbImage> {
let mut args: Vec<String> = vec!["screencap".into(), "-p".into()];
if let Some(d) = display_id {
let real = self.real_display_id(d).await?;
args.push("-d".into());
args.push(real);
}
let png = self.shell_bytes(args).await?;
let img = image::load_from_memory(&png)
.map_err(|e| AdbError::adb(format!("cannot decode screencap png: {e}")))?;
Ok(img.to_rgb8())
}
async fn real_display_id(&self, display_id: i32) -> Result<String> {
static DISPLAY: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"Display (\d+) ").unwrap());
let output = self
.shell(["dumpsys", "SurfaceFlinger", "--display-id"])
.await?;
let ids: Vec<&str> = DISPLAY
.captures_iter(&output)
.filter_map(|c| c.get(1).map(|m| m.as_str()))
.collect();
ids.get(display_id as usize)
.map(|s| s.to_string())
.ok_or_else(|| AdbError::adb(format!("display_id {display_id} not found")))
}
}