1
0
forked from BRT/arc

Add closeGooglePlayBannerIfVisible helper to handle update banners and permission dialogs. Integrate into card info scripts for automated dismissal during screen parsing. Extend ScreenXmlParser with methods to detect specific UI elements.

This commit is contained in:
slava 2026-05-13 16:01:26 +07:00
parent abcc3cadb2
commit 72d582f0ab
7 changed files with 89 additions and 0 deletions

View File

@ -261,4 +261,26 @@ void CommonScript::stop() {
m_running = false; m_running = false;
} }
bool CommonScript::closeGooglePlayBannerIfVisible(
const QString &deviceId, const int width, const int height
) {
// 1. Системный диалог запроса разрешения Android (permissioncontroller) — тапаем "ЗАПРЕТИТЬ"
if (Node denyBtn = xmlScreenParser.tryToFindSystemPermissionDenyButton(); !denyBtn.isEmpty()) {
qDebug() << "[Black] System permission dialog detected mid-task, tapping 'ЗАПРЕТИТЬ'...";
AdbUtils::makeTap(deviceId, denyBtn.x(), denyBtn.y());
QThread::msleep(1500);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
return true;
}
// 2. Google Play in-app update bottom sheet
Node gpNode = xmlScreenParser.tryToFindGooglePlayBanner(width, height);
if (gpNode.isEmpty()) return false;
qDebug() << "[Black] Google Play update banner detected mid-task, closing...";
AdbUtils::makeTap(deviceId, gpNode.x(), gpNode.y());
QThread::msleep(1500);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
return true;
}
} // namespace Black } // namespace Black

View File

@ -49,6 +49,13 @@ protected:
// Создаёт bank_profile на сервере если ещё не создан // Создаёт bank_profile на сервере если ещё не создан
void createBankProfileIfNeeded(const QString &deviceId, const QString &appCode, double parsedBalance = -1.0); void createBankProfileIfNeeded(const QString &deviceId, const QString &appCode, double parsedBalance = -1.0);
// Если виден баннер Google Play "Доступно обновление" или системный
// диалог разрешений — закрывает его и перепарсивает XML. Безопасно
// вызывать на любом экране; возвращает true если что-то было закрыто.
bool closeGooglePlayBannerIfVisible(
const QString &deviceId, int width, int height
);
bool m_running = true; bool m_running = true;
ScreenXmlParser xmlScreenParser; ScreenXmlParser xmlScreenParser;
int m_counter = 0; int m_counter = 0;

View File

@ -41,6 +41,7 @@ void GetCardInfoScript::doStart() {
// Читаем текущий экран // Читаем текущий экран
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
// Если не на домашнем экране — перезапускаем // Если не на домашнем экране — перезапускаем
if (!xmlScreenParser.isHomeScreen()) { if (!xmlScreenParser.isHomeScreen()) {
@ -54,6 +55,7 @@ void GetCardInfoScript::doStart() {
return; return;
} }
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
} }
// 1. Парсим баланс с домашнего экрана // 1. Парсим баланс с домашнего экрана
@ -78,6 +80,7 @@ void GetCardInfoScript::doStart() {
bool cvuScreenFound = false; bool cvuScreenFound = false;
for (int attempt = 0; attempt < 5; ++attempt) { for (int attempt = 0; attempt < 5; ++attempt) {
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
if (xmlScreenParser.isCVUScreen()) { if (xmlScreenParser.isCVUScreen()) {
cvuScreenFound = true; cvuScreenFound = true;
break; break;

View File

@ -542,4 +542,37 @@ Node ScreenXmlParser::findEditTextByHint(const QString &hint) {
return {}; return {};
} }
Node ScreenXmlParser::tryToFindGooglePlayBanner(const int screenWidth, const int screenHeight) {
for (const Node &node : m_nodes) {
if (node.contentDesc.contains("Закрыть диалоговое окно") && node.clickable) {
return node;
}
}
for (const Node &node : m_nodes) {
if (node.contentDesc.contains("Доступно обновление")) {
Node tapNode;
const int cx = screenWidth / 2;
const int cy = screenHeight / 20;
tapNode.setBounds(cx, cy, cx + 1, cy + 1);
return tapNode;
}
}
return {};
}
Node ScreenXmlParser::tryToFindSystemPermissionDenyButton() {
for (const Node &node : m_nodes) {
if (node.resourceId == "com.android.permissioncontroller:id/permission_deny_button"
&& node.clickable) {
return node;
}
}
for (const Node &node : m_nodes) {
if (node.clickable && node.text.trimmed() == QString::fromUtf8("ЗАПРЕТИТЬ")) {
return node;
}
}
return {};
}
} // namespace Black } // namespace Black

View File

@ -110,6 +110,13 @@ public:
// Находит EditText по hint // Находит EditText по hint
Node findEditTextByHint(const QString &hint); Node findEditTextByHint(const QString &hint);
// Находит кнопку закрытия Google Play in-app update bottom sheet
// ("com.android.vending" оверлей "Доступно обновление"), если он показан
Node tryToFindGooglePlayBanner(int screenWidth, int screenHeight);
// Находит кнопку "ЗАПРЕТИТЬ" в системном диалоге разрешений Android
Node tryToFindSystemPermissionDenyButton();
private: private:
QList<Node> m_nodes; QList<Node> m_nodes;
QDomElement m_xml; QDomElement m_xml;

View File

@ -39,6 +39,7 @@ void GetCardInfoScript::doStart() {
TaskDumpRecorder::Scope dumpScope("dushanbe", "FETCH_CARDS", m_deviceId, dumpMeta, &m_error); TaskDumpRecorder::Scope dumpScope("dushanbe", "FETCH_CARDS", m_deviceId, dumpMeta, &m_error);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
if (!xmlScreenParser.isHomeScreen()) { if (!xmlScreenParser.isHomeScreen()) {
qDebug() << "[Dushanbe::GetCardInfo] Not on home screen, restarting app..."; qDebug() << "[Dushanbe::GetCardInfo] Not on home screen, restarting app...";
@ -51,6 +52,7 @@ void GetCardInfoScript::doStart() {
return; return;
} }
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
} }
// Парсим баланс с домашнего экрана // Парсим баланс с домашнего экрана
@ -77,6 +79,7 @@ void GetCardInfoScript::doStart() {
bool cardsScreenFound = false; bool cardsScreenFound = false;
for (int attempt = 0; attempt < 5; ++attempt) { for (int attempt = 0; attempt < 5; ++attempt) {
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
if (xmlScreenParser.isCardsScreen()) { if (xmlScreenParser.isCardsScreen()) {
cardsScreenFound = true; cardsScreenFound = true;
break; break;
@ -127,6 +130,7 @@ void GetCardInfoScript::doStart() {
bool detailFound = false; bool detailFound = false;
for (int attempt = 0; attempt < 5; ++attempt) { for (int attempt = 0; attempt < 5; ++attempt) {
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
if (xmlScreenParser.isCardDetailScreen()) { if (xmlScreenParser.isCardDetailScreen()) {
detailFound = true; detailFound = true;
break; break;
@ -142,6 +146,7 @@ void GetCardInfoScript::doStart() {
// Ждём загрузки баланса (может быть 0 пока данные подтягиваются) // Ждём загрузки баланса (может быть 0 пока данные подтягиваются)
QThread::msleep(1500); QThread::msleep(1500);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
QString fullNumber = xmlScreenParser.parseFullCardNumber(); QString fullNumber = xmlScreenParser.parseFullCardNumber();
const double cardBalance = xmlScreenParser.parseCardDetailBalance(); const double cardBalance = xmlScreenParser.parseCardDetailBalance();
@ -283,6 +288,7 @@ void GetCardInfoScript::doStart() {
// Ждём возврата на экран "Мои карты" // Ждём возврата на экран "Мои карты"
for (int attempt = 0; attempt < 5; ++attempt) { for (int attempt = 0; attempt < 5; ++attempt) {
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
if (xmlScreenParser.isCardsScreen()) break; if (xmlScreenParser.isCardsScreen()) break;
QThread::msleep(1000); QThread::msleep(1000);
} }

View File

@ -90,6 +90,7 @@ void GetCardInfoScript::doStart() {
for (int attempt = 0; attempt < 5; ++attempt) { for (int attempt = 0; attempt < 5; ++attempt) {
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
if (xmlScreenParser.isProfileScreen()) break; if (xmlScreenParser.isProfileScreen()) break;
QThread::msleep(1000); QThread::msleep(1000);
} }
@ -106,12 +107,14 @@ void GetCardInfoScript::doStart() {
AdbUtils::goBack(m_deviceId); AdbUtils::goBack(m_deviceId);
QThread::msleep(1500); QThread::msleep(1500);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
} else { } else {
qDebug() << "[GetCardInfo] Profile info already in DB or username not found, skipping profile parse"; qDebug() << "[GetCardInfo] Profile info already in DB or username not found, skipping profile parse";
} }
// Проверяем что на домашнем экране перед поиском карт // Проверяем что на домашнем экране перед поиском карт
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
if (!xmlScreenParser.isHomeScreen()) { if (!xmlScreenParser.isHomeScreen()) {
qDebug() << "[GetCardInfo] Not on home screen before card search, restarting..."; qDebug() << "[GetCardInfo] Not on home screen before card search, restarting...";
if (!runAppAndGoToHomeScreen(m_deviceId, app.package, app.pinCode, if (!runAppAndGoToHomeScreen(m_deviceId, app.package, app.pinCode,
@ -130,6 +133,9 @@ void GetCardInfoScript::doStart() {
QList<MaterialInfo> cards; QList<MaterialInfo> cards;
for (int attempt = 0; attempt < 5; ++attempt) { for (int attempt = 0; attempt < 5; ++attempt) {
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
if (closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight)) {
// баннер закрыт, дамп уже обновлён внутри helper'а
}
cards = xmlScreenParser.parseCardsOnHomeScreen(); cards = xmlScreenParser.parseCardsOnHomeScreen();
if (!cards.isEmpty()) break; if (!cards.isEmpty()) break;
qDebug() << "[GetCardInfo] No cards found on home screen, attempt" << attempt + 1 << "/ 5"; qDebug() << "[GetCardInfo] No cards found on home screen, attempt" << attempt + 1 << "/ 5";
@ -262,6 +268,7 @@ void GetCardInfoScript::doStart() {
for (int scrollAttempt = 0; scrollAttempt < 6; ++scrollAttempt) { for (int scrollAttempt = 0; scrollAttempt < 6; ++scrollAttempt) {
QThread::msleep(scrollAttempt == 0 ? 2000 : 600); QThread::msleep(scrollAttempt == 0 ? 2000 : 600);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
Node candidate = xmlScreenParser.findButtonNode("Показать", false); Node candidate = xmlScreenParser.findButtonNode("Показать", false);
if (candidate.isEmpty()) { if (candidate.isEmpty()) {
@ -293,6 +300,7 @@ void GetCardInfoScript::doStart() {
for (int attempt = 0; attempt < 10; ++attempt) { for (int attempt = 0; attempt < 10; ++attempt) {
QThread::msleep(attempt == 0 ? 2000 : 500); QThread::msleep(attempt == 0 ? 2000 : 500);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
Node candidate = xmlScreenParser.findButtonNode("Показать", false); Node candidate = xmlScreenParser.findButtonNode("Показать", false);
Node requisites = xmlScreenParser.findTextNode("Реквизиты карты"); Node requisites = xmlScreenParser.findTextNode("Реквизиты карты");
@ -332,6 +340,7 @@ void GetCardInfoScript::doStart() {
AdbUtils::goBack(m_deviceId); AdbUtils::goBack(m_deviceId);
QThread::msleep(1500); QThread::msleep(1500);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
continue; continue;
} }
@ -343,6 +352,7 @@ void GetCardInfoScript::doStart() {
for (int attempt = 0; attempt < 10; ++attempt) { for (int attempt = 0; attempt < 10; ++attempt) {
QThread::msleep(2000); QThread::msleep(2000);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
cardNumber = xmlScreenParser.findFullCardNumber(); cardNumber = xmlScreenParser.findFullCardNumber();
if (!cardNumber.isEmpty()) { if (!cardNumber.isEmpty()) {
qDebug() << "[GetCardInfo] Card number found on attempt" << attempt + 1; qDebug() << "[GetCardInfo] Card number found on attempt" << attempt + 1;
@ -411,6 +421,7 @@ void GetCardInfoScript::doStart() {
AdbUtils::goBack(m_deviceId); AdbUtils::goBack(m_deviceId);
QThread::msleep(2000); QThread::msleep(2000);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
} }
} }