From ac8b5922addcdd364b1c0d9a1459d35d8d08dc99 Mon Sep 17 00:00:00 2001 From: slava Date: Fri, 24 Apr 2026 21:31:37 +0700 Subject: [PATCH] Enable reliable activation of ADB Keyboard and improve fallback handling: - Add comprehensive verification and logging for IME activation steps in `AdbUtils`. - Update `PayByPhoneScript` to handle IME activation failures with error reporting. - Improve edit text detection in `ScreenXmlParser` for devices with missing hint attributes. --- android/adb/AdbUtils.cpp | 64 ++++++++++++++++++++++++++----- android/ozon/PayByPhoneScript.cpp | 6 ++- android/ozon/ScreenXmlParser.cpp | 26 ++++++++++++- 3 files changed, 84 insertions(+), 12 deletions(-) diff --git a/android/adb/AdbUtils.cpp b/android/adb/AdbUtils.cpp index 7ea4079..ac2fc18 100644 --- a/android/adb/AdbUtils.cpp +++ b/android/adb/AdbUtils.cpp @@ -338,6 +338,7 @@ bool AdbUtils::makeTap(const QString &deviceId, const int x, const int y) { bool AdbUtils::enableAdbIMEKeyboard(const QString &deviceId) { const QString adb = adbPath(); + const QString imeId = QStringLiteral("com.android.adbkeyboard/.AdbIME"); // Проверяем, установлен ли ADB Keyboard QString installedList; @@ -353,20 +354,63 @@ bool AdbUtils::enableAdbIMEKeyboard(const QString &deviceId) { qDebug() << "[AdbUtils] ADB Keyboard installed successfully"; } - struct Step { QStringList args; }; - Step steps[] = { - {{"-s", deviceId, "shell", "ime", "enable", "com.android.adbkeyboard/.AdbIME"}}, - {{"-s", deviceId, "shell", "ime", "set", "com.android.adbkeyboard/.AdbIME"}} - }; + // Пакет мог быть отключён производителем (pm disable-user). + // Пытаемся включить; ошибку не считаем фатальной (на некоторых прошивках команда + // отвергается, но сам IME при этом включается). + { + QString pmOut, pmErr; + if (!startProcess(adb, {"-s", deviceId, "shell", "pm", "enable", "com.android.adbkeyboard"}, &pmOut, &pmErr)) { + qWarning() << "[AdbUtils] pm enable com.android.adbkeyboard failed:" << pmErr.trimmed() + << "(продолжаем)"; + } + } - for (const auto &step : steps) { - QString stdErr; - if (!startProcess(adb, step.args, nullptr, &stdErr)) { - qWarning() << "ADB command failed:" << step.args.join(' '); - qWarning() << "Error:" << stdErr; + // ime enable + { + QString out, err; + if (!startProcess(adb, {"-s", deviceId, "shell", "ime", "enable", imeId}, &out, &err)) { + qWarning() << "[AdbUtils] ime enable failed:" << err.trimmed(); + return false; + } + qDebug() << "[AdbUtils] ime enable:" << out.trimmed(); + } + + // Верификация: IME должен появиться в списке разрешённых + { + QString enabledList; + startProcess(adb, {"-s", deviceId, "shell", "ime", "list", "-s"}, &enabledList); + if (!enabledList.contains(imeId)) { + qWarning() << "[AdbUtils] ADB Keyboard отсутствует в 'ime list -s' после 'ime enable'." + << "Вывод:" << enabledList.trimmed() + << "(прошивка/OEM может блокировать сторонние IME)"; return false; } } + + // ime set + { + QString out, err; + if (!startProcess(adb, {"-s", deviceId, "shell", "ime", "set", imeId}, &out, &err)) { + qWarning() << "[AdbUtils] ime set failed:" << err.trimmed(); + return false; + } + qDebug() << "[AdbUtils] ime set:" << out.trimmed(); + } + + // Верификация: активный IME должен совпасть с нашим + { + QString defaultIme; + startProcess(adb, {"-s", deviceId, "shell", "settings", "get", "secure", "default_input_method"}, &defaultIme); + const QString trimmed = defaultIme.trimmed(); + if (!trimmed.contains(imeId)) { + qWarning() << "[AdbUtils] default_input_method =" << trimmed + << "— ожидали" << imeId + << "(прошивка откатывает смену IME)"; + return false; + } + qDebug() << "[AdbUtils] Active IME verified:" << trimmed; + } + return true; } diff --git a/android/ozon/PayByPhoneScript.cpp b/android/ozon/PayByPhoneScript.cpp index 9d49aad..470031d 100644 --- a/android/ozon/PayByPhoneScript.cpp +++ b/android/ozon/PayByPhoneScript.cpp @@ -315,7 +315,11 @@ void PayByPhoneScript::makePayment( QThread::msleep(500); // Ввод кириллицы через ADB Keyboard - AdbUtils::enableAdbIMEKeyboard(deviceId); + if (!AdbUtils::enableAdbIMEKeyboard(deviceId)) { + m_error = "Не удалось активировать ADB Keyboard (см. логи 'ime list -s' / default_input_method)"; + qWarning() << "[PayByPhone]" << m_error; + return; + } QThread::msleep(500); AdbUtils::makeTap(deviceId, bankInput.x(), bankInput.y()); QThread::msleep(500); diff --git a/android/ozon/ScreenXmlParser.cpp b/android/ozon/ScreenXmlParser.cpp index fdf20ca..886e6db 100644 --- a/android/ozon/ScreenXmlParser.cpp +++ b/android/ozon/ScreenXmlParser.cpp @@ -149,7 +149,31 @@ Node ScreenXmlParser::findEditTextByHint(const QString &hintPrefix) { return node; } } - return {}; + // Некоторые устройства/прошивки (напр. Infinix) в uiautomator-дампе не отдают + // атрибут hint для EditText внутри WebView. В этом случае ищем TextView-label + // с нужным текстом и ближайший к нему EditText с горизонтальным перекрытием. + Node label; + for (const Node &node : m_nodes) { + if (node.className == "android.widget.TextView" && node.text.contains(hintPrefix)) { + label = node; + break; + } + } + if (label.isEmpty()) return {}; + + Node best; + int bestDy = INT_MAX; + for (const Node &node : m_nodes) { + if (node.className != "android.widget.EditText") continue; + const bool hOverlap = node.x1() < label.x2() && node.x2() > label.x1(); + if (!hOverlap) continue; + const int dy = std::abs(node.y() - label.y()); + if (dy < bestDy) { + bestDy = dy; + best = node; + } + } + return best; } Node ScreenXmlParser::findButtonNode(const QString &text, const bool contains) {