rust_droid/action/touch.rs
1use crate::common::relative_rect::RelativeRect;
2use crate::{Droid, Result, Target};
3use std::time::Duration;
4
5/// Builds and executes a "touch" action.
6///
7/// A touch can be a simple tap or a long press, depending on the `duration`.
8/// This struct is created by the `Droid::touch()` method.
9pub struct TouchBuilder<'a> {
10 droid: &'a mut Droid,
11 target: Target,
12 duration: Duration,
13 times: u32,
14 threshold: Option<f32>,
15 search_rect: Option<RelativeRect>,
16}
17
18impl<'a> TouchBuilder<'a> {
19 pub fn new(droid: &'a mut Droid, target: Target) -> Self {
20 Self {
21 droid,
22 target,
23 duration: Duration::from_millis(100),
24 times: 1,
25 threshold: None,
26 search_rect: None,
27 }
28 }
29
30 /// Sets the number of times to perform the touch action.
31 ///
32 /// Default is `1`.
33 pub fn times(mut self, count: u32) -> Self {
34 self.times = count;
35 self
36 }
37
38 /// Sets the duration of the touch.
39 ///
40 /// A short duration (e.g., < 200ms) is a tap.
41 /// A longer duration is a long press.
42 ///
43 /// Default is `100ms`.
44 pub fn duration(mut self, duration: Duration) -> Self {
45 self.duration = duration;
46 self
47 }
48
49 /// Sets the confidence threshold for image matching.
50 ///
51 /// This only applies if the `target` is an `Image`.
52 /// The value should be between `0.0` and `1.0`.
53 /// If not set, the default confidence from `DroidConfig` is used.
54 pub fn threshold(mut self, value: f32) -> Self {
55 self.threshold = Some(value);
56 self
57 }
58
59 /// Restricts the image search to a specific region of the screen.
60 ///
61 /// This only applies if the `target` is an `Image`.
62 /// The `rect` is defined using relative coordinates (0.0 to 1.0).
63 pub fn search_in(mut self, rect: RelativeRect) -> Self {
64 self.search_rect = Some(rect);
65 self
66 }
67
68 /// Executes the configured touch action.
69 ///
70 /// It resolves the `target` to a screen coordinate and then performs
71 /// the tap or long press.
72 ///
73 /// # Errors
74 ///
75 /// Returns an error if the target cannot be found (for image targets) or
76 /// if the underlying ADB command fails.
77 pub fn execute(self) -> Result<()> {
78 let threshold = self
79 .threshold
80 .unwrap_or(self.droid.config.default_confidence);
81 let point = self
82 .droid
83 .resolve_target(&self.target, threshold, self.search_rect)?;
84 log::info!(
85 "Executing touch action at {:?} for {} times",
86 point,
87 self.times
88 );
89
90 for i in 0..self.times {
91 if self.duration <= Duration::from_millis(200) {
92 self.droid.controller.tap(point)?;
93 } else {
94 self.droid.controller.swipe(point, point, self.duration)?;
95 }
96
97 if self.times > 1 && i < self.times - 1 {
98 std::thread::sleep(Duration::from_millis(50));
99 }
100 }
101 Ok(())
102 }
103}