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.
This commit is contained in:
parent
f200eae2bd
commit
ac8b5922ad
@ -338,6 +338,7 @@ bool AdbUtils::makeTap(const QString &deviceId, const int x, const int y) {
|
|||||||
|
|
||||||
bool AdbUtils::enableAdbIMEKeyboard(const QString &deviceId) {
|
bool AdbUtils::enableAdbIMEKeyboard(const QString &deviceId) {
|
||||||
const QString adb = adbPath();
|
const QString adb = adbPath();
|
||||||
|
const QString imeId = QStringLiteral("com.android.adbkeyboard/.AdbIME");
|
||||||
|
|
||||||
// Проверяем, установлен ли ADB Keyboard
|
// Проверяем, установлен ли ADB Keyboard
|
||||||
QString installedList;
|
QString installedList;
|
||||||
@ -353,20 +354,63 @@ bool AdbUtils::enableAdbIMEKeyboard(const QString &deviceId) {
|
|||||||
qDebug() << "[AdbUtils] ADB Keyboard installed successfully";
|
qDebug() << "[AdbUtils] ADB Keyboard installed successfully";
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Step { QStringList args; };
|
// Пакет мог быть отключён производителем (pm disable-user).
|
||||||
Step steps[] = {
|
// Пытаемся включить; ошибку не считаем фатальной (на некоторых прошивках команда
|
||||||
{{"-s", deviceId, "shell", "ime", "enable", "com.android.adbkeyboard/.AdbIME"}},
|
// отвергается, но сам IME при этом включается).
|
||||||
{{"-s", deviceId, "shell", "ime", "set", "com.android.adbkeyboard/.AdbIME"}}
|
{
|
||||||
};
|
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) {
|
// ime enable
|
||||||
QString stdErr;
|
{
|
||||||
if (!startProcess(adb, step.args, nullptr, &stdErr)) {
|
QString out, err;
|
||||||
qWarning() << "ADB command failed:" << step.args.join(' ');
|
if (!startProcess(adb, {"-s", deviceId, "shell", "ime", "enable", imeId}, &out, &err)) {
|
||||||
qWarning() << "Error:" << stdErr;
|
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;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -315,7 +315,11 @@ void PayByPhoneScript::makePayment(
|
|||||||
QThread::msleep(500);
|
QThread::msleep(500);
|
||||||
|
|
||||||
// Ввод кириллицы через ADB Keyboard
|
// Ввод кириллицы через 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);
|
QThread::msleep(500);
|
||||||
AdbUtils::makeTap(deviceId, bankInput.x(), bankInput.y());
|
AdbUtils::makeTap(deviceId, bankInput.x(), bankInput.y());
|
||||||
QThread::msleep(500);
|
QThread::msleep(500);
|
||||||
|
|||||||
@ -149,7 +149,31 @@ Node ScreenXmlParser::findEditTextByHint(const QString &hintPrefix) {
|
|||||||
return node;
|
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) {
|
Node ScreenXmlParser::findButtonNode(const QString &text, const bool contains) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user