246 lines
6.4 KiB
Bash
246 lines
6.4 KiB
Bash
#!/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 <<EOF
|
|
Usage:
|
|
$0 [--connect-port 41313] [--host 127.0.0.1] [--no-cleanup-offline] [--debug]
|
|
|
|
Prompts:
|
|
CONNECT PORT (5 digits) # only if --connect-port not provided
|
|
PAIR PORT (5 digits)
|
|
PAIR CODE (6 digits)
|
|
EOF
|
|
}
|
|
|
|
main() {
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--host) HOST="${2:-}"; shift 2 ;;
|
|
--connect-port) CONNECT_PORT="${2:-}"; shift 2 ;;
|
|
--no-cleanup-offline) CLEANUP_OFFLINE=0; shift ;;
|
|
--debug) DEBUG=1; shift ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) die "Unknown arg: $1" ;;
|
|
esac
|
|
done
|
|
|
|
install_if_missing
|
|
trap cleanup_notif EXIT
|
|
|
|
adb start-server >/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 "$@"
|