From 0a6e04c5ba783e868219a65da487b2f771428e19 Mon Sep 17 00:00:00 2001 From: Kuba Orlik Date: Sat, 18 Jan 2025 16:43:36 +0100 Subject: [PATCH] simulate screen dragging Summary: Ref T2890 Reviewers: #reviewers Subscribers: kuba-orlik Maniphest Tasks: T2890 Differential Revision: https://hub.sealcode.org/D1410 --- android/code/index.js | 75 +++++----- android/conf/drag.sh | 1 + http_server/code/index.html | 289 ++++++++++++++++++++---------------- http_server/code/index.mjs | 133 ++++++++++------- 4 files changed, 279 insertions(+), 219 deletions(-) create mode 100644 android/conf/drag.sh diff --git a/android/code/index.js b/android/code/index.js index c85d3c3..d4afc66 100644 --- a/android/code/index.js +++ b/android/code/index.js @@ -5,46 +5,51 @@ const fs = require("fs"); const server = net.createServer(); async function spawnPromise(program, args) { - return new Promise((resolve, reject) => { - const process = child_process.spawn(program, args); - process.on("close", (_) => { - resolve(); - }); - }); + return new Promise((resolve, reject) => { + const process = child_process.spawn(program, args); + process.on("close", (_) => { + resolve(); + }); + }); } //maybe check output of child processe and send errors in some way server.on("connection", (socket) => { - socket.on("data", async (dataBuf) => { - data = dataBuf.toString(); - if (data === "screenshot") { - socket.write("start"); - await spawnPromise("bash", ["/conf/screenshot.sh"]); - socket.write(fs.readFileSync("/screenshot.png")); - socket.write("ENDOFMSG"); - } else if (data.includes("touch")) { - dataSplit = data.split(" "); - await spawnPromise("bash", [ - "/conf/touch.sh", - dataSplit[1], - dataSplit[2], - ]); - } else if (data === "back") { - await spawnPromise("bash", [ - "/conf/back.sh", - ]); - } else if (data === "home") { - await spawnPromise("bash", [ - "/conf/home.sh", - ]); - } - - }); - socket.on("close", (_) => { - socket.end(); - }); + socket.on("data", async (dataBuf) => { + data = dataBuf.toString(); + if (data === "screenshot") { + socket.write("start"); + await spawnPromise("bash", ["/conf/screenshot.sh"]); + socket.write(fs.readFileSync("/screenshot.png")); + socket.write("ENDOFMSG"); + } else if (data.includes("touch")) { + const dataSplit = data.split(" "); + await spawnPromise("bash", [ + "/conf/touch.sh", + dataSplit[1], + dataSplit[2], + ]); + } else if (data === "back") { + await spawnPromise("bash", ["/conf/back.sh"]); + } else if (data === "home") { + await spawnPromise("bash", ["/conf/home.sh"]); + } else if (data.includes("drag")) { + const dataSplit = data.split(" "); + + await spawnPromise("bash", [ + "/conf/drag.sh", + dataSplit[1], + dataSplit[2], + dataSplit[3], + dataSplit[4], + ]); + } + }); + socket.on("close", (_) => { + socket.end(); + }); }); server.listen(3000, () => { - console.log("listening on 3000"); + console.log("listening on 3000"); }); diff --git a/android/conf/drag.sh b/android/conf/drag.sh new file mode 100644 index 0000000..f4c4a76 --- /dev/null +++ b/android/conf/drag.sh @@ -0,0 +1 @@ +/opt/android-sdk-linux/platform-tools/adb shell input swipe $1 $2 $3 $4 1000 \ No newline at end of file diff --git a/http_server/code/index.html b/http_server/code/index.html index 12d17b2..e8053f7 100644 --- a/http_server/code/index.html +++ b/http_server/code/index.html @@ -1,151 +1,186 @@ - - - Rentgen android - - - -
-
- android screen -
- - -
-
-

-

-
- - - + async function screenshot_loop() { + var before; + + while (true) { + before = performance.now(); + await displayImage(); + while (performance.now() - before < ___screenshotDelayMs___) + await sleep(50); + } + } + + screenshot_loop(); + + + diff --git a/http_server/code/index.mjs b/http_server/code/index.mjs index 7b9062f..639917f 100644 --- a/http_server/code/index.mjs +++ b/http_server/code/index.mjs @@ -11,55 +11,64 @@ app.use(express.urlencoded({ extended: false })); const socket_client = net.createConnection({ port: 3000, host: "android" }); async function sleep(time) { - return new Promise((resolve) => setTimeout(resolve, time)); + return new Promise((resolve) => setTimeout(resolve, time)); } let doneWrite = 0; let screenshotPromise = null; async function screenshot() { - socket_client.write("screenshot"); - while (!doneWrite) await sleep(15); - doneWrite = 0; - screenshotPromise = null; + const time_start = Date.now(); + socket_client.write("screenshot"); + while (!doneWrite) { + await sleep(15); + if (Date.now() - time_start > 2000) { + console.error("Screenshot timed out after 2s"); + break; // timeout + } + } + doneWrite = 0; + screenshotPromise = null; } async function guardedScreenshot() { - if (!screenshotPromise) { - screenshotPromise = screenshot(); - } - return screenshotPromise; + console.log("Requesting a screenshot"); + if (!screenshotPromise) { + console.log("no ongoing promise, starting a new one"); + screenshotPromise = screenshot(); + } + return screenshotPromise; } async function waitFullBoot() { - var start = performance.now(); - var counter = 0; + var start = performance.now(); + var counter = 0; - //will timeout after 10 min - while (performance.now() - start < 600 * 1000) { - var before = performance.now(); - await screenshot(); - var after = performance.now(); - if (after - before < process.env.screenshotDelayMs) counter++; - else counter = 0; + //will timeout after 10 min + while (performance.now() - start < 600 * 1000) { + var before = performance.now(); + await screenshot(); + var after = performance.now(); + if (after - before < process.env.screenshotDelayMs) counter++; + else counter = 0; - if (counter === 10) return; - } + if (counter === 10) return; + } - throw new Error("wait for screenshot time to be less than 0.5s timed out"); + throw new Error("wait for screenshot time to be less than 0.5s timed out"); } let fd; socket_client.on("data", (dataBuf) => { - if (dataBuf.toString() === "start") - fd = fs.openSync("/code/screenshot.png", "w"); - else { - if (dataBuf.toString().includes("ENDOFMSG")) { - fs.writeSync(fd, dataBuf); - fs.close(fd); - doneWrite = 1; - } else fs.writeSync(fd, dataBuf); - } + if (dataBuf.toString() === "start") + fd = fs.openSync("/code/screenshot.png", "w"); + else { + if (dataBuf.toString().includes("ENDOFMSG")) { + fs.writeSync(fd, dataBuf); + fs.close(fd); + doneWrite = 1; + } else fs.writeSync(fd, dataBuf); + } }); console.log("Waiting for full boot..."); @@ -67,58 +76,68 @@ await waitFullBoot(); console.log("Boot detected! activating endpoints"); app.get("/screen", async function (req, res) { - await guardedScreenshot(); - res.sendFile("/code/screenshot.png"); + await guardedScreenshot(); + res.sendFile("/code/screenshot.png"); }); app.get("/favicon.ico", function (req, res) { - res.sendFile("/code/favicon.ico"); + res.sendFile("/code/favicon.ico"); }); app.get("/trafficLog.js", function (req, res) { - res.sendFile("/code/dist/trafficLog.js"); + res.sendFile("/code/dist/trafficLog.js"); }); app.get("/trafficLog", async function (req, res) { - res.sendFile("/log/trafficLog"); + res.sendFile("/log/trafficLog"); }); app.post("/touch", function (req, res) { - const x = parseInt(req.body.x); - const y = parseInt(req.body.y); + const x = parseInt(req.body.x); + const y = parseInt(req.body.y); - if (isNaN(x) || isNaN(y) || x > device_size_x || y > device_size_y) { - res.send( - `the query params must be x <= ${device_size_x}, y <= ${device_size_y}\n` - ); - } else { - socket_client.write(`touch ${x} ${y}`); - res.sendStatus(200); - } + if (isNaN(x) || isNaN(y) || x > device_size_x || y > device_size_y) { + res.send( + `the query params must be x <= ${device_size_x}, y <= ${device_size_y}\n` + ); + } else { + socket_client.write(`touch ${x} ${y}`); + res.sendStatus(200); + } }); app.get("/", async function (req, res) { - let fileData = (await readFile("/code/index.html")).toString(); + let fileData = (await readFile("/code/index.html")).toString(); - fileData = fileData.replace( - "___screenshotDelayMs___", - process.env.screenshotDelayMs - ); + fileData = fileData.replace( + "___screenshotDelayMs___", + process.env.screenshotDelayMs + ); - res.setHeader("Content-Type", "text/html"); - res.setHeader("Content-Disposition", "inline"); + res.setHeader("Content-Type", "text/html"); + res.setHeader("Content-Disposition", "inline"); - res.send(fileData); + res.send(fileData); }); app.post("/back", function (req, res) { - socket_client.write(`back`); - res.sendStatus(200); + socket_client.write(`back`); + res.sendStatus(200); }); app.post("/home", function (req, res) { - socket_client.write(`home`); - res.sendStatus(200); + socket_client.write(`home`); + res.sendStatus(200); +}); + +app.post("/drag", function (req, res) { + const body = req.body; + const startX = Number(body.startX); + const startY = Number(body.startY); + const endX = Number(body.endX); + const endY = Number(body.endY); + socket_client.write(`drag ${startX} ${startY} ${endX} ${endY}`); + res.sendStatus(200); }); app.listen(8080, () => console.log("Listening in port 8080"));