Skip to content

Commit f8ec2fa

Browse files
committed
Fix Android rotated touch input
1 parent a63f410 commit f8ec2fa

3 files changed

Lines changed: 155 additions & 33 deletions

File tree

server/src/android.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,23 @@ impl AndroidBridge {
317317
Ok(())
318318
}
319319

320+
pub fn send_tap_adb(&self, id: &str, x: f64, y: f64) -> Result<(), AppError> {
321+
let serial = self.serial_for_id(id)?;
322+
let (width, height) = self.screen_size_for_serial(&serial)?;
323+
let px = (x.clamp(0.0, 1.0) * (width - 1.0)).round().max(0.0);
324+
let py = (y.clamp(0.0, 1.0) * (height - 1.0)).round().max(0.0);
325+
self.run_adb([
326+
"-s",
327+
&serial,
328+
"shell",
329+
"input",
330+
"tap",
331+
&px.to_string(),
332+
&py.to_string(),
333+
])?;
334+
Ok(())
335+
}
336+
320337
pub fn send_swipe(
321338
&self,
322339
id: &str,
@@ -332,6 +349,18 @@ impl AndroidBridge {
332349
{
333350
return Ok(());
334351
}
352+
self.send_swipe_adb(id, start_x, start_y, end_x, end_y, duration_ms)
353+
}
354+
355+
pub fn send_swipe_adb(
356+
&self,
357+
id: &str,
358+
start_x: f64,
359+
start_y: f64,
360+
end_x: f64,
361+
end_y: f64,
362+
duration_ms: u64,
363+
) -> Result<(), AppError> {
335364
let serial = self.serial_for_id(id)?;
336365
let (width, height) = self.screen_size_for_serial(&serial)?;
337366
let coords = [start_x, start_y, end_x, end_y]

server/src/api/routes.rs

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1917,20 +1917,14 @@ async fn handle_android_control_touch(
19171917
latest_x: x,
19181918
latest_y: y,
19191919
});
1920-
run_android_action(state, move |android| {
1921-
android.send_touch(&udid, x, y, "began")
1922-
})
1923-
.await
1920+
Ok(())
19241921
}
19251922
"moved" => {
19261923
if let Some(touch) = active_touch.as_mut() {
19271924
touch.latest_x = x;
19281925
touch.latest_y = y;
19291926
}
1930-
run_android_action(state, move |android| {
1931-
android.send_touch(&udid, x, y, "moved")
1932-
})
1933-
.await
1927+
Ok(())
19341928
}
19351929
"ended" => {
19361930
let touch = active_touch.take().unwrap_or(AndroidControlTouch {
@@ -1947,20 +1941,16 @@ async fn handle_android_control_touch(
19471941
let duration_ms = touch.started_at.elapsed().as_millis().clamp(80, 1500) as u64;
19481942
run_android_action(state, move |android| {
19491943
if distance >= 0.025 {
1950-
android
1951-
.send_touch(&udid, end_x, end_y, "ended")
1952-
.or_else(|_| {
1953-
android.send_swipe(
1954-
&udid,
1955-
touch.start_x,
1956-
touch.start_y,
1957-
end_x,
1958-
end_y,
1959-
duration_ms,
1960-
)
1961-
})
1944+
android.send_swipe_adb(
1945+
&udid,
1946+
touch.start_x,
1947+
touch.start_y,
1948+
end_x,
1949+
end_y,
1950+
duration_ms,
1951+
)
19621952
} else {
1963-
android.send_touch(&udid, end_x, end_y, "ended")
1953+
android.send_tap_adb(&udid, end_x, end_y)
19641954
}
19651955
})
19661956
.await

server/src/transport/webrtc.rs

Lines changed: 115 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ struct WebRtcMediaStreamToken {
7979
cancellation: broadcast::Sender<()>,
8080
}
8181

82+
struct AndroidWebRtcControlTouch {
83+
started_at: Instant,
84+
start_x: f64,
85+
start_y: f64,
86+
latest_x: f64,
87+
latest_y: f64,
88+
}
89+
8290
#[derive(Debug, Deserialize)]
8391
#[serde(rename_all = "camelCase")]
8492
pub struct WebRtcOfferPayload {
@@ -772,6 +780,7 @@ async fn run_android_webrtc_control_queue(
772780
mut receiver: mpsc::UnboundedReceiver<ControlMessage>,
773781
) {
774782
let mut pending = VecDeque::new();
783+
let mut active_touch: Option<AndroidWebRtcControlTouch> = None;
775784
loop {
776785
let mut message = match pending.pop_front() {
777786
Some(message) => message,
@@ -791,8 +800,13 @@ async fn run_android_webrtc_control_queue(
791800
}
792801
}
793802

794-
if let Err(error) =
795-
run_android_webrtc_control_message(state.clone(), udid.clone(), message).await
803+
if let Err(error) = run_android_webrtc_control_message(
804+
state.clone(),
805+
udid.clone(),
806+
message,
807+
&mut active_touch,
808+
)
809+
.await
796810
{
797811
warn!("Android WebRTC control message failed for {udid}: {error}");
798812
}
@@ -803,38 +817,61 @@ async fn run_android_webrtc_control_message(
803817
state: AppState,
804818
udid: String,
805819
message: ControlMessage,
820+
active_touch: &mut Option<AndroidWebRtcControlTouch>,
806821
) -> Result<(), AppError> {
807-
task::spawn_blocking(move || match message {
822+
match message {
808823
ControlMessage::Touch { x, y, phase } => {
809824
if !x.is_finite() || !y.is_finite() {
810825
return Err(AppError::bad_request(
811826
"`x` and `y` must be finite normalized numbers.",
812827
));
813828
}
814-
state
815-
.android
816-
.send_touch(&udid, x.clamp(0.0, 1.0), y.clamp(0.0, 1.0), &phase)
829+
return handle_android_webrtc_touch(
830+
state,
831+
udid,
832+
x.clamp(0.0, 1.0),
833+
y.clamp(0.0, 1.0),
834+
phase,
835+
active_touch,
836+
)
837+
.await;
817838
}
818839
ControlMessage::EdgeTouch { x, y, phase, .. } => {
819840
if !x.is_finite() || !y.is_finite() {
820841
return Err(AppError::bad_request(
821842
"`x` and `y` must be finite normalized numbers.",
822843
));
823844
}
824-
state
825-
.android
826-
.send_touch(&udid, x.clamp(0.0, 1.0), y.clamp(0.0, 1.0), &phase)
845+
return handle_android_webrtc_touch(
846+
state,
847+
udid,
848+
x.clamp(0.0, 1.0),
849+
y.clamp(0.0, 1.0),
850+
phase,
851+
active_touch,
852+
)
853+
.await;
827854
}
828855
ControlMessage::MultiTouch { x1, y1, phase, .. } => {
829856
if !x1.is_finite() || !y1.is_finite() {
830857
return Err(AppError::bad_request(
831858
"`x1` and `y1` must be finite normalized numbers.",
832859
));
833860
}
834-
state
835-
.android
836-
.send_touch(&udid, x1.clamp(0.0, 1.0), y1.clamp(0.0, 1.0), &phase)
861+
return handle_android_webrtc_touch(
862+
state,
863+
udid,
864+
x1.clamp(0.0, 1.0),
865+
y1.clamp(0.0, 1.0),
866+
phase,
867+
active_touch,
868+
)
869+
.await;
837870
}
871+
_ => {}
872+
}
873+
874+
task::spawn_blocking(move || match message {
838875
ControlMessage::Key {
839876
key_code,
840877
modifiers,
@@ -863,11 +900,77 @@ async fn run_android_webrtc_control_message(
863900
ControlMessage::RotateLeft => state.android.rotate_left(&udid),
864901
ControlMessage::RotateRight => state.android.rotate_right(&udid),
865902
ControlMessage::ToggleAppearance => state.android.toggle_appearance(&udid),
903+
ControlMessage::Touch { .. }
904+
| ControlMessage::EdgeTouch { .. }
905+
| ControlMessage::MultiTouch { .. } => Ok(()),
866906
})
867907
.await
868908
.map_err(|error| AppError::internal(format!("Failed to join Android control task: {error}")))?
869909
}
870910

911+
async fn handle_android_webrtc_touch(
912+
state: AppState,
913+
udid: String,
914+
x: f64,
915+
y: f64,
916+
phase: String,
917+
active_touch: &mut Option<AndroidWebRtcControlTouch>,
918+
) -> Result<(), AppError> {
919+
match phase.as_str() {
920+
"began" => {
921+
*active_touch = Some(AndroidWebRtcControlTouch {
922+
started_at: Instant::now(),
923+
start_x: x,
924+
start_y: y,
925+
latest_x: x,
926+
latest_y: y,
927+
});
928+
Ok(())
929+
}
930+
"moved" => {
931+
if let Some(touch) = active_touch.as_mut() {
932+
touch.latest_x = x;
933+
touch.latest_y = y;
934+
}
935+
Ok(())
936+
}
937+
"ended" => {
938+
let touch = active_touch.take().unwrap_or(AndroidWebRtcControlTouch {
939+
started_at: Instant::now(),
940+
start_x: x,
941+
start_y: y,
942+
latest_x: x,
943+
latest_y: y,
944+
});
945+
let distance = ((x - touch.start_x).powi(2) + (y - touch.start_y).powi(2)).sqrt();
946+
let duration_ms = touch.started_at.elapsed().as_millis().clamp(80, 1500) as u64;
947+
task::spawn_blocking(move || {
948+
if distance >= 0.025 {
949+
state.android.send_swipe_adb(
950+
&udid,
951+
touch.start_x,
952+
touch.start_y,
953+
x,
954+
y,
955+
duration_ms,
956+
)
957+
} else {
958+
state.android.send_tap_adb(&udid, x, y)
959+
}
960+
})
961+
.await
962+
.map_err(|error| {
963+
AppError::internal(format!("Failed to join Android touch task: {error}"))
964+
})?
965+
}
966+
"cancelled" => {
967+
*active_touch = None;
968+
Ok(())
969+
}
970+
_ => Ok(()),
971+
}
972+
}
973+
871974
async fn run_webrtc_control_queue(
872975
session: crate::simulators::session::SimulatorSession,
873976
state: AppState,

0 commit comments

Comments
 (0)