import { execFile } from "node:child_process"; import { chmod, stat } from "node:fs/promises"; import { delimiter } from "node:path"; import { fileURLToPath } from "node:url"; const jar = fileURLToPath(new URL("./android/focus.jar", import.meta.url)); let prepared: Promise | undefined; /** 0 = unfocused, 3 = focused; anything else is unknown and must stay quiet. */ export async function termuxFocused( timeoutMs = 5000, ): Promise { try { prepared ??= stat(jar).then(async ({ mode }) => { // Git restores mode 0644; Android rejects writable DEX/JAR files. if (mode & 0o222) await chmod(jar, mode & ~0o222); }); await prepared; return await new Promise((resolve) => { execFile( "app_process", ["/", "F"], { env: { ...process.env, PATH: `${process.env["PATH"] ?? ""}${delimiter}/system/bin`, CLASSPATH: jar, LD_PRELOAD: undefined, LD_LIBRARY_PATH: undefined, }, timeout: timeoutMs, killSignal: "SIGKILL", maxBuffer: 16 * 1024, }, (error) => { if (!error) resolve(false); else resolve( error.code === 3 && !error.killed && !error.signal ? true : undefined, ); }, ); }); } catch { return undefined; } }