#!/data/data/com.termux/files/usr/bin/bash set -euo pipefail RED="\033[31m" YEL="\033[33m" GRN="\033[32m" BLU="\033[34m" RST="\033[0m" BOLD="\033[1m" log() { printf "${BLU}[iiab]${RST} %s\n" "$*"; } ok() { printf "${GRN}[iiab]${RST} %s\n" "$*"; } warn() { printf "${YEL}[iiab] WARNING:${RST} %s\n" "$*" >&2; } warn_red() { printf "${RED}${BOLD}[iiab] WARNING:${RST} %s\n" "$*" >&2; } have() { command -v "$1" >/dev/null 2>&1; } HOST="127.0.0.1" CONNECT_PORT="" TIMEOUT_SECS=180 STATE_DIR="${TMPDIR:-/data/data/com.termux/files/usr/tmp}/adbw_pair" NOTIF_ID=9400 CLEANUP_OFFLINE=1 DEBUG=0 mkdir -p "$STATE_DIR" need() { command -v "$1" >/dev/null 2>&1; } die(){ echo "[!] $*" >&2; exit 1; } dbg(){ [[ "$DEBUG" == "1" ]] && echo "[DBG] $*" >&2 || true; } # Avoid dpkg conffile prompts (Termux layer) TERMUX_APT_OPTS=( "-y" "-o" "Dpkg::Options::=--force-confdef" "-o" "Dpkg::Options::=--force-confold" ) termux_apt() { apt-get "${TERMUX_APT_OPTS[@]}" "$@"; } step_termux_repo_select_once() { local stamp="$STATE_DIR/stamp.termux_repo_selected" if [[ -f "$stamp" ]]; then return 0 fi if ! have termux-change-repo; then warn "termux-change-repo not found; skipping mirror selection." return 0 fi # When running via "curl | bash", stdin is not a TTY. # Try to prompt via /dev/tty if available. If not, skip WITHOUT stamping. if [[ -r /dev/tty ]]; then printf "\n${YEL}[iiab] One-time setup:${RST} Select a nearby Termux repository mirror for faster downloads.\n" >&2 local ans="Y" if ! read -r -p "[iiab] Launch termux-change-repo now? [Y/n]: " ans < /dev/tty; then warn "No interactive TTY available; skipping mirror selection (run the script directly to be prompted)." return 0 fi ans="${ans:-Y}" if [[ "$ans" =~ ^[Yy]$ ]]; then termux-change-repo || true ok "Mirror selection completed (or skipped inside the UI)." else warn "Mirror selection skipped by user." fi date > "$stamp" return 0 fi warn "No /dev/tty available; skipping mirror selection (run the script directly to be prompted)." return 0 } install_if_missing() { local pkgs=() need adb || pkgs+=("android-tools") need termux-notification || pkgs+=("termux-api") termux_apt update || true termux_apt upgrade || true if ((${#pkgs[@]})); then echo "[*] Installing: ${pkgs[*]}" termux_apt install "${pkgs[@]}" >/dev/null fi need adb || die "Missing adb. Install: pkg install android-tools" need termux-notification || die "Missing termux-notification. Install: pkg install termux-api (and install Termux:API app)" } cleanup_notif() { termux-notification-remove "$NOTIF_ID" >/dev/null 2>&1 || true } notify_ask_one() { # args: key title content local key="$1" title="$2" content="$3" local out="$STATE_DIR/$key.txt" rm -f "$out" # Force a "fresh" notification so Android plays sound each time termux-notification-remove "$NOTIF_ID" >/dev/null 2>&1 || true termux-notification \ --id "$NOTIF_ID" \ --ongoing \ --alert-once \ --priority max \ --title "$title" \ --content "$content" \ --sound \ --button1 "Answer" \ --button1-action "sh -lc 'echo \"\$REPLY\" > \"$out\"'" local start now start="$(date +%s)" while true; do if [[ -s "$out" ]]; then tr -d '\r\n' < "$out" return 0 fi now="$(date +%s)" if (( now - start >= TIMEOUT_SECS )); then return 1 fi sleep 1 done } ask_port_5digits() { # args: key title local key="$1" title="$2" local v="" while true; do v="$(notify_ask_one "$key" "$title" "(5 digits)")" || return 1 v="${v//[[:space:]]/}" [[ "$v" =~ ^[0-9]{5}$ ]] || continue echo "$v" return 0 done } ask_code_6digits() { local v="" while true; do v="$(notify_ask_one code "PAIR CODE" "(6 digits)")" || return 1 v="${v//[[:space:]]/}" [[ -n "$v" ]] || continue [[ "$v" =~ ^[0-9]+$ ]] || continue # Allow missing leading zeros, then normalize to exactly 6 digits if ((${#v} < 6)); then v="$(printf "%06d" "$v")" fi [[ "$v" =~ ^[0-9]{6}$ ]] || continue echo "$v" return 0 done } cleanup_offline_loopback() { local keep_serial="$1" # e.g. 127.0.0.1:42371 local line serial state while read -r line; do serial="$(echo "$line" | awk '{print $1}')" state="$(echo "$line" | awk '{print $2}')" [[ "$serial" == ${HOST}:* ]] || continue [[ "$state" == "offline" ]] || continue [[ "$serial" == "$keep_serial" ]] && continue adb disconnect "$serial" >/dev/null 2>&1 || true done < <(adb devices 2>/dev/null | tail -n +2 | sed '/^\s*$/d') } usage() { cat </dev/null 2>&1 || true echo "[*] adb: $(adb version | head -n 1)" if [[ -n "$CONNECT_PORT" ]]; then CONNECT_PORT="${CONNECT_PORT//[[:space:]]/}" [[ "$CONNECT_PORT" =~ ^[0-9]{5}$ ]] || die "Invalid --connect-port (must be 5 digits): '$CONNECT_PORT'" else echo "[*] Asking CONNECT PORT..." CONNECT_PORT="$(ask_port_5digits connect "CONNECT PORT")" || die "Timeout waiting CONNECT PORT." fi echo "[*] Asking PAIR PORT..." local pair_port pair_port="$(ask_port_5digits pair "PAIR PORT")" || die "Timeout waiting PAIR PORT." echo "[*] Asking PAIR CODE..." local code code="$(ask_code_6digits)" || die "Timeout waiting PAIR CODE." local serial="${HOST}:${CONNECT_PORT}" adb disconnect "$serial" >/dev/null 2>&1 || true echo "[*] adb pair ${HOST}:${pair_port}" printf '%s\n' "$code" | adb pair "${HOST}:${pair_port}" echo "[*] adb connect $serial" adb connect "$serial" >/dev/null if [[ "$CLEANUP_OFFLINE" == "1" ]]; then cleanup_offline_loopback "$serial" fi echo "[*] Devices:" adb devices -l echo "[*] ADB check (shell):" adb -s "$serial" shell sh -lc 'echo "it worked: adb shell is working"; getprop ro.product.model; getprop ro.build.version.release' || true echo "[+] OK" } main "$@"