1
0
forked from BRT/arc
arc/android/adb/AdbUtils.h
2026-06-17 19:30:24 +07:00

127 lines
7.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <QList>
#include <QObject>
class AdbUtils final : public QObject {
Q_OBJECT
public:
explicit AdbUtils(QObject *parent = nullptr);
static QString adbPath();
static QList<QPair<QString, QString> > getListDevices();
// --- Wi-Fi подключение (wireless debugging) ---
// Спаривание по коду: `adb pair IP:port code`. true при "Successfully paired".
static bool adbPair(const QString &ip, int port, const QString &code);
// `adb connect IP:port`. Возвращает рабочий "IP:port" при успехе, иначе пусто
// (adb может вернуть exit 0 и при неудаче — судим по тексту вывода).
static QString adbConnect(const QString &ip, int port);
// `adb disconnect <endpoint>` (best-effort).
static bool adbDisconnect(const QString &endpoint);
// Поиск connect-эндпоинта устройства по IP через `adb mdns services`
// (_adb-tls-connect._tcp). Возвращает "IP:port" или пусто.
static QString mdnsFindConnect(const QString &ip);
// android_id устройства (`settings get secure android_id`) — стабильная личность.
// Пусто при ошибке/таймауте.
static QString getAndroidId(const QString &deviceId);
// Fallback-поиск connect-порта, когда он сменился (тоггл/ребут wireless debugging),
// а mDNS в сети не работает: параллельно сканирует IP телефона на открытые порты и
// пробует `adb connect` (pairing сохранён → код не нужен). Возвращает рабочий
// "IP:port" или пусто. Тяжёлая операция — звать только как fallback.
static QString scanFindConnect(const QString &ip, int portStart = 30000, int portEnd = 50000);
static QString tryToGetRunningAppPid(const QString &deviceId, const QString &packageName);
static bool tryToStartApplication(const QString &deviceId, const QString &packageName);
static bool tryToKillApplication(const QString &deviceId, const QString &packageName);
static QString getScreenDumpAsXml(const QString &deviceId, int idx, bool screenshot = false);
// Сырой дамп без фильтра "useful UI" — для ручного превью оператора:
// отдаёт что есть на экране, даже если это PIN-пад / сплэш / WebView-shell.
static QString getRawScreenDumpAsXml(const QString &deviceId);
static bool takeScreenshot(const QString &deviceId, const QString &name);
// IP телефона в Wi-Fi (кэш по serial с TTL). Для IP:port-серийника берётся из
// серийника, иначе `adb shell ip route get 1.1.1.1` → src. Пусто, если не в Wi-Fi.
// Используется и для http-скриншота, и для сохранения IP в БД (wifi_connections).
static QString resolvePhoneIp(const QString &deviceId);
// Текущий режим скриншотов устройства: "http" | "exec-out (fallback)" | "" (ещё не
// определялся). Для индикации в UI. Ключ — adb-серийник.
static QString screenshotMode(const QString &deviceId);
// Захватывает скриншот напрямую в память (PNG-байты), без временного файла.
// Выбирает стратегию по config.ini [screenshot] transport: http (через APK
// arc-shot, мимо adb) с fallback на exec-out, либо сразу exec-out.
static QByteArray captureScreenshotBytes(const QString &deviceId);
// Скриншот через APK arc-shot: adb screencap в файл на /sdcard (дёшево, без
// передачи байтов через adb) + HTTP-GET файла напрямую с телефона по его
// Wi-Fi IP. Разгружает adb. Пусто при недоступности (нет APK/сети) — вызывающий
// откатывается на exec-out. Возвращает PNG-байты.
static QByteArray captureScreenshotHttp(const QString &deviceId);
static bool takeXmlDump(const QString &deviceId, const QString &name);
static bool makeTap(const QString &deviceId, int x, int y);
static bool enableAdbIMEKeyboard(const QString &deviceId);
static bool inputAdbIMEText(const QString &deviceId, const QString &text);
static bool disableAdbIMEKeyboard(const QString &deviceId);
static bool makeSwipe(const QString &deviceId, int x1, int y1, int x2, int y2);
static bool makeSwipe(const QString &deviceId, int x1, int y1, int x2, int y2, int durationMs);
static bool inputText(const QString &deviceId, const QString &text);
static bool hideKeyboard(const QString &deviceId);
static bool goBack(const QString &deviceId);
static void unlockScreen(const QString &deviceId, int screenWidth, int screenHeight);
static QSet<QString> getListApps(const QString &deviceId);
// Возвращает таймзону устройства (напр. "Asia/Bangkok"), либо пустую строку при ошибке
static QString getDeviceTimezone(const QString &deviceId);
// Возвращает versionName установленного пакета (напр. "19.17.0"), либо пустую строку при ошибке/отсутствии
static QString getAppVersion(const QString &deviceId, const QString &packageName);
// Возвращает пакет приложения на переднем плане (foreground), либо пустую строку при ошибке
static QString getForegroundPackage(const QString &deviceId);
// Проверяет реальную ориентацию экрана (dumpsys input → SurfaceOrientation).
// Если экран в горизонтальной ориентации (landscape, 90°/270°), принудительно
// ставит вертикальную: выключает автоповорот и выставляет user_rotation=0.
// Best-effort: при ошибке adb просто ничего не делает. Возвращает true, если
// экран в портрете (изначально или после форсирования).
static bool ensurePortraitOrientation(const QString &deviceId);
private:
static QString adbDir();
static bool startProcess(const QString &program, const QStringList &args,
QString *stdOut = nullptr, QString *stdErr = nullptr);
// Старый способ: exec-out screencap -p (стримит PNG через adb). Fallback для http.
static QByteArray captureScreenshotExecOut(const QString &deviceId);
// Синхронный HTTP/1.0 GET по QTcpSocket (без event-loop, безопасно из worker-потоков).
// Возвращает тело ответа при 200, иначе пусто.
static QByteArray httpGet(const QString &ip, int port, const QString &path, int timeoutMs);
// Поднимает foreground-сервис arc-shot (ставит APK, если удалён). Дёргается из
// http-fail ветки, т.е. не чаще раза в бэкофф-окно.
static void kickArcShot(const QString &deviceId);
};